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