[nginx] Core: added processing of version 2 of the PROXY protocol.

Vladimir Homutov vl at nginx.com
Mon Mar 26 19:58:47 UTC 2018


details:   http://hg.nginx.org/nginx/rev/416953ef0428
branches:  
changeset: 7251:416953ef0428
user:      Vladimir Homutov <vl at nginx.com>
date:      Thu Mar 22 15:55:28 2018 +0300
description:
Core: added processing of version 2 of the PROXY protocol.

The protocol used on inbound connection is auto-detected and corresponding
parser is used to extract passed addresses.  TLV parameters are ignored.

The maximum supported size of PROXY protocol header is 107 bytes
(similar to version 1).

diffstat:

 src/core/ngx_proxy_protocol.c |  192 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 192 insertions(+), 0 deletions(-)

diffs (213 lines):

diff -r ec4d95eed062 -r 416953ef0428 src/core/ngx_proxy_protocol.c
--- a/src/core/ngx_proxy_protocol.c	Thu Mar 22 18:43:49 2018 +0300
+++ b/src/core/ngx_proxy_protocol.c	Thu Mar 22 15:55:28 2018 +0300
@@ -9,6 +9,57 @@
 #include <ngx_core.h>
 
 
+#define NGX_PP_V2_SIGLEN         12
+#define NGX_PP_V2_CMD_PROXY      1
+#define NGX_PP_V2_STREAM         1
+
+#define NGX_PP_V2_AF_UNSPEC      0
+#define NGX_PP_V2_AF_INET        1
+#define NGX_PP_V2_AF_INET6       2
+
+
+#define ngx_pp_v2_get_u16(p)                                                  \
+    ( ((uint16_t) ((u_char *) (p))[0] << 8)                                   \
+    + (           ((u_char *) (p))[1]) )
+
+
+typedef struct {
+    u_char                       signature[NGX_PP_V2_SIGLEN];
+    u_char                       ver_cmd;
+    u_char                       fam_transp;
+    u_char                       len[2];
+} ngx_pp_v2_header_t;
+
+
+typedef struct {
+    u_char                       src[4];
+    u_char                       dst[4];
+    u_char                       sport[2];
+    u_char                       dport[2];
+} ngx_pp_v2_inet_addrs_t;
+
+
+typedef struct {
+    u_char                       src[16];
+    u_char                       dst[16];
+    u_char                       sport[2];
+    u_char                       dport[2];
+} ngx_pp_v2_inet6_addrs_t;
+
+
+typedef union {
+    ngx_pp_v2_inet_addrs_t       inet;
+    ngx_pp_v2_inet6_addrs_t      inet6;
+} ngx_pp_v2_addrs_t;
+
+
+static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
+    u_char *last);
+
+static const u_char ngx_pp_v2_signature[NGX_PP_V2_SIGLEN] =
+    { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };
+
+
 u_char *
 ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
 {
@@ -19,6 +70,12 @@ ngx_proxy_protocol_read(ngx_connection_t
     p = buf;
     len = last - buf;
 
+    if (len >= sizeof(ngx_pp_v2_header_t)
+        && memcmp(p, ngx_pp_v2_signature, NGX_PP_V2_SIGLEN) == 0)
+    {
+        return ngx_proxy_protocol_v2_read(c, buf, last);
+    }
+
     if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
         goto invalid;
     }
@@ -166,3 +223,138 @@ ngx_proxy_protocol_write(ngx_connection_
 
     return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
 }
+
+
+static u_char *
+ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
+{
+    u_char              *end;
+    size_t               len;
+    socklen_t            socklen;
+    ngx_str_t           *name;
+    ngx_uint_t           ver, cmd, family, transport;
+    ngx_sockaddr_t       sockaddr;
+    ngx_pp_v2_addrs_t   *addrs;
+    ngx_pp_v2_header_t  *hdr;
+
+    hdr = (ngx_pp_v2_header_t *) buf;
+
+    buf += sizeof(ngx_pp_v2_header_t);
+
+    ver = hdr->ver_cmd >> 4;
+
+    if (ver != 2) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                      "unsupported PROXY protocol version: %ui", ver);
+        return NULL;
+    }
+
+    len = ngx_pp_v2_get_u16(hdr->len);
+
+    if ((size_t) (last - buf) < len) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large");
+        return NULL;
+    }
+
+    end = buf + len;
+
+    cmd = hdr->ver_cmd & 0x0F;
+
+    if (cmd != NGX_PP_V2_CMD_PROXY) {
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+                       "PROXY protocol v2 unsupported cmd 0x%xi", cmd);
+        return end;
+    }
+
+    transport = hdr->fam_transp & 0x0F;
+
+    if (transport != NGX_PP_V2_STREAM) {
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+                       "PROXY protocol v2 unsupported transport 0x%xi",
+                       transport);
+        return end;
+    }
+
+    family = hdr->fam_transp >> 4;
+
+    addrs = (ngx_pp_v2_addrs_t *) buf;
+
+    switch (family) {
+
+    case NGX_PP_V2_AF_UNSPEC:
+        ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
+                       "PROXY protocol v2 AF_UNSPEC ignored");
+        return end;
+
+    case NGX_PP_V2_AF_INET:
+
+        if ((size_t) (end - buf) < sizeof(ngx_pp_v2_inet_addrs_t)) {
+            return NULL;
+        }
+
+        sockaddr.sockaddr_in.sin_family = AF_INET;
+        sockaddr.sockaddr_in.sin_port = 0;
+        memcpy(&sockaddr.sockaddr_in.sin_addr, addrs->inet.src, 4);
+
+        c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet.sport);
+
+        socklen = sizeof(struct sockaddr_in);
+
+        buf += sizeof(ngx_pp_v2_inet_addrs_t);
+
+        break;
+
+#if (NGX_HAVE_INET6)
+
+    case NGX_PP_V2_AF_INET6:
+
+        if ((size_t) (end - buf) <  sizeof(ngx_pp_v2_inet6_addrs_t)) {
+            return NULL;
+        }
+
+        sockaddr.sockaddr_in6.sin6_family = AF_INET6;
+        sockaddr.sockaddr_in6.sin6_port = 0;
+        memcpy(&sockaddr.sockaddr_in6.sin6_addr, addrs->inet6.src, 16);
+
+        c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet6.sport);
+
+        socklen = sizeof(struct sockaddr_in6);
+
+        buf += sizeof(ngx_pp_v2_inet6_addrs_t);
+
+        break;
+
+#endif
+
+    default:
+
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+                       "PROXY_protocol v2 unsupported address family "
+                       "0x%xi", family);
+        return end;
+    }
+
+    name = &c->proxy_protocol_addr;
+
+    name->data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
+    if (name->data == NULL) {
+        return NULL;
+    }
+
+    name->len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, name->data,
+                              NGX_SOCKADDR_STRLEN, 0);
+    if (name->len == 0) {
+        return NULL;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
+                   "PROXY protocol v2 address: %V %i", name,
+                   (ngx_int_t) c->proxy_protocol_port);
+
+    if (buf < end) {
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+                       "PROXY protocol v2 %z bytes tlv ignored", end - buf);
+    }
+
+    return end;
+}


More information about the nginx-devel mailing list