]> git.kaiwu.me - nginx.git/commitdiff
QUIC: fixed anti-amplification with explicit send.
authorRoman Arutyunyan <arut@nginx.com>
Wed, 22 Nov 2023 10:52:21 +0000 (14:52 +0400)
committerRoman Arutyunyan <arut@nginx.com>
Wed, 22 Nov 2023 10:52:21 +0000 (14:52 +0400)
Previously, when using ngx_quic_frame_sendto() to explicitly send a packet with
a single frame, anti-amplification limit was not properly enforced.  Even when
there was no quota left for the packet, it was sent anyway, but with no padding.
Now the packet is not sent at all.

This function is called to send PATH_CHALLENGE/PATH_RESPONSE, PMTUD and probe
packets.  For all these cases packet send is retried later in case the send was
not successful.

src/event/quic/ngx_event_quic_migration.c
src/event/quic/ngx_event_quic_output.c

index 2fccafa41878c3f1cc69e9ba3e04872376af3e1b..efb167b0adea5d1fa3854bcb8c7b520958476cdc 100644 (file)
@@ -872,6 +872,7 @@ ngx_quic_expire_path_mtu_discovery(ngx_connection_t *c, ngx_quic_path_t *path)
 static ngx_int_t
 ngx_quic_send_path_mtu_probe(ngx_connection_t *c, ngx_quic_path_t *path)
 {
+    size_t                  mtu;
     ngx_int_t               rc;
     ngx_uint_t              log_error;
     ngx_quic_frame_t        frame;
@@ -895,7 +896,12 @@ ngx_quic_send_path_mtu_probe(ngx_connection_t *c, ngx_quic_path_t *path)
     log_error = c->log_error;
     c->log_error = NGX_ERROR_IGNORE_EMSGSIZE;
 
+    mtu = path->mtu;
+    path->mtu = path->mtud;
+
     rc = ngx_quic_frame_sendto(c, &frame, path->mtud, path);
+
+    path->mtu = mtu;
     c->log_error = log_error;
 
     if (rc == NGX_ERROR) {
index a0acdb700231dd16b150d46e6643827bf7b4c889..338451e8b4804f534575b962fbe1d385b3d371c3 100644 (file)
@@ -1181,7 +1181,7 @@ ngx_int_t
 ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
     size_t min, ngx_quic_path_t *path)
 {
-    size_t                  min_payload, pad;
+    size_t                  max, max_payload, min_payload, pad;
     ssize_t                 len, sent;
     ngx_str_t               res;
     ngx_quic_header_t       pkt;
@@ -1194,15 +1194,25 @@ ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
     qc = ngx_quic_get_connection(c);
     ctx = ngx_quic_get_send_ctx(qc, frame->level);
 
-    ngx_quic_init_packet(c, ctx, &pkt, path);
+    max = ngx_quic_path_limit(c, path, path->mtu);
 
-    min = ngx_quic_path_limit(c, path, min);
+    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                   "quic sendto %s packet max:%uz min:%uz",
+                   ngx_quic_level_name(ctx->level), max, min);
 
-    min_payload = min ? ngx_quic_payload_size(&pkt, min) : 0;
+    ngx_quic_init_packet(c, ctx, &pkt, path);
+
+    min_payload = ngx_quic_payload_size(&pkt, min);
+    max_payload = ngx_quic_payload_size(&pkt, max);
 
+    /* RFC 9001, 5.4.2.  Header Protection Sample */
     pad = 4 - pkt.num_len;
     min_payload = ngx_max(min_payload, pad);
 
+    if (min_payload > max_payload) {
+        return NGX_AGAIN;
+    }
+
 #if (NGX_DEBUG)
     frame->pnum = pkt.number;
 #endif
@@ -1210,8 +1220,8 @@ ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
     ngx_quic_log_frame(c->log, frame, 1);
 
     len = ngx_quic_create_frame(NULL, frame);
-    if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) {
-        return NGX_ERROR;
+    if ((size_t) len > max_payload) {
+        return NGX_AGAIN;
     }
 
     len = ngx_quic_create_frame(src, frame);
@@ -1258,8 +1268,6 @@ ngx_quic_path_limit(ngx_connection_t *c, ngx_quic_path_t *path, size_t size)
         max = (path->sent >= max) ? 0 : max - path->sent;
 
         if ((off_t) size > max) {
-            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "quic path limit %uz - %O", size, max);
             return max;
         }
     }