changeset 8939:ddd5e5c0f87d quic

QUIC: improved path validation. Previously, path was considered valid during arbitrary selected 10m timeout since validation. This is quite not what RFC 9000 says; the relevant part is: An endpoint MAY skip validation of a peer address if that address has been seen recently. The patch considers a path to be 'recently seen' if packets were received during idle timeout. If a packet is received from the path that was seen not so recently, such path is considered new, and anti-amplification restrictions apply.
author Vladimir Homutov <vl@nginx.com>
date Mon, 13 Dec 2021 17:27:29 +0300
parents 23880e4ad3e2
children fb41e37ddeb0
files src/event/quic/ngx_event_quic_connection.h src/event/quic/ngx_event_quic_migration.c src/event/quic/ngx_event_quic_migration.h src/event/quic/ngx_event_quic_socket.c
diffstat 4 files changed, 15 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/quic/ngx_event_quic_connection.h
+++ b/src/event/quic/ngx_event_quic_connection.h
@@ -86,6 +86,7 @@ struct ngx_quic_path_s {
     socklen_t                         socklen;
     ngx_uint_t                        state;
     ngx_msec_t                        expires;
+    ngx_msec_t                        last_seen;
     ngx_uint_t                        tries;
     off_t                             sent;
     off_t                             received;
@@ -93,7 +94,6 @@ struct ngx_quic_path_s {
     u_char                            challenge2[8];
     ngx_uint_t                        refcnt;
     uint64_t                          seqnum;
-    time_t                            validated_at;
     ngx_str_t                         addr_text;
     u_char                            text[NGX_SOCKADDR_STRLEN];
 };
--- a/src/event/quic/ngx_event_quic_migration.c
+++ b/src/event/quic/ngx_event_quic_migration.c
@@ -158,7 +158,6 @@ valid:
                    "quic path #%uL successfully validated", path->seqnum);
 
     path->state = NGX_QUIC_PATH_VALIDATED;
-    path->validated_at = ngx_time();
 
     return NGX_OK;
 }
@@ -217,6 +216,7 @@ ngx_quic_add_path(ngx_connection_t *c, s
     }
 
     path->seqnum = qc->path_seqnum++;
+    path->last_seen = ngx_current_msec;
 
     path->socklen = socklen;
     ngx_memcpy(path->sockaddr, sockaddr, socklen);
@@ -272,6 +272,7 @@ ngx_quic_update_paths(ngx_connection_t *
     ngx_quic_client_id_t   *cid;
     ngx_quic_connection_t  *qc;
 
+    qc = ngx_quic_get_connection(c);
     qsock = ngx_quic_get_socket(c);
 
     if (c->udp->dgram == NULL) {
@@ -313,7 +314,6 @@ ngx_quic_update_paths(ngx_connection_t *
         cid = ngx_quic_used_client_id(c, path);
         if (cid == NULL) {
 
-            qc = ngx_quic_get_connection(c);
             qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR;
             qc->error_reason = "no available client ids for new path";
 
@@ -328,6 +328,17 @@ ngx_quic_update_paths(ngx_connection_t *
 
 update:
 
+    if (path->state != NGX_QUIC_PATH_NEW) {
+        /* force limits/revalidation for paths that were not seen recently */
+        if (ngx_current_msec - path->last_seen > qc->tp.max_idle_timeout) {
+            path->state = NGX_QUIC_PATH_NEW;
+            path->sent = 0;
+            path->received = 0;
+        }
+    }
+
+    path->last_seen = ngx_current_msec;
+
     len = pkt->raw->last - pkt->raw->start;
 
     /* TODO: this may be too late in some cases;
@@ -396,31 +407,10 @@ ngx_quic_handle_migration(ngx_connection
                    qsock->sid.seqnum, qsock->cid->seqnum, next->seqnum,
                    ngx_quic_path_state_str(next));
 
-    switch (next->state) {
-    case NGX_QUIC_PATH_NEW:
+    if (next->state == NGX_QUIC_PATH_NEW) {
         if (ngx_quic_validate_path(c, qsock) != NGX_OK) {
             return NGX_ERROR;
         }
-        break;
-
-    /* migration to previously known path */
-
-    case NGX_QUIC_PATH_VALIDATING:
-        /* alredy validating, nothing to do */
-        break;
-
-    case NGX_QUIC_PATH_VALIDATED:
-        /* if path is old enough, revalidate */
-        if (ngx_time() - next->validated_at > NGX_QUIC_PATH_VALID_TIME) {
-
-            next->state = NGX_QUIC_PATH_NEW;
-
-            if (ngx_quic_validate_path(c, qsock) != NGX_OK) {
-                return NGX_ERROR;
-            }
-        }
-
-        break;
     }
 
     ctx = ngx_quic_get_send_ctx(qc, pkt->level);
--- a/src/event/quic/ngx_event_quic_migration.h
+++ b/src/event/quic/ngx_event_quic_migration.h
@@ -17,8 +17,6 @@
 #define NGX_QUIC_PATH_VALIDATING       1
 #define NGX_QUIC_PATH_VALIDATED        2
 
-#define NGX_QUIC_PATH_VALID_TIME       600 /* seconds */
-
 
 #define ngx_quic_path_state_str(p)                                            \
     ((p)->state == NGX_QUIC_PATH_NEW) ? "new" :                               \
--- a/src/event/quic/ngx_event_quic_socket.c
+++ b/src/event/quic/ngx_event_quic_socket.c
@@ -82,7 +82,6 @@ ngx_quic_open_sockets(ngx_connection_t *
 
     if (pkt->validated) {
         path->state = NGX_QUIC_PATH_VALIDATED;
-        path->validated_at = ngx_time();
     }
 
     /* now bind socket to client and path */