src/core/ngx_proxy_protocol.c - nginx-1.31.4 nginx/ @ 8d9666701

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Roman Arutyunyan
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>


  7. #define NGX_PROXY_PROTOCOL_V2_MAX_HEADER    52

  8. #define NGX_PROXY_PROTOCOL_CMD_LOCAL        0
  9. #define NGX_PROXY_PROTOCOL_CMD_PROXY        1

  10. #define NGX_PROXY_PROTOCOL_AF_UNSPEC        0
  11. #define NGX_PROXY_PROTOCOL_AF_INET          1
  12. #define NGX_PROXY_PROTOCOL_AF_INET6         2

  13. #define NGX_PROXY_PROTOCOL_TYPE_UNSPEC      0
  14. #define NGX_PROXY_PROTOCOL_TYPE_STREAM      1
  15. #define NGX_PROXY_PROTOCOL_TYPE_DGRAM       2

  16. #define NGX_PROXY_PROTOCOL_TLV_ALPN         0x01
  17. #define NGX_PROXY_PROTOCOL_TLV_AUTHORITY    0x02
  18. #define NGX_PROXY_PROTOCOL_TLV_CRC32C       0x03
  19. #define NGX_PROXY_PROTOCOL_TLV_UNIQUE_ID    0x05
  20. #define NGX_PROXY_PROTOCOL_TLV_SSL          0x20
  21. #define NGX_PROXY_PROTOCOL_TLV_SSL_VERSION  0x21
  22. #define NGX_PROXY_PROTOCOL_TLV_SSL_CN       0x22
  23. #define NGX_PROXY_PROTOCOL_TLV_SSL_CIPHER   0x23
  24. #define NGX_PROXY_PROTOCOL_TLV_SSL_SIG_ALG  0x24
  25. #define NGX_PROXY_PROTOCOL_TLV_SSL_KEY_ALG  0x25
  26. #define NGX_PROXY_PROTOCOL_TLV_NETNS        0x30

  27. #define NGX_PROXY_PROTOCOL_V2_CLIENT_SSL          0x01
  28. #define NGX_PROXY_PROTOCOL_V2_CLIENT_CERT_CONN    0x02
  29. #define NGX_PROXY_PROTOCOL_V2_CLIENT_CERT_SESS    0x04


  30. #define ngx_proxy_protocol_parse_uint16(p)                                    \
  31.     ( ((uint16_t) (p)[0] << 8)                                                \
  32.     + (           (p)[1]) )

  33. #define ngx_proxy_protocol_parse_uint32(p)                                    \
  34.     ( ((uint32_t) (p)[0] << 24)                                               \
  35.     + (           (p)[1] << 16)                                               \
  36.     + (           (p)[2] << 8)                                                \
  37.     + (           (p)[3]) )


  38. typedef struct {
  39.     u_char                                  signature[12];
  40.     u_char                                  version_command;
  41.     u_char                                  family_transport;
  42.     u_char                                  len[2];
  43. } ngx_proxy_protocol_header_t;


  44. typedef struct {
  45.     u_char                                  src_addr[4];
  46.     u_char                                  dst_addr[4];
  47.     u_char                                  src_port[2];
  48.     u_char                                  dst_port[2];
  49. } ngx_proxy_protocol_inet_addrs_t;


  50. typedef struct {
  51.     u_char                                  src_addr[16];
  52.     u_char                                  dst_addr[16];
  53.     u_char                                  src_port[2];
  54.     u_char                                  dst_port[2];
  55. } ngx_proxy_protocol_inet6_addrs_t;


  56. typedef struct {
  57.     u_char                                  type;
  58.     u_char                                  len[2];
  59. } ngx_proxy_protocol_tlv_t;


  60. typedef struct {
  61.     u_char                                  client;
  62.     u_char                                  verify[4];
  63. } ngx_proxy_protocol_tlv_ssl_t;


  64. typedef struct {
  65.     ngx_str_t                               name;
  66.     ngx_uint_t                              type;
  67. } ngx_proxy_protocol_tlv_entry_t;


  68. typedef struct {
  69.     ngx_uint_t                              type;
  70.     ngx_str_t                               value;
  71. } ngx_proxy_protocol_tlv_value_t;


  72. static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p,
  73.     u_char *last, ngx_str_t *addr);
  74. static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last,
  75.     in_port_t *port, u_char sep);
  76. static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
  77.     u_char *last);
  78. static ngx_int_t ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c,
  79.     ngx_str_t *tlvs, ngx_uint_t type, ngx_str_t *value);
  80. #if (NGX_OPENSSL)
  81. static ngx_int_t ngx_proxy_protocol_v2_eval_ssl(ngx_connection_t *c,
  82.     ngx_array_t *tlvs, ngx_array_t *ssl_tlvs, ngx_uint_t *client,
  83.     uint32_t *verify);
  84. static ngx_int_t ngx_proxy_protocol_v2_authority(ngx_connection_t *c,
  85.     ngx_str_t *out);
  86. static ngx_int_t ngx_proxy_protocol_v2_alpn(ngx_connection_t *c,
  87.     ngx_str_t *out);
  88. static ngx_int_t ngx_proxy_protocol_v2_ssl_sub(ngx_connection_t *c,
  89.     ngx_uint_t type, ngx_str_t *out);
  90. #endif
  91. static u_char *ngx_proxy_protocol_v2_write_header(ngx_connection_t *c,
  92.     u_char *buf, u_char *last);
  93. static u_char ngx_proxy_protocol_v2_family(ngx_uint_t family);
  94. static void ngx_proxy_protocol_v2_write_ipv4(struct sockaddr *sa, u_char *addr,
  95.     u_char *port);
  96. static void ngx_proxy_protocol_v2_write_ipv6(struct sockaddr *sa, u_char *addr,
  97.     u_char *port);
  98. static u_char *ngx_proxy_protocol_v2_write_tlv(ngx_connection_t *c, u_char *p,
  99.     u_char *last, ngx_uint_t type, ngx_str_t *value);
  100. static u_char *ngx_proxy_protocol_v2_write_ssl(ngx_connection_t *c, u_char *p,
  101.     u_char *last, ngx_array_t *ssl_tlvs, ngx_uint_t client, uint32_t verify);
  102. static void ngx_proxy_protocol_v2_set_len(u_char *buf, u_char *p);
  103. static u_char *ngx_proxy_protocol_v2_write_crc32c(ngx_connection_t *c,
  104.     u_char *buf, u_char *p, u_char *last);


  105. static ngx_proxy_protocol_tlv_entry_t  ngx_proxy_protocol_tlv_entries[] = {
  106.     { ngx_string("alpn"),       NGX_PROXY_PROTOCOL_TLV_ALPN },
  107.     { ngx_string("authority"),  NGX_PROXY_PROTOCOL_TLV_AUTHORITY },
  108.     { ngx_string("unique_id"),  NGX_PROXY_PROTOCOL_TLV_UNIQUE_ID },
  109.     { ngx_string("ssl"),        NGX_PROXY_PROTOCOL_TLV_SSL },
  110.     { ngx_string("netns"),      NGX_PROXY_PROTOCOL_TLV_NETNS },
  111.     { ngx_null_string,          0x00 }
  112. };


  113. static ngx_proxy_protocol_tlv_entry_t  ngx_proxy_protocol_tlv_ssl_entries[] = {
  114.     { ngx_string("version"),    NGX_PROXY_PROTOCOL_TLV_SSL_VERSION },
  115.     { ngx_string("cn"),         NGX_PROXY_PROTOCOL_TLV_SSL_CN },
  116.     { ngx_string("cipher"),     NGX_PROXY_PROTOCOL_TLV_SSL_CIPHER },
  117.     { ngx_string("sig_alg"),    NGX_PROXY_PROTOCOL_TLV_SSL_SIG_ALG },
  118.     { ngx_string("key_alg"),    NGX_PROXY_PROTOCOL_TLV_SSL_KEY_ALG },
  119.     { ngx_null_string,          0x00 }
  120. };


  121. static const u_char  ngx_proxy_protocol_signature[] = "\r\n\r\n\0\r\nQUIT\n";


  122. u_char *
  123. ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
  124. {
  125.     size_t                 len;
  126.     u_char                *p;
  127.     ngx_proxy_protocol_t  *pp;

  128.     p = buf;
  129.     len = last - buf;

  130.     if (len >= sizeof(ngx_proxy_protocol_header_t)
  131.         && ngx_memcmp(p, ngx_proxy_protocol_signature,
  132.                       sizeof(ngx_proxy_protocol_signature) - 1)
  133.            == 0)
  134.     {
  135.         return ngx_proxy_protocol_v2_read(c, buf, last);
  136.     }

  137.     if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
  138.         goto invalid;
  139.     }

  140.     p += 6;
  141.     len -= 6;

  142.     if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) {
  143.         ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
  144.                        "PROXY protocol unknown protocol");
  145.         p += 7;
  146.         goto skip;
  147.     }

  148.     if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0
  149.         || (p[3] != '4' && p[3] != '6') || p[4] != ' ')
  150.     {
  151.         goto invalid;
  152.     }

  153.     p += 5;

  154.     pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
  155.     if (pp == NULL) {
  156.         return NULL;
  157.     }

  158.     p = ngx_proxy_protocol_read_addr(c, p, last, &pp->src_addr);
  159.     if (p == NULL) {
  160.         goto invalid;
  161.     }

  162.     p = ngx_proxy_protocol_read_addr(c, p, last, &pp->dst_addr);
  163.     if (p == NULL) {
  164.         goto invalid;
  165.     }

  166.     p = ngx_proxy_protocol_read_port(p, last, &pp->src_port, ' ');
  167.     if (p == NULL) {
  168.         goto invalid;
  169.     }

  170.     p = ngx_proxy_protocol_read_port(p, last, &pp->dst_port, CR);
  171.     if (p == NULL) {
  172.         goto invalid;
  173.     }

  174.     if (p == last) {
  175.         goto invalid;
  176.     }

  177.     if (*p++ != LF) {
  178.         goto invalid;
  179.     }

  180.     ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
  181.                    "PROXY protocol src: %V %d, dst: %V %d",
  182.                    &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);

  183.     c->proxy_protocol = pp;

  184.     return p;

  185. skip:

  186.     for ( /* void */ ; p < last - 1; p++) {
  187.         if (p[0] == CR && p[1] == LF) {
  188.             return p + 2;
  189.         }
  190.     }

  191. invalid:

  192.     for (p = buf; p < last; p++) {
  193.         if (*p == CR || *p == LF) {
  194.             break;
  195.         }
  196.     }

  197.     ngx_log_error(NGX_LOG_ERR, c->log, 0,
  198.                   "broken header: \"%*s\"", (size_t) (p - buf), buf);

  199.     return NULL;
  200. }


  201. static u_char *
  202. ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, u_char *last,
  203.     ngx_str_t *addr)
  204. {
  205.     size_t  len;
  206.     u_char  ch, *pos;

  207.     pos = p;

  208.     for ( ;; ) {
  209.         if (p == last) {
  210.             return NULL;
  211.         }

  212.         ch = *p++;

  213.         if (ch == ' ') {
  214.             break;
  215.         }

  216.         if (ch != ':' && ch != '.'
  217.             && (ch < 'a' || ch > 'f')
  218.             && (ch < 'A' || ch > 'F')
  219.             && (ch < '0' || ch > '9'))
  220.         {
  221.             return NULL;
  222.         }
  223.     }

  224.     len = p - pos - 1;

  225.     addr->data = ngx_pnalloc(c->pool, len);
  226.     if (addr->data == NULL) {
  227.         return NULL;
  228.     }

  229.     ngx_memcpy(addr->data, pos, len);
  230.     addr->len = len;

  231.     return p;
  232. }


  233. static u_char *
  234. ngx_proxy_protocol_read_port(u_char *p, u_char *last, in_port_t *port,
  235.     u_char sep)
  236. {
  237.     size_t      len;
  238.     u_char     *pos;
  239.     ngx_int_t   n;

  240.     pos = p;

  241.     for ( ;; ) {
  242.         if (p == last) {
  243.             return NULL;
  244.         }

  245.         if (*p++ == sep) {
  246.             break;
  247.         }
  248.     }

  249.     len = p - pos - 1;

  250.     n = ngx_atoi(pos, len);
  251.     if (n < 0 || n > 65535) {
  252.         return NULL;
  253.     }

  254.     *port = (in_port_t) n;

  255.     return p;
  256. }


  257. u_char *
  258. ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
  259. {
  260.     ngx_uint_t  port, lport;

  261.     if (last - buf < NGX_PROXY_PROTOCOL_V1_MAX_HEADER) {
  262.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  263.                       "too small buffer for PROXY protocol");
  264.         return NULL;
  265.     }

  266.     if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
  267.         return NULL;
  268.     }

  269.     switch (c->sockaddr->sa_family) {

  270.     case AF_INET:
  271.         buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1);
  272.         break;

  273. #if (NGX_HAVE_INET6)
  274.     case AF_INET6:
  275.         buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1);
  276.         break;
  277. #endif

  278.     default:
  279.         return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF,
  280.                           sizeof("PROXY UNKNOWN" CRLF) - 1);
  281.     }

  282.     buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0);

  283.     *buf++ = ' ';

  284.     buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf,
  285.                          0);

  286.     port = ngx_inet_get_port(c->sockaddr);
  287.     lport = ngx_inet_get_port(c->local_sockaddr);

  288.     return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
  289. }


  290. static u_char *
  291. ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
  292. {
  293.     u_char                             *end;
  294.     size_t                              len;
  295.     socklen_t                           socklen;
  296.     ngx_uint_t                          version, command, family, transport;
  297.     ngx_sockaddr_t                      src_sockaddr, dst_sockaddr;
  298.     ngx_proxy_protocol_t               *pp;
  299.     ngx_proxy_protocol_header_t        *header;
  300.     ngx_proxy_protocol_inet_addrs_t    *in;
  301. #if (NGX_HAVE_INET6)
  302.     ngx_proxy_protocol_inet6_addrs_t   *in6;
  303. #endif

  304.     header = (ngx_proxy_protocol_header_t *) buf;

  305.     buf += sizeof(ngx_proxy_protocol_header_t);

  306.     version = header->version_command >> 4;

  307.     if (version != 2) {
  308.         ngx_log_error(NGX_LOG_ERR, c->log, 0,
  309.                       "unknown PROXY protocol version: %ui", version);
  310.         return NULL;
  311.     }

  312.     len = ngx_proxy_protocol_parse_uint16(header->len);

  313.     if ((size_t) (last - buf) < len) {
  314.         ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large");
  315.         return NULL;
  316.     }

  317.     end = buf + len;

  318.     command = header->version_command & 0x0f;

  319.     /* only PROXY is supported */
  320.     if (command != NGX_PROXY_PROTOCOL_CMD_PROXY) {
  321.         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
  322.                        "PROXY protocol v2 unsupported command %ui", command);
  323.         return end;
  324.     }

  325.     transport = header->family_transport & 0x0f;

  326.     /* only STREAM is supported */
  327.     if (transport != NGX_PROXY_PROTOCOL_TYPE_STREAM) {
  328.         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
  329.                        "PROXY protocol v2 unsupported transport %ui",
  330.                        transport);
  331.         return end;
  332.     }

  333.     pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
  334.     if (pp == NULL) {
  335.         return NULL;
  336.     }

  337.     family = header->family_transport >> 4;

  338.     switch (family) {

  339.     case NGX_PROXY_PROTOCOL_AF_INET:

  340.         if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet_addrs_t)) {
  341.             return NULL;
  342.         }

  343.         in = (ngx_proxy_protocol_inet_addrs_t *) buf;

  344.         src_sockaddr.sockaddr_in.sin_family = AF_INET;
  345.         src_sockaddr.sockaddr_in.sin_port = 0;
  346.         ngx_memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4);

  347.         dst_sockaddr.sockaddr_in.sin_family = AF_INET;
  348.         dst_sockaddr.sockaddr_in.sin_port = 0;
  349.         ngx_memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4);

  350.         pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port);
  351.         pp->dst_port = ngx_proxy_protocol_parse_uint16(in->dst_port);

  352.         socklen = sizeof(struct sockaddr_in);

  353.         buf += sizeof(ngx_proxy_protocol_inet_addrs_t);

  354.         break;

  355. #if (NGX_HAVE_INET6)

  356.     case NGX_PROXY_PROTOCOL_AF_INET6:

  357.         if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet6_addrs_t)) {
  358.             return NULL;
  359.         }

  360.         in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf;

  361.         src_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
  362.         src_sockaddr.sockaddr_in6.sin6_port = 0;
  363.         ngx_memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16);

  364.         dst_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
  365.         dst_sockaddr.sockaddr_in6.sin6_port = 0;
  366.         ngx_memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16);

  367.         pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port);
  368.         pp->dst_port = ngx_proxy_protocol_parse_uint16(in6->dst_port);

  369.         socklen = sizeof(struct sockaddr_in6);

  370.         buf += sizeof(ngx_proxy_protocol_inet6_addrs_t);

  371.         break;

  372. #endif

  373.     default:
  374.         ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
  375.                        "PROXY protocol v2 unsupported address family %ui",
  376.                        family);
  377.         return end;
  378.     }

  379.     pp->src_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
  380.     if (pp->src_addr.data == NULL) {
  381.         return NULL;
  382.     }

  383.     pp->src_addr.len = ngx_sock_ntop(&src_sockaddr.sockaddr, socklen,
  384.                                      pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0);

  385.     pp->dst_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
  386.     if (pp->dst_addr.data == NULL) {
  387.         return NULL;
  388.     }

  389.     pp->dst_addr.len = ngx_sock_ntop(&dst_sockaddr.sockaddr, socklen,
  390.                                      pp->dst_addr.data, NGX_SOCKADDR_STRLEN, 0);

  391.     ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
  392.                    "PROXY protocol v2 src: %V %d, dst: %V %d",
  393.                    &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);

  394.     if (buf < end) {
  395.         pp->tlvs.data = ngx_pnalloc(c->pool, end - buf);
  396.         if (pp->tlvs.data == NULL) {
  397.             return NULL;
  398.         }

  399.         ngx_memcpy(pp->tlvs.data, buf, end - buf);
  400.         pp->tlvs.len = end - buf;
  401.     }

  402.     c->proxy_protocol = pp;

  403.     return end;
  404. }


  405. ngx_int_t
  406. ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name,
  407.     ngx_str_t *value)
  408. {
  409.     u_char                          *p;
  410.     size_t                           n;
  411.     uint32_t                         verify;
  412.     ngx_str_t                        ssl, *tlvs;
  413.     ngx_int_t                        rc, type;
  414.     ngx_proxy_protocol_tlv_ssl_t    *tlv_ssl;
  415.     ngx_proxy_protocol_tlv_entry_t  *te;

  416.     if (c->proxy_protocol == NULL) {
  417.         return NGX_DECLINED;
  418.     }

  419.     ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
  420.                    "PROXY protocol v2 get tlv \"%V\"", name);

  421.     te = ngx_proxy_protocol_tlv_entries;
  422.     tlvs = &c->proxy_protocol->tlvs;

  423.     p = name->data;
  424.     n = name->len;

  425.     if (n >= 4 && p[0] == 's' && p[1] == 's' && p[2] == 'l' && p[3] == '_') {

  426.         rc = ngx_proxy_protocol_lookup_tlv(c, tlvs,
  427.                                            NGX_PROXY_PROTOCOL_TLV_SSL, &ssl);
  428.         if (rc != NGX_OK) {
  429.             return rc;
  430.         }

  431.         if (ssl.len < sizeof(ngx_proxy_protocol_tlv_ssl_t)) {
  432.             return NGX_ERROR;
  433.         }

  434.         p += 4;
  435.         n -= 4;

  436.         if (n == 6 && ngx_strncmp(p, "verify", 6) == 0) {

  437.             tlv_ssl = (ngx_proxy_protocol_tlv_ssl_t *) ssl.data;
  438.             verify = ngx_proxy_protocol_parse_uint32(tlv_ssl->verify);

  439.             value->data = ngx_pnalloc(c->pool, NGX_INT32_LEN);
  440.             if (value->data == NULL) {
  441.                 return NGX_ERROR;
  442.             }

  443.             value->len = ngx_sprintf(value->data, "%uD", verify)
  444.                          - value->data;
  445.             return NGX_OK;
  446.         }

  447.         ssl.data += sizeof(ngx_proxy_protocol_tlv_ssl_t);
  448.         ssl.len -= sizeof(ngx_proxy_protocol_tlv_ssl_t);

  449.         te = ngx_proxy_protocol_tlv_ssl_entries;
  450.         tlvs = &ssl;
  451.     }

  452.     if (n >= 2 && p[0] == '0' && p[1] == 'x') {

  453.         type = ngx_hextoi(p + 2, n - 2);
  454.         if (type == NGX_ERROR) {
  455.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  456.                           "invalid PROXY protocol TLV \"%V\"", name);
  457.             return NGX_ERROR;
  458.         }

  459.         return ngx_proxy_protocol_lookup_tlv(c, tlvs, type, value);
  460.     }

  461.     for ( /* void */ ; te->type; te++) {
  462.         if (te->name.len == n && ngx_strncmp(te->name.data, p, n) == 0) {
  463.             return ngx_proxy_protocol_lookup_tlv(c, tlvs, te->type, value);
  464.         }
  465.     }

  466.     ngx_log_error(NGX_LOG_ERR, c->log, 0,
  467.                   "unknown PROXY protocol TLV \"%V\"", name);

  468.     return NGX_DECLINED;
  469. }


  470. static ngx_int_t
  471. ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c, ngx_str_t *tlvs,
  472.     ngx_uint_t type, ngx_str_t *value)
  473. {
  474.     u_char                    *p;
  475.     size_t                     n, len;
  476.     ngx_proxy_protocol_tlv_t  *tlv;

  477.     ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
  478.                    "PROXY protocol v2 lookup tlv:%02xi", type);

  479.     p = tlvs->data;
  480.     n = tlvs->len;

  481.     while (n) {
  482.         if (n < sizeof(ngx_proxy_protocol_tlv_t)) {
  483.             ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV");
  484.             return NGX_ERROR;
  485.         }

  486.         tlv = (ngx_proxy_protocol_tlv_t *) p;
  487.         len = ngx_proxy_protocol_parse_uint16(tlv->len);

  488.         p += sizeof(ngx_proxy_protocol_tlv_t);
  489.         n -= sizeof(ngx_proxy_protocol_tlv_t);

  490.         if (n < len) {
  491.             ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV");
  492.             return NGX_ERROR;
  493.         }

  494.         if (tlv->type == type) {
  495.             value->data = p;
  496.             value->len = len;
  497.             return NGX_OK;
  498.         }

  499.         p += len;
  500.         n -= len;
  501.     }

  502.     return NGX_DECLINED;
  503. }


  504. u_char *
  505. ngx_proxy_protocol_v2_write(ngx_connection_t *c, u_char *buf, u_char *last,
  506.     ngx_array_t *tlvs /* reserved */ )
  507. {
  508.     u_char                          *p;
  509.     uint32_t                         verify;
  510.     ngx_uint_t                       i, client;
  511.     ngx_array_t                      base_tlvs, ssl_tlvs;
  512.     ngx_proxy_protocol_tlv_value_t  *tlv;

  513.     client = 0;
  514.     verify = 0;

  515.     ngx_memzero(&base_tlvs, sizeof(ngx_array_t));
  516.     ngx_memzero(&ssl_tlvs, sizeof(ngx_array_t));

  517. #if (NGX_OPENSSL)

  518.     if (c->ssl != NULL) {
  519.         if (ngx_array_init(&base_tlvs, c->pool, 2,
  520.                            sizeof(ngx_proxy_protocol_tlv_value_t))
  521.             != NGX_OK)
  522.         {
  523.             return NULL;
  524.         }

  525.         if (ngx_array_init(&ssl_tlvs, c->pool, 5,
  526.                            sizeof(ngx_proxy_protocol_tlv_value_t))
  527.             != NGX_OK)
  528.         {
  529.             return NULL;
  530.         }

  531.         if (ngx_proxy_protocol_v2_eval_ssl(c, &base_tlvs, &ssl_tlvs, &client,
  532.                                            &verify)
  533.             != NGX_OK)
  534.         {
  535.             return NULL;
  536.         }
  537.     }

  538. #endif

  539.     p = ngx_proxy_protocol_v2_write_header(c, buf, last);
  540.     if (p == NULL) {
  541.         return NULL;
  542.     }

  543.     tlv = base_tlvs.elts;

  544.     for (i = 0; i < base_tlvs.nelts; i++) {
  545.         p = ngx_proxy_protocol_v2_write_tlv(c, p, last, tlv[i].type,
  546.                                            &tlv[i].value);
  547.         if (p == NULL) {
  548.             return NULL;
  549.         }
  550.     }

  551.     if (client) {
  552.         p = ngx_proxy_protocol_v2_write_ssl(c, p, last, &ssl_tlvs, client,
  553.                                             verify);
  554.         if (p == NULL) {
  555.             return NULL;
  556.         }
  557.     }

  558.     ngx_proxy_protocol_v2_set_len(buf,
  559.                                   p + sizeof(ngx_proxy_protocol_tlv_t) + 4);

  560.     return ngx_proxy_protocol_v2_write_crc32c(c, buf, p, last);
  561. }


  562. #if (NGX_OPENSSL)

  563. static ngx_int_t
  564. ngx_proxy_protocol_v2_eval_ssl(ngx_connection_t *c, ngx_array_t *tlvs,
  565.     ngx_array_t *ssl_tlvs, ngx_uint_t *client, uint32_t *verify)
  566. {
  567.     X509                            *cert;
  568.     long                             n;
  569.     ngx_int_t                        rc;
  570.     ngx_str_t                        value;
  571.     ngx_uint_t                       type;
  572.     const char                      *s;
  573.     ngx_proxy_protocol_tlv_value_t  *tlv;

  574.     if (ngx_proxy_protocol_v2_authority(c, &value) == NGX_OK) {
  575.         tlv = ngx_array_push(tlvs);
  576.         if (tlv == NULL) {
  577.             return NGX_ERROR;
  578.         }

  579.         tlv->type = NGX_PROXY_PROTOCOL_TLV_AUTHORITY;
  580.         tlv->value = value;
  581.     }

  582.     if (ngx_proxy_protocol_v2_alpn(c, &value) == NGX_OK) {
  583.         tlv = ngx_array_push(tlvs);
  584.         if (tlv == NULL) {
  585.             return NGX_ERROR;
  586.         }

  587.         tlv->type = NGX_PROXY_PROTOCOL_TLV_ALPN;
  588.         tlv->value = value;
  589.     }

  590.     for (type = NGX_PROXY_PROTOCOL_TLV_SSL_VERSION;
  591.          type <= NGX_PROXY_PROTOCOL_TLV_SSL_KEY_ALG;
  592.          type++)
  593.     {
  594.         rc = ngx_proxy_protocol_v2_ssl_sub(c, type, &value);

  595.         if (rc == NGX_ERROR) {
  596.             return NGX_ERROR;
  597.         }

  598.         if (rc != NGX_OK) {
  599.             continue;
  600.         }

  601.         tlv = ngx_array_push(ssl_tlvs);
  602.         if (tlv == NULL) {
  603.             return NGX_ERROR;
  604.         }

  605.         tlv->type = type;
  606.         tlv->value = value;
  607.     }

  608.     *client = NGX_PROXY_PROTOCOL_V2_CLIENT_SSL;
  609.     *verify = 1/* X509_V_ERR_UNSPECIFIED */

  610.     cert = SSL_get_peer_certificate(c->ssl->connection);

  611.     if (cert != NULL) {
  612.         X509_free(cert);

  613.         *client |= NGX_PROXY_PROTOCOL_V2_CLIENT_CERT_SESS;

  614.         if (!SSL_session_reused(c->ssl->connection)) {
  615.             *client |= NGX_PROXY_PROTOCOL_V2_CLIENT_CERT_CONN;
  616.         }

  617.         n = SSL_get_verify_result(c->ssl->connection);

  618.         if (n == X509_V_OK) {

  619.             if (ngx_ssl_ocsp_get_status(c, &s) != NGX_OK) {
  620.                 n = X509_V_ERR_CERT_REVOKED;
  621.             }
  622.         }

  623.         *verify = (uint32_t) n;
  624.     }

  625.     return NGX_OK;
  626. }


  627. static ngx_int_t
  628. ngx_proxy_protocol_v2_authority(ngx_connection_t *c, ngx_str_t *out)
  629. {
  630. #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME

  631.     const char  *sni;

  632.     sni = SSL_get_servername(c->ssl->connection, TLSEXT_NAMETYPE_host_name);
  633.     if (sni == NULL) {
  634.         return NGX_DECLINED;
  635.     }

  636.     out->data = (u_char *) sni;
  637.     out->len = ngx_strlen(sni);
  638.     return NGX_OK;

  639. #else
  640.     return NGX_DECLINED;
  641. #endif
  642. }


  643. static ngx_int_t
  644. ngx_proxy_protocol_v2_alpn(ngx_connection_t *c, ngx_str_t *out)
  645. {
  646. #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation

  647.     unsigned int          alpnlen;
  648.     const unsigned char  *alpn;

  649.     SSL_get0_alpn_selected(c->ssl->connection, &alpn, &alpnlen);
  650.     if (alpn == NULL || alpnlen == 0) {
  651.         return NGX_DECLINED;
  652.     }

  653.     out->data = (u_char *) alpn;
  654.     out->len = alpnlen;
  655.     return NGX_OK;

  656. #else
  657.     return NGX_DECLINED;
  658. #endif
  659. }


  660. static ngx_int_t
  661. ngx_proxy_protocol_v2_ssl_sub(ngx_connection_t *c, ngx_uint_t type,
  662.     ngx_str_t *out)
  663. {
  664.     int               i, len;
  665.     X509             *cert;
  666.     u_char           *alg, *s;
  667.     EVP_PKEY         *pkey;
  668. #if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
  669.     const
  670. #endif
  671.     X509_NAME        *subject;
  672. #if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
  673.     const
  674. #endif
  675.     X509_NAME_ENTRY  *entry;

  676.     switch (type) {

  677.     case NGX_PROXY_PROTOCOL_TLV_SSL_VERSION:
  678.         out->data = (u_char *) SSL_get_version(c->ssl->connection);
  679.         out->len = ngx_strlen(out->data);
  680.         return NGX_OK;

  681.     case NGX_PROXY_PROTOCOL_TLV_SSL_CIPHER:
  682.         out->data = (u_char *) SSL_get_cipher_name(c->ssl->connection);
  683.         out->len = ngx_strlen(out->data);
  684.         return NGX_OK;

  685.     case NGX_PROXY_PROTOCOL_TLV_SSL_CN:
  686.         cert = SSL_get_peer_certificate(c->ssl->connection);
  687.         if (cert == NULL) {
  688.             return NGX_DECLINED;
  689.         }

  690.         subject = X509_get_subject_name(cert);
  691.         if (subject == NULL) {
  692.             X509_free(cert);
  693.             return NGX_ERROR;
  694.         }

  695.         i = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
  696.         if (i < 0) {
  697.             X509_free(cert);
  698.             return NGX_DECLINED;
  699.         }

  700.         entry = X509_NAME_get_entry(subject, i);

  701.         len = ASN1_STRING_to_UTF8(&s, X509_NAME_ENTRY_get_data(entry));
  702.         if (len < 0) {
  703.             ngx_ssl_error(NGX_LOG_ALERT, c->log, 0,
  704.                           "ASN1_STRING_to_UTF8() failed");
  705.             X509_free(cert);
  706.             return NGX_ERROR;
  707.         }

  708.         out->len = len;
  709.         out->data = ngx_pnalloc(c->pool, len);
  710.         if (out->data == NULL) {
  711.             OPENSSL_free(s);
  712.             X509_free(cert);
  713.             return NGX_ERROR;
  714.         }

  715.         ngx_memcpy(out->data, s, len);

  716.         OPENSSL_free(s);
  717.         X509_free(cert);
  718.         return NGX_OK;

  719.     case NGX_PROXY_PROTOCOL_TLV_SSL_SIG_ALG:
  720.         cert = SSL_get_certificate(c->ssl->connection);

  721.         out->data = (u_char *) OBJ_nid2sn(X509_get_signature_nid(cert));
  722.         out->len = ngx_strlen(out->data);
  723.         return NGX_OK;

  724.     case NGX_PROXY_PROTOCOL_TLV_SSL_KEY_ALG:
  725.         cert = SSL_get_certificate(c->ssl->connection);

  726.         pkey = X509_get_pubkey(cert);
  727.         if (pkey == NULL) {
  728.             return NGX_ERROR;
  729.         }

  730.         switch (EVP_PKEY_base_id(pkey)) {

  731.         case EVP_PKEY_RSA:
  732. #ifdef EVP_PKEY_RSA_PSS
  733.         case EVP_PKEY_RSA_PSS:
  734. #endif
  735.             alg = (u_char *) "RSA";
  736.             break;

  737.         case EVP_PKEY_EC:
  738.             alg = (u_char *) "EC";
  739.             break;

  740.         case EVP_PKEY_DSA:
  741.             alg = (u_char *) "DSA";
  742.             break;

  743.         default:
  744.             EVP_PKEY_free(pkey);
  745.             return NGX_DECLINED;
  746.         }

  747.         out->len = sizeof("RSA16384") - 1;
  748.         out->data = ngx_pnalloc(c->pool, out->len);
  749.         if (out->data == NULL) {
  750.             EVP_PKEY_free(pkey);
  751.             return NGX_ERROR;
  752.         }

  753.         out->len = ngx_snprintf(out->data, out->len, "%s%d",
  754.                                 alg, EVP_PKEY_bits(pkey))
  755.                    - out->data;

  756.         EVP_PKEY_free(pkey);

  757.         return NGX_OK;
  758.     }

  759.     return NGX_DECLINED;
  760. }

  761. #endif


  762. static u_char *
  763. ngx_proxy_protocol_v2_write_header(ngx_connection_t *c, u_char *buf,
  764.     u_char *last)
  765. {
  766.     u_char                            *p, src_af, dst_af,
  767.                                        family, command, transport;
  768.     ngx_uint_t                         src_fam, dst_fam;
  769.     ngx_proxy_protocol_header_t       *header;
  770.     ngx_proxy_protocol_inet_addrs_t   *in;
  771. #if (NGX_HAVE_INET6)
  772.     ngx_uint_t                         port, lport;
  773.     struct in6_addr                   *src6, *dst6;
  774.     ngx_proxy_protocol_inet6_addrs_t  *in6;
  775. #endif

  776.     if (last - buf < NGX_PROXY_PROTOCOL_V2_MAX_HEADER) {
  777.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  778.                       "too small buffer for PROXY protocol v2");
  779.         return NULL;
  780.     }

  781.     if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
  782.         return NULL;
  783.     }

  784.     /* the length field is set by the caller once all TLVs are written */

  785.     header = (ngx_proxy_protocol_header_t *) buf;

  786.     ngx_memcpy(header->signature, ngx_proxy_protocol_signature,
  787.                sizeof(ngx_proxy_protocol_signature) - 1);

  788.     p = buf + sizeof(ngx_proxy_protocol_header_t);

  789.     src_fam = c->sockaddr->sa_family;
  790.     dst_fam = c->local_sockaddr->sa_family;

  791.     src_af = ngx_proxy_protocol_v2_family(src_fam);
  792.     dst_af = ngx_proxy_protocol_v2_family(dst_fam);

  793.     /* promote to the highest address family present on either side */

  794.     if (src_af == NGX_PROXY_PROTOCOL_AF_UNSPEC
  795.         || dst_af == NGX_PROXY_PROTOCOL_AF_UNSPEC)
  796.     {
  797.         command = NGX_PROXY_PROTOCOL_CMD_LOCAL;
  798.         family = NGX_PROXY_PROTOCOL_AF_UNSPEC;
  799.         transport = NGX_PROXY_PROTOCOL_TYPE_UNSPEC;

  800.     } else {
  801.         command = NGX_PROXY_PROTOCOL_CMD_PROXY;
  802.         family = ngx_max(src_af, dst_af);

  803.         switch (c->type) {
  804.         case SOCK_STREAM:
  805.             transport = NGX_PROXY_PROTOCOL_TYPE_STREAM;
  806.             break;
  807.         case SOCK_DGRAM:
  808.             transport = NGX_PROXY_PROTOCOL_TYPE_DGRAM;
  809.             break;
  810.         default:
  811.             transport = NGX_PROXY_PROTOCOL_TYPE_UNSPEC;
  812.             break;
  813.         }
  814.     }

  815.     header->version_command = 0x20 | command;
  816.     header->family_transport = (family << 4) | transport;

  817.     switch (family) {

  818.     case NGX_PROXY_PROTOCOL_AF_INET:

  819.         in = (ngx_proxy_protocol_inet_addrs_t *) p;

  820.         ngx_proxy_protocol_v2_write_ipv4(c->sockaddr,
  821.                                          in->src_addr, in->src_port);
  822.         ngx_proxy_protocol_v2_write_ipv4(c->local_sockaddr,
  823.                                          in->dst_addr, in->dst_port);

  824.         p += sizeof(ngx_proxy_protocol_inet_addrs_t);

  825.         break;

  826. #if (NGX_HAVE_INET6)

  827.     case NGX_PROXY_PROTOCOL_AF_INET6:

  828.         if (src_fam == AF_INET6 && dst_fam == AF_INET6) {
  829.             src6 = &((struct sockaddr_in6 *) c->sockaddr)->sin6_addr;
  830.             dst6 = &((struct sockaddr_in6 *) c->local_sockaddr)->sin6_addr;

  831.             if (IN6_IS_ADDR_V4MAPPED(src6) && IN6_IS_ADDR_V4MAPPED(dst6)) {

  832.                 /* both v4-mapped: demote to AF_INET */

  833.                 header->family_transport = (NGX_PROXY_PROTOCOL_AF_INET << 4)
  834.                                            | transport;

  835.                 in = (ngx_proxy_protocol_inet_addrs_t *) p;

  836.                 ngx_memcpy(in->src_addr, src6->s6_addr + 12, 4);
  837.                 ngx_memcpy(in->dst_addr, dst6->s6_addr + 12, 4);

  838.                 port  = ngx_inet_get_port(c->sockaddr);
  839.                 lport = ngx_inet_get_port(c->local_sockaddr);

  840.                 in->src_port[0] = (u_char) (port >> 8);
  841.                 in->src_port[1] = (u_char)  port;
  842.                 in->dst_port[0] = (u_char) (lport >> 8);
  843.                 in->dst_port[1] = (u_char)  lport;

  844.                 p += sizeof(ngx_proxy_protocol_inet_addrs_t);
  845.                 break;
  846.             }
  847.         }

  848.         in6 = (ngx_proxy_protocol_inet6_addrs_t *) p;

  849.         ngx_proxy_protocol_v2_write_ipv6(c->sockaddr,
  850.                                          in6->src_addr, in6->src_port);
  851.         ngx_proxy_protocol_v2_write_ipv6(c->local_sockaddr,
  852.                                          in6->dst_addr, in6->dst_port);

  853.         p += sizeof(ngx_proxy_protocol_inet6_addrs_t);

  854.         break;

  855. #endif

  856.     default/* NGX_PROXY_PROTOCOL_AF_UNSPEC */
  857.         break;
  858.     }

  859.     return p;
  860. }


  861. static u_char
  862. ngx_proxy_protocol_v2_family(ngx_uint_t family)
  863. {
  864.     switch (family) {

  865.     case AF_INET:
  866.         return NGX_PROXY_PROTOCOL_AF_INET;

  867. #if (NGX_HAVE_INET6)
  868.     case AF_INET6:
  869.         return NGX_PROXY_PROTOCOL_AF_INET6;
  870. #endif

  871.     default:
  872.         return NGX_PROXY_PROTOCOL_AF_UNSPEC;
  873.     }
  874. }


  875. static void
  876. ngx_proxy_protocol_v2_write_ipv4(struct sockaddr *sa, u_char *addr,
  877.     u_char *port)
  878. {
  879.     struct sockaddr_in  *sin;

  880.     sin = (struct sockaddr_in *) sa;
  881.     ngx_memcpy(addr, &sin->sin_addr, 4);
  882.     ngx_memcpy(port, &sin->sin_port, 2);
  883. }


  884. #if (NGX_HAVE_INET6)

  885. static void
  886. ngx_proxy_protocol_v2_write_ipv6(struct sockaddr *sa, u_char *addr,
  887.     u_char *port)
  888. {
  889.     struct sockaddr_in   *sin;
  890.     struct sockaddr_in6  *sin6;

  891.     /* IPv4-mapped prefix: 80 zero bits + 16 one bits */
  892.     static const u_char  mapped[]   = { 0x00, 0x00, 0x00, 0x00,
  893.                                         0x00, 0x00, 0x00, 0x00,
  894.                                         0x00, 0x00, 0xff, 0xff };

  895.     if (sa->sa_family == AF_INET6) {
  896.         sin6 = (struct sockaddr_in6 *) sa;
  897.         ngx_memcpy(addr, &sin6->sin6_addr, 16);
  898.         ngx_memcpy(port, &sin6->sin6_port, 2);

  899.     } else {
  900.         /* promote AF_INET to ::ffff:a.b.c.d */
  901.         sin = (struct sockaddr_in *) sa;
  902.         ngx_memcpy(addr, mapped, sizeof(mapped));
  903.         ngx_memcpy(addr + sizeof(mapped), &sin->sin_addr, 4);
  904.         ngx_memcpy(port, &sin->sin_port, 2);
  905.     }
  906. }

  907. #endif


  908. static u_char *
  909. ngx_proxy_protocol_v2_write_tlv(ngx_connection_t *c, u_char *p, u_char *last,
  910.     ngx_uint_t type, ngx_str_t *value)
  911. {
  912.     ngx_proxy_protocol_tlv_t  *tlv;

  913.     if ((size_t) (last - p) < sizeof(ngx_proxy_protocol_tlv_t) + value->len) {
  914.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  915.                       "too small buffer for PROXY protocol v2 TLV");
  916.         return NULL;
  917.     }

  918.     tlv = (ngx_proxy_protocol_tlv_t *) p;
  919.     tlv->type = (u_char) type;
  920.     tlv->len[0] = (u_char) (value->len >> 8);
  921.     tlv->len[1] = (u_char)  value->len;

  922.     p += sizeof(ngx_proxy_protocol_tlv_t);

  923.     return ngx_cpymem(p, value->data, value->len);
  924. }


  925. static u_char *
  926. ngx_proxy_protocol_v2_write_ssl(ngx_connection_t *c, u_char *p, u_char *last,
  927.     ngx_array_t *ssl_tlvs, ngx_uint_t client, uint32_t verify)
  928. {
  929.     u_char                          *start;
  930.     uint16_t                         len;
  931.     ngx_uint_t                       i;
  932.     ngx_proxy_protocol_tlv_t        *tlv;
  933.     ngx_proxy_protocol_tlv_ssl_t    *tlv_ssl;
  934.     ngx_proxy_protocol_tlv_value_t  *sub;

  935.     if ((size_t) (last - p) < sizeof(ngx_proxy_protocol_tlv_t)
  936.                               + sizeof(ngx_proxy_protocol_tlv_ssl_t))
  937.     {
  938.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  939.                       "too small buffer for PROXY protocol v2 SSL TLV");
  940.         return NULL;
  941.     }

  942.     start = p;
  943.     p += sizeof(ngx_proxy_protocol_tlv_t);

  944.     tlv_ssl = (ngx_proxy_protocol_tlv_ssl_t *) p;
  945.     tlv_ssl->client = (u_char) client;
  946.     tlv_ssl->verify[0] = (u_char) (verify >> 24);
  947.     tlv_ssl->verify[1] = (u_char) (verify >> 16);
  948.     tlv_ssl->verify[2] = (u_char) (verify >> 8);
  949.     tlv_ssl->verify[3] = (u_char)  verify;

  950.     p += sizeof(ngx_proxy_protocol_tlv_ssl_t);

  951.     sub = ssl_tlvs->elts;

  952.     for (i = 0; i < ssl_tlvs->nelts; i++) {
  953.         p = ngx_proxy_protocol_v2_write_tlv(c, p, last, sub[i].type,
  954.                                             &sub[i].value);
  955.         if (p == NULL) {
  956.             return NULL;
  957.         }
  958.     }

  959.     len = (uint16_t) (p - start - sizeof(ngx_proxy_protocol_tlv_t));

  960.     tlv = (ngx_proxy_protocol_tlv_t *) start;
  961.     tlv->type = NGX_PROXY_PROTOCOL_TLV_SSL;
  962.     tlv->len[0] = (u_char) (len >> 8);
  963.     tlv->len[1] = (u_char)  len;

  964.     return p;
  965. }


  966. static void
  967. ngx_proxy_protocol_v2_set_len(u_char *buf, u_char *p)
  968. {
  969.     uint16_t                      len;
  970.     ngx_proxy_protocol_header_t  *header;

  971.     len = (uint16_t) (p - buf - sizeof(ngx_proxy_protocol_header_t));

  972.     header = (ngx_proxy_protocol_header_t *) buf;
  973.     header->len[0] = (u_char) (len >> 8);
  974.     header->len[1] = (u_char) len;
  975. }


  976. static u_char *
  977. ngx_proxy_protocol_v2_write_crc32c(ngx_connection_t *c, u_char *buf,
  978.     u_char *p, u_char *last)
  979. {
  980.     u_char                    *value;
  981.     uint32_t                   crc;
  982.     ngx_proxy_protocol_tlv_t  *tlv;

  983.     if ((size_t) (last - p) < sizeof(ngx_proxy_protocol_tlv_t) + 4) {
  984.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  985.                       "too small buffer for PROXY protocol v2 CRC32c TLV");
  986.         return NULL;
  987.     }

  988.     /* append the CRC32c TLV with a zeroed value field */

  989.     tlv = (ngx_proxy_protocol_tlv_t *) p;
  990.     tlv->type = NGX_PROXY_PROTOCOL_TLV_CRC32C;
  991.     tlv->len[0] = 0;
  992.     tlv->len[1] = 4;

  993.     value = p + sizeof(ngx_proxy_protocol_tlv_t);

  994.     ngx_memzero(value, 4);

  995.     p = value + 4;

  996.     /* the checksum covers the entire header with the zeroed value */

  997.     crc = ngx_crc32c_long(buf, p - buf);

  998.     value[0] = (u_char) (crc >> 24);
  999.     value[1] = (u_char) (crc >> 16);
  1000.     value[2] = (u_char) (crc >> 8);
  1001.     value[3] = (u_char) crc;

  1002.     return p;
  1003. }