Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.2 ]​

0001 
0002 /*
0003  * Copyright (C) Roman Arutyunyan
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 
0011 
0012 #define NGX_PROXY_PROTOCOL_AF_INET          1
0013 #define NGX_PROXY_PROTOCOL_AF_INET6         2
0014 
0015 
0016 #define ngx_proxy_protocol_parse_uint16(p)  ((p)[0] << 8 | (p)[1])
0017 
0018 
0019 typedef struct {
0020     u_char                                  signature[12];
0021     u_char                                  version_command;
0022     u_char                                  family_transport;
0023     u_char                                  len[2];
0024 } ngx_proxy_protocol_header_t;
0025 
0026 
0027 typedef struct {
0028     u_char                                  src_addr[4];
0029     u_char                                  dst_addr[4];
0030     u_char                                  src_port[2];
0031     u_char                                  dst_port[2];
0032 } ngx_proxy_protocol_inet_addrs_t;
0033 
0034 
0035 typedef struct {
0036     u_char                                  src_addr[16];
0037     u_char                                  dst_addr[16];
0038     u_char                                  src_port[2];
0039     u_char                                  dst_port[2];
0040 } ngx_proxy_protocol_inet6_addrs_t;
0041 
0042 
0043 static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
0044     u_char *last);
0045 
0046 
0047 u_char *
0048 ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
0049 {
0050     size_t     len;
0051     u_char     ch, *p, *addr, *port;
0052     ngx_int_t  n;
0053 
0054     static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n";
0055 
0056     p = buf;
0057     len = last - buf;
0058 
0059     if (len >= sizeof(ngx_proxy_protocol_header_t)
0060         && memcmp(p, signature, sizeof(signature) - 1) == 0)
0061     {
0062         return ngx_proxy_protocol_v2_read(c, buf, last);
0063     }
0064 
0065     if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
0066         goto invalid;
0067     }
0068 
0069     p += 6;
0070     len -= 6;
0071 
0072     if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) {
0073         ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
0074                        "PROXY protocol unknown protocol");
0075         p += 7;
0076         goto skip;
0077     }
0078 
0079     if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0
0080         || (p[3] != '4' && p[3] != '6') || p[4] != ' ')
0081     {
0082         goto invalid;
0083     }
0084 
0085     p += 5;
0086     addr = p;
0087 
0088     for ( ;; ) {
0089         if (p == last) {
0090             goto invalid;
0091         }
0092 
0093         ch = *p++;
0094 
0095         if (ch == ' ') {
0096             break;
0097         }
0098 
0099         if (ch != ':' && ch != '.'
0100             && (ch < 'a' || ch > 'f')
0101             && (ch < 'A' || ch > 'F')
0102             && (ch < '0' || ch > '9'))
0103         {
0104             goto invalid;
0105         }
0106     }
0107 
0108     len = p - addr - 1;
0109     c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len);
0110 
0111     if (c->proxy_protocol_addr.data == NULL) {
0112         return NULL;
0113     }
0114 
0115     ngx_memcpy(c->proxy_protocol_addr.data, addr, len);
0116     c->proxy_protocol_addr.len = len;
0117 
0118     for ( ;; ) {
0119         if (p == last) {
0120             goto invalid;
0121         }
0122 
0123         if (*p++ == ' ') {
0124             break;
0125         }
0126     }
0127 
0128     port = p;
0129 
0130     for ( ;; ) {
0131         if (p == last) {
0132             goto invalid;
0133         }
0134 
0135         if (*p++ == ' ') {
0136             break;
0137         }
0138     }
0139 
0140     len = p - port - 1;
0141 
0142     n = ngx_atoi(port, len);
0143 
0144     if (n < 0 || n > 65535) {
0145         goto invalid;
0146     }
0147 
0148     c->proxy_protocol_port = (in_port_t) n;
0149 
0150     ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
0151                    "PROXY protocol address: %V %d", &c->proxy_protocol_addr,
0152                    c->proxy_protocol_port);
0153 
0154 skip:
0155 
0156     for ( /* void */ ; p < last - 1; p++) {
0157         if (p[0] == CR && p[1] == LF) {
0158             return p + 2;
0159         }
0160     }
0161 
0162 invalid:
0163 
0164     ngx_log_error(NGX_LOG_ERR, c->log, 0,
0165                   "broken header: \"%*s\"", (size_t) (last - buf), buf);
0166 
0167     return NULL;
0168 }
0169 
0170 
0171 u_char *
0172 ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
0173 {
0174     ngx_uint_t  port, lport;
0175 
0176     if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) {
0177         return NULL;
0178     }
0179 
0180     if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
0181         return NULL;
0182     }
0183 
0184     switch (c->sockaddr->sa_family) {
0185 
0186     case AF_INET:
0187         buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1);
0188         break;
0189 
0190 #if (NGX_HAVE_INET6)
0191     case AF_INET6:
0192         buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1);
0193         break;
0194 #endif
0195 
0196     default:
0197         return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF,
0198                           sizeof("PROXY UNKNOWN" CRLF) - 1);
0199     }
0200 
0201     buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0);
0202 
0203     *buf++ = ' ';
0204 
0205     buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf,
0206                          0);
0207 
0208     port = ngx_inet_get_port(c->sockaddr);
0209     lport = ngx_inet_get_port(c->local_sockaddr);
0210 
0211     return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
0212 }
0213 
0214 
0215 static u_char *
0216 ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
0217 {
0218     u_char                             *end;
0219     size_t                              len;
0220     socklen_t                           socklen;
0221     ngx_uint_t                          version, command, family, transport;
0222     ngx_sockaddr_t                      sockaddr;
0223     ngx_proxy_protocol_header_t        *header;
0224     ngx_proxy_protocol_inet_addrs_t    *in;
0225 #if (NGX_HAVE_INET6)
0226     ngx_proxy_protocol_inet6_addrs_t   *in6;
0227 #endif
0228 
0229     header = (ngx_proxy_protocol_header_t *) buf;
0230 
0231     buf += sizeof(ngx_proxy_protocol_header_t);
0232 
0233     version = header->version_command >> 4;
0234 
0235     if (version != 2) {
0236         ngx_log_error(NGX_LOG_ERR, c->log, 0,
0237                       "unknown PROXY protocol version: %ui", version);
0238         return NULL;
0239     }
0240 
0241     len = ngx_proxy_protocol_parse_uint16(header->len);
0242 
0243     if ((size_t) (last - buf) < len) {
0244         ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large");
0245         return NULL;
0246     }
0247 
0248     end = buf + len;
0249 
0250     command = header->version_command & 0x0f;
0251 
0252     /* only PROXY is supported */
0253     if (command != 1) {
0254         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0255                        "PROXY protocol v2 unsupported command %ui", command);
0256         return end;
0257     }
0258 
0259     transport = header->family_transport & 0x0f;
0260 
0261     /* only STREAM is supported */
0262     if (transport != 1) {
0263         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0264                        "PROXY protocol v2 unsupported transport %ui",
0265                        transport);
0266         return end;
0267     }
0268 
0269     family = header->family_transport >> 4;
0270 
0271     switch (family) {
0272 
0273     case NGX_PROXY_PROTOCOL_AF_INET:
0274 
0275         if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet_addrs_t)) {
0276             return NULL;
0277         }
0278 
0279         in = (ngx_proxy_protocol_inet_addrs_t *) buf;
0280 
0281         sockaddr.sockaddr_in.sin_family = AF_INET;
0282         sockaddr.sockaddr_in.sin_port = 0;
0283         memcpy(&sockaddr.sockaddr_in.sin_addr, in->src_addr, 4);
0284 
0285         c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in->src_port);
0286 
0287         socklen = sizeof(struct sockaddr_in);
0288 
0289         buf += sizeof(ngx_proxy_protocol_inet_addrs_t);
0290 
0291         break;
0292 
0293 #if (NGX_HAVE_INET6)
0294 
0295     case NGX_PROXY_PROTOCOL_AF_INET6:
0296 
0297         if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet6_addrs_t)) {
0298             return NULL;
0299         }
0300 
0301         in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf;
0302 
0303         sockaddr.sockaddr_in6.sin6_family = AF_INET6;
0304         sockaddr.sockaddr_in6.sin6_port = 0;
0305         memcpy(&sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16);
0306 
0307         c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in6->src_port);
0308 
0309         socklen = sizeof(struct sockaddr_in6);
0310 
0311         buf += sizeof(ngx_proxy_protocol_inet6_addrs_t);
0312 
0313         break;
0314 
0315 #endif
0316 
0317     default:
0318         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0319                        "PROXY protocol v2 unsupported address family %ui",
0320                        family);
0321         return end;
0322     }
0323 
0324     c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
0325     if (c->proxy_protocol_addr.data == NULL) {
0326         return NULL;
0327     }
0328 
0329     c->proxy_protocol_addr.len = ngx_sock_ntop(&sockaddr.sockaddr, socklen,
0330                                                c->proxy_protocol_addr.data,
0331                                                NGX_SOCKADDR_STRLEN, 0);
0332 
0333     ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
0334                    "PROXY protocol v2 address: %V %d", &c->proxy_protocol_addr,
0335                    c->proxy_protocol_port);
0336 
0337     if (buf < end) {
0338         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0339                        "PROXY protocol v2 %z bytes of tlv ignored", end - buf);
0340     }
0341 
0342     return end;
0343 }