| |
| /* |
| * 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; |
| } |