[PATCH] Core: support for reading PROXY protocol v2 TLVs

Maxim Dounin mdounin at mdounin.ru
Mon Sep 12 21:30:17 UTC 2022


Hello!

On Fri, Sep 09, 2022 at 07:46:58PM +0400, Roman Arutyunyan wrote:

> On Mon, Sep 05, 2022 at 06:58:38PM +0300, Maxim Dounin wrote:
> > Hello!
> > 
> > On Mon, Sep 05, 2022 at 05:23:18PM +0400, Roman Arutyunyan wrote:
> > 
> > > Hi,
> > > 
> > > On Mon, Sep 05, 2022 at 03:52:49AM +0300, Maxim Dounin wrote:
> > > > Hello!
> > > > 
> > > > On Wed, Aug 31, 2022 at 07:52:15PM +0400, Roman Arutyunyan wrote:
> > > > 
> > > > > # HG changeset patch
> > > > > # User Roman Arutyunyan <arut at 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.
> > > > 
> > > > First of all, could you please provide details on the use case?  
> > > > I've seen requests for writing proxy protocol TLVs to upstream 
> > > > servers (see ticket #1639), but not yet seen any meaningful 
> > > > reading requests.
> > > 
> > > The known cases are these:
> > > 
> > > - https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol
> > > - https://docs.microsoft.com/en-us/azure/private-link/private-link-service-overview#getting-connection-information-using-tcp-proxy-v2
> > > - https://cloud.google.com/vpc/docs/configure-private-service-connect-producer#proxy-protocol
> > > 
> > > The data may need further parsing, but it can be done in njs or perl.
> > 
> > Thanks for the details.  So, basically, it's about vendor-specific 
> > endpoint IDs.
> > 
> > > > > 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.
> > > > 
> > > > I can't say I like the "hexadecimal TLV type number with no 
> > > > leading zeroes" approach, especially given that the specification 
> > > > uses leading zeroes in TLV types.  With leading zeros might be 
> > > > better, to match specification.
> 
> With on-demand approach this is no longer an issue.
> 
> > > > Also, it might worth the effort to actually add names for known 
> > > > types instead or in addition to numbers.
> > > 
> > > This is indeed a good idea and we have such plans as a further extenion of this
> > > work.  One of the problems is however that the abovementioned TLV variables
> > > are specified in internal documents of AWS/Azure/GCP which are not standards.
> > > They can be changed anytime, while we have to maintain those variables in
> > > nginx.  Also, raw variables give more flexibility in supporting less known TLVs.
> > 
> > Of course I'm not suggesting to ditch raw variables, at least not 
> > for unknown/non-standard values.  But for known/standard values it 
> > should be easy enough to provide alternative names for easier use, 
> > probably with type-specific parsing.
> > 
> > With on-demand parsing it would be trivial to support both 
> > $proxy_protocol_tlv_alpn and $proxy_protocol_tlv_0x01.  Further, 
> > it will be trivial to support $proxy_protocol_tlv_aws_vpc_id while 
> > still providing $proxy_protocol_tlv_0xea for raw data.

[...]

> # HG changeset patch
> # User Roman Arutyunyan <arut at nginx.com>
> # Date 1662718130 -14400
> #      Fri Sep 09 14:08:50 2022 +0400
> # Node ID 832f6c96b26c3009640072e3f4b1f0bf43e644d0
> # Parent  80714f1b0f597ce5e530e7274457450db4587fc9
> Standard PROXY protocol v2 TLV variables.
> 
> 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
> @@ -13,7 +13,18 @@
>  #include <ngx_core.h>
>  
>  
> -#define NGX_PROXY_PROTOCOL_MAX_HEADER  107
> +#define NGX_PROXY_PROTOCOL_MAX_HEADER       107
> +
> +#define NGX_PROXY_PROTOCOL_TLV_ALPN         0x01
> +#define NGX_PROXY_PROTOCOL_TLV_AUTHORITY    0x02
> +#define NGX_PROXY_PROTOCOL_TLV_UNIQUE_ID    0x05
> +#define NGX_PROXY_PROTOCOL_TLV_SSL          0x20
> +#define NGX_PROXY_PROTOCOL_TLV_SSL_VERSION  0x21
> +#define NGX_PROXY_PROTOCOL_TLV_SSL_CN       0x22
> +#define NGX_PROXY_PROTOCOL_TLV_SSL_CIPHER   0x23
> +#define NGX_PROXY_PROTOCOL_TLV_SSL_SIG_ALG  0x24
> +#define NGX_PROXY_PROTOCOL_TLV_SSL_KEY_ALG  0x25
> +#define NGX_PROXY_PROTOCOL_TLV_NETNS        0x30
>  
>  
>  struct ngx_proxy_protocol_s {
> @@ -25,6 +36,12 @@ struct ngx_proxy_protocol_s {
>  };
>  
>  
> +typedef struct {
> +    u_char              client;
> +    u_char              verify[4];

Note that these two are completely ignored.

> +} ngx_proxy_protocol_tlv_ssl_t;
> +
> +
>  u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf,
>      u_char *last);
>  u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
> 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
> @@ -63,6 +63,10 @@ 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_tlv_0x(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_proxy_protocol_tlv_ssl(
> +    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,
> @@ -220,6 +224,42 @@ static ngx_http_variable_t  ngx_http_cor
>        ngx_http_variable_proxy_protocol_tlv_0x,
>        0, NGX_HTTP_VAR_PREFIX, 0 },
>  
> +    { ngx_string("proxy_protocol_tlv_alpn"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv,
> +      NGX_PROXY_PROTOCOL_TLV_ALPN, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_authority"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv,
> +      NGX_PROXY_PROTOCOL_TLV_AUTHORITY, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_unique_id"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv,
> +      NGX_PROXY_PROTOCOL_TLV_UNIQUE_ID, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_ssl_version"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv_ssl,
> +      NGX_PROXY_PROTOCOL_TLV_SSL_VERSION, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_ssl_cn"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv_ssl,
> +      NGX_PROXY_PROTOCOL_TLV_SSL_CN, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_ssl_cipher"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv_ssl,
> +      NGX_PROXY_PROTOCOL_TLV_SSL_CIPHER, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_ssl_sig_alg"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv_ssl,
> +      NGX_PROXY_PROTOCOL_TLV_SSL_SIG_ALG, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_ssl_key_alg"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv_ssl,
> +      NGX_PROXY_PROTOCOL_TLV_SSL_KEY_ALG, 0, 0 },
> +
> +    { ngx_string("proxy_protocol_tlv_netns"), NULL,
> +      ngx_http_variable_proxy_protocol_tlv,
> +      NGX_PROXY_PROTOCOL_TLV_NETNS, 0, 0 },
> +

Further, these provide no interface to support arbitrary SSL TLVs 
(that is, something like "$proxy_protocol_tlv_ssl_0x10").

Overall, I tend to think it would be much easier / less intrusive 
to keep all the TLV handling logic in the 
src/core/ngx_proxy_protocol.c, including both arbitrary TLVs with 
hexadecimal type and known named TLVs, and only provide a single 
prefix variable in stream / http modules.

That is, use "$proxy_protocol_tlv_" prefix variable and call a 
function to obtain TLV with the rest of the variable name.

This might imply slightly more complex/less efficient name parsing 
logic for known TLVs, but I don't think it will be noticeable.  On 
the other hand, it will reduce clutter in the variables hash, and 
therefore will save some resources in configurations where these 
variables are not used.

[...]

-- 
Maxim Dounin
http://mdounin.ru/



More information about the nginx-devel mailing list