Hi, > On 31 Aug 2022, at 19:52, Roman Arutyunyan <a...@nginx.com> wrote: > > # HG changeset patch > # User Roman Arutyunyan <a...@nginx.com> > # Date 1661436099 -14400 > # Thu Aug 25 18:01:39 2022 +0400 > # Node ID 4b856f1dff939e4eb9c131e17af061cf2c38cfac > # Parent 069a4813e8d6d7ec662d282a10f5f7062ebd817f > Core: support for reading PROXY protocol v2 TLVs. > > The TLV values are available in HTTP and Stream variables > $proxy_protocol_tlv_0xN, where N is a hexadecimal TLV type number with no > leading zeroes.
A small update, thanks to Eran Kornblau. diff --git a/src/core/ngx_proxy_protocol.c b/src/core/ngx_proxy_protocol.c --- a/src/core/ngx_proxy_protocol.c +++ b/src/core/ngx_proxy_protocol.c @@ -446,7 +446,7 @@ ngx_proxy_protocol_v2_read(ngx_connectio } ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol v2 TLV type:0x%0xd len:%uz", + "PROXY protocol v2 TLV type:0x%xd len:%uz", tlv->type, len); t = ngx_list_push(pp_tlv); @@ -462,7 +462,7 @@ ngx_proxy_protocol_v2_read(ngx_connectio return NULL; } - t->key.len = ngx_sprintf(t->key.data, "%0xd", tlv->type) + t->key.len = ngx_sprintf(t->key.data, "%xd", tlv->type) - t->key.data; t->value.data = ngx_pnalloc(c->pool, len); Another possible update is support for arbitrary number of leading zeroes. Not sure we need this right now though. > diff --git a/src/core/ngx_proxy_protocol.c b/src/core/ngx_proxy_protocol.c > --- a/src/core/ngx_proxy_protocol.c > +++ b/src/core/ngx_proxy_protocol.c > @@ -40,6 +40,12 @@ typedef struct { > } ngx_proxy_protocol_inet6_addrs_t; > > > +typedef struct { > + u_char type; > + u_char len[2]; > +} ngx_proxy_protocol_tlv_t; > + > + > static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, > u_char *last, ngx_str_t *addr); > static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last, > @@ -273,8 +279,11 @@ ngx_proxy_protocol_v2_read(ngx_connectio > size_t len; > socklen_t socklen; > ngx_uint_t version, command, family, transport; > + ngx_list_t *pp_tlv; > ngx_sockaddr_t src_sockaddr, dst_sockaddr; > + ngx_table_elt_t *t; > ngx_proxy_protocol_t *pp; > + ngx_proxy_protocol_tlv_t *tlv; > ngx_proxy_protocol_header_t *header; > ngx_proxy_protocol_inet_addrs_t *in; > #if (NGX_HAVE_INET6) > @@ -412,8 +421,63 @@ ngx_proxy_protocol_v2_read(ngx_connectio > &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port); > > if (buf < end) { > - ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, > - "PROXY protocol v2 %z bytes of tlv ignored", end - > buf); > + pp_tlv = ngx_list_create(c->pool, 1, sizeof(ngx_table_elt_t)); > + if (pp_tlv == NULL) { > + return NULL; > + } > + > + while (buf < end) { > + if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_tlv_t)) { > + ngx_log_error(NGX_LOG_ERR, c->log, 0, > + "broken PROXY protocol TLV"); > + return NULL; > + } > + > + tlv = (ngx_proxy_protocol_tlv_t *) buf; > + > + buf += sizeof(ngx_proxy_protocol_tlv_t); > + > + len = ngx_proxy_protocol_parse_uint16(tlv->len); > + > + if ((size_t) (end - buf) < len) { > + ngx_log_error(NGX_LOG_ERR, c->log, 0, > + "broken PROXY protocol TLV"); > + return NULL; > + } > + > + ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, > + "PROXY protocol v2 TLV type:0x%0xd len:%uz", > + tlv->type, len); > + > + t = ngx_list_push(pp_tlv); > + if (t == NULL) { > + return NULL; > + } > + > + t->hash = 1; > + t->lowcase_key = NULL; > + > + t->key.data = ngx_pnalloc(c->pool, 2); > + if (t->key.data == NULL) { > + return NULL; > + } > + > + t->key.len = ngx_sprintf(t->key.data, "%0xd", tlv->type) > + - t->key.data; > + > + t->value.data = ngx_pnalloc(c->pool, len); > + if (t->value.data == NULL) { > + return NULL; > + } > + > + ngx_memcpy(t->value.data, buf, len); > + > + t->value.len = len; > + > + buf += len; > + } > + > + pp->tlv = pp_tlv; > } > > c->proxy_protocol = pp; > diff --git a/src/core/ngx_proxy_protocol.h b/src/core/ngx_proxy_protocol.h > --- a/src/core/ngx_proxy_protocol.h > +++ b/src/core/ngx_proxy_protocol.h > @@ -21,6 +21,7 @@ struct ngx_proxy_protocol_s { > ngx_str_t dst_addr; > in_port_t src_port; > in_port_t dst_port; > + ngx_list_t *tlv; > }; > > > diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c > --- a/src/http/ngx_http_variables.c > +++ b/src/http/ngx_http_variables.c > @@ -61,6 +61,8 @@ static ngx_int_t ngx_http_variable_proxy > ngx_http_variable_value_t *v, uintptr_t data); > static ngx_int_t ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r, > ngx_http_variable_value_t *v, uintptr_t data); > +static ngx_int_t ngx_http_variable_proxy_protocol_tlv(ngx_http_request_t *r, > + ngx_http_variable_value_t *v, uintptr_t data); > static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, > ngx_http_variable_value_t *v, uintptr_t data); > static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r, > @@ -214,6 +216,10 @@ static ngx_http_variable_t ngx_http_cor > ngx_http_variable_proxy_protocol_port, > offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 }, > > + { ngx_string("proxy_protocol_tlv_0x"), NULL, > + ngx_http_variable_proxy_protocol_tlv, > + 0, NGX_HTTP_VAR_PREFIX, 0 }, > + > { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 > }, > > { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 > }, > @@ -1387,6 +1393,24 @@ ngx_http_variable_proxy_protocol_port(ng > > > static ngx_int_t > +ngx_http_variable_proxy_protocol_tlv(ngx_http_request_t *r, > + ngx_http_variable_value_t *v, uintptr_t data) > +{ > + ngx_proxy_protocol_t *pp; > + > + pp = r->connection->proxy_protocol; > + if (pp == NULL || pp->tlv == NULL) { > + v->not_found = 1; > + return NGX_OK; > + } > + > + return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data, > + &pp->tlv->part, > + sizeof("proxy_protocol_tlv_0x") - > 1); > +} > + > + > +static ngx_int_t > ngx_http_variable_server_addr(ngx_http_request_t *r, > ngx_http_variable_value_t *v, uintptr_t data) > { > diff --git a/src/stream/ngx_stream_variables.c > b/src/stream/ngx_stream_variables.c > --- a/src/stream/ngx_stream_variables.c > +++ b/src/stream/ngx_stream_variables.c > @@ -23,6 +23,8 @@ static ngx_int_t ngx_stream_variable_pro > ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); > static ngx_int_t ngx_stream_variable_proxy_protocol_port( > ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); > +static ngx_int_t ngx_stream_variable_proxy_protocol_tlv( > + ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); > static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s, > ngx_stream_variable_value_t *v, uintptr_t data); > static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s, > @@ -51,6 +53,10 @@ static ngx_int_t ngx_stream_variable_tim > static ngx_int_t ngx_stream_variable_protocol(ngx_stream_session_t *s, > ngx_stream_variable_value_t *v, uintptr_t data); > > +static ngx_int_t ngx_stream_variable_unknown_header(ngx_stream_session_t *s, > + ngx_stream_variable_value_t *v, ngx_str_t *var, ngx_list_part_t *part, > + size_t prefix); > + > > static ngx_stream_variable_t ngx_stream_core_variables[] = { > > @@ -79,6 +85,10 @@ static ngx_stream_variable_t ngx_stream > ngx_stream_variable_proxy_protocol_port, > offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 }, > > + { ngx_string("proxy_protocol_tlv_0x"), NULL, > + ngx_stream_variable_proxy_protocol_tlv, > + 0, NGX_STREAM_VAR_PREFIX, 0 }, > + > { ngx_string("server_addr"), NULL, > ngx_stream_variable_server_addr, 0, 0, 0 }, > > @@ -622,6 +632,24 @@ ngx_stream_variable_proxy_protocol_port( > > > static ngx_int_t > +ngx_stream_variable_proxy_protocol_tlv(ngx_stream_session_t *s, > + ngx_stream_variable_value_t *v, uintptr_t data) > +{ > + ngx_proxy_protocol_t *pp; > + > + pp = s->connection->proxy_protocol; > + if (pp == NULL || pp->tlv == NULL) { > + v->not_found = 1; > + return NGX_OK; > + } > + > + return ngx_stream_variable_unknown_header(s, v, (ngx_str_t *) data, > + &pp->tlv->part, > + sizeof("proxy_protocol_tlv_0x") - > 1); > +} > + > + > +static ngx_int_t > ngx_stream_variable_server_addr(ngx_stream_session_t *s, > ngx_stream_variable_value_t *v, uintptr_t data) > { > @@ -911,6 +939,116 @@ ngx_stream_variable_protocol(ngx_stream_ > } > > > +static ngx_int_t > +ngx_stream_variable_unknown_header(ngx_stream_session_t *s, > + ngx_stream_variable_value_t *v, ngx_str_t *var, > + ngx_list_part_t *part, size_t prefix) > +{ > + u_char *p, ch; > + size_t len; > + ngx_uint_t i, n; > + ngx_table_elt_t *header, *h, **ph; > + > + ph = &h; > +#if (NGX_SUPPRESS_WARN) > + len = 0; > +#endif > + > + header = part->elts; > + > + for (i = 0; /* void */ ; i++) { > + > + if (i >= part->nelts) { > + if (part->next == NULL) { > + break; > + } > + > + part = part->next; > + header = part->elts; > + i = 0; > + } > + > + if (header[i].hash == 0) { > + continue; > + } > + > + if (header[i].key.len != var->len - prefix) { > + continue; > + } > + > + for (n = 0; n < var->len - prefix; n++) { > + ch = header[i].key.data[n]; > + > + if (ch >= 'A' && ch <= 'Z') { > + ch |= 0x20; > + > + } else if (ch == '-') { > + ch = '_'; > + } > + > + if (var->data[n + prefix] != ch) { > + break; > + } > + } > + > + if (n != var->len - prefix) { > + continue; > + } > + > + len += header[i].value.len + 2; > + > + *ph = &header[i]; > + ph = &header[i].next; > + } > + > + *ph = NULL; > + > + if (h == NULL) { > + v->not_found = 1; > + return NGX_OK; > + } > + > + len -= 2; > + > + if (h->next == NULL) { > + > + v->len = h->value.len; > + v->valid = 1; > + v->no_cacheable = 0; > + v->not_found = 0; > + v->data = h->value.data; > + > + return NGX_OK; > + } > + > + p = ngx_pnalloc(s->connection->pool, len); > + if (p == NULL) { > + return NGX_ERROR; > + } > + > + v->len = len; > + v->valid = 1; > + v->no_cacheable = 0; > + v->not_found = 0; > + v->data = p; > + > + for ( ;; ) { > + > + p = ngx_copy(p, h->value.data, h->value.len); > + > + if (h->next == NULL) { > + break; > + } > + > + *p++ = ','; *p++ = ' '; > + > + h = h->next; > + } > + > + return NGX_OK; > +} > + > + > void * > ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map, > ngx_str_t *match) > > _______________________________________________ > nginx-devel mailing list -- nginx-devel@nginx.org > To unsubscribe send an email to nginx-devel-le...@nginx.org ---- Roman Arutyunyan a...@nginx.com
_______________________________________________ nginx-devel mailing list -- nginx-devel@nginx.org To unsubscribe send an email to nginx-devel-le...@nginx.org