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

Roman Arutyunyan arut at nginx.com
Wed Nov 2 13:06:25 UTC 2022


Hi,

On Tue, Nov 01, 2022 at 05:14:02PM +0300, Maxim Dounin wrote:
> Hello!
> 
> On Mon, Oct 31, 2022 at 04:07:00PM +0400, Roman Arutyunyan wrote:
> 
> > While testing the feature, it became clear that 107 bytes as maximum PROXY
> > protocol header size may not be enough.  This limit came from v1 and stayed
> > unchanged when v2 was added.  With this limit, there are only 79 bytes left for
> > TLVs in case of IPv4 and 55 bytes in case of IPv6.
> > 
> > Attached is a patch that increases buffer size up to 65K while reading PROXY
> > protocl header.  Writing is not changed since only v1 is supported.
> 
> [...]
> 
> > # HG changeset patch
> > # User Roman Arutyunyan <arut at nginx.com>
> > # Date 1667216033 -14400
> > #      Mon Oct 31 15:33:53 2022 +0400
> > # Node ID 8c99314f90eccc2ad5aaf4b3de5368e964c4ffe0
> > # Parent  81b4326daac70d6de70abbc3fe36d4f6e3da54a2
> > Increased maximum read PROXY protocol header size.
> > 
> > Maximum size for reading the PROXY protocol header is increased to 65536 to
> > accommodate a bigger number of TLVs, which are supported since cca4c8a715de.
> > 
> > Maximum size for writing the PROXY protocol header is not changed since only
> > version 1 is currently supported.
> > 
> > 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
> > @@ -281,7 +281,7 @@ ngx_proxy_protocol_write(ngx_connection_
> >  {
> >      ngx_uint_t  port, lport;
> >  
> > -    if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) {
> > +    if (last - buf < NGX_PROXY_PROTOCOL_V1_MAX_HEADER) {
> >          return NULL;
> >      }
> >  
> > 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,8 @@
> >  #include <ngx_core.h>
> >  
> >  
> > -#define NGX_PROXY_PROTOCOL_MAX_HEADER  107
> > +#define NGX_PROXY_PROTOCOL_V1_MAX_HEADER  107
> > +#define NGX_PROXY_PROTOCOL_MAX_HEADER     65536
> >  
> >  
> >  struct ngx_proxy_protocol_s {
> > diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> > --- a/src/http/ngx_http_request.c
> > +++ b/src/http/ngx_http_request.c
> > @@ -641,7 +641,7 @@ ngx_http_alloc_request(ngx_connection_t 
> >  static void
> >  ngx_http_ssl_handshake(ngx_event_t *rev)
> >  {
> > -    u_char                    *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];
> > +    u_char                    *p;
> >      size_t                     size;
> >      ssize_t                    n;
> >      ngx_err_t                  err;
> > @@ -651,6 +651,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
> >      ngx_http_ssl_srv_conf_t   *sscf;
> >      ngx_http_core_loc_conf_t  *clcf;
> >      ngx_http_core_srv_conf_t  *cscf;
> > +    static u_char              buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];
> >  
> 
> I'm somewhat sceptical about the idea of allocation of up to 3 
> global 64k buffers, especially given that the protocol requires 
> atomic sending of the header, which means it cannot reliably 
> exceed 1500 bytes in most configurations.
> 
> Further, the maximum size of the proxy protocol header in non-SSL 
> case is still limited by client_header_buffer_size, which is 1024 
> bytes by default.  Assuming there will be headers which does not 
> fit into 1k buffer, it is not clear why these will magically work 
> in case of SSL, but will require client_header_buffer_size tuning 
> otherwise.

It will require tuning in some cases and work automatically in others.
Currently it only works where tuning is available.

> Might be some dynamically allocated buffer, sized after 
> client_header_buffer_size, like in non-SSL case, would be a better 
> idea?

We read PROXY protocol in mail and stream as well, which would require
similar settings there.

> (It also might make sense to avoid assuming atomicity, which 
> clearly cannot be guaranteed if the header is larger than MTU.  
> This will also require dynamically allocated per-connection 
> buffers.)

Yes, dynamic per-connection buffers is what I've been trying to avoid.

> Alternatively, we can consider using some larger-than-now on-stack 
> buffers, something like 4k should be acceptable given we use such 
> buffers in other places anyway.  It should be enough for most 
> proxy protocol headers.

I like this alternative.  This was in fact my first thought, but the actual
number was (and still is) hard to pick.  I suggest that we increase the
on-stack buffer for reading and leave the writing buffer size as is for now.
The writing part will need refactoring anyway when we add ppv2 support.

--
Roman Arutyunyan
-------------- next part --------------
# HG changeset patch
# User Roman Arutyunyan <arut at nginx.com>
# Date 1667382376 -14400
#      Wed Nov 02 13:46:16 2022 +0400
# Node ID dc5f16e6a243c15f58e2c6a62f7a83f536729174
# Parent  81b4326daac70d6de70abbc3fe36d4f6e3da54a2
Increased maximum read PROXY protocol header size.

Maximum size for reading the PROXY protocol header is increased to 4096 to
accommodate a bigger number of TLVs, which are supported since cca4c8a715de.

Maximum size for writing the PROXY protocol header is not changed since only
version 1 is currently supported.

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
@@ -281,7 +281,7 @@ ngx_proxy_protocol_write(ngx_connection_
 {
     ngx_uint_t  port, lport;
 
-    if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) {
+    if (last - buf < NGX_PROXY_PROTOCOL_V1_MAX_HEADER) {
         return NULL;
     }
 
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,8 @@
 #include <ngx_core.h>
 
 
-#define NGX_PROXY_PROTOCOL_MAX_HEADER  107
+#define NGX_PROXY_PROTOCOL_V1_MAX_HEADER  107
+#define NGX_PROXY_PROTOCOL_MAX_HEADER     4096
 
 
 struct ngx_proxy_protocol_s {
diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -890,7 +890,7 @@ ngx_mail_proxy_send_proxy_protocol(ngx_m
     u_char            *p;
     ssize_t            n, size;
     ngx_connection_t  *c;
-    u_char             buf[NGX_PROXY_PROTOCOL_MAX_HEADER];
+    u_char             buf[NGX_PROXY_PROTOCOL_V1_MAX_HEADER];
 
     s->connection->log->action = "sending PROXY protocol header to upstream";
 
@@ -898,7 +898,7 @@ ngx_mail_proxy_send_proxy_protocol(ngx_m
                    "mail proxy send PROXY protocol header");
 
     p = ngx_proxy_protocol_write(s->connection, buf,
-                                 buf + NGX_PROXY_PROTOCOL_MAX_HEADER);
+                                 buf + NGX_PROXY_PROTOCOL_V1_MAX_HEADER);
     if (p == NULL) {
         ngx_mail_proxy_internal_server_error(s);
         return NGX_ERROR;
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -894,7 +894,7 @@ ngx_stream_proxy_init_upstream(ngx_strea
             return;
         }
 
-        p = ngx_pnalloc(c->pool, NGX_PROXY_PROTOCOL_MAX_HEADER);
+        p = ngx_pnalloc(c->pool, NGX_PROXY_PROTOCOL_V1_MAX_HEADER);
         if (p == NULL) {
             ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
             return;
@@ -902,7 +902,8 @@ ngx_stream_proxy_init_upstream(ngx_strea
 
         cl->buf->pos = p;
 
-        p = ngx_proxy_protocol_write(c, p, p + NGX_PROXY_PROTOCOL_MAX_HEADER);
+        p = ngx_proxy_protocol_write(c, p,
+                                     p + NGX_PROXY_PROTOCOL_V1_MAX_HEADER);
         if (p == NULL) {
             ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
             return;
@@ -946,14 +947,15 @@ ngx_stream_proxy_send_proxy_protocol(ngx
     ngx_connection_t             *c, *pc;
     ngx_stream_upstream_t        *u;
     ngx_stream_proxy_srv_conf_t  *pscf;
-    u_char                        buf[NGX_PROXY_PROTOCOL_MAX_HEADER];
+    u_char                        buf[NGX_PROXY_PROTOCOL_V1_MAX_HEADER];
 
     c = s->connection;
 
     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
                    "stream proxy send PROXY protocol header");
 
-    p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER);
+    p = ngx_proxy_protocol_write(c, buf,
+                                 buf + NGX_PROXY_PROTOCOL_V1_MAX_HEADER);
     if (p == NULL) {
         ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
         return NGX_ERROR;


More information about the nginx-devel mailing list