changeset 8315:fdda518d10ba quic

Proper handling of packet number in header. - fixed setting of largest received packet number. - sending properly truncated packet number - added support for multi-byte packet number
author Vladimir Homutov <vl@nginx.com>
date Fri, 03 Apr 2020 14:02:16 +0300
parents de8981bf2dd5
children 0dc0552335bd
files src/event/ngx_event_quic.c src/event/ngx_event_quic_protection.c src/event/ngx_event_quic_transport.c src/event/ngx_event_quic_transport.h
diffstat 4 files changed, 96 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -48,7 +48,7 @@ typedef struct {
     ngx_quic_secret_t                 server_secret;
 
     uint64_t                          pnum;
-    uint64_t                          largest;
+    uint64_t                          largest; /* number received from peer */
 
     ngx_queue_t                       frames;
     ngx_queue_t                       sent;
@@ -150,6 +150,9 @@ static ngx_int_t ngx_quic_output_ns(ngx_
     ngx_quic_namespace_t *ns, ngx_uint_t nsi);
 static void ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames);
 static ngx_int_t ngx_quic_send_frames(ngx_connection_t *c, ngx_queue_t *frames);
+
+static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt,
+    ngx_quic_namespace_t *ns);
 static void ngx_quic_retransmit_handler(ngx_event_t *ev);
 static ngx_int_t ngx_quic_retransmit_ns(ngx_connection_t *c,
     ngx_quic_namespace_t *ns, ngx_msec_t *waitp);
@@ -1235,7 +1238,7 @@ ngx_quic_handle_ack_frame(ngx_connection
 
         if (ack->largest <= ns->pnum) {
             /* duplicate ACK or ACK for non-ack-eliciting frame */
-            return NGX_OK;
+            goto done;
         }
 
         ngx_log_error(NGX_LOG_INFO, c->log, 0,
@@ -1244,9 +1247,13 @@ ngx_quic_handle_ack_frame(ngx_connection
         return NGX_ERROR;
     }
 
+done:
+
     /* 13.2.3.  Receiver Tracking of ACK Frames */
     if (ns->largest < ack->largest) {
-        ack->largest = ns->largest;
+        ns->largest = ack->largest;
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "updated largest received: %ui", ns->largest);
     }
 
     return NGX_OK;
@@ -1740,7 +1747,6 @@ ngx_quic_send_frames(ngx_connection_t *c
     keys = &c->quic->keys[start->level];
 
     pkt.secret = &keys->server;
-    pkt.number = ns->pnum;
 
     if (start->level == ssl_encryption_initial) {
         pkt.flags = NGX_QUIC_PKT_INITIAL;
@@ -1748,8 +1754,13 @@ ngx_quic_send_frames(ngx_connection_t *c
 
     } else if (start->level == ssl_encryption_handshake) {
         pkt.flags = NGX_QUIC_PKT_HANDSHAKE;
+
+    } else {
+        pkt.flags = 0x40; // TODO: macro, set FIXED bit
     }
 
+    ngx_quic_set_packet_number(&pkt, ns);
+
     pkt.log = c->log;
     pkt.level = start->level;
     pkt.dcid = qc->dcid;
@@ -1780,6 +1791,36 @@ ngx_quic_send_frames(ngx_connection_t *c
 
 
 static void
+ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_namespace_t *ns)
+{
+    uint64_t  delta;
+
+    delta = ns->pnum - ns->largest;
+    pkt->number = ns->pnum;
+
+    if (delta <= 0x7F) {
+        pkt->num_len = 1;
+        pkt->trunc = ns->pnum & 0xff;
+
+    } else if (delta <= 0x7FFF) {
+        pkt->num_len = 2;
+        pkt->flags |= 0x1;
+        pkt->trunc = ns->pnum & 0xffff;
+
+    } else if (delta <= 0x7FFFFF) {
+        pkt->num_len = 3;
+        pkt->flags |= 0x2;
+        pkt->trunc = ns->pnum & 0xffffff;
+
+    } else {
+        pkt->num_len = 4;
+        pkt->flags |= 0x3;
+        pkt->trunc = ns->pnum & 0xffffffff;
+    }
+}
+
+
+static void
 ngx_quic_retransmit_handler(ngx_event_t *ev)
 {
     ngx_uint_t              i;
--- a/src/event/ngx_event_quic_protection.c
+++ b/src/event/ngx_event_quic_protection.c
@@ -656,6 +656,7 @@ ngx_quic_create_long_packet(ngx_quic_hea
 {
     u_char              *pnp, *sample;
     ngx_str_t            ad, out;
+    ngx_uint_t           i;
     ngx_quic_ciphers_t   ciphers;
     u_char               nonce[12], mask[16];
 
@@ -685,7 +686,7 @@ ngx_quic_create_long_packet(ngx_quic_hea
         return NGX_ERROR;
     }
 
-    sample = &out.data[3]; // pnl=0
+    sample = &out.data[4 - pkt->num_len];
     if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample)
         != NGX_OK)
     {
@@ -696,9 +697,12 @@ ngx_quic_create_long_packet(ngx_quic_hea
     ngx_quic_hexdump0(pkt->log, "mask", mask, 16);
     ngx_quic_hexdump0(pkt->log, "hp_key", pkt->secret->hp.data, 16);
 
-    // header protection, pnl = 0
+    /* quic-tls: 5.4.1.  Header Protection Application */
     ad.data[0] ^= mask[0] & 0x0f;
-    *pnp ^= mask[1];
+
+    for (i = 0; i < pkt->num_len; i++) {
+        pnp[i] ^= mask[i + 1];
+    }
 
     res->len = ad.len + out.len;
 
@@ -712,6 +716,7 @@ ngx_quic_create_short_packet(ngx_quic_he
 {
     u_char              *pnp, *sample;
     ngx_str_t            ad, out;
+    ngx_uint_t           i;
     ngx_quic_ciphers_t   ciphers;
     u_char               nonce[12], mask[16];
 
@@ -743,7 +748,7 @@ ngx_quic_create_short_packet(ngx_quic_he
 
     ngx_quic_hexdump0(pkt->log, "out", out.data, out.len);
 
-    sample = &out.data[3]; // pnl=0
+    sample = &out.data[4 - pkt->num_len];
     if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample)
         != NGX_OK)
     {
@@ -754,9 +759,12 @@ ngx_quic_create_short_packet(ngx_quic_he
     ngx_quic_hexdump0(pkt->log, "mask", mask, 16);
     ngx_quic_hexdump0(pkt->log, "hp_key", pkt->secret->hp.data, 16);
 
-    // header protection, pnl = 0
+    /* quic-tls: 5.4.1.  Header Protection Application */
     ad.data[0] ^= mask[0] & 0x1f;
-    *pnp ^= mask[1];
+
+    for (i = 0; i < pkt->num_len; i++) {
+        pnp[i] ^= mask[i + 1];
+    }
 
     res->len = ad.len + out.len;
 
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -37,6 +37,11 @@
 
 #endif
 
+#define ngx_quic_write_uint24(p, s)                                           \
+    ((p)[0] = (u_char) ((s) >> 16),                                           \
+     (p)[1] = (u_char) ((s) >> 8),                                            \
+     (p)[2] = (u_char)  (s),                                                  \
+     (p) + 3)
 
 #define ngx_quic_write_uint16_aligned(p, s)                                   \
     (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))
@@ -362,11 +367,24 @@ ngx_quic_create_long_header(ngx_quic_hea
         ngx_quic_build_int(&p, pkt->token.len);
     }
 
-    ngx_quic_build_int(&p, pkt_len + 1); // length (inc. pnl)
+    ngx_quic_build_int(&p, pkt_len + pkt->num_len);
 
     *pnp = p;
 
-    *p++ = pkt->number; // XXX: uint64
+    switch (pkt->num_len) {
+    case 1:
+        *p++ = pkt->trunc;
+        break;
+    case 2:
+        p = ngx_quic_write_uint16(p, pkt->trunc);
+        break;
+    case 3:
+        p = ngx_quic_write_uint24(p, pkt->trunc);
+        break;
+    case 4:
+        p = ngx_quic_write_uint32(p, pkt->trunc);
+        break;
+    }
 
     return p - start;
 }
@@ -380,13 +398,26 @@ ngx_quic_create_short_header(ngx_quic_he
 
     p = start = out;
 
-    *p++ = 0x40;
+    *p++ = pkt->flags;
 
     p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);
 
     *pnp = p;
 
-    *p++ = pkt->number; // XXX: uint64
+    switch (pkt->num_len) {
+    case 1:
+        *p++ = pkt->trunc;
+        break;
+    case 2:
+        p = ngx_quic_write_uint16(p, pkt->trunc);
+        break;
+    case 3:
+        p = ngx_quic_write_uint24(p, pkt->trunc);
+        break;
+    case 4:
+        p = ngx_quic_write_uint32(p, pkt->trunc);
+        break;
+    }
 
     return p - start;
 }
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -238,6 +238,8 @@ typedef struct {
 
     struct ngx_quic_secret_s                   *secret;
     uint64_t                                    number;
+    uint8_t                                     num_len;
+    uint32_t                                    trunc;
     uint8_t                                     flags;
     uint32_t                                    version;
     ngx_str_t                                   token;