mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 06:11:32 +02:00
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.
This commit is contained in:
parent
6ac0fb0f13
commit
1a5cc19cec
@ -131,6 +131,9 @@ enum quic_pkt_type {
|
|||||||
* own convenience.
|
* own convenience.
|
||||||
*/
|
*/
|
||||||
QUIC_PACKET_TYPE_SHORT,
|
QUIC_PACKET_TYPE_SHORT,
|
||||||
|
|
||||||
|
/* unknown type */
|
||||||
|
QUIC_PACKET_TYPE_UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Packet number field length. */
|
/* Packet number field length. */
|
||||||
|
@ -687,6 +687,8 @@ void quic_conn_release(struct quic_conn *qc);
|
|||||||
|
|
||||||
void qc_kill_conn(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,
|
int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *qc,
|
||||||
struct listener *li);
|
struct listener *li);
|
||||||
|
|
||||||
|
@ -119,6 +119,11 @@ const struct quic_version quic_versions[] = {
|
|||||||
const size_t quic_versions_nb = sizeof quic_versions / sizeof *quic_versions;
|
const size_t quic_versions_nb = sizeof quic_versions / sizeof *quic_versions;
|
||||||
/* Listener only preferred version */
|
/* Listener only preferred version */
|
||||||
const struct quic_version *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 */
|
/* trace source and events */
|
||||||
static void quic_trace(enum trace_level level, uint64_t mask, \
|
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
|
/* Check that the length of this received DCID matches the CID lengths
|
||||||
* of our implementation for non Initials packets only.
|
* 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 &&
|
pkt->type != QUIC_PACKET_TYPE_0RTT &&
|
||||||
dcid_len != QUIC_HAP_CID_LEN) {
|
dcid_len != QUIC_HAP_CID_LEN) {
|
||||||
TRACE_ERROR("wrong DCID length", QUIC_EV_CONN_RXPKT);
|
TRACE_ERROR("wrong DCID length", QUIC_EV_CONN_RXPKT);
|
||||||
@ -6015,32 +6021,55 @@ static inline int qc_try_rm_hp(struct quic_conn *qc,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the header form from <byte0> first byte of <pkt> packet to set its type.
|
/* Return the QUIC version (quic_version struct) with <version> as version number
|
||||||
* Also set <*long_header> to 1 if this form is long, 0 if not and the version
|
* if supported or NULL if not.
|
||||||
* of this packet into <*version>.
|
|
||||||
*/
|
*/
|
||||||
static inline int qc_parse_hd_form(struct quic_rx_packet *pkt,
|
static inline const struct quic_version *qc_supported_version(uint32_t version)
|
||||||
unsigned char **buf, const unsigned char *end,
|
|
||||||
int *long_header, 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 <buf> without exceeding <end>.
|
||||||
|
* Version and type are stored in <pkt> 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.
|
||||||
|
*/
|
||||||
|
int qc_parse_hd_form(struct quic_rx_packet *pkt,
|
||||||
|
unsigned char **buf, const unsigned char *end)
|
||||||
|
{
|
||||||
|
uint32_t version;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const unsigned char byte0 = **buf;
|
const unsigned char byte0 = **buf;
|
||||||
|
|
||||||
TRACE_ENTER(QUIC_EV_CONN_RXPKT);
|
TRACE_ENTER(QUIC_EV_CONN_RXPKT);
|
||||||
|
pkt->version = NULL;
|
||||||
|
pkt->type = QUIC_PACKET_TYPE_UNKNOWN;
|
||||||
|
|
||||||
(*buf)++;
|
(*buf)++;
|
||||||
if (byte0 & QUIC_PACKET_LONG_HEADER_BIT) {
|
if (byte0 & QUIC_PACKET_LONG_HEADER_BIT) {
|
||||||
unsigned char type =
|
unsigned char type =
|
||||||
(byte0 >> QUIC_PACKET_TYPE_SHIFT) & QUIC_PACKET_TYPE_BITMASK;
|
(byte0 >> QUIC_PACKET_TYPE_SHIFT) & QUIC_PACKET_TYPE_BITMASK;
|
||||||
|
|
||||||
*long_header = 1;
|
|
||||||
/* Version */
|
/* 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);
|
TRACE_ERROR("could not read the packet version", QUIC_EV_CONN_RXPKT);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*version != QUIC_PROTOCOL_VERSION_2) {
|
pkt->version = qc_supported_version(version);
|
||||||
|
if (version && pkt->version) {
|
||||||
|
if (version != QUIC_PROTOCOL_VERSION_2) {
|
||||||
pkt->type = type;
|
pkt->type = type;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -6060,11 +6089,11 @@ static inline int qc_parse_hd_form(struct quic_rx_packet *pkt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (byte0 & QUIC_PACKET_SPIN_BIT)
|
if (byte0 & QUIC_PACKET_SPIN_BIT)
|
||||||
pkt->flags |= QUIC_FL_RX_PACKET_SPIN_BIT;
|
pkt->flags |= QUIC_FL_RX_PACKET_SPIN_BIT;
|
||||||
pkt->type = QUIC_PACKET_TYPE_SHORT;
|
pkt->type = QUIC_PACKET_TYPE_SHORT;
|
||||||
*long_header = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
@ -6073,20 +6102,6 @@ static inline int qc_parse_hd_form(struct quic_rx_packet *pkt,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the QUIC version (quic_version struct) with <version> 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 <pkt> on socket <fd> to
|
* Send a Version Negotiation packet on response to <pkt> on socket <fd> to
|
||||||
* address <addr>.
|
* address <addr>.
|
||||||
@ -6743,8 +6758,6 @@ static int quic_rx_pkt_parse(struct quic_rx_packet *pkt,
|
|||||||
const unsigned char *beg = buf;
|
const unsigned char *beg = buf;
|
||||||
struct proxy *prx;
|
struct proxy *prx;
|
||||||
struct quic_counters *prx_counters;
|
struct quic_counters *prx_counters;
|
||||||
int long_header = 0;
|
|
||||||
uint32_t version = 0;
|
|
||||||
const struct quic_version *qv = NULL;
|
const struct quic_version *qv = NULL;
|
||||||
|
|
||||||
TRACE_ENTER(QUIC_EV_CONN_LPKT);
|
TRACE_ENTER(QUIC_EV_CONN_LPKT);
|
||||||
@ -6778,15 +6791,15 @@ static int quic_rx_pkt_parse(struct quic_rx_packet *pkt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Header form */
|
/* 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);
|
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long_header) {
|
if (pkt->type != QUIC_PACKET_TYPE_SHORT) {
|
||||||
uint64_t len;
|
uint64_t len;
|
||||||
|
|
||||||
TRACE_PROTO("long header packet received", QUIC_EV_CONN_LPKT);
|
TRACE_PROTO("long header packet received", QUIC_EV_CONN_LPKT);
|
||||||
|
|
||||||
if (!quic_packet_read_long_header(&buf, end, pkt)) {
|
if (!quic_packet_read_long_header(&buf, end, pkt)) {
|
||||||
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
|
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
|
||||||
goto drop;
|
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 */
|
/* 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);
|
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RFC9000 6. Version Negotiation */
|
/* RFC9000 6. Version Negotiation */
|
||||||
qv = qc_supported_version(version);
|
if (!pkt->version) {
|
||||||
if (!qv) {
|
|
||||||
/* unsupported version, send Negotiation packet */
|
/* unsupported version, send Negotiation packet */
|
||||||
if (send_version_negotiation(l->rx.fd, &dgram->saddr, pkt)) {
|
if (send_version_negotiation(l->rx.fd, &dgram->saddr, pkt)) {
|
||||||
TRACE_ERROR("VN packet not sent", QUIC_EV_CONN_LPKT);
|
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);
|
TRACE_PROTO("VN packet sent", QUIC_EV_CONN_LPKT);
|
||||||
goto drop_silent;
|
goto drop_silent;
|
||||||
}
|
}
|
||||||
pkt->version = qv;
|
|
||||||
|
|
||||||
/* For Initial packets, and for servers (QUIC clients connections),
|
/* For Initial packets, and for servers (QUIC clients connections),
|
||||||
* there is no Initial connection IDs storage.
|
* there is no Initial connection IDs storage.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user