Hello! On Tue, Oct 11, 2022 at 05:01:11PM +0400, Roman Arutyunyan wrote:
[...] > # HG changeset patch > # User Roman Arutyunyan <a...@nginx.com> > # Date 1664263604 -14400 > # Tue Sep 27 11:26:44 2022 +0400 > # Node ID 2774f8d59b108635752f9f2dbe3a5394a3650b85 > # Parent ba5cf8f73a2d0a3615565bf9545f3d65216a0530 > PROXY protocol v2 TLV variables. > > The variables have prefix $proxy_protocol_tlv_ and are accessible by name > and by type. Examples are: $proxy_protocol_tlv_0x01, > $proxy_protocol_tlv_alpn. > > 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 > @@ -15,6 +15,12 @@ > > #define ngx_proxy_protocol_parse_uint16(p) ((p)[0] << 8 | (p)[1]) > > +#define ngx_proxy_protocol_parse_uint32(p) > \ > + ( ((uint32_t) (p)[0] << 24) > \ > + + ( (p)[1] << 16) > \ > + + ( (p)[2] << 8) > \ > + + ( (p)[3]) ) > + > > typedef struct { > u_char signature[12]; > @@ -40,12 +46,52 @@ typedef struct { > } ngx_proxy_protocol_inet6_addrs_t; > > > +typedef struct { > + u_char type; > + u_char len[2]; > +} ngx_proxy_protocol_tlv_t; > + > + > +typedef struct { > + u_char client; > + u_char verify[4]; > +} ngx_proxy_protocol_tlv_ssl_t; > + > + > +typedef struct { > + ngx_str_t name; > + ngx_uint_t type; > +} ngx_proxy_protocol_tlv_entry_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, > in_port_t *port, u_char sep); > static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, > u_char *last); > +static ngx_int_t ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c, > + ngx_str_t *tlvs, ngx_uint_t type, ngx_str_t *value); > + > + > +static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_entries[] = { > + { ngx_string("alpn"), 0x01 }, > + { ngx_string("authority"), 0x02 }, > + { ngx_string("unique_id"), 0x05 }, > + { ngx_string("ssl"), 0x20 }, > + { ngx_string("netns"), 0x30 }, > + { ngx_null_string, 0x00 } > +}; > + > + > +static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_ssl_entries[] > = { > + { ngx_string("version"), 0x21 }, > + { ngx_string("cn"), 0x22 }, > + { ngx_string("cipher"), 0x23 }, > + { ngx_string("sig_alg"), 0x24 }, > + { ngx_string("key_alg"), 0x25 }, > + { ngx_null_string, 0x00 } > +}; > > > u_char * > @@ -412,11 +458,147 @@ 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->tlvs.data = ngx_pnalloc(c->pool, end - buf); > + if (pp->tlvs.data == NULL) { > + return NULL; > + } > + > + ngx_memcpy(pp->tlvs.data, buf, end - buf); > + pp->tlvs.len = end - buf; > } > > c->proxy_protocol = pp; > > return end; > } > + > + > +ngx_int_t > +ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name, > + ngx_str_t *value) > +{ > + u_char *p; > + size_t n; > + uint32_t verify; > + ngx_str_t ssl, *tlvs; > + ngx_int_t rc, type; > + ngx_proxy_protocol_tlv_ssl_t *tlv_ssl; > + ngx_proxy_protocol_tlv_entry_t *te; > + > + if (c->proxy_protocol == NULL) { > + return NGX_DECLINED; > + } > + > + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, > + "PROXY protocol v2 get tlv \"%V\"", name); > + > + te = ngx_proxy_protocol_tlv_entries; > + tlvs = &c->proxy_protocol->tlvs; > + > + p = name->data; > + n = name->len; > + > + if (n >= 4 && p[0] == 's' && p[1] == 's' && p[2] == 'l' && p[3] == '_') { > + > + rc = ngx_proxy_protocol_lookup_tlv(c, tlvs, 0x20, &ssl); > + if (rc != NGX_OK) { > + return rc; > + } > + > + if (ssl.len < sizeof(ngx_proxy_protocol_tlv_ssl_t)) { > + return NGX_ERROR; > + } > + > + p += 4; > + n -= 4; > + > + if (n == 6 && ngx_strncmp(p, "verify", 6) == 0) { > + > + tlv_ssl = (ngx_proxy_protocol_tlv_ssl_t *) ssl.data; > + verify = ngx_proxy_protocol_parse_uint32(tlv_ssl->verify); > + > + value->data = ngx_pnalloc(c->pool, NGX_INT32_LEN); > + if (value->data == NULL) { > + return NGX_ERROR; > + } > + > + value->len = ngx_sprintf(value->data, "%uD", verify) > + - value->data; > + return NGX_OK; > + } > + > + ssl.data += sizeof(ngx_proxy_protocol_tlv_ssl_t); > + ssl.len -= sizeof(ngx_proxy_protocol_tlv_ssl_t); > + > + te = ngx_proxy_protocol_tlv_ssl_entries; > + tlvs = &ssl; > + } > + > + if (n >= 2 && p[0] == '0' && p[1] == 'x') { > + > + type = ngx_hextoi(p + 2, n - 2); > + if (type == NGX_ERROR) { > + ngx_log_error(NGX_LOG_ERR, c->log, 0, > + "invalid PROXY protocol TLV \"%V\"", name); > + return NGX_ERROR; > + } > + > + return ngx_proxy_protocol_lookup_tlv(c, tlvs, type, value); > + } > + > + for ( /* void */ ; te->type; te++) { > + if (te->name.len == n && ngx_strncmp(te->name.data, p, n) == 0) { > + return ngx_proxy_protocol_lookup_tlv(c, tlvs, te->type, value); > + } > + } > + > + ngx_log_error(NGX_LOG_ERR, c->log, 0, > + "PROXY protocol TLV \"%V\" not found", name); "not found" suggests it's something known/valid yet not present in the TLVs provided by the client. "unknown PROXY protocol TLV ..."? > + > + return NGX_DECLINED; > +} > + > + > +static ngx_int_t > +ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c, ngx_str_t *tlvs, > + ngx_uint_t type, ngx_str_t *value) > +{ > + u_char *p; > + size_t n, len; > + ngx_proxy_protocol_tlv_t *tlv; > + > + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, > + "PROXY protocol v2 lookup tlv:%02xi", type); > + > + p = tlvs->data; > + n = tlvs->len; > + > + while (n) { > + if (n < sizeof(ngx_proxy_protocol_tlv_t)) { > + ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol > TLV"); > + return NGX_ERROR; > + } > + > + tlv = (ngx_proxy_protocol_tlv_t *) p; > + len = ngx_proxy_protocol_parse_uint16(tlv->len); > + > + p += sizeof(ngx_proxy_protocol_tlv_t); > + n -= sizeof(ngx_proxy_protocol_tlv_t); > + > + if (n < len) { > + ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol > TLV"); > + return NGX_ERROR; > + } > + > + if (tlv->type == type) { > + value->data = p; > + value->len = len; > + return NGX_OK; > + } > + > + p += len; > + n -= len; > + } > + > + return NGX_DECLINED; > +} > 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_str_t tlvs; > }; > > > @@ -28,6 +29,8 @@ u_char *ngx_proxy_protocol_read(ngx_conn > u_char *last); > u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, > u_char *last); > +ngx_int_t ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name, > + ngx_str_t *value); > > > #endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */ > 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_"), 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,39 @@ 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_str_t *name = (ngx_str_t *) data; > + > + ngx_int_t rc; > + ngx_str_t tlv, value; > + > + tlv.len = name->len - (sizeof("proxy_protocol_tlv_") - 1); > + tlv.data = name->data + sizeof("proxy_protocol_tlv_") - 1; > + > + rc = ngx_proxy_protocol_get_tlv(r->connection, &tlv, &value); > + > + if (rc == NGX_ERROR) { > + return NGX_ERROR; > + } > + > + if (rc == NGX_DECLINED) { > + v->not_found = 1; > + return NGX_OK; > + } > + > + v->len = value.len; > + v->valid = 1; > + v->no_cacheable = 0; > + v->not_found = 0; > + v->data = value.data; > + > + return NGX_OK; > +} > + > + > +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, > @@ -79,6 +81,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_"), 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 +628,39 @@ 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_str_t *name = (ngx_str_t *) data; > + > + ngx_int_t rc; > + ngx_str_t tlv, value; > + > + tlv.len = name->len - (sizeof("proxy_protocol_tlv_") - 1); > + tlv.data = name->data + sizeof("proxy_protocol_tlv_") - 1; > + > + rc = ngx_proxy_protocol_get_tlv(s->connection, &tlv, &value); > + > + if (rc == NGX_ERROR) { > + return NGX_ERROR; > + } > + > + if (rc == NGX_DECLINED) { > + v->not_found = 1; > + return NGX_OK; > + } > + > + v->len = value.len; > + v->valid = 1; > + v->no_cacheable = 0; > + v->not_found = 0; > + v->data = value.data; > + > + return NGX_OK; > +} > + > + > +static ngx_int_t > ngx_stream_variable_server_addr(ngx_stream_session_t *s, > ngx_stream_variable_value_t *v, uintptr_t data) > { Otherwise looks good. -- Maxim Dounin http://mdounin.ru/ _______________________________________________ nginx-devel mailing list -- nginx-devel@nginx.org To unsubscribe send an email to nginx-devel-le...@nginx.org