# HG changeset patch # User Vladimir Homutov # Date 1585911736 -10800 # Node ID fdda518d10ba30c2889dbd061d784390ca117fc5 # Parent de8981bf2dd5909af52f0b9736c6fa15c7b45451 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 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 @@ -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; diff --git a/src/event/ngx_event_quic_protection.c b/src/event/ngx_event_quic_protection.c --- 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; 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 @@ -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; } diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h --- 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;