From: Frédéric Lécaille Date: Sat, 21 May 2022 21:58:40 +0000 (+0200) Subject: MINOR: quic: QUIC transport parameters split. X-Git-Tag: v2.6.0~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=748ece68b89d8ffd4a4ad4421e9b1f377697029b;p=thirdparty%2Fhaproxy.git MINOR: quic: QUIC transport parameters split. 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 to use the trace API into this module. --- diff --git a/Makefile b/Makefile index fb57ef8aef..59b383cff7 100644 --- 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 index 0000000000..36dd376518 --- /dev/null +++ b/include/haproxy/quic_tp-t.h @@ -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 + +#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 index 0000000000..92ec9fedd0 --- /dev/null +++ b/include/haproxy/quic_tp.h @@ -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 +#include + +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 */ diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h index bb7569f525..b9c728c6f3 100644 --- a/include/haproxy/xprt_quic-t.h +++ b/include/haproxy/xprt_quic-t.h @@ -35,8 +35,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -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 */ diff --git a/include/haproxy/xprt_quic.h b/include/haproxy/xprt_quic.h index fa13c4cfae..7e3bb35daa 100644 --- a/include/haproxy/xprt_quic.h +++ b/include/haproxy/xprt_quic.h @@ -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 QUIC connection ID. */ -static inline size_t sizeof_quic_cid(const struct quic_cid *cid) -{ - return sizeof cid->len + cid->len; -} - /* Copy QUIC CID to . * This is the responsibility of the caller to check there is enough room in * to copy . @@ -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 transport parameters with default values (when absent) - * from . - * 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

transport parameters. 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 preferred address transport parameter in 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 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 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

struct a transport parameter found in <*buf> buffer with - * as type and as length, depending on 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 and variable length values in . - * 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 and 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 bytes stream with as type and 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 64-bits value as variable length integer into . - * 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 preferred address into . - * 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

transport parameter into depending on 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 buffer into

, depending on - * 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 buffer into QUIC connection - * depending on 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. */ diff --git a/src/listener.c b/src/listener.c index 53039bb60d..65bb766927 100644 --- a/src/listener.c +++ b/src/listener.c @@ -31,12 +31,12 @@ #include #include #include +#include #include #include #include #include #include -#include /* List head of all known bind keywords */ diff --git a/src/mux_quic.c b/src/mux_quic.c index a904c97f78..04ed1bac67 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/src/proxy.c b/src/proxy.c index 3dc1d2429e..c10a8cf838 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include int listeners; /* # of proxy listeners, set by cfgparse */ diff --git a/src/quic_tp.c b/src/quic_tp.c new file mode 100644 index 0000000000..522ff576e7 --- /dev/null +++ b/src/quic_tp.c @@ -0,0 +1,570 @@ +#include +#include +#include +#include +#include +#include + +#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 transport parameters with default values (when absent) + * from . + * 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

transport parameters. 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 preferred address transport parameter in 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 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 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

struct a transport parameter found in <*buf> buffer with + * as type and as length, depending on 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 and variable length values in . + * 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 and 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 bytes stream with as type and 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 64-bits value as variable length integer into . + * 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 QUIC connection ID. */ +static inline size_t sizeof_quic_cid(const struct tp_cid *cid) +{ + return sizeof cid->len + cid->len; +} + +/* Encode preferred address into . + * 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

transport parameter into depending on 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 buffer into

, depending on + * 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 buffer into QUIC connection + * depending on 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 from + * 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 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; +} + diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 83204c1694..db255fa9e1 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 6e75501cbc..502db44af6 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -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 QUIC connection attached - * to listener from 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 as QUIC version. * boolean is set to 1 for IPv4 connection, 0 for IPv6. 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;