]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: refactor qc_new_conn() prototype
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 12 Nov 2025 10:35:25 +0000 (11:35 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 17 Nov 2025 09:13:40 +0000 (10:13 +0100)
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, <target> 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
src/quic_conn.c
src/quic_rx.c
src/xprt_quic.c

index a86e02426e23250b2da8449df7c241e93e09c637..0c8c77c6372b0253725a3ca989443bb00849fef9 100644 (file)
@@ -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);
index 88adc84f8493f1846e0591fbac9706f190bb7259..9dc690d1c5b1691c94a94ba11bfb92419786371a 100644 (file)
@@ -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 <version> as QUIC version. <ipv4>
- * boolean is set to 1 for IPv4 connection, 0 for IPv6. <server> is set to 1
- * for QUIC servers (or haproxy listeners), 0 for QUIC clients.
- * <dcid> is the destination connection ID, <scid> is the source connection ID.
- * This latter <scid> CID as the same value on the wire as the one for <conn_id>
- * 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
- * <conn_id> in the CIDs tree for this connection (qc->cids).
- * <token> is a boolean denoting if a token was received for this connection
- * from an Initial packet.
- * <token_odcid> 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. <target> represents the internal connection
+ * endpoint, either a listener for a server-side connection or a server on
+ * client side. <ipv4> boolean is set to 1 for IPv4 connection or 0 for IPv6.
+ *
+ * On server side, <initial_pkt> 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. <token_odcid>
+ * represents the associated Retry token from the INITIAL packet.
+ *
+ * On client side, both <initial_pkt> and <token_odcid> 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 <conn_id> 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 <local_addr> and <peer_addr>.
- * Returns the connection if succeeded, NULL if not.
- * For QUIC clients, <dcid>, <scid> and <token_odcid> must be null, and <token>
- * 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 <odcid> field.
+        */
+       if (!qc_new_isecs(qc, &qc->iel->tls_ctx, qc->original_version, qc->odcid.data, qc->odcid.len, !!l))
                goto err;
 
        /* Counters initialization */
index 90cbe476b4acfdf4a4b7be9745184a5589168065..6714c903766676e0d9543dad33649df2946865ab 100644 (file)
@@ -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);
index 7c21cd71dc9433583b6912bcf18b089218595e12..913fda80383b20d72ac6aad4722637575b7eece1 100644 (file)
@@ -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;