# HG changeset patch # User Sergey Kandaurov # Date 1604956844 -10800 # Node ID 340cd26158fb6bd362fc72c4ea4f52568af23e23 # Parent 8550b91e8e35a1d507838a10a1b60ea9089a249b QUIC: preparatory changes for multiple QUIC versions support. 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. diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c --- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -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 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 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_set_packet_number(&pkt, ctx); + pkt.version = qc->version; pkt.log = c->log; pkt.level = start->level; pkt.dcid = qc->scid; diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c --- a/src/event/ngx_event_quic_transport.c +++ b/src/event/ngx_event_quic_transport.c @@ -72,6 +72,7 @@ static ngx_int_t ngx_quic_parse_short_he 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 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_hea *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_head *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 } +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)