changeset 9087:3bb003fcd682 quic

QUIC: keep stream sockaddr and addr_text constant. HTTP and Stream variables $remote_addr and $binary_remote_addr rely on constant client address, particularly because they are cacheable. However, QUIC client may migrate to a new address. While there's no perfect way to handle this, the proposed solution is to copy client address to QUIC stream at stream creation. The change also fixes truncated $remote_addr if migration happened while the stream was active. The reason is addr_text string was copied to stream by value.
author Roman Arutyunyan <arut@nginx.com>
date Thu, 11 May 2023 19:40:11 +0400
parents cc3d24a9b76f
children 3028db26a0f5
files src/event/quic/ngx_event_quic_streams.c
diffstat 1 files changed, 29 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/quic/ngx_event_quic_streams.c
+++ b/src/event/quic/ngx_event_quic_streams.c
@@ -637,10 +637,12 @@ ngx_quic_do_init_streams(ngx_connection_
 static ngx_quic_stream_t *
 ngx_quic_create_stream(ngx_connection_t *c, uint64_t id)
 {
+    ngx_str_t               addr_text;
     ngx_log_t              *log;
     ngx_pool_t             *pool;
     ngx_uint_t              reusable;
     ngx_queue_t            *q;
+    struct sockaddr        *sockaddr;
     ngx_connection_t       *sc;
     ngx_quic_stream_t      *qs;
     ngx_pool_cleanup_t     *cln;
@@ -692,6 +694,31 @@ ngx_quic_create_stream(ngx_connection_t 
     *log = *c->log;
     pool->log = log;
 
+    sockaddr = ngx_palloc(pool, c->socklen);
+    if (sockaddr == NULL) {
+        ngx_destroy_pool(pool);
+        ngx_queue_insert_tail(&qc->streams.free, &qs->queue);
+        return NULL;
+    }
+
+    ngx_memcpy(sockaddr, c->sockaddr, c->socklen);
+
+    if (c->addr_text.data) {
+        addr_text.data = ngx_pnalloc(pool, c->addr_text.len);
+        if (addr_text.data == NULL) {
+            ngx_destroy_pool(pool);
+            ngx_queue_insert_tail(&qc->streams.free, &qs->queue);
+            return NULL;
+        }
+
+        ngx_memcpy(addr_text.data, c->addr_text.data, c->addr_text.len);
+        addr_text.len = c->addr_text.len;
+
+    } else {
+        addr_text.len = 0;
+        addr_text.data = NULL;
+    }
+
     reusable = c->reusable;
     ngx_reusable_connection(c, 0);
 
@@ -710,10 +737,10 @@ ngx_quic_create_stream(ngx_connection_t 
     sc->type = SOCK_STREAM;
     sc->pool = pool;
     sc->ssl = c->ssl;
-    sc->sockaddr = c->sockaddr;
+    sc->sockaddr = sockaddr;
     sc->socklen = c->socklen;
     sc->listening = c->listening;
-    sc->addr_text = c->addr_text;
+    sc->addr_text = addr_text;
     sc->local_sockaddr = c->local_sockaddr;
     sc->local_socklen = c->local_socklen;
     sc->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);