Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.19.2 ]​[ nginx-1.18.0 ]​

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_read_addr(ngx_connection_t *c, u_char *p,
0044     u_char *last, ngx_str_t *addr);
0045 static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last,
0046     in_port_t *port, u_char sep);
0047 static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
0048     u_char *last);
0049 
0050 
0051 u_char *
0052 ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
0053 {
0054     size_t                 len;
0055     u_char                *p;
0056     ngx_proxy_protocol_t  *pp;
0057 
0058     static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n";
0059 
0060     p = buf;
0061     len = last - buf;
0062 
0063     if (len >= sizeof(ngx_proxy_protocol_header_t)
0064         && memcmp(p, signature, sizeof(signature) - 1) == 0)
0065     {
0066         return ngx_proxy_protocol_v2_read(c, buf, last);
0067     }
0068 
0069     if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
0070         goto invalid;
0071     }
0072 
0073     p += 6;
0074     len -= 6;
0075 
0076     if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) {
0077         ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
0078                        "PROXY protocol unknown protocol");
0079         p += 7;
0080         goto skip;
0081     }
0082 
0083     if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0
0084         || (p[3] != '4' && p[3] != '6') || p[4] != ' ')
0085     {
0086         goto invalid;
0087     }
0088 
0089     p += 5;
0090 
0091     pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
0092     if (pp == NULL) {
0093         return NULL;
0094     }
0095 
0096     p = ngx_proxy_protocol_read_addr(c, p, last, &pp->src_addr);
0097     if (p == NULL) {
0098         goto invalid;
0099     }
0100 
0101     p = ngx_proxy_protocol_read_addr(c, p, last, &pp->dst_addr);
0102     if (p == NULL) {
0103         goto invalid;
0104     }
0105 
0106     p = ngx_proxy_protocol_read_port(p, last, &pp->src_port, ' ');
0107     if (p == NULL) {
0108         goto invalid;
0109     }
0110 
0111     p = ngx_proxy_protocol_read_port(p, last, &pp->dst_port, CR);
0112     if (p == NULL) {
0113         goto invalid;
0114     }
0115 
0116     if (p == last) {
0117         goto invalid;
0118     }
0119 
0120     if (*p++ != LF) {
0121         goto invalid;
0122     }
0123 
0124     ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
0125                    "PROXY protocol src: %V %d, dst: %V %d",
0126                    &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
0127 
0128     c->proxy_protocol = pp;
0129 
0130     return p;
0131 
0132 skip:
0133 
0134     for ( /* void */ ; p < last - 1; p++) {
0135         if (p[0] == CR && p[1] == LF) {
0136             return p + 2;
0137         }
0138     }
0139 
0140 invalid:
0141 
0142     ngx_log_error(NGX_LOG_ERR, c->log, 0,
0143                   "broken header: \"%*s\"", (size_t) (last - buf), buf);
0144 
0145     return NULL;
0146 }
0147 
0148 
0149 static u_char *
0150 ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, u_char *last,
0151     ngx_str_t *addr)
0152 {
0153     size_t  len;
0154     u_char  ch, *pos;
0155 
0156     pos = p;
0157 
0158     for ( ;; ) {
0159         if (p == last) {
0160             return NULL;
0161         }
0162 
0163         ch = *p++;
0164 
0165         if (ch == ' ') {
0166             break;
0167         }
0168 
0169         if (ch != ':' && ch != '.'
0170             && (ch < 'a' || ch > 'f')
0171             && (ch < 'A' || ch > 'F')
0172             && (ch < '0' || ch > '9'))
0173         {
0174             return NULL;
0175         }
0176     }
0177 
0178     len = p - pos - 1;
0179 
0180     addr->data = ngx_pnalloc(c->pool, len);
0181     if (addr->data == NULL) {
0182         return NULL;
0183     }
0184 
0185     ngx_memcpy(addr->data, pos, len);
0186     addr->len = len;
0187 
0188     return p;
0189 }
0190 
0191 
0192 static u_char *
0193 ngx_proxy_protocol_read_port(u_char *p, u_char *last, in_port_t *port,
0194     u_char sep)
0195 {
0196     size_t      len;
0197     u_char     *pos;
0198     ngx_int_t   n;
0199 
0200     pos = p;
0201 
0202     for ( ;; ) {
0203         if (p == last) {
0204             return NULL;
0205         }
0206 
0207         if (*p++ == sep) {
0208             break;
0209         }
0210     }
0211 
0212     len = p - pos - 1;
0213 
0214     n = ngx_atoi(pos, len);
0215     if (n < 0 || n > 65535) {
0216         return NULL;
0217     }
0218 
0219     *port = (in_port_t) n;
0220 
0221     return p;
0222 }
0223 
0224 
0225 u_char *
0226 ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
0227 {
0228     ngx_uint_t  port, lport;
0229 
0230     if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) {
0231         return NULL;
0232     }
0233 
0234     if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
0235         return NULL;
0236     }
0237 
0238     switch (c->sockaddr->sa_family) {
0239 
0240     case AF_INET:
0241         buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1);
0242         break;
0243 
0244 #if (NGX_HAVE_INET6)
0245     case AF_INET6:
0246         buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1);
0247         break;
0248 #endif
0249 
0250     default:
0251         return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF,
0252                           sizeof("PROXY UNKNOWN" CRLF) - 1);
0253     }
0254 
0255     buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0);
0256 
0257     *buf++ = ' ';
0258 
0259     buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf,
0260                          0);
0261 
0262     port = ngx_inet_get_port(c->sockaddr);
0263     lport = ngx_inet_get_port(c->local_sockaddr);
0264 
0265     return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
0266 }
0267 
0268 
0269 static u_char *
0270 ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
0271 {
0272     u_char                             *end;
0273     size_t                              len;
0274     socklen_t                           socklen;
0275     ngx_uint_t                          version, command, family, transport;
0276     ngx_sockaddr_t                      src_sockaddr, dst_sockaddr;
0277     ngx_proxy_protocol_t               *pp;
0278     ngx_proxy_protocol_header_t        *header;
0279     ngx_proxy_protocol_inet_addrs_t    *in;
0280 #if (NGX_HAVE_INET6)
0281     ngx_proxy_protocol_inet6_addrs_t   *in6;
0282 #endif
0283 
0284     header = (ngx_proxy_protocol_header_t *) buf;
0285 
0286     buf += sizeof(ngx_proxy_protocol_header_t);
0287 
0288     version = header->version_command >> 4;
0289 
0290     if (version != 2) {
0291         ngx_log_error(NGX_LOG_ERR, c->log, 0,
0292                       "unknown PROXY protocol version: %ui", version);
0293         return NULL;
0294     }
0295 
0296     len = ngx_proxy_protocol_parse_uint16(header->len);
0297 
0298     if ((size_t) (last - buf) < len) {
0299         ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large");
0300         return NULL;
0301     }
0302 
0303     end = buf + len;
0304 
0305     command = header->version_command & 0x0f;
0306 
0307     /* only PROXY is supported */
0308     if (command != 1) {
0309         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0310                        "PROXY protocol v2 unsupported command %ui", command);
0311         return end;
0312     }
0313 
0314     transport = header->family_transport & 0x0f;
0315 
0316     /* only STREAM is supported */
0317     if (transport != 1) {
0318         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0319                        "PROXY protocol v2 unsupported transport %ui",
0320                        transport);
0321         return end;
0322     }
0323 
0324     pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
0325     if (pp == NULL) {
0326         return NULL;
0327     }
0328 
0329     family = header->family_transport >> 4;
0330 
0331     switch (family) {
0332 
0333     case NGX_PROXY_PROTOCOL_AF_INET:
0334 
0335         if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet_addrs_t)) {
0336             return NULL;
0337         }
0338 
0339         in = (ngx_proxy_protocol_inet_addrs_t *) buf;
0340 
0341         src_sockaddr.sockaddr_in.sin_family = AF_INET;
0342         src_sockaddr.sockaddr_in.sin_port = 0;
0343         memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4);
0344 
0345         dst_sockaddr.sockaddr_in.sin_family = AF_INET;
0346         dst_sockaddr.sockaddr_in.sin_port = 0;
0347         memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4);
0348 
0349         pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port);
0350         pp->dst_port = ngx_proxy_protocol_parse_uint16(in->dst_port);
0351 
0352         socklen = sizeof(struct sockaddr_in);
0353 
0354         buf += sizeof(ngx_proxy_protocol_inet_addrs_t);
0355 
0356         break;
0357 
0358 #if (NGX_HAVE_INET6)
0359 
0360     case NGX_PROXY_PROTOCOL_AF_INET6:
0361 
0362         if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet6_addrs_t)) {
0363             return NULL;
0364         }
0365 
0366         in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf;
0367 
0368         src_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
0369         src_sockaddr.sockaddr_in6.sin6_port = 0;
0370         memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16);
0371 
0372         dst_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
0373         dst_sockaddr.sockaddr_in6.sin6_port = 0;
0374         memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16);
0375 
0376         pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port);
0377         pp->dst_port = ngx_proxy_protocol_parse_uint16(in6->dst_port);
0378 
0379         socklen = sizeof(struct sockaddr_in6);
0380 
0381         buf += sizeof(ngx_proxy_protocol_inet6_addrs_t);
0382 
0383         break;
0384 
0385 #endif
0386 
0387     default:
0388         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0389                        "PROXY protocol v2 unsupported address family %ui",
0390                        family);
0391         return end;
0392     }
0393 
0394     pp->src_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
0395     if (pp->src_addr.data == NULL) {
0396         return NULL;
0397     }
0398 
0399     pp->src_addr.len = ngx_sock_ntop(&src_sockaddr.sockaddr, socklen,
0400                                      pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0);
0401 
0402     pp->dst_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
0403     if (pp->dst_addr.data == NULL) {
0404         return NULL;
0405     }
0406 
0407     pp->dst_addr.len = ngx_sock_ntop(&dst_sockaddr.sockaddr, socklen,
0408                                      pp->dst_addr.data, NGX_SOCKADDR_STRLEN, 0);
0409 
0410     ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
0411                    "PROXY protocol v2 src: %V %d, dst: %V %d",
0412                    &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
0413 
0414     if (buf < end) {
0415         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
0416                        "PROXY protocol v2 %z bytes of tlv ignored", end - buf);
0417     }
0418 
0419     c->proxy_protocol = pp;
0420 
0421     return end;
0422 }