]> git.kaiwu.me - nginx.git/commitdiff
QUIC: preparatory changes for multiple QUIC versions support.
authorSergey Kandaurov <pluknet@nginx.com>
Mon, 9 Nov 2020 21:20:44 +0000 (00:20 +0300)
committerSergey Kandaurov <pluknet@nginx.com>
Mon, 9 Nov 2020 21:20:44 +0000 (00:20 +0300)
A negotiated version is decoupled from NGX_QUIC_VERSION and, if supported,
now stored in c->quic->version after packets processing.  It is then used
to create long header packets.  Otherwise, the list of supported versions
(which may be many now) is sent in the Version Negotiation packet.

All packets in the connection are expected to have the same version.
Incoming packets with mismatched version are now rejected.

src/event/ngx_event_quic.c
src/event/ngx_event_quic_transport.c

index 60f22b026eb992d37aa0193d3c34cb6d8a79affc..4b0050d074c7044bab377dc1074109bd4fefb58c 100644 (file)
@@ -115,6 +115,7 @@ typedef struct {
 
 
 struct ngx_quic_connection_s {
+    uint32_t                          version;
     ngx_str_t                         scid;  /* initial client ID */
     ngx_str_t                         dcid;  /* server (our own) ID */
     ngx_str_t                         odcid; /* original server ID */
@@ -958,6 +959,8 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf,
         return NULL;
     }
 
+    qc->version = pkt->version;
+
     ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel,
                     ngx_quic_rbtree_insert_stream);
 
@@ -1224,6 +1227,7 @@ ngx_quic_send_retry(ngx_connection_t *c)
 
     ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
     pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY;
+    pkt.version = c->quic->version;
     pkt.log = c->log;
     pkt.odcid = c->quic->odcid;
     pkt.dcid = c->quic->scid;
@@ -2020,6 +2024,14 @@ ngx_quic_process_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
             return NGX_DECLINED;
         }
 
+        if (pkt->level != ssl_encryption_application) {
+            if (pkt->version != qc->version) {
+                ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                              "quic version mismatch: 0x%xD", pkt->version);
+                return NGX_DECLINED;
+            }
+        }
+
         if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
 
             if (pkt->level == ssl_encryption_application) {
@@ -4549,6 +4561,7 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
 
     ngx_quic_set_packet_number(&pkt, ctx);
 
+    pkt.version = qc->version;
     pkt.log = c->log;
     pkt.level = start->level;
     pkt.dcid = qc->scid;
index 26cc690bf35869261fe74644e8cc5c861448ac6f..4248e867ae1cda19f26601dc654447b318f164bf 100644 (file)
@@ -72,6 +72,7 @@ static ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt,
     size_t dcid_len);
 static ngx_int_t ngx_quic_parse_initial_header(ngx_quic_header_t *pkt);
 static ngx_int_t ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt);
+static ngx_int_t ngx_quic_supported_version(uint32_t version);
 
 static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt,
     ngx_uint_t frame_type);
@@ -268,7 +269,7 @@ ngx_quic_parse_packet(ngx_quic_header_t *pkt)
         return NGX_DECLINED;
     }
 
-    if (pkt->version != NGX_QUIC_VERSION) {
+    if (!ngx_quic_supported_version(pkt->version)) {
         return NGX_ABORT;
     }
 
@@ -430,7 +431,7 @@ ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
 
     *p++ = pkt->flags;
 
-    p = ngx_quic_write_uint32(p, NGX_QUIC_VERSION);
+    p = ngx_quic_write_uint32(p, pkt->version);
 
     *p++ = pkt->dcid.len;
     p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len);
@@ -517,7 +518,7 @@ ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out,
 
     *p++ = 0xff;
 
-    p = ngx_quic_write_uint32(p, NGX_QUIC_VERSION);
+    p = ngx_quic_write_uint32(p, pkt->version);
 
     *p++ = pkt->dcid.len;
     p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len);
@@ -651,6 +652,21 @@ ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt)
 }
 
 
+static ngx_int_t
+ngx_quic_supported_version(uint32_t version)
+{
+    ngx_uint_t  i;
+
+    for (i = 0; i < NGX_QUIC_NVERSIONS; i++) {
+        if (ngx_quic_versions[i] == version) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+
 #define ngx_quic_stream_bit_off(val)  (((val) & 0x04) ? 1 : 0)
 #define ngx_quic_stream_bit_len(val)  (((val) & 0x02) ? 1 : 0)
 #define ngx_quic_stream_bit_fin(val)  (((val) & 0x01) ? 1 : 0)