]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: QUIC transport parameters split.
authorFrédéric Lécaille <flecaille@haproxy.com>
Sat, 21 May 2022 21:58:40 +0000 (23:58 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 30 May 2022 07:59:26 +0000 (09:59 +0200)
Make the transport parameters be standlone as much as possible as
it consists only in encoding/decoding data into/from buffers.
Reduce the size of xprt_quic.h. Unfortunalety, I think we will
have to continue to include <xprt_quic-t.h> to use the trace API
into this module.

Makefile
include/haproxy/quic_tp-t.h [new file with mode: 0644]
include/haproxy/quic_tp.h [new file with mode: 0644]
include/haproxy/xprt_quic-t.h
include/haproxy/xprt_quic.h
src/listener.c
src/mux_quic.c
src/proxy.c
src/quic_tp.c [new file with mode: 0644]
src/ssl_sock.c
src/xprt_quic.c

index fb57ef8aef339a0eba707e5fa69914b566037c1a..59b383cff70b74464140b1f72fbf860d462bf3c3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -637,7 +637,7 @@ OPTIONS_OBJS += src/quic_sock.o src/proto_quic.o src/xprt_quic.o src/quic_tls.o
                 src/quic_frame.o src/quic_cc.o src/quic_cc_newreno.o src/mux_quic.o \
                 src/cbuf.o src/qpack-dec.o src/qpack-tbl.o src/h3.o src/qpack-enc.o \
                 src/hq_interop.o src/cfgparse-quic.o src/quic_loss.o \
-                src/quic_stream.o src/quic_stats.o
+                src/quic_tp.o src/quic_stream.o src/quic_stats.o
 endif
 
 ifneq ($(USE_LUA),)
diff --git a/include/haproxy/quic_tp-t.h b/include/haproxy/quic_tp-t.h
new file mode 100644 (file)
index 0000000..36dd376
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _HAPROXY_QUIC_TP_T_H
+#define _HAPROXY_QUIC_TP_T_H
+#ifdef USE_QUIC
+#ifndef USE_OPENSSL
+#error "Must define USE_OPENSSL"
+#endif
+
+#include <stdint.h>
+
+#define QUIC_STATELESS_RESET_TOKEN_LEN 16
+
+/* Default QUIC connection transport parameters */
+extern struct quic_transport_params quic_dflt_transport_params;
+
+struct tp_cid {
+       uint8_t len;
+       uint8_t data[20];
+};
+
+struct tp_preferred_address {
+       uint16_t ipv4_port;
+       uint16_t ipv6_port;
+       uint8_t ipv4_addr[4];
+       uint8_t ipv6_addr[16];
+       struct tp_cid cid;
+       uint8_t stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
+};
+
+/* Default values for the absent transport parameters */
+#define QUIC_DFLT_MAX_UDP_PAYLOAD_SIZE   65527 /* bytes */
+#define QUIC_DFLT_ACK_DELAY_COMPONENT        3 /* milliseconds */
+#define QUIC_DFLT_MAX_ACK_DELAY             25 /* milliseconds */
+#define QUIC_ACTIVE_CONNECTION_ID_LIMIT      2 /* number of connections */
+
+/* Types of QUIC transport parameters */
+#define QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID   0
+#define QUIC_TP_MAX_IDLE_TIMEOUT                     1
+#define QUIC_TP_STATELESS_RESET_TOKEN                2
+#define QUIC_TP_MAX_UDP_PAYLOAD_SIZE                 3
+#define QUIC_TP_INITIAL_MAX_DATA                     4
+#define QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL   5
+#define QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE  6
+#define QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI          7
+#define QUIC_TP_INITIAL_MAX_STREAMS_BIDI             8
+#define QUIC_TP_INITIAL_MAX_STREAMS_UNI              9
+#define QUIC_TP_ACK_DELAY_EXPONENT                  10
+#define QUIC_TP_MAX_ACK_DELAY                       11
+#define QUIC_TP_DISABLE_ACTIVE_MIGRATION            12
+#define QUIC_TP_PREFERRED_ADDRESS                   13
+#define QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT          14
+#define QUIC_TP_INITIAL_SOURCE_CONNECTION_ID        15
+#define QUIC_TP_RETRY_SOURCE_CONNECTION_ID          16
+
+/*
+ * These defines are not for transport parameter type, but the maximum accepted value for
+ * transport parameter types.
+ */
+#define QUIC_TP_ACK_DELAY_EXPONENT_LIMIT 20
+#define QUIC_TP_MAX_ACK_DELAY_LIMIT      (1UL << 14)
+
+/* The maximum length of encoded transport parameters for any QUIC peer. */
+#define QUIC_TP_MAX_ENCLEN    128
+/*
+ * QUIC transport parameters.
+ * Note that forbidden parameters sent by clients MUST generate TRANSPORT_PARAMETER_ERROR errors.
+ */
+struct quic_transport_params {
+       uint64_t max_idle_timeout;
+       uint64_t max_udp_payload_size;                 /* Default: 65527 bytes (max of UDP payload for IPv6) */
+       uint64_t initial_max_data;
+       uint64_t initial_max_stream_data_bidi_local;
+       uint64_t initial_max_stream_data_bidi_remote;
+       uint64_t initial_max_stream_data_uni;
+       uint64_t initial_max_streams_bidi;
+       uint64_t initial_max_streams_uni;
+       uint64_t ack_delay_exponent;                   /* Default: 3, max: 20 */
+       uint64_t max_ack_delay;                        /* Default: 3ms, max: 2^14ms*/
+       uint64_t active_connection_id_limit;
+
+       /* Booleans */
+       uint8_t disable_active_migration;
+       uint8_t with_stateless_reset_token;
+       uint8_t with_preferred_address;
+       uint8_t original_destination_connection_id_present;
+       uint8_t initial_source_connection_id_present;
+
+       uint8_t stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN]; /* Forbidden for clients */
+       /*
+        * MUST be sent by servers.
+        * When received by clients, must be set to 1 if present.
+        */
+       struct tp_cid original_destination_connection_id;            /* Forbidden for clients */
+       /*
+        * MUST be sent by servers after Retry.
+        */
+       struct tp_cid retry_source_connection_id;                    /* Forbidden for clients */
+       /* MUST be present both for servers and clients. */
+       struct tp_cid initial_source_connection_id;
+       struct tp_preferred_address preferred_address;                    /* Forbidden for clients */
+};
+
+#endif /* USE_QUIC */
+#endif /* _HAPROXY_QUIC_TP_T_H */
diff --git a/include/haproxy/quic_tp.h b/include/haproxy/quic_tp.h
new file mode 100644 (file)
index 0000000..92ec9fe
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _HAPROXY_QUIC_TP_H
+#define _HAPROXY_QUIC_TP_H
+#ifdef USE_QUIC
+#ifndef USE_OPENSSL
+#error "Must define USE_OPENSSL"
+#endif
+
+#include <haproxy/quic_tp-t.h>
+#include <haproxy/xprt_quic-t.h>
+
+void quic_transport_params_init(struct quic_transport_params *p, int server);
+int quic_transport_params_encode(unsigned char *buf,
+                                 const unsigned char *end,
+                                 struct quic_transport_params *p,
+                                 int server);
+
+int quic_transport_params_store(struct quic_conn *conn, int server,
+                                const unsigned char *buf,
+                                const unsigned char *end);
+
+int qc_lstnr_params_init(struct quic_conn *qc,
+                         const struct quic_transport_params *listener_params,
+                         const unsigned char *stateless_reset_token,
+                         const unsigned char *dcid, size_t dcidlen,
+                         const unsigned char *scid, size_t scidlen,
+                         const unsigned char *odcid, size_t odcidlen, int token);
+#endif /* USE_QUIC */
+#endif /* _HAPROXY_QUIC_TP_H */
index bb7569f525ea7fd5cf72a76ad80a3f2c57bf7531..b9c728c6f3a6a0b0e499d89aee08bc465a12cdd0 100644 (file)
@@ -35,8 +35,9 @@
 #include <haproxy/mux_quic-t.h>
 #include <haproxy/quic_cc-t.h>
 #include <haproxy/quic_frame-t.h>
-#include <haproxy/quic_tls-t.h>
 #include <haproxy/quic_loss-t.h>
+#include <haproxy/quic_tls-t.h>
+#include <haproxy/quic_tp-t.h>
 #include <haproxy/task.h>
 
 #include <import/ebtree-t.h>
@@ -49,9 +50,6 @@ typedef unsigned long long ull;
 
 #define QUIC_INITIAL_IPV4_MTU      1252 /* (bytes) */
 #define QUIC_INITIAL_IPV6_MTU      1232
-/* XXX TO DO XXX */
-/* Maximum packet length during handshake */
-#define QUIC_PACKET_MAXLEN     2048
 
 /* The minimum length of Initial packets. */
 #define QUIC_INITIAL_PACKET_MINLEN 1200
@@ -194,7 +192,6 @@ enum quic_pkt_type {
  */
 #define QUIC_CONN_MAX_PACKET  64
 
-#define QUIC_STATELESS_RESET_TOKEN_LEN 16
 #define QUIC_STATELESS_RESET_PACKET_HEADER_LEN 5
 #define QUIC_STATELESS_RESET_PACKET_MINLEN     (22 + QUIC_HAP_CID_LEN)
 
@@ -298,88 +295,6 @@ struct quic_connection_id {
        struct quic_conn *qc;  /* QUIC connection using this CID */
 };
 
-struct preferred_address {
-       uint16_t ipv4_port;
-       uint16_t ipv6_port;
-       uint8_t ipv4_addr[4];
-       uint8_t ipv6_addr[16];
-       struct quic_cid cid;
-       uint8_t stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
-};
-
-/* Default values for the absent transport parameters */
-#define QUIC_DFLT_MAX_UDP_PAYLOAD_SIZE   65527 /* bytes */
-#define QUIC_DFLT_ACK_DELAY_COMPONENT        3 /* milliseconds */
-#define QUIC_DFLT_MAX_ACK_DELAY             25 /* milliseconds */
-#define QUIC_ACTIVE_CONNECTION_ID_LIMIT      2 /* number of connections */
-
-/* Types of QUIC transport parameters */
-#define QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID   0
-#define QUIC_TP_MAX_IDLE_TIMEOUT                     1
-#define QUIC_TP_STATELESS_RESET_TOKEN                2
-#define QUIC_TP_MAX_UDP_PAYLOAD_SIZE                 3
-#define QUIC_TP_INITIAL_MAX_DATA                     4
-#define QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL   5
-#define QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE  6
-#define QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI          7
-#define QUIC_TP_INITIAL_MAX_STREAMS_BIDI             8
-#define QUIC_TP_INITIAL_MAX_STREAMS_UNI              9
-#define QUIC_TP_ACK_DELAY_EXPONENT                  10
-#define QUIC_TP_MAX_ACK_DELAY                       11
-#define QUIC_TP_DISABLE_ACTIVE_MIGRATION            12
-#define QUIC_TP_PREFERRED_ADDRESS                   13
-#define QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT          14
-#define QUIC_TP_INITIAL_SOURCE_CONNECTION_ID        15
-#define QUIC_TP_RETRY_SOURCE_CONNECTION_ID          16
-
-/*
- * These defines are not for transport parameter type, but the maximum accepted value for
- * transport parameter types.
- */
-#define QUIC_TP_ACK_DELAY_EXPONENT_LIMIT 20
-#define QUIC_TP_MAX_ACK_DELAY_LIMIT      (1UL << 14)
-
-/* The maximum length of encoded transport parameters for any QUIC peer. */
-#define QUIC_TP_MAX_ENCLEN    128
-/*
- * QUIC transport parameters.
- * Note that forbidden parameters sent by clients MUST generate TRANSPORT_PARAMETER_ERROR errors.
- */
-struct quic_transport_params {
-       uint64_t max_idle_timeout;
-       uint64_t max_udp_payload_size;                 /* Default: 65527 bytes (max of UDP payload for IPv6) */
-       uint64_t initial_max_data;
-       uint64_t initial_max_stream_data_bidi_local;
-       uint64_t initial_max_stream_data_bidi_remote;
-       uint64_t initial_max_stream_data_uni;
-       uint64_t initial_max_streams_bidi;
-       uint64_t initial_max_streams_uni;
-       uint64_t ack_delay_exponent;                   /* Default: 3, max: 20 */
-       uint64_t max_ack_delay;                        /* Default: 3ms, max: 2^14ms*/
-       uint64_t active_connection_id_limit;
-
-       /* Booleans */
-       uint8_t disable_active_migration;
-       uint8_t with_stateless_reset_token;
-       uint8_t with_preferred_address;
-       uint8_t original_destination_connection_id_present;
-       uint8_t initial_source_connection_id_present;
-
-       uint8_t stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN]; /* Forbidden for clients */
-       /*
-        * MUST be sent by servers.
-        * When received by clients, must be set to 1 if present.
-        */
-       struct quic_cid original_destination_connection_id;            /* Forbidden for clients */
-       /*
-        * MUST be sent by servers after Retry.
-        */
-       struct quic_cid retry_source_connection_id;                    /* Forbidden for clients */
-       /* MUST be present both for servers and clients. */
-       struct quic_cid initial_source_connection_id;
-       struct preferred_address preferred_address;                    /* Forbidden for clients */
-};
-
 /* Structure to hold a range of ACKs sent in ACK frames. */
 struct quic_arng {
        int64_t first;
@@ -467,9 +382,6 @@ struct quic_dgram {
 /* The QUIC packet numbers are 62-bits integers */
 #define QUIC_MAX_PACKET_NUM      ((1ULL << 62) - 1)
 
-/* Default QUIC connection transport parameters */
-extern struct quic_transport_params quic_dflt_transport_params;
-
 /* Maximum number of ack-eliciting received packets since the last
  * ACK frame was sent
  */
index fa13c4cfae75eae7d82efd9c5c375c37c91a1ed8..7e3bb35daa736b0add7ec496914d21de74835cd1 100644 (file)
@@ -57,12 +57,6 @@ static inline int qc_is_listener(struct quic_conn *qc)
        return qc->flags & QUIC_FL_CONN_LISTENER;
 }
 
-/* Returns the required length in bytes to encode <cid> QUIC connection ID. */
-static inline size_t sizeof_quic_cid(const struct quic_cid *cid)
-{
-       return sizeof cid->len + cid->len;
-}
-
 /* Copy <src> QUIC CID to <dst>.
  * This is the responsibility of the caller to check there is enough room in
  * <dst> to copy <src>.
@@ -477,509 +471,6 @@ static inline uint64_t quic_compute_ack_delay_us(unsigned int time_received,
        return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent;
 }
 
-/* Initialize <dst> transport parameters with default values (when absent)
- * from <quic_dflt_transport_params>.
- * Never fails.
- */
-static inline void quic_dflt_transport_params_cpy(struct quic_transport_params *dst)
-{
-       dst->max_udp_payload_size = quic_dflt_transport_params.max_udp_payload_size;
-       dst->ack_delay_exponent   = quic_dflt_transport_params.ack_delay_exponent;
-       dst->max_ack_delay        = quic_dflt_transport_params.max_ack_delay;
-       dst->active_connection_id_limit = quic_dflt_transport_params.active_connection_id_limit;
-}
-
-/* Initialize <p> transport parameters. <server> is a boolean, set if TPs are
- * used by a server (haproxy frontend) else this is for a client (haproxy
- * backend).
- *
- * This must only be used for haproxy local parameters. To initialize peer
- * parameters, see quic_dflt_transport_params_cpy().
- *
- * Never fails.
- */
-static inline void quic_transport_params_init(struct quic_transport_params *p,
-                                              int server)
-{
-       const uint64_t ncb_size = global.tune.bufsize - NCB_RESERVED_SZ;
-       const int max_streams_bidi = 100;
-       const int max_streams_uni = 3;
-
-       /* Set RFC default values for unspecified parameters. */
-       quic_dflt_transport_params_cpy(p);
-
-       p->max_idle_timeout                    = 30000;
-
-       p->initial_max_streams_bidi            = max_streams_bidi;
-       p->initial_max_streams_uni             = max_streams_uni;
-       p->initial_max_stream_data_bidi_local  = ncb_size;
-       p->initial_max_stream_data_bidi_remote = ncb_size;
-       p->initial_max_stream_data_uni         = ncb_size;
-       p->initial_max_data = (max_streams_bidi + max_streams_uni) * ncb_size;
-
-       if (server)
-               p->with_stateless_reset_token  = 1;
-
-       p->active_connection_id_limit          = 8;
-
-       p->retry_source_connection_id.len = 0;
-}
-
-/* Encode <addr> preferred address transport parameter in <buf> without its
- * "type+len" prefix. Note that the IP addresses must be encoded in network byte
- * order.
- * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained values
- * already encoded in network byte order.
- * It is the responsibility of the caller to check there is enough room in <buf> to encode
- * this address.
- * Never fails.
- */
-static inline void quic_transport_param_enc_pref_addr_val(unsigned char **buf,
-                                                          const unsigned char *end,
-                                                          struct preferred_address *addr)
-{
-       write_n16(*buf, addr->ipv4_port);
-       *buf += sizeof addr->ipv4_port;
-
-       memcpy(*buf, addr->ipv4_addr, sizeof addr->ipv4_addr);
-       *buf += sizeof addr->ipv4_addr;
-
-       write_n16(*buf, addr->ipv6_port);
-       *buf += sizeof addr->ipv6_port;
-
-       memcpy(*buf, addr->ipv6_addr, sizeof addr->ipv6_addr);
-       *buf += sizeof addr->ipv6_addr;
-
-       *(*buf)++ = addr->cid.len;
-       if (addr->cid.len) {
-               memcpy(*buf, addr->cid.data, addr->cid.len);
-               *buf += addr->cid.len;
-       }
-
-       memcpy(*buf, addr->stateless_reset_token, sizeof addr->stateless_reset_token);
-       *buf += sizeof addr->stateless_reset_token;
-}
-
-/* Decode into <addr> preferred address transport parameter found in <*buf> buffer.
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_param_dec_pref_addr(struct preferred_address *addr,
-                                                     const unsigned char **buf,
-                                                     const unsigned char *end)
-{
-       ssize_t addr_len;
-
-       addr_len = sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
-       addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
-       addr_len += sizeof addr->cid.len;
-
-       if (end - *buf < addr_len)
-               return 0;
-
-       addr->ipv4_port = read_n16(*buf);
-       *buf += sizeof addr->ipv4_port;
-
-       memcpy(addr->ipv4_addr, *buf, sizeof addr->ipv4_addr);
-       *buf += sizeof addr->ipv4_addr;
-
-       addr->ipv6_port = read_n16(*buf);
-       *buf += sizeof addr->ipv6_port;
-
-       memcpy(addr->ipv6_addr, *buf, sizeof addr->ipv6_addr);
-       *buf += sizeof addr->ipv6_addr;
-
-       addr->cid.len = *(*buf)++;
-       if (addr->cid.len) {
-               if (end - *buf > addr->cid.len || addr->cid.len > sizeof addr->cid.data)
-                       return 0;
-               memcpy(addr->cid.data, *buf, addr->cid.len);
-               *buf += addr->cid.len;
-       }
-
-       if (end - *buf != sizeof addr->stateless_reset_token)
-               return 0;
-
-       memcpy(addr->stateless_reset_token, *buf, end - *buf);
-       *buf += sizeof addr->stateless_reset_token;
-
-       return *buf == end;
-}
-
-/* Decode into <p> struct a transport parameter found in <*buf> buffer with
- * <type> as type and <len> as length, depending on <server> boolean value which
- * must be set to 1 for a server (haproxy listener) or 0 for a client (connection
- * to an haproxy server).
- */
-static inline int quic_transport_param_decode(struct quic_transport_params *p,
-                                              int server, uint64_t type,
-                                              const unsigned char **buf, size_t len)
-{
-       const unsigned char *end = *buf + len;
-
-       switch (type) {
-       case QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID:
-               if (!server || len >= sizeof p->original_destination_connection_id.data)
-                       return 0;
-
-               if (len)
-                       memcpy(p->original_destination_connection_id.data, *buf, len);
-               p->original_destination_connection_id.len = len;
-               *buf += len;
-               p->original_destination_connection_id_present = 1;
-               break;
-       case QUIC_TP_INITIAL_SOURCE_CONNECTION_ID:
-               if (len >= sizeof p->initial_source_connection_id.data)
-                       return 0;
-
-               if (len)
-                       memcpy(p->initial_source_connection_id.data, *buf, len);
-               p->initial_source_connection_id.len = len;
-               *buf += len;
-               p->initial_source_connection_id_present = 1;
-               break;
-       case QUIC_TP_STATELESS_RESET_TOKEN:
-               if (!server || len != sizeof p->stateless_reset_token)
-                       return 0;
-               memcpy(p->stateless_reset_token, *buf, len);
-               *buf += len;
-               p->with_stateless_reset_token = 1;
-               break;
-       case QUIC_TP_PREFERRED_ADDRESS:
-               if (!server)
-                       return 0;
-               if (!quic_transport_param_dec_pref_addr(&p->preferred_address, buf, *buf + len))
-                       return 0;
-               p->with_preferred_address = 1;
-               break;
-       case QUIC_TP_MAX_IDLE_TIMEOUT:
-               if (!quic_dec_int(&p->max_idle_timeout, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
-               if (!quic_dec_int(&p->max_udp_payload_size, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_INITIAL_MAX_DATA:
-               if (!quic_dec_int(&p->initial_max_data, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
-               if (!quic_dec_int(&p->initial_max_stream_data_bidi_local, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
-               if (!quic_dec_int(&p->initial_max_stream_data_bidi_remote, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
-               if (!quic_dec_int(&p->initial_max_stream_data_uni, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
-               if (!quic_dec_int(&p->initial_max_streams_bidi, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_INITIAL_MAX_STREAMS_UNI:
-               if (!quic_dec_int(&p->initial_max_streams_uni, buf, end))
-                       return 0;
-               break;
-       case QUIC_TP_ACK_DELAY_EXPONENT:
-               if (!quic_dec_int(&p->ack_delay_exponent, buf, end) ||
-                       p->ack_delay_exponent > QUIC_TP_ACK_DELAY_EXPONENT_LIMIT)
-                       return 0;
-               break;
-       case QUIC_TP_MAX_ACK_DELAY:
-               if (!quic_dec_int(&p->max_ack_delay, buf, end) ||
-                       p->max_ack_delay > QUIC_TP_MAX_ACK_DELAY_LIMIT)
-                       return 0;
-               break;
-       case QUIC_TP_DISABLE_ACTIVE_MIGRATION:
-               /* Zero-length parameter type. */
-               if (len != 0)
-                       return 0;
-               p->disable_active_migration = 1;
-               break;
-       case QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
-               if (!quic_dec_int(&p->active_connection_id_limit, buf, end))
-                       return 0;
-               break;
-       default:
-               *buf += len;
-       };
-
-       return *buf == end;
-}
-
-/* Encode <type> and <len> variable length values in <buf>.
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_param_encode_type_len(unsigned char **buf,
-                                                       const unsigned char *end,
-                                                       uint64_t type, uint64_t len)
-{
-       return quic_enc_int(buf, end, type) && quic_enc_int(buf, end, len);
-}
-
-/* Decode variable length type and length values of a QUIC transport parameter
- * into <type> and <len> found in <*buf> buffer.
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_param_decode_type_len(uint64_t *type, uint64_t *len,
-                                                       const unsigned char **buf,
-                                                       const unsigned char *end)
-{
-       return quic_dec_int(type, buf, end) && quic_dec_int(len, buf, end);
-}
-
-/* Encode <param> bytes stream with <type> as type and <length> as length into buf.
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_param_enc_mem(unsigned char **buf, const unsigned char *end,
-                                               uint64_t type, void *param, uint64_t length)
-{
-       if (!quic_transport_param_encode_type_len(buf, end, type, length))
-               return 0;
-
-       if (end - *buf < length)
-               return 0;
-
-       if (length)
-               memcpy(*buf, param, length);
-       *buf += length;
-
-       return 1;
-}
-
-/* Encode <val> 64-bits value as variable length integer into <buf>.
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_param_enc_int(unsigned char **buf,
-                                               const unsigned char *end,
-                                               uint64_t type, uint64_t val)
-{
-       size_t len;
-
-       len = quic_int_getsize(val);
-
-       return len && quic_transport_param_encode_type_len(buf, end, type, len) &&
-               quic_enc_int(buf, end, val);
-}
-
-/* Encode <addr> preferred address into <buf>.
- * Note that the IP addresses must be encoded in network byte order.
- * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained
- * values already encoded in network byte order.
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_param_enc_pref_addr(unsigned char **buf,
-                                                     const unsigned char *end,
-                                                     struct preferred_address *addr)
-{
-       uint64_t addr_len = 0;
-
-       addr_len += sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
-       addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
-       addr_len += sizeof_quic_cid(&addr->cid);
-       addr_len += sizeof addr->stateless_reset_token;
-
-       if (!quic_transport_param_encode_type_len(buf, end, QUIC_TP_PREFERRED_ADDRESS, addr_len))
-               return 0;
-
-       if (end - *buf < addr_len)
-               return 0;
-
-       quic_transport_param_enc_pref_addr_val(buf, end, addr);
-
-       return 1;
-}
-
-/* Encode <p> transport parameter into <buf> depending on <server> value which
- * must be set to 1 for a server (haproxy listener) or 0 for a client
- * (connection to a haproxy server).
- * Return the number of bytes consumed if succeeded, 0 if not.
- */
-static inline int quic_transport_params_encode(unsigned char *buf,
-                                               const unsigned char *end,
-                                               struct quic_transport_params *p,
-                                               int server)
-{
-       unsigned char *head;
-       unsigned char *pos;
-
-       head = pos = buf;
-       if (server) {
-               if (!quic_transport_param_enc_mem(&pos, end,
-                                                 QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID,
-                                                 p->original_destination_connection_id.data,
-                                                 p->original_destination_connection_id.len))
-                       return 0;
-
-               if (p->retry_source_connection_id.len) {
-                       if (!quic_transport_param_enc_mem(&pos, end,
-                                                         QUIC_TP_RETRY_SOURCE_CONNECTION_ID,
-                                                         p->retry_source_connection_id.data,
-                                                         p->retry_source_connection_id.len))
-                               return 0;
-               }
-
-               if (p->with_stateless_reset_token &&
-                       !quic_transport_param_enc_mem(&pos, end, QUIC_TP_STATELESS_RESET_TOKEN,
-                                                     p->stateless_reset_token,
-                                                     sizeof p->stateless_reset_token))
-                       return 0;
-               if (p->with_preferred_address &&
-                       !quic_transport_param_enc_pref_addr(&pos, end, &p->preferred_address))
-                       return 0;
-       }
-
-       if (!quic_transport_param_enc_mem(&pos, end,
-                                         QUIC_TP_INITIAL_SOURCE_CONNECTION_ID,
-                                         p->initial_source_connection_id.data,
-                                         p->initial_source_connection_id.len))
-               return 0;
-
-       if (p->max_idle_timeout &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_IDLE_TIMEOUT, p->max_idle_timeout))
-               return 0;
-
-       /*
-        * "max_packet_size" transport parameter must be transmitted only if different
-        * of the default value.
-        */
-       if (p->max_udp_payload_size != QUIC_DFLT_MAX_UDP_PAYLOAD_SIZE &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_UDP_PAYLOAD_SIZE, p->max_udp_payload_size))
-               return 0;
-
-       if (p->initial_max_data &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_DATA, p->initial_max_data))
-           return 0;
-
-       if (p->initial_max_stream_data_bidi_local &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
-                                                 p->initial_max_stream_data_bidi_local))
-           return 0;
-
-       if (p->initial_max_stream_data_bidi_remote &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
-                                                 p->initial_max_stream_data_bidi_remote))
-           return 0;
-
-       if (p->initial_max_stream_data_uni &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
-                                                 p->initial_max_stream_data_uni))
-           return 0;
-
-       if (p->initial_max_streams_bidi &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
-                                                 p->initial_max_streams_bidi))
-           return 0;
-
-       if (p->initial_max_streams_uni &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_UNI,
-                                                 p->initial_max_streams_uni))
-           return 0;
-
-       /*
-        * "ack_delay_exponent" transport parameter must be transmitted only if different
-        * of the default value.
-        */
-       if (p->ack_delay_exponent != QUIC_DFLT_ACK_DELAY_COMPONENT  &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACK_DELAY_EXPONENT, p->ack_delay_exponent))
-           return 0;
-
-       /*
-        * "max_ack_delay" transport parameter must be transmitted only if different
-        * of the default value.
-        */
-       if (p->max_ack_delay != QUIC_DFLT_MAX_ACK_DELAY &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_ACK_DELAY, p->max_ack_delay))
-           return 0;
-
-       /* 0-length value */
-       if (p->disable_active_migration &&
-           !quic_transport_param_encode_type_len(&pos, end, QUIC_TP_DISABLE_ACTIVE_MIGRATION, 0))
-               return 0;
-
-       if (p->active_connection_id_limit &&
-           p->active_connection_id_limit != QUIC_ACTIVE_CONNECTION_ID_LIMIT &&
-           !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
-                                         p->active_connection_id_limit))
-           return 0;
-
-       return pos - head;
-}
-
-/* Decode transport parameters found in <buf> buffer into <p>, depending on
- * <server> boolean value which must be set to 1 for a server (haproxy listener)
- * or 0 for a client (connection to a haproxy server).
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_params_decode(struct quic_transport_params *p, int server,
-                                               const unsigned char *buf,
-                                               const unsigned char *end)
-{
-       const unsigned char *pos;
-
-       pos = buf;
-
-       while (pos != end) {
-               uint64_t type, len;
-
-               if (!quic_transport_param_decode_type_len(&type, &len, &pos, end))
-                       return 0;
-
-               if (end - pos < len)
-                       return 0;
-
-               if (!quic_transport_param_decode(p, server, type, &pos, len))
-                       return 0;
-       }
-
-       /*
-        * A server MUST send original_destination_connection_id transport parameter.
-        * initial_source_connection_id must be present both for server and client.
-        */
-       if ((server && !p->original_destination_connection_id_present) ||
-           !p->initial_source_connection_id_present)
-               return 0;
-
-       return 1;
-}
-
-/* Store transport parameters found in <buf> buffer into <conn> QUIC connection
- * depending on <server> value which must be 1 for a server (haproxy listener)
- * or 0 for a client (connection to a haproxy server).
- * Note that peer transport parameters are stored in the TX part of the connection:
- * they are used to send packets to the peer with its transport parameters as
- * limitations.
- * Returns 1 if succeeded, 0 if not.
- */
-static inline int quic_transport_params_store(struct quic_conn *conn, int server,
-                                              const unsigned char *buf,
-                                              const unsigned char *end)
-{
-       struct quic_transport_params *tx_params = &conn->tx.params;
-       struct quic_transport_params *rx_params = &conn->rx.params;
-
-       /* initialize peer TPs to RFC default value */
-       quic_dflt_transport_params_cpy(tx_params);
-
-       if (!quic_transport_params_decode(tx_params, server, buf, end))
-               return 0;
-
-       if (tx_params->max_ack_delay)
-               conn->max_ack_delay = tx_params->max_ack_delay;
-
-       if (tx_params->max_idle_timeout && rx_params->max_idle_timeout)
-               conn->max_idle_timeout =
-                       QUIC_MIN(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
-       else
-               conn->max_idle_timeout =
-                       QUIC_MAX(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
-
-       return 1;
-}
-
 /* Initialize a QUIC packet number space.
  * Never fails.
  */
index 53039bb60d03dbd225992e1c69f3f74a44a3385e..65bb766927873b41933d12f9d49cb1611274bde4 100644 (file)
 #include <haproxy/log.h>
 #include <haproxy/protocol.h>
 #include <haproxy/proxy.h>
+#include <haproxy/quic_tp.h>
 #include <haproxy/sample.h>
 #include <haproxy/stream.h>
 #include <haproxy/task.h>
 #include <haproxy/ticks.h>
 #include <haproxy/tools.h>
-#include <haproxy/xprt_quic.h>
 
 
 /* List head of all known bind keywords */
index a904c97f7801fb80fe0f1a16e4d1b63e76b9be5c..04ed1bac679982d853c133dd631ada67dc75a2e3 100644 (file)
@@ -10,6 +10,7 @@
 #include <haproxy/ncbuf.h>
 #include <haproxy/pool.h>
 #include <haproxy/quic_stream.h>
+#include <haproxy/quic_tp-t.h>
 #include <haproxy/ssl_sock-t.h>
 #include <haproxy/stconn.h>
 #include <haproxy/trace.h>
index 3dc1d2429ecc7310016e088a501c8fb567b2a939..c10a8cf838c9eaef2ebba43fa79342e08686187b 100644 (file)
@@ -40,6 +40,7 @@
 #include <haproxy/proto_tcp.h>
 #include <haproxy/proxy.h>
 #include <haproxy/sc_strm.h>
+#include <haproxy/quic_tp.h>
 #include <haproxy/server-t.h>
 #include <haproxy/signal.h>
 #include <haproxy/stats-t.h>
@@ -49,7 +50,6 @@
 #include <haproxy/tcpcheck.h>
 #include <haproxy/time.h>
 #include <haproxy/tools.h>
-#include <haproxy/xprt_quic.h>
 
 
 int listeners; /* # of proxy listeners, set by cfgparse */
diff --git a/src/quic_tp.c b/src/quic_tp.c
new file mode 100644 (file)
index 0000000..522ff57
--- /dev/null
@@ -0,0 +1,570 @@
+#include <haproxy/global.h>
+#include <haproxy/ncbuf-t.h>
+#include <haproxy/net_helper.h>
+#include <haproxy/quic_enc.h>
+#include <haproxy/quic_tp.h>
+#include <haproxy/xprt_quic-t.h>
+
+#define QUIC_MAX_UDP_PAYLOAD_SIZE     2048
+
+/* This is the values of some QUIC transport parameters when absent.
+ * Should be used to initialize any transport parameters (local or remote)
+ * before updating them with customized values.
+ */
+struct quic_transport_params quic_dflt_transport_params = {
+       .max_udp_payload_size = QUIC_MAX_UDP_PAYLOAD_SIZE,
+       .ack_delay_exponent   = QUIC_DFLT_ACK_DELAY_COMPONENT,
+       .max_ack_delay        = QUIC_DFLT_MAX_ACK_DELAY,
+       .active_connection_id_limit = QUIC_ACTIVE_CONNECTION_ID_LIMIT,
+};
+
+/* Initialize <dst> transport parameters with default values (when absent)
+ * from <quic_dflt_transport_params>.
+ * Never fails.
+ */
+static void quic_dflt_transport_params_cpy(struct quic_transport_params *dst)
+{
+       dst->max_udp_payload_size = quic_dflt_transport_params.max_udp_payload_size;
+       dst->ack_delay_exponent   = quic_dflt_transport_params.ack_delay_exponent;
+       dst->max_ack_delay        = quic_dflt_transport_params.max_ack_delay;
+       dst->active_connection_id_limit = quic_dflt_transport_params.active_connection_id_limit;
+}
+
+/* Initialize <p> transport parameters. <server> is a boolean, set if TPs are
+ * used by a server (haproxy frontend) else this is for a client (haproxy
+ * backend).
+ *
+ * This must only be used for haproxy local parameters. To initialize peer
+ * parameters, see quic_dflt_transport_params_cpy().
+ *
+ * Never fails.
+ */
+void quic_transport_params_init(struct quic_transport_params *p, int server)
+{
+       const uint64_t ncb_size = global.tune.bufsize - NCB_RESERVED_SZ;
+       const int max_streams_bidi = 100;
+       const int max_streams_uni = 3;
+
+       /* Set RFC default values for unspecified parameters. */
+       quic_dflt_transport_params_cpy(p);
+
+       p->max_idle_timeout                    = 30000;
+
+       p->initial_max_streams_bidi            = max_streams_bidi;
+       p->initial_max_streams_uni             = max_streams_uni;
+       p->initial_max_stream_data_bidi_local  = ncb_size;
+       p->initial_max_stream_data_bidi_remote = ncb_size;
+       p->initial_max_stream_data_uni         = ncb_size;
+       p->initial_max_data = (max_streams_bidi + max_streams_uni) * ncb_size;
+
+       if (server)
+               p->with_stateless_reset_token  = 1;
+
+       p->active_connection_id_limit          = 8;
+
+       p->retry_source_connection_id.len = 0;
+}
+
+/* Encode <addr> preferred address transport parameter in <buf> without its
+ * "type+len" prefix. Note that the IP addresses must be encoded in network byte
+ * order.
+ * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained values
+ * already encoded in network byte order.
+ * It is the responsibility of the caller to check there is enough room in <buf> to encode
+ * this address.
+ * Never fails.
+ */
+static void quic_transport_param_enc_pref_addr_val(unsigned char **buf,
+                                                   const unsigned char *end,
+                                                   struct tp_preferred_address *addr)
+{
+       write_n16(*buf, addr->ipv4_port);
+       *buf += sizeof addr->ipv4_port;
+
+       memcpy(*buf, addr->ipv4_addr, sizeof addr->ipv4_addr);
+       *buf += sizeof addr->ipv4_addr;
+
+       write_n16(*buf, addr->ipv6_port);
+       *buf += sizeof addr->ipv6_port;
+
+       memcpy(*buf, addr->ipv6_addr, sizeof addr->ipv6_addr);
+       *buf += sizeof addr->ipv6_addr;
+
+       *(*buf)++ = addr->cid.len;
+       if (addr->cid.len) {
+               memcpy(*buf, addr->cid.data, addr->cid.len);
+               *buf += addr->cid.len;
+       }
+
+       memcpy(*buf, addr->stateless_reset_token, sizeof addr->stateless_reset_token);
+       *buf += sizeof addr->stateless_reset_token;
+}
+
+/* Decode into <addr> preferred address transport parameter found in <*buf> buffer.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_transport_param_dec_pref_addr(struct tp_preferred_address *addr,
+                                              const unsigned char **buf,
+                                              const unsigned char *end)
+{
+       ssize_t addr_len;
+
+       addr_len = sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
+       addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
+       addr_len += sizeof addr->cid.len;
+
+       if (end - *buf < addr_len)
+               return 0;
+
+       addr->ipv4_port = read_n16(*buf);
+       *buf += sizeof addr->ipv4_port;
+
+       memcpy(addr->ipv4_addr, *buf, sizeof addr->ipv4_addr);
+       *buf += sizeof addr->ipv4_addr;
+
+       addr->ipv6_port = read_n16(*buf);
+       *buf += sizeof addr->ipv6_port;
+
+       memcpy(addr->ipv6_addr, *buf, sizeof addr->ipv6_addr);
+       *buf += sizeof addr->ipv6_addr;
+
+       addr->cid.len = *(*buf)++;
+       if (addr->cid.len) {
+               if (end - *buf > addr->cid.len || addr->cid.len > sizeof addr->cid.data)
+                       return 0;
+               memcpy(addr->cid.data, *buf, addr->cid.len);
+               *buf += addr->cid.len;
+       }
+
+       if (end - *buf != sizeof addr->stateless_reset_token)
+               return 0;
+
+       memcpy(addr->stateless_reset_token, *buf, end - *buf);
+       *buf += sizeof addr->stateless_reset_token;
+
+       return *buf == end;
+}
+
+/* Decode into <p> struct a transport parameter found in <*buf> buffer with
+ * <type> as type and <len> as length, depending on <server> boolean value which
+ * must be set to 1 for a server (haproxy listener) or 0 for a client (connection
+ * to an haproxy server).
+ */
+static int quic_transport_param_decode(struct quic_transport_params *p,
+                                       int server, uint64_t type,
+                                       const unsigned char **buf, size_t len)
+{
+       const unsigned char *end = *buf + len;
+
+       switch (type) {
+       case QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID:
+               if (!server || len > sizeof p->original_destination_connection_id.data)
+                       return 0;
+
+               if (len)
+                       memcpy(p->original_destination_connection_id.data, *buf, len);
+               p->original_destination_connection_id.len = len;
+               *buf += len;
+               p->original_destination_connection_id_present = 1;
+               break;
+       case QUIC_TP_INITIAL_SOURCE_CONNECTION_ID:
+               if (len > sizeof p->initial_source_connection_id.data)
+                       return 0;
+
+               if (len)
+                       memcpy(p->initial_source_connection_id.data, *buf, len);
+               p->initial_source_connection_id.len = len;
+               *buf += len;
+               p->initial_source_connection_id_present = 1;
+               break;
+       case QUIC_TP_STATELESS_RESET_TOKEN:
+               if (!server || len != sizeof p->stateless_reset_token)
+                       return 0;
+               memcpy(p->stateless_reset_token, *buf, len);
+               *buf += len;
+               p->with_stateless_reset_token = 1;
+               break;
+       case QUIC_TP_PREFERRED_ADDRESS:
+               if (!server)
+                       return 0;
+               if (!quic_transport_param_dec_pref_addr(&p->preferred_address, buf, *buf + len))
+                       return 0;
+               p->with_preferred_address = 1;
+               break;
+       case QUIC_TP_MAX_IDLE_TIMEOUT:
+               if (!quic_dec_int(&p->max_idle_timeout, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
+               if (!quic_dec_int(&p->max_udp_payload_size, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_INITIAL_MAX_DATA:
+               if (!quic_dec_int(&p->initial_max_data, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
+               if (!quic_dec_int(&p->initial_max_stream_data_bidi_local, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
+               if (!quic_dec_int(&p->initial_max_stream_data_bidi_remote, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
+               if (!quic_dec_int(&p->initial_max_stream_data_uni, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
+               if (!quic_dec_int(&p->initial_max_streams_bidi, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_INITIAL_MAX_STREAMS_UNI:
+               if (!quic_dec_int(&p->initial_max_streams_uni, buf, end))
+                       return 0;
+               break;
+       case QUIC_TP_ACK_DELAY_EXPONENT:
+               if (!quic_dec_int(&p->ack_delay_exponent, buf, end) ||
+                       p->ack_delay_exponent > QUIC_TP_ACK_DELAY_EXPONENT_LIMIT)
+                       return 0;
+               break;
+       case QUIC_TP_MAX_ACK_DELAY:
+               if (!quic_dec_int(&p->max_ack_delay, buf, end) ||
+                       p->max_ack_delay > QUIC_TP_MAX_ACK_DELAY_LIMIT)
+                       return 0;
+               break;
+       case QUIC_TP_DISABLE_ACTIVE_MIGRATION:
+               /* Zero-length parameter type. */
+               if (len != 0)
+                       return 0;
+               p->disable_active_migration = 1;
+               break;
+       case QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
+               if (!quic_dec_int(&p->active_connection_id_limit, buf, end))
+                       return 0;
+               break;
+       default:
+               *buf += len;
+       };
+
+       return *buf == end;
+}
+
+/* Encode <type> and <len> variable length values in <buf>.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_transport_param_encode_type_len(unsigned char **buf,
+                                                const unsigned char *end,
+                                                uint64_t type, uint64_t len)
+{
+       return quic_enc_int(buf, end, type) && quic_enc_int(buf, end, len);
+}
+
+/* Decode variable length type and length values of a QUIC transport parameter
+ * into <type> and <len> found in <*buf> buffer.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_transport_param_decode_type_len(uint64_t *type, uint64_t *len,
+                                                const unsigned char **buf,
+                                                const unsigned char *end)
+{
+       return quic_dec_int(type, buf, end) && quic_dec_int(len, buf, end);
+}
+
+/* Encode <param> bytes stream with <type> as type and <length> as length into buf.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_transport_param_enc_mem(unsigned char **buf, const unsigned char *end,
+                                        uint64_t type, void *param, uint64_t length)
+{
+       if (!quic_transport_param_encode_type_len(buf, end, type, length))
+               return 0;
+
+       if (end - *buf < length)
+               return 0;
+
+       if (length)
+               memcpy(*buf, param, length);
+       *buf += length;
+
+       return 1;
+}
+
+/* Encode <val> 64-bits value as variable length integer into <buf>.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_transport_param_enc_int(unsigned char **buf,
+                                        const unsigned char *end,
+                                        uint64_t type, uint64_t val)
+{
+       size_t len;
+
+       len = quic_int_getsize(val);
+
+       return len && quic_transport_param_encode_type_len(buf, end, type, len) &&
+               quic_enc_int(buf, end, val);
+}
+
+/* Returns the required length in bytes to encode <cid> QUIC connection ID. */
+static inline size_t sizeof_quic_cid(const struct tp_cid *cid)
+{
+       return sizeof cid->len + cid->len;
+}
+
+/* Encode <addr> preferred address into <buf>.
+ * Note that the IP addresses must be encoded in network byte order.
+ * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained
+ * values already encoded in network byte order.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_transport_param_enc_pref_addr(unsigned char **buf,
+                                              const unsigned char *end,
+                                              struct tp_preferred_address *addr)
+{
+       uint64_t addr_len = 0;
+
+       addr_len += sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
+       addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
+       addr_len += sizeof_quic_cid(&addr->cid);
+       addr_len += sizeof addr->stateless_reset_token;
+
+       if (!quic_transport_param_encode_type_len(buf, end, QUIC_TP_PREFERRED_ADDRESS, addr_len))
+               return 0;
+
+       if (end - *buf < addr_len)
+               return 0;
+
+       quic_transport_param_enc_pref_addr_val(buf, end, addr);
+
+       return 1;
+}
+
+/* Encode <p> transport parameter into <buf> depending on <server> value which
+ * must be set to 1 for a server (haproxy listener) or 0 for a client
+ * (connection to a haproxy server).
+ * Return the number of bytes consumed if succeeded, 0 if not.
+ */
+int quic_transport_params_encode(unsigned char *buf,
+                                 const unsigned char *end,
+                                 struct quic_transport_params *p,
+                                 int server)
+{
+       unsigned char *head;
+       unsigned char *pos;
+
+       head = pos = buf;
+       if (server) {
+               if (!quic_transport_param_enc_mem(&pos, end,
+                                                 QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID,
+                                                 p->original_destination_connection_id.data,
+                                                 p->original_destination_connection_id.len))
+                       return 0;
+
+               if (p->retry_source_connection_id.len) {
+                       if (!quic_transport_param_enc_mem(&pos, end,
+                                                         QUIC_TP_RETRY_SOURCE_CONNECTION_ID,
+                                                         p->retry_source_connection_id.data,
+                                                         p->retry_source_connection_id.len))
+                               return 0;
+               }
+
+               if (p->with_stateless_reset_token &&
+                       !quic_transport_param_enc_mem(&pos, end, QUIC_TP_STATELESS_RESET_TOKEN,
+                                                     p->stateless_reset_token,
+                                                     sizeof p->stateless_reset_token))
+                       return 0;
+               if (p->with_preferred_address &&
+                       !quic_transport_param_enc_pref_addr(&pos, end, &p->preferred_address))
+                       return 0;
+       }
+
+       if (!quic_transport_param_enc_mem(&pos, end,
+                                         QUIC_TP_INITIAL_SOURCE_CONNECTION_ID,
+                                         p->initial_source_connection_id.data,
+                                         p->initial_source_connection_id.len))
+               return 0;
+
+       if (p->max_idle_timeout &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_IDLE_TIMEOUT, p->max_idle_timeout))
+               return 0;
+
+       /*
+        * "max_packet_size" transport parameter must be transmitted only if different
+        * of the default value.
+        */
+       if (p->max_udp_payload_size != QUIC_DFLT_MAX_UDP_PAYLOAD_SIZE &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_UDP_PAYLOAD_SIZE, p->max_udp_payload_size))
+               return 0;
+
+       if (p->initial_max_data &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_DATA, p->initial_max_data))
+           return 0;
+
+       if (p->initial_max_stream_data_bidi_local &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
+                                                 p->initial_max_stream_data_bidi_local))
+           return 0;
+
+       if (p->initial_max_stream_data_bidi_remote &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
+                                                 p->initial_max_stream_data_bidi_remote))
+           return 0;
+
+       if (p->initial_max_stream_data_uni &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
+                                                 p->initial_max_stream_data_uni))
+           return 0;
+
+       if (p->initial_max_streams_bidi &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
+                                                 p->initial_max_streams_bidi))
+           return 0;
+
+       if (p->initial_max_streams_uni &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_UNI,
+                                                 p->initial_max_streams_uni))
+           return 0;
+
+       /*
+        * "ack_delay_exponent" transport parameter must be transmitted only if different
+        * of the default value.
+        */
+       if (p->ack_delay_exponent != QUIC_DFLT_ACK_DELAY_COMPONENT  &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACK_DELAY_EXPONENT, p->ack_delay_exponent))
+           return 0;
+
+       /*
+        * "max_ack_delay" transport parameter must be transmitted only if different
+        * of the default value.
+        */
+       if (p->max_ack_delay != QUIC_DFLT_MAX_ACK_DELAY &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_ACK_DELAY, p->max_ack_delay))
+           return 0;
+
+       /* 0-length value */
+       if (p->disable_active_migration &&
+           !quic_transport_param_encode_type_len(&pos, end, QUIC_TP_DISABLE_ACTIVE_MIGRATION, 0))
+               return 0;
+
+       if (p->active_connection_id_limit &&
+           p->active_connection_id_limit != QUIC_ACTIVE_CONNECTION_ID_LIMIT &&
+           !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
+                                         p->active_connection_id_limit))
+           return 0;
+
+       return pos - head;
+}
+
+/* Decode transport parameters found in <buf> buffer into <p>, depending on
+ * <server> boolean value which must be set to 1 for a server (haproxy listener)
+ * or 0 for a client (connection to a haproxy server).
+ * Returns 1 if succeeded, 0 if not.
+ */
+static int quic_transport_params_decode(struct quic_transport_params *p, int server,
+                                        const unsigned char *buf,
+                                        const unsigned char *end)
+{
+       const unsigned char *pos;
+
+       pos = buf;
+
+       while (pos != end) {
+               uint64_t type, len;
+
+               if (!quic_transport_param_decode_type_len(&type, &len, &pos, end))
+                       return 0;
+
+               if (end - pos < len)
+                       return 0;
+
+               if (!quic_transport_param_decode(p, server, type, &pos, len))
+                       return 0;
+       }
+
+       /*
+        * A server MUST send original_destination_connection_id transport parameter.
+        * initial_source_connection_id must be present both for server and client.
+        */
+       if ((server && !p->original_destination_connection_id_present) ||
+           !p->initial_source_connection_id_present)
+               return 0;
+
+       return 1;
+}
+
+/* Store transport parameters found in <buf> buffer into <qc> QUIC connection
+ * depending on <server> value which must be 1 for a server (haproxy listener)
+ * or 0 for a client (connection to a haproxy server).
+ * Note that peer transport parameters are stored in the TX part of the connection:
+ * they are used to send packets to the peer with its transport parameters as
+ * limitations.
+ * Returns 1 if succeeded, 0 if not.
+ */
+int quic_transport_params_store(struct quic_conn *qc, int server,
+                                const unsigned char *buf,
+                                const unsigned char *end)
+{
+       struct quic_transport_params *tx_params = &qc->tx.params;
+       struct quic_transport_params *rx_params = &qc->rx.params;
+
+       /* initialize peer TPs to RFC default value */
+       quic_dflt_transport_params_cpy(tx_params);
+
+       if (!quic_transport_params_decode(tx_params, server, buf, end))
+               return 0;
+
+       if (tx_params->max_ack_delay)
+               qc->max_ack_delay = tx_params->max_ack_delay;
+
+       if (tx_params->max_idle_timeout && rx_params->max_idle_timeout)
+               qc->max_idle_timeout =
+                       QUIC_MIN(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
+       else
+               qc->max_idle_timeout =
+                       QUIC_MAX(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
+
+       return 1;
+}
+
+/* QUIC server (or haproxy listener) only function.
+ * Initialize the local transport parameters <rx_params> from <listener_params>
+ * coming from configuration and Initial packet information (destintation
+ * connection ID, source connection ID, original destination connection ID,
+ * and if a token was present denoted by <token> boolean value.
+ * Returns 1 if succeeded, 0 if not.
+ */
+int qc_lstnr_params_init(struct quic_conn *qc,
+                         const struct quic_transport_params *listener_params,
+                         const unsigned char *stateless_reset_token,
+                         const unsigned char *dcid, size_t dcidlen,
+                         const unsigned char *scid, size_t scidlen,
+                         const unsigned char *odcid, size_t odcidlen, int token)
+{
+       struct quic_transport_params *rx_params = &qc->rx.params;
+       struct tp_cid *odcid_param = &rx_params->original_destination_connection_id;
+
+       /* Copy the transport parameters. */
+       *rx_params = *listener_params;
+       /* Copy the stateless reset token */
+       memcpy(rx_params->stateless_reset_token, stateless_reset_token,
+              sizeof rx_params->stateless_reset_token);
+       /* Copy original_destination_connection_id transport parameter. */
+       if (token) {
+               memcpy(odcid_param->data, odcid, odcidlen);
+               odcid_param->len = odcidlen;
+               /* Copy retry_source_connection_id transport parameter. */
+               memcpy(rx_params->retry_source_connection_id.data, dcid, dcidlen);
+               rx_params->retry_source_connection_id.len = dcidlen;
+       }
+       else {
+               memcpy(odcid_param->data, dcid, dcidlen);
+               odcid_param->len = dcidlen;
+       }
+
+       /* Copy the initial source connection ID. */
+       memcpy(rx_params->initial_source_connection_id.data, scid, scidlen);
+       rx_params->initial_source_connection_id.len = scidlen;
+
+       return 1;
+}
+
index 83204c169409edff5fcc65e10e280936df717c90..db255fa9e1e136176e62706de053dac2ca829352 100644 (file)
@@ -65,6 +65,7 @@
 #include <haproxy/proxy.h>
 #include <haproxy/sample.h>
 #include <haproxy/sc_strm.h>
+#include <haproxy/quic_tp.h>
 #include <haproxy/server.h>
 #include <haproxy/shctx.h>
 #include <haproxy/ssl_ckch.h>
index 6e75501cbcb45421f814ff25158609e47d56bd50..502db44af63b9747b6b21629853d8980147d3e97 100644 (file)
@@ -47,6 +47,7 @@
 #include <haproxy/quic_sock.h>
 #include <haproxy/quic_stats-t.h>
 #include <haproxy/quic_stream.h>
+#include <haproxy/quic_tp.h>
 #include <haproxy/cbuf.h>
 #include <haproxy/proto_quic.h>
 #include <haproxy/quic_tls.h>
@@ -64,17 +65,6 @@ static int quic_supported_version[] = {
        0x0
 };
 
-/* This is the values of some QUIC transport parameters when absent.
- * Should be used to initialize any transport parameters (local or remote)
- * before updating them with customized values.
- */
-struct quic_transport_params quic_dflt_transport_params = {
-       .max_udp_payload_size = QUIC_PACKET_MAXLEN,
-       .ack_delay_exponent   = QUIC_DFLT_ACK_DELAY_COMPONENT,
-       .max_ack_delay        = QUIC_DFLT_MAX_ACK_DELAY,
-       .active_connection_id_limit = QUIC_ACTIVE_CONNECTION_ID_LIMIT,
-};
-
 /* trace source and events */
 static void quic_trace(enum trace_level level, uint64_t mask, \
                        const struct trace_source *src,
@@ -4223,40 +4213,6 @@ static int parse_retry_token(const unsigned char *token, const unsigned char *en
        return 0;
 }
 
-/* Initialize the transport parameters for <qc> QUIC connection attached
- * to <l> listener from <pkt> Initial packet information.
- * Returns 1 if succeeded, 0 if not.
- */
-static int qc_lstnr_params_init(struct quic_conn *qc, struct listener *l,
-                                const unsigned char *token, size_t token_len,
-                                const struct quic_connection_id *icid,
-                                const struct quic_cid *dcid, const struct quic_cid *odcid)
-{
-       struct quic_cid *odcid_param = &qc->rx.params.original_destination_connection_id;
-
-       /* Copy the transport parameters. */
-       qc->rx.params = l->bind_conf->quic_params;
-       /* Copy the stateless reset token */
-       memcpy(qc->rx.params.stateless_reset_token, icid->stateless_reset_token,
-              sizeof qc->rx.params.stateless_reset_token);
-       /* Copy original_destination_connection_id transport parameter. */
-       if (token_len) {
-               memcpy(odcid_param->data, odcid->data, odcid->len);
-               odcid_param->len = odcid->len;
-               /* Copy retry_source_connection_id transport parameter. */
-               quic_cid_cpy(&qc->rx.params.retry_source_connection_id, dcid);
-       }
-       else {
-               memcpy(odcid_param->data, dcid->data, dcid->len);
-               odcid_param->len = dcid->len;
-       }
-
-       /* Copy the initial source connection ID. */
-       quic_cid_cpy(&qc->rx.params.initial_source_connection_id, &qc->scid);
-
-       return 1;
-}
-
 /* 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).
@@ -4269,8 +4225,7 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
                                      struct quic_cid *dcid, struct quic_cid *scid,
                                      const struct quic_cid *odcid,
                                      struct sockaddr_storage *saddr,
-                                     const unsigned char *token, size_t token_len,
-                                     int server, void *owner)
+                                     int server, int token, void *owner)
 {
        int i;
        struct quic_conn *qc;
@@ -4389,7 +4344,11 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
        qc->sendto_err = 0;
        memcpy(&qc->peer_addr, saddr, sizeof qc->peer_addr);
 
-       if (server && !qc_lstnr_params_init(qc, l, token, token_len, icid, dcid, odcid))
+       if (server && !qc_lstnr_params_init(qc, &l->bind_conf->quic_params,
+                                           icid->stateless_reset_token,
+                                           dcid->data, dcid->len,
+                                           qc->scid.data, qc->scid.len,
+                                           odcid->data, odcid->len, token))
                goto err;
 
        qc->enc_params_len =
@@ -5376,8 +5335,8 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end,
 
                        pkt->saddr = dgram->saddr;
                        ipv4 = dgram->saddr.ss_family == AF_INET;
-                       qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, &odcid, &pkt->saddr,
-                                        pkt->token, pkt->token_len, 1, l);
+                       qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, &odcid,
+                                        &pkt->saddr, 1, !!pkt->token_len, l);
                        if (qc == NULL)
                                goto drop;