|  |  | 
|  | /* | 
|  | * Copyright (C) Roman Arutyunyan | 
|  | * Copyright (C) Nginx, Inc. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <ngx_config.h> | 
|  | #include <ngx_core.h> | 
|  |  | 
|  |  | 
|  | u_char * | 
|  | ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, u_char *last) | 
|  | { | 
|  | size_t  len; | 
|  | u_char  ch, *p, *addr; | 
|  |  | 
|  | p = buf; | 
|  | len = last - buf; | 
|  |  | 
|  | if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) { | 
|  | goto invalid; | 
|  | } | 
|  |  | 
|  | p += 6; | 
|  | len -= 6; | 
|  |  | 
|  | if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) { | 
|  | ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, | 
|  | "PROXY protocol unknown protocol"); | 
|  | p += 7; | 
|  | goto skip; | 
|  | } | 
|  |  | 
|  | if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0 | 
|  | || (p[3] != '4' && p[3] != '6') || p[4] != ' ') | 
|  | { | 
|  | goto invalid; | 
|  | } | 
|  |  | 
|  | p += 5; | 
|  | addr = p; | 
|  |  | 
|  | for ( ;; ) { | 
|  | if (p == last) { | 
|  | goto invalid; | 
|  | } | 
|  |  | 
|  | ch = *p++; | 
|  |  | 
|  | if (ch == ' ') { | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (ch != ':' && ch != '.' | 
|  | && (ch < 'a' || ch > 'f') | 
|  | && (ch < 'A' || ch > 'F') | 
|  | && (ch < '0' || ch > '9')) | 
|  | { | 
|  | goto invalid; | 
|  | } | 
|  | } | 
|  |  | 
|  | len = p - addr - 1; | 
|  | c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len); | 
|  |  | 
|  | if (c->proxy_protocol_addr.data == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | ngx_memcpy(c->proxy_protocol_addr.data, addr, len); | 
|  | c->proxy_protocol_addr.len = len; | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, | 
|  | "PROXY protocol address: \"%V\"", &c->proxy_protocol_addr); | 
|  |  | 
|  | skip: | 
|  |  | 
|  | for ( /* void */ ; p < last - 1; p++) { | 
|  | if (p[0] == CR && p[1] == LF) { | 
|  | return p + 2; | 
|  | } | 
|  | } | 
|  |  | 
|  | invalid: | 
|  |  | 
|  | ngx_log_error(NGX_LOG_ERR, c->log, 0, | 
|  | "broken header: \"%*s\"", (size_t) (last - buf), buf); | 
|  |  | 
|  | return NULL; | 
|  | } |