From 449b1a8f552ddbf08be707fae1824a79fe862955 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 19 Oct 2022 15:28:44 +0200 Subject: [PATCH] MINOR: quic: extract connection retrieval Simplify qc_lstnr_pkt_rcv() by extracting code responsible to retrieve the quic-conn instance. This code is put in a dedicated function named quic_rx_pkt_retrieve_conn(). This new function could be skipped if a FD-owned quic-conn socket is used. The first traces of qc_lstnr_pkt_rcv() have been clean up as qc instance is always NULL here : thus qc parameter can be removed without any change. This change has no functional impact. It is a part of a refactoring series on qc_lstnr_pkt_rcv(). The objective is facilitate integration of FD-owned socket patches. This should be backported up to 2.6. --- src/quic_conn.c | 220 ++++++++++++++++++++++++++++-------------------- 1 file changed, 127 insertions(+), 93 deletions(-) diff --git a/src/quic_conn.c b/src/quic_conn.c index 203a36747..3fce3685f 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -5926,6 +5926,119 @@ static inline int quic_padding_check(const unsigned char *buf, return buf == end; } +/* Find the associated connection to the packet or create a new one if + * this is an Initial packet. is the datagram containing the packet and + * is the listener instance on which it was received. + * + * Returns the quic-conn instance or NULL. + */ +static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt, + struct quic_dgram *dgram, + struct listener *l) +{ + struct quic_cid odcid; + const struct quic_cid *token_odcid = NULL; // ODCID received from client token + struct quic_conn *qc = NULL; + struct proxy *prx; + struct quic_counters *prx_counters; + + TRACE_ENTER(QUIC_EV_CONN_LPKT); + + prx = l->bind_conf->frontend; + prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module); + + qc = retrieve_qc_conn_from_cid(pkt, l, &dgram->saddr); + + if (pkt->type == QUIC_PACKET_TYPE_INITIAL) { + BUG_ON(!pkt->version); /* This must not happen. */ + + if (global.cluster_secret && pkt->token_len) { + if (*pkt->token == QUIC_TOKEN_FMT_RETRY) { + const struct quic_version *ver = qc ? qc->original_version : pkt->version; + if (!quic_retry_token_check(pkt->token, pkt->token_len, ver, &odcid, + &pkt->scid, qc, &dgram->saddr)) { + HA_ATOMIC_INC(&prx_counters->retry_error); + TRACE_PROTO("Wrong retry token", + QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version); + /* TODO: RFC 9000 8.1.2 A server SHOULD immediately close the connection + * with an INVALID_TOKEN error. + */ + goto out; + } + + token_odcid = &odcid; + HA_ATOMIC_INC(&prx_counters->retry_validated); + } + else { + /* TODO: New token check */ + TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version); + goto out; + } + } + + if (!qc) { + int ipv4; + + if (global.cluster_secret && !pkt->token_len && !(l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) && + HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) { + TRACE_PROTO("Initial without token, sending retry", + QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); + if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) { + TRACE_ERROR("Error during Retry generation", + QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); + goto out; + } + + HA_ATOMIC_INC(&prx_counters->retry_sent); + goto out; + } + + /* RFC 9000 7.2. Negotiating Connection IDs: + * When an Initial packet is sent by a client that has not previously + * received an Initial or Retry packet from the server, the client + * populates the Destination Connection ID field with an unpredictable + * value. This Destination Connection ID MUST be at least 8 bytes in length. + */ + if (pkt->dcid.len < QUIC_ODCID_MINLEN) { + TRACE_PROTO("dropped packet", + QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); + goto err; + } + + pkt->saddr = dgram->saddr; + ipv4 = dgram->saddr.ss_family == AF_INET; + + qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, token_odcid, + &dgram->daddr, &pkt->saddr, 1, + !!pkt->token_len, l); + if (qc == NULL) + goto err; + + HA_ATOMIC_INC(&prx_counters->half_open_conn); + /* Insert the DCID the QUIC client has chosen (only for listeners) */ + ebmb_insert(&quic_dghdlrs[tid].odcids, &qc->odcid_node, + qc->odcid.len + qc->odcid.addrlen); + } + } + else if (!qc) { + TRACE_PROTO("No connection on a non Initial packet", QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); + if (global.cluster_secret && !send_stateless_reset(l, &dgram->saddr, pkt)) + TRACE_ERROR("stateless reset not sent", QUIC_EV_CONN_LPKT, qc); + goto err; + } + + pkt->qc = qc; + + out: + TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc); + return qc; + + err: + HA_ATOMIC_INC(&prx_counters->dropped_pkt); + TRACE_LEAVE(QUIC_EV_CONN_LPKT); + return NULL; +} + /* Parse a QUIC packet from UDP datagram found in buffer with the * end of this buffer past one byte and populate RX packet structure * with the information collected from the packet. @@ -5994,22 +6107,20 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, if (long_header) { uint64_t len; - struct quic_cid odcid; - const struct quic_cid *token_odcid = NULL; // ODCID received from client token - TRACE_PROTO("long header packet received", QUIC_EV_CONN_LPKT, qc); + 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; } if (pkt->type == QUIC_PACKET_TYPE_0RTT && !l->bind_conf->ssl_conf.early_data) { - TRACE_PROTO("0-RTT packet not supported", QUIC_EV_CONN_LPKT, qc); + TRACE_PROTO("0-RTT packet not supported", QUIC_EV_CONN_LPKT); drop_no_conn = 1; } else if (pkt->type == QUIC_PACKET_TYPE_INITIAL && dgram->len < QUIC_INITIAL_PACKET_MINLEN) { - TRACE_PROTO("Too short datagram with an Initial packet", QUIC_EV_CONN_LPKT, qc); + TRACE_PROTO("Too short datagram with an Initial packet", QUIC_EV_CONN_LPKT); HA_ATOMIC_INC(&prx_counters->too_short_initial_dgram); goto drop; } @@ -6020,7 +6131,7 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, if (!(pkt->flags & QUIC_FL_RX_PACKET_DGRAM_FIRST) && (pkt->dcid.len != dgram->dcid_len || memcmp(dgram->dcid, pkt->dcid.data, pkt->dcid.len))) { - TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc); + TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT); goto drop; } @@ -6109,84 +6220,9 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, pkt->len = pkt->pn_offset + len; if (drop_no_conn) goto drop_no_conn; - - qc = retrieve_qc_conn_from_cid(pkt, l, &dgram->saddr); - if (global.cluster_secret && pkt->token_len) { - if (*pkt->token == QUIC_TOKEN_FMT_RETRY) { - const struct quic_version *ver = qc ? qc->original_version : qv; - if (!quic_retry_token_check(pkt->token, pkt->token_len, ver, &odcid, - &pkt->scid, qc, &dgram->saddr)) { - HA_ATOMIC_INC(&prx_counters->retry_error); - TRACE_PROTO("Wrong retry token", - QUIC_EV_CONN_LPKT, qc, NULL, NULL, qv); - /* TODO: RFC 9000 8.1.2 A server SHOULD immediately close the connection - * with an INVALID_TOKEN error. - */ - goto drop; - } - - token_odcid = &odcid; - HA_ATOMIC_INC(&prx_counters->retry_validated); - } - else { - /* TODO: New token check */ - TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc, NULL, NULL, qv); - goto drop; - } - } - if (!qc) { - int ipv4; - - if (pkt->type != QUIC_PACKET_TYPE_INITIAL) { - TRACE_PROTO("Non Initial packet", QUIC_EV_CONN_LPKT, NULL, NULL, NULL, qv); - goto drop; - } - - if (global.cluster_secret && !pkt->token_len && !(l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) && - HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) { - TRACE_PROTO("Initial without token, sending retry", - QUIC_EV_CONN_LPKT, NULL, NULL, NULL, qv); - if (send_retry(l->rx.fd, &dgram->saddr, pkt, qv)) { - TRACE_ERROR("Error during Retry generation", - QUIC_EV_CONN_LPKT, NULL, NULL, NULL, qv); - goto err; - } - - HA_ATOMIC_INC(&prx_counters->retry_sent); - goto err; - } - - /* RFC 9000 7.2. Negotiating Connection IDs: - * When an Initial packet is sent by a client that has not previously - * received an Initial or Retry packet from the server, the client - * populates the Destination Connection ID field with an unpredictable - * value. This Destination Connection ID MUST be at least 8 bytes in length. - */ - if (pkt->dcid.len < QUIC_ODCID_MINLEN) { - TRACE_PROTO("dropped packet", - QUIC_EV_CONN_LPKT, NULL, NULL, NULL, qv); - goto drop; - } - - pkt->saddr = dgram->saddr; - ipv4 = dgram->saddr.ss_family == AF_INET; - - qc = qc_new_conn(qv, ipv4, &pkt->dcid, &pkt->scid, token_odcid, - &dgram->daddr, &pkt->saddr, 1, - !!pkt->token_len, l); - if (qc == NULL) - goto drop; - - HA_ATOMIC_INC(&prx_counters->half_open_conn); - /* Insert the DCID the QUIC client has chosen (only for listeners) */ - ebmb_insert(&quic_dghdlrs[tid].odcids, &qc->odcid_node, - qc->odcid.len + qc->odcid.addrlen); - } - - pkt->qc = qc; } else { - TRACE_PROTO("short header packet received", QUIC_EV_CONN_LPKT, qc); + TRACE_PROTO("short header packet received", QUIC_EV_CONN_LPKT); if (end - buf < QUIC_HAP_CID_LEN) { TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT); goto drop; @@ -6201,7 +6237,7 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, if (!(pkt->flags & QUIC_FL_RX_PACKET_DGRAM_FIRST) && (pkt->dcid.len != dgram->dcid_len || memcmp(dgram->dcid, pkt->dcid.data, pkt->dcid.len))) { - TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc); + TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT); goto drop; } @@ -6210,17 +6246,15 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, pkt->pn_offset = buf - beg; /* A short packet is the last one of a UDP datagram. */ pkt->len = end - beg; + } - qc = retrieve_qc_conn_from_cid(pkt, l, &dgram->saddr); - if (!qc) { - size_t pktlen = end - buf; - TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, NULL, pkt, &pktlen); - if (global.cluster_secret && !send_stateless_reset(l, &dgram->saddr, pkt)) - TRACE_ERROR("stateless reset not sent", QUIC_EV_CONN_LPKT, qc); - goto drop; - } - - pkt->qc = qc; + qc = quic_rx_pkt_retrieve_conn(pkt, dgram, dgram->owner); + if (!qc) { + size_t pktlen = end - buf; + TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, NULL, pkt, &pktlen); + if (global.cluster_secret && !send_stateless_reset(l, &dgram->saddr, pkt)) + TRACE_ERROR("stateless reset not sent", QUIC_EV_CONN_LPKT, qc); + goto drop; } if (qc->flags & QUIC_FL_CONN_CLOSING) {