From 133f1004676a397b156b307b9563bfe825d73466 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 12 Nov 2025 11:35:25 +0100 Subject: [PATCH] MINOR: quic: refactor qc_new_conn() prototype The objective of this patch is to streamline qc_new_conn() usage so that it is similar for frontend and backend sides. Previously, several parameters were set only for frontend connections. These arguments are replaced by a single quic_rx_packet argument, which represents the INITIAL packet triggering the connection allocation on the server side. For a QUIC client endpoint, it remains NULL. This usage is consider more explicit. As a minor change, is moved as the first argument of the function. This is considered useful as this argument determines whether the connection is a frontend or backend entry. Along with these changes, qc_new_conn() documentation has been reworded so that it is now up-to-date with the newest usage. --- include/haproxy/quic_conn.h | 7 ++-- src/quic_conn.c | 74 ++++++++++++++++++------------------- src/quic_rx.c | 5 +-- src/xprt_quic.c | 3 +- 4 files changed, 43 insertions(+), 46 deletions(-) diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index a86e02426..0c8c77c63 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -64,13 +64,12 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta void quic_conn_closed_err_count_inc(struct quic_conn *qc, struct quic_frame *frm); int qc_h3_request_reject(struct quic_conn *qc, uint64_t id); -struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, - struct quic_cid *dcid, struct quic_cid *scid, +struct quic_conn *qc_new_conn(void *target, int ipv4, + const struct quic_rx_packet *initial_pkt, const struct quic_cid *token_odcid, struct quic_connection_id *conn_id, struct sockaddr_storage *local_addr, - struct sockaddr_storage *peer_addr, - int token, void *owner); + struct sockaddr_storage *peer_addr); int quic_build_post_handshake_frames(struct quic_conn *qc, struct list *to_frms_list); const struct quic_version *qc_supported_version(uint32_t version); diff --git a/src/quic_conn.c b/src/quic_conn.c index 88adc84f8..9dc690d1c 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -1093,32 +1093,32 @@ struct task *qc_process_timer(struct task *task, void *ctx, unsigned int state) return task; } -/* Allocate a new QUIC connection with as QUIC version. - * boolean is set to 1 for IPv4 connection, 0 for IPv6. is set to 1 - * for QUIC servers (or haproxy listeners), 0 for QUIC clients. - * is the destination connection ID, is the source connection ID. - * This latter CID as the same value on the wire as the one for - * which is the first CID of this connection but a different internal - * representation used to build - * NEW_CONNECTION_ID frames. This is the responsibility of the caller to insert - * in the CIDs tree for this connection (qc->cids). - * is a boolean denoting if a token was received for this connection - * from an Initial packet. - * is the original destination connection ID which was embedded - * into the Retry token sent to the client before instantiated this connection. +/* Allocate a new QUIC connection. represents the internal connection + * endpoint, either a listener for a server-side connection or a server on + * client side. boolean is set to 1 for IPv4 connection or 0 for IPv6. + * + * On server side, must points to the client INITIAL packet which + * initiate this connection allocation. It is used as a source to determine the + * QUIC version used and to populate the first set of CIDs. + * represents the associated Retry token from the INITIAL packet. + * + * On client side, both and must be NULL. In this + * case, the version is hardcoded to QUICv1. A random CID will be generated to + * be used as DCID of the first INITIAL packet sent to the server. + * + * Parameter must be set to the CID generated locally. It will serve + * to identify the connection when datagrams dispatch is performed. + * * Endpoints addresses are specified via and . - * Returns the connection if succeeded, NULL if not. - * For QUIC clients, , and must be null, and - * value must be 0. This is the responsibility of the caller to ensure this is - * the case. + * + * Returns the newly allocated quic_conn instance on success or NULL on error. */ -struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, - struct quic_cid *dcid, struct quic_cid *scid, +struct quic_conn *qc_new_conn(void *target, int ipv4, + const struct quic_rx_packet *initial_pkt, const struct quic_cid *token_odcid, struct quic_connection_id *conn_id, struct sockaddr_storage *local_addr, - struct sockaddr_storage *peer_addr, - int token, void *target) + struct sockaddr_storage *peer_addr) { struct quic_conn *qc = NULL; struct listener *l = objt_listener(target); @@ -1221,6 +1221,7 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, } *qc->cids = EB_ROOT; qc->next_cid_seq_num = 0; + qc->scid = conn_id->cid; /* QUIC Server (or listener). */ if (l) { @@ -1233,13 +1234,13 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, qc->flags |= QUIC_FL_CONN_UDP_GSO_EIO; /* Mark this connection as having not received any token when 0-RTT is enabled. */ - if (l->bind_conf->ssl_conf.early_data && !token) + if (l->bind_conf->ssl_conf.early_data && !initial_pkt->token_len) qc->flags |= QUIC_FL_CONN_NO_TOKEN_RCVD; qc->state = QUIC_HS_ST_SERVER_INITIAL; /* Copy the client original DCID. */ - qc->odcid = *dcid; + qc->odcid = initial_pkt->dcid; /* Copy the packet SCID to reuse it as DCID for sending */ - qc->dcid = *scid; + qc->dcid = initial_pkt->scid; } /* QUIC Client (outgoing connection to servers) */ else { @@ -1250,19 +1251,16 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, qc->state = QUIC_HS_ST_CLIENT_INITIAL; - /* This is the original connection ID from the peer server - * point of view. + /* Randomly generate the first DCID used for the first INITIAL + * packet sent by our endpoint as client and save it as ODCID. + * It will be replaced by a peer chosen value. */ if (RAND_bytes(qc->dcid.data, sizeof(qc->dcid.data)) != 1) goto err; - qc->dcid.len = sizeof(qc->dcid.data); - - memcpy(&qc->odcid, qc->dcid.data, sizeof(qc->dcid.data)); - qc->odcid.len = qc->dcid.len; - - dcid = &qc->dcid; + qc->odcid = qc->dcid; } + qc->err = quic_err_transport(QC_ERR_NO_ERROR); /* Listener only: if connection is instantiated due to an INITIAL packet with an @@ -1300,15 +1298,14 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, _HA_ATOMIC_INC(&jobs); } - /* Select our SCID which is the first CID with 0 as sequence number. */ - qc->scid = conn_id->cid; - if (!qc_enc_level_alloc(qc, &qc->ipktns, &qc->iel, ssl_encryption_initial)) { TRACE_ERROR("Could not initialize an encryption level", QUIC_EV_CONN_INIT, qc); goto err; } - qc->original_version = qv; + qc->original_version = initial_pkt ? + initial_pkt->version : quic_version_1; + qc->negotiated_version = NULL; qc->tps_tls_ext = (qc->original_version->num & 0xff000000) == 0xff000000 ? TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS_DRAFT: @@ -1385,7 +1382,10 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, !quic_conn_init_idle_timer_task(qc, prx)) goto err; - if (!qc_new_isecs(qc, &qc->iel->tls_ctx, qc->original_version, dcid->data, dcid->len, !!l)) + /* INITIAL secrets are derived from the DCID of the INITIAL packet. + * This corresponds to quic_conn field. + */ + if (!qc_new_isecs(qc, &qc->iel->tls_ctx, qc->original_version, qc->odcid.data, qc->odcid.len, !!l)) goto err; /* Counters initialization */ diff --git a/src/quic_rx.c b/src/quic_rx.c index 90cbe476b..6714c9037 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -1825,9 +1825,8 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt, pool_free(pool_head_quic_connection_id, conn_id); } else { - qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, &token_odcid, - conn_id, &dgram->daddr, &pkt->saddr, - !!pkt->token_len, l); + qc = qc_new_conn(l, ipv4, pkt, &token_odcid, + conn_id, &dgram->daddr, &pkt->saddr); if (qc == NULL) { quic_cid_delete(conn_id); /* Removes CID from global tree as it points to a NULL qc. */ pool_free(pool_head_quic_connection_id, conn_id); diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 7c21cd71d..913fda803 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -162,8 +162,7 @@ static int qc_conn_init(struct connection *conn, void **xprt_ctx) goto out; } - qc = qc_new_conn(quic_version_1, ipv4, NULL, NULL, NULL, - conn_id, NULL, &srv->addr, 0, srv); + qc = qc_new_conn(srv, ipv4, NULL, NULL, conn_id, NULL, &srv->addr); if (!qc) { pool_free(pool_head_quic_connection_id, conn_id); goto out; -- 2.47.3