]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: quic: use ncbuf2 for CRYPTO handling 20251014-ade-implement-ncbuf2
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 16 Oct 2025 14:43:16 +0000 (16:43 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 17 Oct 2025 09:06:07 +0000 (11:06 +0200)
include/haproxy/quic_conn.h
include/haproxy/quic_tls-t.h
src/quic_rx.c
src/quic_ssl.c
src/quic_tls.c

index 78517753de43998f94b96ee1b25beb4221626f05..943a620b975a5d4a635c159fa71f06d1ac4ec390 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <haproxy/chunk.h>
 #include <haproxy/dynbuf.h>
-#include <haproxy/ncbuf.h>
+#include <haproxy/ncbuf2.h>
 #include <haproxy/net_helper.h>
 #include <haproxy/openssl-compat.h>
 #include <haproxy/ticks.h>
@@ -135,35 +135,35 @@ static inline void quic_conn_mv_cids_to_cc_conn(struct quic_conn_closed *cc_conn
  *
  * Returns the buffer instance or NULL on allocation failure.
  */
-static inline struct ncbuf *quic_get_ncbuf(struct ncbuf *ncbuf)
+static inline struct ncbuf2 *quic_get_ncbuf(struct ncbuf2 *ncbuf)
 {
        struct buffer buf = BUF_NULL;
 
-       if (!ncb_is_null(ncbuf))
+       if (!ncb2_is_null(ncbuf))
                return ncbuf;
 
        if (!b_alloc(&buf, DB_MUX_RX))
                return NULL;
 
-       *ncbuf = ncb_make(buf.area, buf.size, 0);
-       ncb_init(ncbuf, 0);
+       *ncbuf = ncb2_make(buf.area, buf.size, 0);
+       ncb2_init(ncbuf, 0);
 
        return ncbuf;
 }
 
 /* Release the underlying memory use by <ncbuf> non-contiguous buffer */
-static inline void quic_free_ncbuf(struct ncbuf *ncbuf)
+static inline void quic_free_ncbuf(struct ncbuf2 *ncbuf)
 {
        struct buffer buf;
 
-       if (ncb_is_null(ncbuf))
+       if (ncb2_is_null(ncbuf))
                return;
 
        buf = b_make(ncbuf->area, ncbuf->size, 0, 0);
        b_free(&buf);
        offer_buffers(NULL, 1);
 
-       *ncbuf = NCBUF_NULL;
+       *ncbuf = NCBUF2_NULL;
 }
 
 /* Return the address of the QUIC counters attached to the proxy of
index 1a39919b6d8f15c0cbe3be0604d0a9becf4ec677..1efc6505225b9715ad4ccbf83b7f86837f42606d 100644 (file)
@@ -26,7 +26,7 @@
 #include <import/ebtree.h>
 
 #include <haproxy/buf-t.h>
-#include <haproxy/ncbuf-t.h>
+#include <haproxy/ncbuf2-t.h>
 #include <haproxy/quic_ack-t.h>
 
 /* Use EVP_CIPHER or EVP_AEAD API depending on the library */
@@ -255,7 +255,7 @@ struct quic_crypto_buf {
 struct quic_cstream {
        struct {
                uint64_t offset;       /* absolute current base offset of ncbuf */
-               struct ncbuf ncbuf;    /* receive buffer - can handle out-of-order offset frames */
+               struct ncbuf2 ncbuf;    /* receive buffer - can handle out-of-order offset frames */
        } rx;
        struct {
                uint64_t offset;      /* last offset of data ready to be sent */
index 07a0481e7403dd84be55cdfb5663e6df4d23a911..e780798907d0dce5df145b7e971688ab56de618d 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <haproxy/h3.h>
 #include <haproxy/list.h>
-#include <haproxy/ncbuf.h>
+#include <haproxy/ncbuf2.h>
 #include <haproxy/proto_quic.h>
 #include <haproxy/quic_ack.h>
 #include <haproxy/quic_cc_drs.h>
@@ -666,7 +666,7 @@ static enum quic_rx_ret_frm qc_handle_crypto_frm(struct quic_conn *qc,
                .len = crypto_frm->len,
        };
        struct quic_cstream *cstream = qel->cstream;
-       struct ncbuf *ncbuf = &qel->cstream->rx.ncbuf;
+       struct ncbuf2 *ncbuf = &qel->cstream->rx.ncbuf;
        uint64_t off_rel;
 
        TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc);
@@ -691,7 +691,7 @@ static enum quic_rx_ret_frm qc_handle_crypto_frm(struct quic_conn *qc,
                crypto_frm->offset_node.key = cstream->rx.offset;
        }
 
-       if (!quic_get_ncbuf(ncbuf) || ncb_is_null(ncbuf)) {
+       if (!quic_get_ncbuf(ncbuf) || ncb2_is_null(ncbuf)) {
                TRACE_ERROR("CRYPTO ncbuf allocation failed", QUIC_EV_CONN_PRSHPKT, qc);
                goto err;
        }
@@ -707,31 +707,18 @@ static enum quic_rx_ret_frm qc_handle_crypto_frm(struct quic_conn *qc,
         * handshake. If an endpoint does not expand its buffer, it MUST close
         * the connection with a CRYPTO_BUFFER_EXCEEDED error code.
         */
-       if (off_rel + crypto_frm->len > ncb_size(ncbuf)) {
+       if (off_rel + crypto_frm->len > ncb2_size(ncbuf)) {
                TRACE_ERROR("CRYPTO frame too large", QUIC_EV_CONN_PRSHPKT, qc);
                quic_set_connection_close(qc, quic_err_transport(QC_ERR_CRYPTO_BUFFER_EXCEEDED));
                goto err;
        }
 
-       ncb_ret = ncb_add(ncbuf, off_rel, (const char *)crypto_frm->data,
-                         crypto_frm->len, NCB_ADD_COMPARE);
-       if (ncb_ret != NCB_RET_OK) {
-               if (ncb_ret == NCB_RET_DATA_REJ) {
-                       TRACE_ERROR("overlapping data rejected", QUIC_EV_CONN_PRSHPKT, qc);
-                       quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION));
-                       qc_notify_err(qc);
-                       goto err;
-               }
-               else if (ncb_ret == NCB_RET_GAP_SIZE) {
-                       TRACE_DATA("cannot bufferize frame due to gap size limit",
-                                  QUIC_EV_CONN_PRSHPKT, qc);
-                       ret = QUIC_RX_RET_FRM_AGAIN;
-                       goto done;
-               }
-       }
+       ncb_ret = ncb2_add(ncbuf, off_rel, (const char *)crypto_frm->data,
+                          crypto_frm->len, NCB_ADD_COMPARE);
+       BUG_ON(ncb_ret != NCB_RET_OK);
 
        /* Reschedule with TASK_HEAVY if CRYPTO data ready for decoding. */
-       if (ncb_data(ncbuf, 0)) {
+       if (ncb2_data(ncbuf, 0)) {
                HA_ATOMIC_OR(&qc->wait_event.tasklet->state, TASK_HEAVY);
                tasklet_wakeup(qc->wait_event.tasklet);
        }
index 60e79a5166faa29b4840846bec75b0f2b8158db8..838b7eec3daaa3f0473ba8d45c7de6f5b8943dba 100644 (file)
@@ -1,5 +1,5 @@
 #include <haproxy/errors.h>
-#include <haproxy/ncbuf.h>
+#include <haproxy/ncbuf2.h>
 #include <haproxy/proxy.h>
 #include <haproxy/quic_conn.h>
 #include <haproxy/quic_sock.h>
@@ -438,9 +438,9 @@ static int ha_quic_ossl_crypto_recv_rcd(SSL *ssl,
 {
        struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index);
        struct quic_enc_level *qel;
-       struct ncbuf *ncbuf = NULL;
+       struct ncbuf2 *ncbuf = NULL;
        struct quic_cstream *cstream = NULL;
-       ncb_sz_t data = 0;
+       ncb2_sz_t data = 0;
 
        TRACE_ENTER(QUIC_EV_CONN_SSLDATA, qc);
 
@@ -450,10 +450,10 @@ static int ha_quic_ossl_crypto_recv_rcd(SSL *ssl,
                        continue;
 
                ncbuf = &cstream->rx.ncbuf;
-               if (ncb_is_null(ncbuf))
+               if (ncb2_is_null(ncbuf))
                        continue;
 
-               data = ncb_data(ncbuf, 0);
+               data = ncb2_data(ncbuf, 0);
                if (data)
                        break;
        }
@@ -461,9 +461,9 @@ static int ha_quic_ossl_crypto_recv_rcd(SSL *ssl,
        if (data) {
                const unsigned char *cdata;
 
-               BUG_ON(ncb_is_null(ncbuf) || !cstream);
+               BUG_ON(ncb2_is_null(ncbuf) || !cstream);
                /* <ncbuf> must not be released at this time. */
-               cdata = (const unsigned char *)ncb_head(ncbuf);
+               cdata = (const unsigned char *)ncb2_head(ncbuf);
                cstream->rx.offset += data;
                TRACE_DEVEL("buffered crypto data were provided to TLS stack",
                                        QUIC_EV_CONN_PHPKTS, qc, qel);
@@ -495,24 +495,24 @@ static int ha_quic_ossl_crypto_release_rcd(SSL *ssl,
 
        list_for_each_entry(qel, &qc->qel_list, list) {
                struct quic_cstream *cstream = qel->cstream;
-               struct ncbuf *ncbuf;
-               ncb_sz_t data;
+               struct ncbuf2 *ncbuf;
+               ncb2_sz_t data;
 
                if (!cstream)
                        continue;
 
                ncbuf = &cstream->rx.ncbuf;
-               if (ncb_is_null(ncbuf))
+               if (ncb2_is_null(ncbuf))
                        continue;
 
-               data = ncb_data(ncbuf, 0);
+               data = ncb2_data(ncbuf, 0);
                if (!data)
                        continue;
 
                data = data > bytes_read ? bytes_read : data;
-               ncb_advance(ncbuf, data);
+               ncb2_advance(ncbuf, data);
                bytes_read -= data;
-               if (ncb_is_empty(ncbuf)) {
+               if (ncb2_is_empty(ncbuf)) {
                        TRACE_DEVEL("freeing crypto buf", QUIC_EV_CONN_PHPKTS, qc, qel);
                        quic_free_ncbuf(ncbuf);
                }
@@ -1047,7 +1047,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
  * Remaining parameter are there for debugging purposes.
  * Return 1 if succeeded, 0 if not.
  */
-static int qc_ssl_provide_quic_data(struct ncbuf *ncbuf,
+static int qc_ssl_provide_quic_data(struct ncbuf2 *ncbuf,
                                     enum ssl_encryption_level_t level,
                                     struct ssl_sock_ctx *ctx,
                                     const unsigned char *data, size_t len)
@@ -1077,17 +1077,12 @@ static int qc_ssl_provide_quic_data(struct ncbuf *ncbuf,
        /* The CRYPTO data are consumed even in case of an error to release
         * the memory asap.
         */
-       if (!ncb_is_null(ncbuf)) {
+       if (!ncb2_is_null(ncbuf)) {
 #ifdef DEBUG_STRICT
-               ncb_ret = ncb_advance(ncbuf, len);
-               /* ncb_advance() must always succeed. This is guaranteed as
-                * this is only done inside a data block. If false, this will
-                * lead to handshake failure with quic_enc_level offset shifted
-                * from buffer data.
-                */
+               ncb_ret = ncb2_advance(ncbuf, len);
                BUG_ON(ncb_ret != NCB_RET_OK);
 #else
-               ncb_advance(ncbuf, len);
+               ncb2_advance(ncbuf, len);
 #endif
        }
 
@@ -1102,8 +1097,8 @@ int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
 {
        int ret = 0;
        struct quic_enc_level *qel;
-       struct ncbuf *ncbuf;
-       ncb_sz_t data;
+       struct ncbuf2 *ncbuf;
+       ncb2_sz_t data;
 
        TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
        list_for_each_entry(qel, &qc->qel_list, list) {
@@ -1113,12 +1108,12 @@ int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
                        continue;
 
                ncbuf = &cstream->rx.ncbuf;
-               if (ncb_is_null(ncbuf))
+               if (ncb2_is_null(ncbuf))
                        continue;
 
                /* TODO not working if buffer is wrapping */
-               while ((data = ncb_data(ncbuf, 0))) {
-                       const unsigned char *cdata = (const unsigned char *)ncb_head(ncbuf);
+               while ((data = ncb2_data(ncbuf, 0))) {
+                       const unsigned char *cdata = (const unsigned char *)ncb2_head(ncbuf);
 
                        if (!qc_ssl_provide_quic_data(&qel->cstream->rx.ncbuf, qel->level,
                                                      ctx, cdata, data))
@@ -1129,7 +1124,7 @@ int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
                                    QUIC_EV_CONN_PHPKTS, qc, qel);
                }
 
-               if (!ncb_is_null(ncbuf) && ncb_is_empty(ncbuf)) {
+               if (!ncb2_is_null(ncbuf) && ncb2_is_empty(ncbuf)) {
                        TRACE_DEVEL("freeing crypto buf", QUIC_EV_CONN_PHPKTS, qc, qel);
                        quic_free_ncbuf(ncbuf);
                }
index 40213a1bde89a65a608b7b6505f865719bb3a933..ff8b4e20c4a5583eeb6109d5285ee9b1408d9850 100644 (file)
@@ -143,7 +143,7 @@ struct quic_cstream *quic_cstream_new(struct quic_conn *qc)
        }
 
        cs->rx.offset = 0;
-       cs->rx.ncbuf = NCBUF_NULL;
+       cs->rx.ncbuf = NCBUF2_NULL;
        cs->rx.offset = 0;
 
        cs->tx.offset = 0;