mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-10 00:57:02 +02:00
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 <xprt_quic-t.h> to use the trace API into this module.
This commit is contained in:
parent
57ac3faed7
commit
748ece68b8
2
Makefile
2
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/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/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/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
|
endif
|
||||||
|
|
||||||
ifneq ($(USE_LUA),)
|
ifneq ($(USE_LUA),)
|
||||||
|
103
include/haproxy/quic_tp-t.h
Normal file
103
include/haproxy/quic_tp-t.h
Normal file
@ -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 */
|
28
include/haproxy/quic_tp.h
Normal file
28
include/haproxy/quic_tp.h
Normal file
@ -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 */
|
@ -35,8 +35,9 @@
|
|||||||
#include <haproxy/mux_quic-t.h>
|
#include <haproxy/mux_quic-t.h>
|
||||||
#include <haproxy/quic_cc-t.h>
|
#include <haproxy/quic_cc-t.h>
|
||||||
#include <haproxy/quic_frame-t.h>
|
#include <haproxy/quic_frame-t.h>
|
||||||
#include <haproxy/quic_tls-t.h>
|
|
||||||
#include <haproxy/quic_loss-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 <haproxy/task.h>
|
||||||
|
|
||||||
#include <import/ebtree-t.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_IPV4_MTU 1252 /* (bytes) */
|
||||||
#define QUIC_INITIAL_IPV6_MTU 1232
|
#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. */
|
/* The minimum length of Initial packets. */
|
||||||
#define QUIC_INITIAL_PACKET_MINLEN 1200
|
#define QUIC_INITIAL_PACKET_MINLEN 1200
|
||||||
@ -194,7 +192,6 @@ enum quic_pkt_type {
|
|||||||
*/
|
*/
|
||||||
#define QUIC_CONN_MAX_PACKET 64
|
#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_HEADER_LEN 5
|
||||||
#define QUIC_STATELESS_RESET_PACKET_MINLEN (22 + QUIC_HAP_CID_LEN)
|
#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 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. */
|
/* Structure to hold a range of ACKs sent in ACK frames. */
|
||||||
struct quic_arng {
|
struct quic_arng {
|
||||||
int64_t first;
|
int64_t first;
|
||||||
@ -467,9 +382,6 @@ struct quic_dgram {
|
|||||||
/* The QUIC packet numbers are 62-bits integers */
|
/* The QUIC packet numbers are 62-bits integers */
|
||||||
#define QUIC_MAX_PACKET_NUM ((1ULL << 62) - 1)
|
#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
|
/* Maximum number of ack-eliciting received packets since the last
|
||||||
* ACK frame was sent
|
* ACK frame was sent
|
||||||
*/
|
*/
|
||||||
|
@ -57,12 +57,6 @@ static inline int qc_is_listener(struct quic_conn *qc)
|
|||||||
return qc->flags & QUIC_FL_CONN_LISTENER;
|
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>.
|
/* Copy <src> QUIC CID to <dst>.
|
||||||
* This is the responsibility of the caller to check there is enough room in
|
* This is the responsibility of the caller to check there is enough room in
|
||||||
* <dst> to copy <src>.
|
* <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;
|
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.
|
/* Initialize a QUIC packet number space.
|
||||||
* Never fails.
|
* Never fails.
|
||||||
*/
|
*/
|
||||||
|
@ -31,12 +31,12 @@
|
|||||||
#include <haproxy/log.h>
|
#include <haproxy/log.h>
|
||||||
#include <haproxy/protocol.h>
|
#include <haproxy/protocol.h>
|
||||||
#include <haproxy/proxy.h>
|
#include <haproxy/proxy.h>
|
||||||
|
#include <haproxy/quic_tp.h>
|
||||||
#include <haproxy/sample.h>
|
#include <haproxy/sample.h>
|
||||||
#include <haproxy/stream.h>
|
#include <haproxy/stream.h>
|
||||||
#include <haproxy/task.h>
|
#include <haproxy/task.h>
|
||||||
#include <haproxy/ticks.h>
|
#include <haproxy/ticks.h>
|
||||||
#include <haproxy/tools.h>
|
#include <haproxy/tools.h>
|
||||||
#include <haproxy/xprt_quic.h>
|
|
||||||
|
|
||||||
|
|
||||||
/* List head of all known bind keywords */
|
/* List head of all known bind keywords */
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <haproxy/ncbuf.h>
|
#include <haproxy/ncbuf.h>
|
||||||
#include <haproxy/pool.h>
|
#include <haproxy/pool.h>
|
||||||
#include <haproxy/quic_stream.h>
|
#include <haproxy/quic_stream.h>
|
||||||
|
#include <haproxy/quic_tp-t.h>
|
||||||
#include <haproxy/ssl_sock-t.h>
|
#include <haproxy/ssl_sock-t.h>
|
||||||
#include <haproxy/stconn.h>
|
#include <haproxy/stconn.h>
|
||||||
#include <haproxy/trace.h>
|
#include <haproxy/trace.h>
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <haproxy/proto_tcp.h>
|
#include <haproxy/proto_tcp.h>
|
||||||
#include <haproxy/proxy.h>
|
#include <haproxy/proxy.h>
|
||||||
#include <haproxy/sc_strm.h>
|
#include <haproxy/sc_strm.h>
|
||||||
|
#include <haproxy/quic_tp.h>
|
||||||
#include <haproxy/server-t.h>
|
#include <haproxy/server-t.h>
|
||||||
#include <haproxy/signal.h>
|
#include <haproxy/signal.h>
|
||||||
#include <haproxy/stats-t.h>
|
#include <haproxy/stats-t.h>
|
||||||
@ -49,7 +50,6 @@
|
|||||||
#include <haproxy/tcpcheck.h>
|
#include <haproxy/tcpcheck.h>
|
||||||
#include <haproxy/time.h>
|
#include <haproxy/time.h>
|
||||||
#include <haproxy/tools.h>
|
#include <haproxy/tools.h>
|
||||||
#include <haproxy/xprt_quic.h>
|
|
||||||
|
|
||||||
|
|
||||||
int listeners; /* # of proxy listeners, set by cfgparse */
|
int listeners; /* # of proxy listeners, set by cfgparse */
|
||||||
|
570
src/quic_tp.c
Normal file
570
src/quic_tp.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -65,6 +65,7 @@
|
|||||||
#include <haproxy/proxy.h>
|
#include <haproxy/proxy.h>
|
||||||
#include <haproxy/sample.h>
|
#include <haproxy/sample.h>
|
||||||
#include <haproxy/sc_strm.h>
|
#include <haproxy/sc_strm.h>
|
||||||
|
#include <haproxy/quic_tp.h>
|
||||||
#include <haproxy/server.h>
|
#include <haproxy/server.h>
|
||||||
#include <haproxy/shctx.h>
|
#include <haproxy/shctx.h>
|
||||||
#include <haproxy/ssl_ckch.h>
|
#include <haproxy/ssl_ckch.h>
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include <haproxy/quic_sock.h>
|
#include <haproxy/quic_sock.h>
|
||||||
#include <haproxy/quic_stats-t.h>
|
#include <haproxy/quic_stats-t.h>
|
||||||
#include <haproxy/quic_stream.h>
|
#include <haproxy/quic_stream.h>
|
||||||
|
#include <haproxy/quic_tp.h>
|
||||||
#include <haproxy/cbuf.h>
|
#include <haproxy/cbuf.h>
|
||||||
#include <haproxy/proto_quic.h>
|
#include <haproxy/proto_quic.h>
|
||||||
#include <haproxy/quic_tls.h>
|
#include <haproxy/quic_tls.h>
|
||||||
@ -64,17 +65,6 @@ static int quic_supported_version[] = {
|
|||||||
0x0
|
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 */
|
/* trace source and events */
|
||||||
static void quic_trace(enum trace_level level, uint64_t mask, \
|
static void quic_trace(enum trace_level level, uint64_t mask, \
|
||||||
const struct trace_source *src,
|
const struct trace_source *src,
|
||||||
@ -4223,40 +4213,6 @@ static int parse_retry_token(const unsigned char *token, const unsigned char *en
|
|||||||
return 0;
|
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>
|
/* 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
|
* boolean is set to 1 for IPv4 connection, 0 for IPv6. <server> is set to 1
|
||||||
* for QUIC servers (or haproxy listeners).
|
* 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,
|
struct quic_cid *dcid, struct quic_cid *scid,
|
||||||
const struct quic_cid *odcid,
|
const struct quic_cid *odcid,
|
||||||
struct sockaddr_storage *saddr,
|
struct sockaddr_storage *saddr,
|
||||||
const unsigned char *token, size_t token_len,
|
int server, int token, void *owner)
|
||||||
int server, void *owner)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct quic_conn *qc;
|
struct quic_conn *qc;
|
||||||
@ -4389,7 +4344,11 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
|
|||||||
qc->sendto_err = 0;
|
qc->sendto_err = 0;
|
||||||
memcpy(&qc->peer_addr, saddr, sizeof qc->peer_addr);
|
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;
|
goto err;
|
||||||
|
|
||||||
qc->enc_params_len =
|
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;
|
pkt->saddr = dgram->saddr;
|
||||||
ipv4 = dgram->saddr.ss_family == AF_INET;
|
ipv4 = dgram->saddr.ss_family == AF_INET;
|
||||||
qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, &odcid, &pkt->saddr,
|
qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, &odcid,
|
||||||
pkt->token, pkt->token_len, 1, l);
|
&pkt->saddr, 1, !!pkt->token_len, l);
|
||||||
if (qc == NULL)
|
if (qc == NULL)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user