]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: quic: Add a new module to handle QUIC connection IDs
authorFrédéric Lécaille <flecaille@haproxy.com>
Thu, 23 Nov 2023 18:21:03 +0000 (19:21 +0100)
committerFrédéric Lécaille <flecaille@haproxy.com>
Tue, 28 Nov 2023 14:37:22 +0000 (15:37 +0100)
Move quic_cid and quic_connnection_id from quic_conn-t.h to new quic_cid-t.h header.
Move defintions of quic_stateless_reset_token_init(), quic_derive_cid(),
new_quic_cid(), quic_get_cid_tid() and retrieve_qc_conn_from_cid() to quic_cid.c
new C file.

Makefile
include/haproxy/quic_cid-t.h [new file with mode: 0644]
include/haproxy/quic_cid.h [new file with mode: 0644]
include/haproxy/quic_conn-t.h
include/haproxy/quic_conn.h
src/quic_cid.c [new file with mode: 0644]
src/quic_conn.c
src/quic_rx.c
src/quic_sock.c
src/quic_tx.c

index 03f7e7165bb3235e3dc0b840fea37a22aa69bbc9..48734b98f906021de79c1c61fe03493a2db21ebd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -620,7 +620,7 @@ OPTIONS_OBJS += src/quic_conn.o src/mux_quic.o src/h3.o src/xprt_quic.o    \
                 src/h3_stats.o src/qmux_http.o src/cfgparse-quic.o         \
                 src/cbuf.o src/quic_cc.o src/quic_cc_nocc.o src/quic_ack.o \
                 src/quic_trace.o src/quic_cli.o src/quic_ssl.o             \
-                src/quic_rx.o src/quic_tx.o
+                src/quic_rx.o src/quic_tx.o src/quic_cid.o
 endif
 
 ifneq ($(USE_QUIC_OPENSSL_COMPAT),)
diff --git a/include/haproxy/quic_cid-t.h b/include/haproxy/quic_cid-t.h
new file mode 100644 (file)
index 0000000..d355bae
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _HAPROXY_QUIC_CID_T_H
+#define _HAPROXY_QUIC_CID_T_H
+
+#include <haproxy/quic_tp-t.h>
+
+/* QUIC connection ID maximum length for version 1. */
+#define QUIC_CID_MAXLEN               20 /* bytes */
+
+/* QUIC connection id data.
+ *
+ * This struct is used by ebmb_node structs as last member of flexible arrays.
+ * So do not change the order of the member of quic_cid struct.
+ * <data> member must be the first one.
+ */
+struct quic_cid {
+       unsigned char data[QUIC_CID_MAXLEN];
+       unsigned char len; /* size of QUIC CID */
+};
+
+/* QUIC connection id attached to a QUIC connection.
+ *
+ * This structure is used to match received packets DCIDs with the
+ * corresponding QUIC connection.
+ */
+struct quic_connection_id {
+       struct eb64_node seq_num;
+       uint64_t retire_prior_to;
+       unsigned char stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
+
+       struct ebmb_node node; /* node for receiver tree, cid.data as key */
+       struct quic_cid cid;   /* CID data */
+
+       struct quic_conn *qc;  /* QUIC connection using this CID */
+       uint tid;              /* Attached Thread ID for the connection. */
+};
+
+#endif /* _HAPROXY_QUIC_CID_T_H */
diff --git a/include/haproxy/quic_cid.h b/include/haproxy/quic_cid.h
new file mode 100644 (file)
index 0000000..9e02e5b
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef _HAPROXY_QUIC_CID_H
+#define _HAPROXY_QUIC_CID_H
+
+#ifdef USE_QUIC
+#ifndef USE_OPENSSL
+#error "Must define USE_OPENSSL"
+#endif
+
+#include <import/ebmbtree.h>
+
+#include <haproxy/buf-t.h>
+#include <haproxy/chunk.h>
+#include <haproxy/quic_conn-t.h>
+#include <haproxy/quic_rx-t.h>
+#include <haproxy/proto_quic.h>
+
+struct quic_connection_id *new_quic_cid(struct eb_root *root,
+                                        struct quic_conn *qc,
+                                        const struct quic_cid *orig,
+                                        const struct sockaddr_storage *addr);
+int quic_get_cid_tid(const unsigned char *cid, size_t cid_len,
+                     const struct sockaddr_storage *cli_addr,
+                     unsigned char *pos, size_t len);
+struct quic_cid quic_derive_cid(const struct quic_cid *orig,
+                                const struct sockaddr_storage *addr);
+struct quic_conn *retrieve_qc_conn_from_cid(struct quic_rx_packet *pkt,
+                                            struct listener *l,
+                                            struct sockaddr_storage *saddr,
+                                            int *new_tid);
+
+/* Copy <src> QUIC CID to <dst>.
+ * This is the responsibility of the caller to check there is enough room in
+ * <dst> to copy <src>.
+ * Always succeeds.
+ */
+static inline void quic_cid_cpy(struct quic_cid *dst, const struct quic_cid *src)
+{
+       memcpy(dst->data, src->data, src->len);
+       dst->len = src->len;
+}
+
+/* Dump the QUIC connection ID value if present (non null length). Used only for
+ * debugging purposes.
+ * Always succeeds.
+ */
+static inline void quic_cid_dump(struct buffer *buf,
+                                 const struct quic_cid *cid)
+{
+       int i;
+
+       chunk_appendf(buf, "(%d", cid->len);
+       if (cid->len)
+               chunk_appendf(buf, ",");
+       for (i = 0; i < cid->len; i++)
+               chunk_appendf(buf, "%02x", cid->data[i]);
+       chunk_appendf(buf, ")");
+}
+
+/* Return tree index where <cid> is stored. */
+static inline uchar _quic_cid_tree_idx(const unsigned char *cid)
+{
+       return cid[0];
+}
+
+/* Return tree index where <cid> is stored. */
+static inline uchar quic_cid_tree_idx(const struct quic_cid *cid)
+{
+       return _quic_cid_tree_idx(cid->data);
+}
+
+/* Insert <conn_id> into global CID tree as a thread-safe operation. */
+static inline void quic_cid_insert(struct quic_connection_id *conn_id)
+{
+       const uchar idx = quic_cid_tree_idx(&conn_id->cid);
+       struct quic_cid_tree *tree = &quic_cid_trees[idx];
+
+       HA_RWLOCK_WRLOCK(QC_CID_LOCK, &tree->lock);
+       ebmb_insert(&tree->root, &conn_id->node, conn_id->cid.len);
+       HA_RWLOCK_WRUNLOCK(QC_CID_LOCK, &tree->lock);
+}
+
+/* Remove <conn_id> from global CID tree as a thread-safe operation. */
+static inline void quic_cid_delete(struct quic_connection_id *conn_id)
+{
+       const uchar idx = quic_cid_tree_idx(&conn_id->cid);
+       struct quic_cid_tree __maybe_unused *tree = &quic_cid_trees[idx];
+
+       HA_RWLOCK_WRLOCK(QC_CID_LOCK, &tree->lock);
+       ebmb_delete(&conn_id->node);
+       HA_RWLOCK_WRUNLOCK(QC_CID_LOCK, &tree->lock);
+}
+
+#endif /* USE_QUIC */
+#endif /* _HAPROXY_QUIC_CID_H */
index 86d80a7b54d2d1467bb21033017ed10d0a6ba87d..edf2e304ec775661466a6f1f0ae71751b570f23d 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <haproxy/openssl-compat.h>
 #include <haproxy/mux_quic-t.h>
+#include <haproxy/quic_cid-t.h>
 #include <haproxy/quic_cc-t.h>
 #include <haproxy/quic_loss-t.h>
 #include <haproxy/quic_openssl_compat-t.h>
@@ -61,8 +62,6 @@ typedef unsigned long long ull;
 #define QUIC_HAP_CID_LEN               8
 
 /* Common definitions for short and long QUIC packet headers. */
-/* QUIC connection ID maximum length for version 1. */
-#define QUIC_CID_MAXLEN               20 /* bytes */
 /* QUIC original destination connection ID minial length */
 #define QUIC_ODCID_MINLEN              8 /* bytes */
 /*
@@ -219,34 +218,6 @@ extern const struct quic_version quic_versions[];
 extern const size_t quic_versions_nb;
 extern const struct quic_version *preferred_version;
 
-/* QUIC connection id data.
- *
- * This struct is used by ebmb_node structs as last member of flexible arrays.
- * So do not change the order of the member of quic_cid struct.
- * <data> member must be the first one.
- */
-struct quic_cid {
-       unsigned char data[QUIC_CID_MAXLEN];
-       unsigned char len; /* size of QUIC CID */
-};
-
-/* QUIC connection id attached to a QUIC connection.
- *
- * This structure is used to match received packets DCIDs with the
- * corresponding QUIC connection.
- */
-struct quic_connection_id {
-       struct eb64_node seq_num;
-       uint64_t retire_prior_to;
-       unsigned char stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
-
-       struct ebmb_node node; /* node for receiver tree, cid.data as key */
-       struct quic_cid cid;   /* CID data */
-
-       struct quic_conn *qc;  /* QUIC connection using this CID */
-       uint tid;              /* Attached Thread ID for the connection. */
-};
-
 /* unused: 0x01 */
 /* Flag the packet number space as requiring an ACK frame to be sent. */
 #define QUIC_FL_PKTNS_ACK_REQUIRED  (1UL << 1)
index 95f871b97df7b1165aca0317f26f24e4a754e7e1..ec8d4b24ea833b8ca8c33bc8f879f8487b4711af 100644 (file)
@@ -40,6 +40,7 @@
 #include <haproxy/listener.h>
 #include <haproxy/proto_quic.h>
 #include <haproxy/quic_cc.h>
+#include <haproxy/quic_cid.h>
 #include <haproxy/quic_conn-t.h>
 #include <haproxy/quic_enc.h>
 #include <haproxy/quic_frame.h>
@@ -109,17 +110,6 @@ static inline int qc_is_listener(struct quic_conn *qc)
        return qc->flags & QUIC_FL_CONN_LISTENER;
 }
 
-/* Copy <src> QUIC CID to <dst>.
- * This is the responsibility of the caller to check there is enough room in
- * <dst> to copy <src>.
- * Always succeeds.
- */
-static inline void quic_cid_cpy(struct quic_cid *dst, const struct quic_cid *src)
-{
-       memcpy(dst->data, src->data, src->len);
-       dst->len = src->len;
-}
-
 /* Copy <saddr> socket address data into <buf> buffer.
  * This is the responsibility of the caller to check the output buffer is big
  * enough to contain these socket address data.
@@ -153,57 +143,6 @@ static inline size_t quic_saddr_cpy(unsigned char *buf,
        return p - buf;
 }
 
-/* Dump the QUIC connection ID value if present (non null length). Used only for
- * debugging purposes.
- * Always succeeds.
- */
-static inline void quic_cid_dump(struct buffer *buf,
-                                 const struct quic_cid *cid)
-{
-       int i;
-
-       chunk_appendf(buf, "(%d", cid->len);
-       if (cid->len)
-               chunk_appendf(buf, ",");
-       for (i = 0; i < cid->len; i++)
-               chunk_appendf(buf, "%02x", cid->data[i]);
-       chunk_appendf(buf, ")");
-}
-
-/* Return tree index where <cid> is stored. */
-static inline uchar _quic_cid_tree_idx(const unsigned char *cid)
-{
-       return cid[0];
-}
-
-/* Return tree index where <cid> is stored. */
-static inline uchar quic_cid_tree_idx(const struct quic_cid *cid)
-{
-       return _quic_cid_tree_idx(cid->data);
-}
-
-/* Insert <conn_id> into global CID tree as a thread-safe operation. */
-static inline void quic_cid_insert(struct quic_connection_id *conn_id)
-{
-       const uchar idx = quic_cid_tree_idx(&conn_id->cid);
-       struct quic_cid_tree *tree = &quic_cid_trees[idx];
-
-       HA_RWLOCK_WRLOCK(QC_CID_LOCK, &tree->lock);
-       ebmb_insert(&tree->root, &conn_id->node, conn_id->cid.len);
-       HA_RWLOCK_WRUNLOCK(QC_CID_LOCK, &tree->lock);
-}
-
-/* Remove <conn_id> from global CID tree as a thread-safe operation. */
-static inline void quic_cid_delete(struct quic_connection_id *conn_id)
-{
-       const uchar idx = quic_cid_tree_idx(&conn_id->cid);
-       struct quic_cid_tree __maybe_unused *tree = &quic_cid_trees[idx];
-
-       HA_RWLOCK_WRLOCK(QC_CID_LOCK, &tree->lock);
-       ebmb_delete(&conn_id->node);
-       HA_RWLOCK_WRUNLOCK(QC_CID_LOCK, &tree->lock);
-}
-
 /* Free the CIDs attached to <conn> QUIC connection. */
 static inline void free_quic_conn_cids(struct quic_conn *conn)
 {
diff --git a/src/quic_cid.c b/src/quic_cid.c
new file mode 100644 (file)
index 0000000..bef90f6
--- /dev/null
@@ -0,0 +1,261 @@
+#include <import/eb64tree.h>
+#include <import/ebmbtree.h>
+
+#include <haproxy/pool.h>
+#include <haproxy/quic_cid.h>
+#include <haproxy/quic_conn.h>
+#include <haproxy/quic_rx-t.h>
+#include <haproxy/quic_trace.h>
+#include <haproxy/trace.h>
+#include <haproxy/xxhash.h>
+
+/* Initialize the stateless reset token attached to <conn_id> connection ID.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_stateless_reset_token_init(struct quic_connection_id *conn_id)
+{
+       /* Output secret */
+       unsigned char *token = conn_id->stateless_reset_token;
+       size_t tokenlen = sizeof conn_id->stateless_reset_token;
+       /* Salt */
+       const unsigned char *cid = conn_id->cid.data;
+       size_t cidlen = conn_id->cid.len;
+
+       return quic_stateless_reset_token_cpy(token, tokenlen, cid, cidlen);
+}
+
+/* Generate a CID directly derived from <orig> CID and <addr> address.
+ *
+ * Returns the derived CID.
+ */
+struct quic_cid quic_derive_cid(const struct quic_cid *orig,
+                                const struct sockaddr_storage *addr)
+{
+       struct quic_cid cid;
+       const struct sockaddr_in *in;
+       const struct sockaddr_in6 *in6;
+       char *pos = trash.area;
+       size_t idx = 0;
+       uint64_t hash;
+       int i;
+
+       /* Prepare buffer for hash using original CID first. */
+       memcpy(pos, orig->data, orig->len);
+       idx += orig->len;
+
+       /* Concatenate client address. */
+       switch (addr->ss_family) {
+       case AF_INET:
+               in = (struct sockaddr_in *)addr;
+
+               memcpy(&pos[idx], &in->sin_addr, sizeof(in->sin_addr));
+               idx += sizeof(in->sin_addr);
+               memcpy(&pos[idx], &in->sin_port, sizeof(in->sin_port));
+               idx += sizeof(in->sin_port);
+               break;
+
+       case AF_INET6:
+               in6 = (struct sockaddr_in6 *)addr;
+
+               memcpy(&pos[idx], &in6->sin6_addr, sizeof(in6->sin6_addr));
+               idx += sizeof(in6->sin6_addr);
+               memcpy(&pos[idx], &in6->sin6_port, sizeof(in6->sin6_port));
+               idx += sizeof(in6->sin6_port);
+               break;
+
+       default:
+               /* TODO to implement */
+               ABORT_NOW();
+       }
+
+       /* Avoid similar values between multiple haproxy process. */
+       memcpy(&pos[idx], boot_seed, sizeof(boot_seed));
+       idx += sizeof(boot_seed);
+
+       /* Hash the final buffer content. */
+       hash = XXH64(pos, idx, 0);
+
+       for (i = 0; i < sizeof(hash); ++i)
+               cid.data[i] = hash >> ((sizeof(hash) * 7) - (8 * i));
+       cid.len = sizeof(hash);
+
+       return cid;
+}
+
+/* Allocate a new CID and attach it to <root> ebtree.
+ *
+ * If <orig> and <addr> params are non null, the new CID value is directly
+ * derived from them. Else a random value is generated. The CID is then marked
+ * with the current thread ID.
+ *
+ * Returns the new CID if succeeded, NULL if not.
+ */
+struct quic_connection_id *new_quic_cid(struct eb_root *root,
+                                        struct quic_conn *qc,
+                                        const struct quic_cid *orig,
+                                        const struct sockaddr_storage *addr)
+{
+       struct quic_connection_id *conn_id;
+
+       TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
+
+       /* Caller must set either none or both values. */
+       BUG_ON(!!orig != !!addr);
+
+       conn_id = pool_alloc(pool_head_quic_connection_id);
+       if (!conn_id) {
+               TRACE_ERROR("cid allocation failed", QUIC_EV_CONN_TXPKT, qc);
+               goto err;
+       }
+
+       conn_id->cid.len = QUIC_HAP_CID_LEN;
+
+       if (!orig) {
+               if (quic_newcid_from_hash64)
+                       quic_newcid_from_hash64(conn_id->cid.data, conn_id->cid.len, qc->hash64,
+                                               global.cluster_secret, sizeof(global.cluster_secret));
+               else if (RAND_bytes(conn_id->cid.data, conn_id->cid.len) != 1) {
+                       /* TODO: RAND_bytes() should be replaced */
+                       TRACE_ERROR("RAND_bytes() failed", QUIC_EV_CONN_TXPKT, qc);
+                       goto err;
+               }
+       }
+       else {
+               /* Derive the new CID value from original CID. */
+               conn_id->cid = quic_derive_cid(orig, addr);
+       }
+
+       if (quic_stateless_reset_token_init(conn_id) != 1) {
+               TRACE_ERROR("quic_stateless_reset_token_init() failed", QUIC_EV_CONN_TXPKT, qc);
+               goto err;
+       }
+
+       conn_id->qc = qc;
+       HA_ATOMIC_STORE(&conn_id->tid, tid);
+
+       conn_id->seq_num.key = qc ? qc->next_cid_seq_num++ : 0;
+       conn_id->retire_prior_to = 0;
+       /* insert the allocated CID in the quic_conn tree */
+       if (root)
+               eb64_insert(root, &conn_id->seq_num);
+
+       TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
+       return conn_id;
+
+ err:
+       pool_free(pool_head_quic_connection_id, conn_id);
+       TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
+       return NULL;
+}
+
+/* Retrieve the thread ID associated to QUIC connection ID <cid> of length
+ * <cid_len>. CID may be not found on the CID tree because it is an ODCID. In
+ * this case, it will derived using client address <cli_addr> as hash
+ * parameter. However, this is done only if <pos> points to an INITIAL or 0RTT
+ * packet of length <len>.
+ *
+ * Returns the thread ID or a negative error code.
+ */
+int quic_get_cid_tid(const unsigned char *cid, size_t cid_len,
+                     const struct sockaddr_storage *cli_addr,
+                     unsigned char *pos, size_t len)
+{
+       struct quic_cid_tree *tree;
+       struct quic_connection_id *conn_id;
+       struct ebmb_node *node;
+
+       tree = &quic_cid_trees[_quic_cid_tree_idx(cid)];
+       HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
+       node = ebmb_lookup(&tree->root, cid, cid_len);
+       HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
+
+       if (!node) {
+               struct quic_cid orig, derive_cid;
+               struct quic_rx_packet pkt;
+
+               if (!qc_parse_hd_form(&pkt, &pos, pos + len))
+                       goto not_found;
+
+               if (pkt.type != QUIC_PACKET_TYPE_INITIAL &&
+                   pkt.type != QUIC_PACKET_TYPE_0RTT) {
+                       goto not_found;
+               }
+
+               memcpy(orig.data, cid, cid_len);
+               orig.len = cid_len;
+               derive_cid = quic_derive_cid(&orig, cli_addr);
+
+               tree = &quic_cid_trees[quic_cid_tree_idx(&derive_cid)];
+               HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
+               node = ebmb_lookup(&tree->root, cid, cid_len);
+               HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
+       }
+
+       if (!node)
+               goto not_found;
+
+       conn_id = ebmb_entry(node, struct quic_connection_id, node);
+       return HA_ATOMIC_LOAD(&conn_id->tid);
+
+ not_found:
+       return -1;
+}
+
+/* Retrieve a quic_conn instance from the <pkt> DCID field. If the packet is an
+ * INITIAL or 0RTT type, we may have to use client address <saddr> if an ODCID
+ * is used.
+ *
+ * Returns the instance or NULL if not found.
+ */
+struct quic_conn *retrieve_qc_conn_from_cid(struct quic_rx_packet *pkt,
+                                            struct listener *l,
+                                            struct sockaddr_storage *saddr,
+                                            int *new_tid)
+{
+       struct quic_conn *qc = NULL;
+       struct ebmb_node *node;
+       struct quic_connection_id *conn_id;
+       struct quic_cid_tree *tree;
+       uint conn_id_tid;
+
+       TRACE_ENTER(QUIC_EV_CONN_RXPKT);
+       *new_tid = -1;
+
+       /* First look into DCID tree. */
+       tree = &quic_cid_trees[_quic_cid_tree_idx(pkt->dcid.data)];
+       HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
+       node = ebmb_lookup(&tree->root, pkt->dcid.data, pkt->dcid.len);
+
+       /* If not found on an Initial/0-RTT packet, it could be because an
+        * ODCID is reused by the client. Calculate the derived CID value to
+        * retrieve it from the DCID tree.
+        */
+       if (!node && (pkt->type == QUIC_PACKET_TYPE_INITIAL ||
+            pkt->type == QUIC_PACKET_TYPE_0RTT)) {
+               const struct quic_cid derive_cid = quic_derive_cid(&pkt->dcid, saddr);
+
+               HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
+
+               tree = &quic_cid_trees[quic_cid_tree_idx(&derive_cid)];
+               HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
+               node = ebmb_lookup(&tree->root, derive_cid.data, derive_cid.len);
+       }
+
+       if (!node)
+               goto end;
+
+       conn_id = ebmb_entry(node, struct quic_connection_id, node);
+       conn_id_tid = HA_ATOMIC_LOAD(&conn_id->tid);
+       if (conn_id_tid != tid) {
+               *new_tid = conn_id_tid;
+               goto end;
+       }
+       qc = conn_id->qc;
+
+ end:
+       HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
+       TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc);
+       return qc;
+}
+
+
index 0f5377a20b02fd254f53786e0d41a1fe0a5e6284..2b175d83d56e852dea54be47a2427280566ec4bc 100644 (file)
@@ -32,7 +32,6 @@
 #include <haproxy/debug.h>
 #include <haproxy/tools.h>
 #include <haproxy/ticks.h>
-#include <haproxy/xxhash.h>
 
 #include <haproxy/connection.h>
 #include <haproxy/fd.h>
@@ -485,198 +484,6 @@ int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len,
        return ret;
 }
 
-/* Initialize the stateless reset token attached to <conn_id> connection ID.
- * Returns 1 if succeeded, 0 if not.
- */
-static int quic_stateless_reset_token_init(struct quic_connection_id *conn_id)
-{
-       /* Output secret */
-       unsigned char *token = conn_id->stateless_reset_token;
-       size_t tokenlen = sizeof conn_id->stateless_reset_token;
-       /* Salt */
-       const unsigned char *cid = conn_id->cid.data;
-       size_t cidlen = conn_id->cid.len;
-
-       return quic_stateless_reset_token_cpy(token, tokenlen, cid, cidlen);
-}
-
-/* Generate a CID directly derived from <orig> CID and <addr> address.
- *
- * Returns the derived CID.
- */
-struct quic_cid quic_derive_cid(const struct quic_cid *orig,
-                                const struct sockaddr_storage *addr)
-{
-       struct quic_cid cid;
-       const struct sockaddr_in *in;
-       const struct sockaddr_in6 *in6;
-       char *pos = trash.area;
-       size_t idx = 0;
-       uint64_t hash;
-       int i;
-
-       /* Prepare buffer for hash using original CID first. */
-       memcpy(pos, orig->data, orig->len);
-       idx += orig->len;
-
-       /* Concatenate client address. */
-       switch (addr->ss_family) {
-       case AF_INET:
-               in = (struct sockaddr_in *)addr;
-
-               memcpy(&pos[idx], &in->sin_addr, sizeof(in->sin_addr));
-               idx += sizeof(in->sin_addr);
-               memcpy(&pos[idx], &in->sin_port, sizeof(in->sin_port));
-               idx += sizeof(in->sin_port);
-               break;
-
-       case AF_INET6:
-               in6 = (struct sockaddr_in6 *)addr;
-
-               memcpy(&pos[idx], &in6->sin6_addr, sizeof(in6->sin6_addr));
-               idx += sizeof(in6->sin6_addr);
-               memcpy(&pos[idx], &in6->sin6_port, sizeof(in6->sin6_port));
-               idx += sizeof(in6->sin6_port);
-               break;
-
-       default:
-               /* TODO to implement */
-               ABORT_NOW();
-       }
-
-       /* Avoid similar values between multiple haproxy process. */
-       memcpy(&pos[idx], boot_seed, sizeof(boot_seed));
-       idx += sizeof(boot_seed);
-
-       /* Hash the final buffer content. */
-       hash = XXH64(pos, idx, 0);
-
-       for (i = 0; i < sizeof(hash); ++i)
-               cid.data[i] = hash >> ((sizeof(hash) * 7) - (8 * i));
-       cid.len = sizeof(hash);
-
-       return cid;
-}
-
-/* Retrieve the thread ID associated to QUIC connection ID <cid> of length
- * <cid_len>. CID may be not found on the CID tree because it is an ODCID. In
- * this case, it will derived using client address <cli_addr> as hash
- * parameter. However, this is done only if <pos> points to an INITIAL or 0RTT
- * packet of length <len>.
- *
- * Returns the thread ID or a negative error code.
- */
-int quic_get_cid_tid(const unsigned char *cid, size_t cid_len,
-                     const struct sockaddr_storage *cli_addr,
-                     unsigned char *pos, size_t len)
-{
-       struct quic_cid_tree *tree;
-       struct quic_connection_id *conn_id;
-       struct ebmb_node *node;
-
-       tree = &quic_cid_trees[_quic_cid_tree_idx(cid)];
-       HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
-       node = ebmb_lookup(&tree->root, cid, cid_len);
-       HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
-
-       if (!node) {
-               struct quic_cid orig, derive_cid;
-               struct quic_rx_packet pkt;
-
-               if (!qc_parse_hd_form(&pkt, &pos, pos + len))
-                       goto not_found;
-
-               if (pkt.type != QUIC_PACKET_TYPE_INITIAL &&
-                   pkt.type != QUIC_PACKET_TYPE_0RTT) {
-                       goto not_found;
-               }
-
-               memcpy(orig.data, cid, cid_len);
-               orig.len = cid_len;
-               derive_cid = quic_derive_cid(&orig, cli_addr);
-
-               tree = &quic_cid_trees[quic_cid_tree_idx(&derive_cid)];
-               HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
-               node = ebmb_lookup(&tree->root, cid, cid_len);
-               HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
-       }
-
-       if (!node)
-               goto not_found;
-
-       conn_id = ebmb_entry(node, struct quic_connection_id, node);
-       return HA_ATOMIC_LOAD(&conn_id->tid);
-
- not_found:
-       return -1;
-}
-
-/* Allocate a new CID and attach it to <root> ebtree.
- *
- * If <orig> and <addr> params are non null, the new CID value is directly
- * derived from them. Else a random value is generated. The CID is then marked
- * with the current thread ID.
- *
- * Returns the new CID if succeeded, NULL if not.
- */
-struct quic_connection_id *new_quic_cid(struct eb_root *root,
-                                        struct quic_conn *qc,
-                                        const struct quic_cid *orig,
-                                        const struct sockaddr_storage *addr)
-{
-       struct quic_connection_id *conn_id;
-
-       TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
-
-       /* Caller must set either none or both values. */
-       BUG_ON(!!orig != !!addr);
-
-       conn_id = pool_alloc(pool_head_quic_connection_id);
-       if (!conn_id) {
-               TRACE_ERROR("cid allocation failed", QUIC_EV_CONN_TXPKT, qc);
-               goto err;
-       }
-
-       conn_id->cid.len = QUIC_HAP_CID_LEN;
-
-       if (!orig) {
-               if (quic_newcid_from_hash64)
-                       quic_newcid_from_hash64(conn_id->cid.data, conn_id->cid.len, qc->hash64,
-                                               global.cluster_secret, sizeof(global.cluster_secret));
-               else if (RAND_bytes(conn_id->cid.data, conn_id->cid.len) != 1) {
-                       /* TODO: RAND_bytes() should be replaced */
-                       TRACE_ERROR("RAND_bytes() failed", QUIC_EV_CONN_TXPKT, qc);
-                       goto err;
-               }
-       }
-       else {
-               /* Derive the new CID value from original CID. */
-               conn_id->cid = quic_derive_cid(orig, addr);
-       }
-
-       if (quic_stateless_reset_token_init(conn_id) != 1) {
-               TRACE_ERROR("quic_stateless_reset_token_init() failed", QUIC_EV_CONN_TXPKT, qc);
-               goto err;
-       }
-
-       conn_id->qc = qc;
-       HA_ATOMIC_STORE(&conn_id->tid, tid);
-
-       conn_id->seq_num.key = qc ? qc->next_cid_seq_num++ : 0;
-       conn_id->retire_prior_to = 0;
-       /* insert the allocated CID in the quic_conn tree */
-       if (root)
-               eb64_insert(root, &conn_id->seq_num);
-
-       TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
-       return conn_id;
-
- err:
-       pool_free(pool_head_quic_connection_id, conn_id);
-       TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
-       return NULL;
-}
-
 /* QUIC connection packet handler task (post handshake) */
 struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state)
 {
index 3374e1a9b7af2be55b02de4212dbb54858704568..c717b73e1a4ddbc02676f8f26bd1248035887feb 100644 (file)
@@ -19,6 +19,7 @@
 #include <haproxy/ncbuf.h>
 #include <haproxy/proto_quic.h>
 #include <haproxy/quic_ack.h>
+#include <haproxy/quic_cid.h>
 #include <haproxy/quic_sock.h>
 #include <haproxy/quic_stream.h>
 #include <haproxy/quic_ssl.h>
@@ -1840,63 +1841,6 @@ static int quic_retry_token_check(struct quic_rx_packet *pkt,
        goto leave;
 }
 
-/* Retrieve a quic_conn instance from the <pkt> DCID field. If the packet is an
- * INITIAL or 0RTT type, we may have to use client address <saddr> if an ODCID
- * is used.
- *
- * Returns the instance or NULL if not found.
- */
-static struct quic_conn *retrieve_qc_conn_from_cid(struct quic_rx_packet *pkt,
-                                                   struct listener *l,
-                                                   struct sockaddr_storage *saddr,
-                                                   int *new_tid)
-{
-       struct quic_conn *qc = NULL;
-       struct ebmb_node *node;
-       struct quic_connection_id *conn_id;
-       struct quic_cid_tree *tree;
-       uint conn_id_tid;
-
-       TRACE_ENTER(QUIC_EV_CONN_RXPKT);
-       *new_tid = -1;
-
-       /* First look into DCID tree. */
-       tree = &quic_cid_trees[_quic_cid_tree_idx(pkt->dcid.data)];
-       HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
-       node = ebmb_lookup(&tree->root, pkt->dcid.data, pkt->dcid.len);
-
-       /* If not found on an Initial/0-RTT packet, it could be because an
-        * ODCID is reused by the client. Calculate the derived CID value to
-        * retrieve it from the DCID tree.
-        */
-       if (!node && (pkt->type == QUIC_PACKET_TYPE_INITIAL ||
-            pkt->type == QUIC_PACKET_TYPE_0RTT)) {
-               const struct quic_cid derive_cid = quic_derive_cid(&pkt->dcid, saddr);
-
-               HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
-
-               tree = &quic_cid_trees[quic_cid_tree_idx(&derive_cid)];
-               HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
-               node = ebmb_lookup(&tree->root, derive_cid.data, derive_cid.len);
-       }
-
-       if (!node)
-               goto end;
-
-       conn_id = ebmb_entry(node, struct quic_connection_id, node);
-       conn_id_tid = HA_ATOMIC_LOAD(&conn_id->tid);
-       if (conn_id_tid != tid) {
-               *new_tid = conn_id_tid;
-               goto end;
-       }
-       qc = conn_id->qc;
-
- end:
-       HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
-       TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc);
-       return qc;
-}
-
 /* Check that all the bytes between <pos> included and <end> address
  * excluded are null. This is the responsibility of the caller to
  * check that there is at least one byte between <pos> end <end>.
index afffdf302bdea9508c3da9e84ae17313714ba525..323fe6cbded3e4d6d9309acd6b74e7d088d9c517 100644 (file)
@@ -31,6 +31,7 @@
 #include <haproxy/pool.h>
 #include <haproxy/proto_quic.h>
 #include <haproxy/proxy-t.h>
+#include <haproxy/quic_cid.h>
 #include <haproxy/quic_conn.h>
 #include <haproxy/quic_rx.h>
 #include <haproxy/quic_sock.h>
index 4c1157f6376b396f20eee84be2a8bbdb45f0dbca..7953c04817f88526640d27fc7ac88f2251cdb0c4 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <haproxy/pool.h>
 #include <haproxy/trace.h>
+#include <haproxy/quic_cid.h>
 #include <haproxy/quic_sock.h>
 #include <haproxy/quic_tls.h>
 #include <haproxy/quic_trace.h>