summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Homutov <vl@nginx.com>2018-03-22 15:55:28 +0300
committerVladimir Homutov <vl@nginx.com>2018-03-22 15:55:28 +0300
commit9207cc84b21e94283478cee7a953b1859c4434cb (patch)
tree28ffbae8a2a37892eac272b2d3bf328895c7b3dc
parentf39d5e8b33d507f95e800a6d6301da510a72a3af (diff)
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).
-rw-r--r--src/core/ngx_proxy_protocol.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/core/ngx_proxy_protocol.c b/src/core/ngx_proxy_protocol.c
index 523ec35dd..e9a6bcca8 100644
--- a/src/core/ngx_proxy_protocol.c
+++ b/src/core/ngx_proxy_protocol.c
@@ -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 *c, u_char *buf, u_char *last)
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_t *c, u_char *buf, u_char *last)
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;
+}