From: Amaury Denoyelle Date: Mon, 17 Apr 2023 13:03:51 +0000 (+0200) Subject: MINOR: quic: adjust Rx packet type parsing X-Git-Tag: v2.8-dev8~115 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1a5cc19cecfa84bfd0fdd7b9d5d20899cce40662;p=thirdparty%2Fhaproxy.git MINOR: quic: adjust Rx packet type parsing qc_parse_hd_form() is the function used to parse the first byte of a packet and return its type and version. Its API has been simplified with the following changes : * extra out paremeters are removed (long_header and version). All infos are now stored directly in quic_rx_packet instance * a new dummy version is declared in quic_versions array with a 0 number code. This can be used to match Version negotiation packets. * a new default packet type is defined QUIC_PACKET_TYPE_UNKNOWN to be used as an initial value. Also, the function has been exported to an include file. This will be useful to be able to reuse on quic-sock to parse the first packet of a datagram. This should be backported up to 2.7. --- diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index 1efb8f9da4..5e6b5d6c09 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -131,6 +131,9 @@ enum quic_pkt_type { * own convenience. */ QUIC_PACKET_TYPE_SHORT, + + /* unknown type */ + QUIC_PACKET_TYPE_UNKNOWN }; /* Packet number field length. */ diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index ade8a81d83..78a97552f0 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -687,6 +687,8 @@ void quic_conn_release(struct quic_conn *qc); void qc_kill_conn(struct quic_conn *qc); +int qc_parse_hd_form(struct quic_rx_packet *pkt, + unsigned char **buf, const unsigned char *end); int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *qc, struct listener *li); diff --git a/src/quic_conn.c b/src/quic_conn.c index 17962276e4..788ba18a2d 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -119,6 +119,11 @@ const struct quic_version quic_versions[] = { const size_t quic_versions_nb = sizeof quic_versions / sizeof *quic_versions; /* Listener only preferred version */ const struct quic_version *preferred_version; +/* RFC 8999 5.4. Version + * A Version field with a + * value of 0x00000000 is reserved for version negotiation + */ +const struct quic_version quic_version_VN_reserved = { .num = 0, }; /* trace source and events */ static void quic_trace(enum trace_level level, uint64_t mask, \ @@ -5884,7 +5889,8 @@ static inline int quic_packet_read_long_header(unsigned char **buf, const unsign /* Check that the length of this received DCID matches the CID lengths * of our implementation for non Initials packets only. */ - if (pkt->type != QUIC_PACKET_TYPE_INITIAL && + if (pkt->version && pkt->version->num && + pkt->type != QUIC_PACKET_TYPE_INITIAL && pkt->type != QUIC_PACKET_TYPE_0RTT && dcid_len != QUIC_HAP_CID_LEN) { TRACE_ERROR("wrong DCID length", QUIC_EV_CONN_RXPKT); @@ -6015,48 +6021,72 @@ static inline int qc_try_rm_hp(struct quic_conn *qc, return ret; } -/* Parse the header form from first byte of packet to set its type. - * Also set <*long_header> to 1 if this form is long, 0 if not and the version - * of this packet into <*version>. +/* Return the QUIC version (quic_version struct) with as version number + * if supported or NULL if not. + */ +static inline const struct quic_version *qc_supported_version(uint32_t version) +{ + int i; + + if (unlikely(!version)) + return &quic_version_VN_reserved; + + for (i = 0; i < quic_versions_nb; i++) + if (quic_versions[i].num == version) + return &quic_versions[i]; + + return NULL; +} + +/* Parse a QUIC packet header starting at without exceeding . + * Version and type are stored in packet instance. Type is set to unknown + * on two occasions : for unsupported version, in this case version field is + * set to NULL; for Version Negotiation packet with version number set to 0. + * + * Returns 1 on success else 0. */ -static inline int qc_parse_hd_form(struct quic_rx_packet *pkt, - unsigned char **buf, const unsigned char *end, - int *long_header, uint32_t *version) +int qc_parse_hd_form(struct quic_rx_packet *pkt, + unsigned char **buf, const unsigned char *end) { + uint32_t version; int ret = 0; const unsigned char byte0 = **buf; TRACE_ENTER(QUIC_EV_CONN_RXPKT); + pkt->version = NULL; + pkt->type = QUIC_PACKET_TYPE_UNKNOWN; (*buf)++; if (byte0 & QUIC_PACKET_LONG_HEADER_BIT) { unsigned char type = (byte0 >> QUIC_PACKET_TYPE_SHIFT) & QUIC_PACKET_TYPE_BITMASK; - *long_header = 1; /* Version */ - if (!quic_read_uint32(version, (const unsigned char **)buf, end)) { + if (!quic_read_uint32(&version, (const unsigned char **)buf, end)) { TRACE_ERROR("could not read the packet version", QUIC_EV_CONN_RXPKT); goto out; } - if (*version != QUIC_PROTOCOL_VERSION_2) { - pkt->type = type; - } - else { - switch (type) { - case 0: - pkt->type = QUIC_PACKET_TYPE_RETRY; - break; - case 1: - pkt->type = QUIC_PACKET_TYPE_INITIAL; - break; - case 2: - pkt->type = QUIC_PACKET_TYPE_0RTT; - break; - case 3: - pkt->type = QUIC_PACKET_TYPE_HANDSHAKE; - break; + pkt->version = qc_supported_version(version); + if (version && pkt->version) { + if (version != QUIC_PROTOCOL_VERSION_2) { + pkt->type = type; + } + else { + switch (type) { + case 0: + pkt->type = QUIC_PACKET_TYPE_RETRY; + break; + case 1: + pkt->type = QUIC_PACKET_TYPE_INITIAL; + break; + case 2: + pkt->type = QUIC_PACKET_TYPE_0RTT; + break; + case 3: + pkt->type = QUIC_PACKET_TYPE_HANDSHAKE; + break; + } } } } @@ -6064,7 +6094,6 @@ static inline int qc_parse_hd_form(struct quic_rx_packet *pkt, if (byte0 & QUIC_PACKET_SPIN_BIT) pkt->flags |= QUIC_FL_RX_PACKET_SPIN_BIT; pkt->type = QUIC_PACKET_TYPE_SHORT; - *long_header = 0; } ret = 1; @@ -6073,20 +6102,6 @@ static inline int qc_parse_hd_form(struct quic_rx_packet *pkt, return ret; } -/* Return the QUIC version (quic_version struct) with as version number - * if supported or NULL if not. - */ -static inline const struct quic_version *qc_supported_version(uint32_t version) -{ - int i; - - for (i = 0; i < quic_versions_nb; i++) - if (quic_versions[i].num == version) - return &quic_versions[i]; - - return NULL; -} - /* * Send a Version Negotiation packet on response to on socket to * address . @@ -6743,8 +6758,6 @@ static int quic_rx_pkt_parse(struct quic_rx_packet *pkt, const unsigned char *beg = buf; struct proxy *prx; struct quic_counters *prx_counters; - int long_header = 0; - uint32_t version = 0; const struct quic_version *qv = NULL; TRACE_ENTER(QUIC_EV_CONN_LPKT); @@ -6778,15 +6791,15 @@ static int quic_rx_pkt_parse(struct quic_rx_packet *pkt, } /* Header form */ - if (!qc_parse_hd_form(pkt, &buf, end, &long_header, &version)) { + if (!qc_parse_hd_form(pkt, &buf, end)) { TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT); goto drop; } - if (long_header) { + if (pkt->type != QUIC_PACKET_TYPE_SHORT) { uint64_t len; - TRACE_PROTO("long header packet received", QUIC_EV_CONN_LPKT); + if (!quic_packet_read_long_header(&buf, end, pkt)) { TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT); goto drop; @@ -6803,14 +6816,14 @@ static int quic_rx_pkt_parse(struct quic_rx_packet *pkt, } /* Retry of Version Negotiation packets are only sent by servers */ - if (pkt->type == QUIC_PACKET_TYPE_RETRY || !version) { + if (pkt->type == QUIC_PACKET_TYPE_RETRY || + (pkt->version && !pkt->version->num)) { TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT); goto drop; } /* RFC9000 6. Version Negotiation */ - qv = qc_supported_version(version); - if (!qv) { + if (!pkt->version) { /* unsupported version, send Negotiation packet */ if (send_version_negotiation(l->rx.fd, &dgram->saddr, pkt)) { TRACE_ERROR("VN packet not sent", QUIC_EV_CONN_LPKT); @@ -6820,7 +6833,6 @@ static int quic_rx_pkt_parse(struct quic_rx_packet *pkt, TRACE_PROTO("VN packet sent", QUIC_EV_CONN_LPKT); goto drop_silent; } - pkt->version = qv; /* For Initial packets, and for servers (QUIC clients connections), * there is no Initial connection IDs storage.