blob: ae013613aad08af2e6dba309d32e08b0ca59f9f1 [file] [log] [blame]
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +02001#include <arpa/inet.h>
2#include <string.h>
3
Frédéric Lécaille748ece62022-05-21 23:58:40 +02004#include <haproxy/global.h>
5#include <haproxy/ncbuf-t.h>
6#include <haproxy/net_helper.h>
Frédéric Lécaille0aa79952023-02-03 16:15:08 +01007#include <haproxy/quic_conn.h>
Frédéric Lécaille748ece62022-05-21 23:58:40 +02008#include <haproxy/quic_enc.h>
9#include <haproxy/quic_tp.h>
Frédéric Lécaillec7785b52022-05-23 09:08:54 +020010#include <haproxy/trace.h>
Frédéric Lécaille748ece62022-05-21 23:58:40 +020011
12#define QUIC_MAX_UDP_PAYLOAD_SIZE 2048
13
Frédéric Lécaillec7785b52022-05-23 09:08:54 +020014#define TRACE_SOURCE &trace_quic
15
Frédéric Lécaille748ece62022-05-21 23:58:40 +020016/* This is the values of some QUIC transport parameters when absent.
17 * Should be used to initialize any transport parameters (local or remote)
18 * before updating them with customized values.
19 */
20struct quic_transport_params quic_dflt_transport_params = {
Frédéric Lécailleaee67572022-05-23 18:29:39 +020021 .max_udp_payload_size = QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE,
22 .ack_delay_exponent = QUIC_TP_DFLT_ACK_DELAY_COMPONENT,
23 .max_ack_delay = QUIC_TP_DFLT_MAX_ACK_DELAY,
24 .active_connection_id_limit = QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT,
Frédéric Lécaille748ece62022-05-21 23:58:40 +020025};
26
27/* Initialize <dst> transport parameters with default values (when absent)
28 * from <quic_dflt_transport_params>.
29 * Never fails.
30 */
31static void quic_dflt_transport_params_cpy(struct quic_transport_params *dst)
32{
33 dst->max_udp_payload_size = quic_dflt_transport_params.max_udp_payload_size;
34 dst->ack_delay_exponent = quic_dflt_transport_params.ack_delay_exponent;
35 dst->max_ack_delay = quic_dflt_transport_params.max_ack_delay;
36 dst->active_connection_id_limit = quic_dflt_transport_params.active_connection_id_limit;
37}
38
39/* Initialize <p> transport parameters. <server> is a boolean, set if TPs are
40 * used by a server (haproxy frontend) else this is for a client (haproxy
41 * backend).
42 *
43 * This must only be used for haproxy local parameters. To initialize peer
44 * parameters, see quic_dflt_transport_params_cpy().
45 *
46 * Never fails.
47 */
48void quic_transport_params_init(struct quic_transport_params *p, int server)
49{
50 const uint64_t ncb_size = global.tune.bufsize - NCB_RESERVED_SZ;
Frédéric Lécaille26740982022-05-23 17:28:01 +020051 const int max_streams_bidi = global.tune.quic_frontend_max_streams_bidi;
Frédéric Lécaille748ece62022-05-21 23:58:40 +020052 const int max_streams_uni = 3;
53
54 /* Set RFC default values for unspecified parameters. */
55 quic_dflt_transport_params_cpy(p);
56
Frédéric Lécailleaee67572022-05-23 18:29:39 +020057 /* Set the max_udp_payload_size value. If not would equal to
58 * QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE
59 */
60 p->max_udp_payload_size = QUIC_MAX_UDP_PAYLOAD_SIZE;
Frédéric Lécaille1d96d6e2022-05-23 16:38:14 +020061 if (server)
62 p->max_idle_timeout = global.tune.quic_frontend_max_idle_timeout;
63 else
64 p->max_idle_timeout = global.tune.quic_backend_max_idle_timeout;
Frédéric Lécaille748ece62022-05-21 23:58:40 +020065
66 p->initial_max_streams_bidi = max_streams_bidi;
67 p->initial_max_streams_uni = max_streams_uni;
68 p->initial_max_stream_data_bidi_local = ncb_size;
69 p->initial_max_stream_data_bidi_remote = ncb_size;
70 p->initial_max_stream_data_uni = ncb_size;
71 p->initial_max_data = (max_streams_bidi + max_streams_uni) * ncb_size;
72
Frédéric Lécaille6fc86972023-01-12 08:29:23 +010073 if (server) {
Frédéric Lécaille748ece62022-05-21 23:58:40 +020074 p->with_stateless_reset_token = 1;
Frédéric Lécaille6fc86972023-01-12 08:29:23 +010075 p->disable_active_migration = 1;
76 }
Frédéric Lécaille748ece62022-05-21 23:58:40 +020077
78 p->active_connection_id_limit = 8;
79
80 p->retry_source_connection_id.len = 0;
81}
82
83/* Encode <addr> preferred address transport parameter in <buf> without its
84 * "type+len" prefix. Note that the IP addresses must be encoded in network byte
85 * order.
86 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained values
87 * already encoded in network byte order.
88 * It is the responsibility of the caller to check there is enough room in <buf> to encode
89 * this address.
90 * Never fails.
91 */
92static void quic_transport_param_enc_pref_addr_val(unsigned char **buf,
93 const unsigned char *end,
94 struct tp_preferred_address *addr)
95{
96 write_n16(*buf, addr->ipv4_port);
97 *buf += sizeof addr->ipv4_port;
98
99 memcpy(*buf, addr->ipv4_addr, sizeof addr->ipv4_addr);
100 *buf += sizeof addr->ipv4_addr;
101
102 write_n16(*buf, addr->ipv6_port);
103 *buf += sizeof addr->ipv6_port;
104
105 memcpy(*buf, addr->ipv6_addr, sizeof addr->ipv6_addr);
106 *buf += sizeof addr->ipv6_addr;
107
108 *(*buf)++ = addr->cid.len;
109 if (addr->cid.len) {
110 memcpy(*buf, addr->cid.data, addr->cid.len);
111 *buf += addr->cid.len;
112 }
113
114 memcpy(*buf, addr->stateless_reset_token, sizeof addr->stateless_reset_token);
115 *buf += sizeof addr->stateless_reset_token;
116}
117
118/* Decode into <addr> preferred address transport parameter found in <*buf> buffer.
119 * Returns 1 if succeeded, 0 if not.
120 */
121static int quic_transport_param_dec_pref_addr(struct tp_preferred_address *addr,
122 const unsigned char **buf,
123 const unsigned char *end)
124{
125 ssize_t addr_len;
126
127 addr_len = sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
128 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
129 addr_len += sizeof addr->cid.len;
130
131 if (end - *buf < addr_len)
132 return 0;
133
134 addr->ipv4_port = read_n16(*buf);
135 *buf += sizeof addr->ipv4_port;
136
137 memcpy(addr->ipv4_addr, *buf, sizeof addr->ipv4_addr);
138 *buf += sizeof addr->ipv4_addr;
139
140 addr->ipv6_port = read_n16(*buf);
141 *buf += sizeof addr->ipv6_port;
142
143 memcpy(addr->ipv6_addr, *buf, sizeof addr->ipv6_addr);
144 *buf += sizeof addr->ipv6_addr;
145
146 addr->cid.len = *(*buf)++;
147 if (addr->cid.len) {
148 if (end - *buf > addr->cid.len || addr->cid.len > sizeof addr->cid.data)
149 return 0;
150 memcpy(addr->cid.data, *buf, addr->cid.len);
151 *buf += addr->cid.len;
152 }
153
154 if (end - *buf != sizeof addr->stateless_reset_token)
155 return 0;
156
157 memcpy(addr->stateless_reset_token, *buf, end - *buf);
158 *buf += sizeof addr->stateless_reset_token;
159
160 return *buf == end;
161}
162
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200163/* Decode into <v> version information received transport parameters from <*buf>
164 * buffer. <server> must be set to 1 for QUIC clients which receive server
165 * transport parameters, and 0 for QUIC servers which receive client transport
166 * parameters.
167 * Also set the QUIC negotiated version into <tp>.
168 * Return 1 if succeeded, 0 if not.
169 */
170static int quic_transport_param_dec_version_info(struct tp_version_information *tp,
171 const unsigned char **buf,
172 const unsigned char *end, int server)
173{
174 size_t tp_len = end - *buf;
175 const uint32_t *ver;
176
177 /* <tp_len> must be a multiple of sizeof(uint32_t) */
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500178 if (tp_len < sizeof tp->chosen || (tp_len & 0x3))
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200179 return 0;
180
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500181 tp->chosen = ntohl(*(uint32_t *)*buf);
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200182 /* Must not be null */
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500183 if (!tp->chosen)
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200184 return 0;
185
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500186 *buf += sizeof tp->chosen;
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200187 tp->others = (const uint32_t *)*buf;
188
189 /* Others versions must not be null */
190 for (ver = tp->others; ver < (const uint32_t *)end; ver++) {
191 if (!*ver)
192 return 0;
193 }
194
195 if (server)
196 /* TODO: not supported */
197 return 0;
198
Frédéric Lécaille4f5777a2022-06-20 19:39:26 +0200199 tp->nb_others = (end - (const unsigned char *)tp->others) / sizeof *tp->others;
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200200 for (ver = tp->others; ver < (const uint32_t *)end; ver++) {
201 if (!tp->negotiated_version) {
202 int i;
203
204 for (i = 0; i < quic_versions_nb; i++) {
205 if (ntohl(*ver) == quic_versions[i].num) {
206 tp->negotiated_version = &quic_versions[i];
207 break;
208 }
209 }
210 }
211
212 if (preferred_version && ntohl(*ver) == preferred_version->num) {
213 tp->negotiated_version = preferred_version;
214 goto out;
215 }
216 }
217
218 out:
219 *buf = end;
220
221 return 1;
222}
223
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200224/* Decode into <p> struct a transport parameter found in <*buf> buffer with
225 * <type> as type and <len> as length, depending on <server> boolean value which
226 * must be set to 1 for a server (haproxy listener) or 0 for a client (connection
227 * to an haproxy server).
228 */
229static int quic_transport_param_decode(struct quic_transport_params *p,
230 int server, uint64_t type,
231 const unsigned char **buf, size_t len)
232{
233 const unsigned char *end = *buf + len;
234
235 switch (type) {
236 case QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID:
237 if (!server || len > sizeof p->original_destination_connection_id.data)
238 return 0;
239
240 if (len)
241 memcpy(p->original_destination_connection_id.data, *buf, len);
242 p->original_destination_connection_id.len = len;
243 *buf += len;
244 p->original_destination_connection_id_present = 1;
245 break;
246 case QUIC_TP_INITIAL_SOURCE_CONNECTION_ID:
247 if (len > sizeof p->initial_source_connection_id.data)
248 return 0;
249
250 if (len)
251 memcpy(p->initial_source_connection_id.data, *buf, len);
252 p->initial_source_connection_id.len = len;
253 *buf += len;
254 p->initial_source_connection_id_present = 1;
255 break;
256 case QUIC_TP_STATELESS_RESET_TOKEN:
257 if (!server || len != sizeof p->stateless_reset_token)
258 return 0;
259 memcpy(p->stateless_reset_token, *buf, len);
260 *buf += len;
261 p->with_stateless_reset_token = 1;
262 break;
263 case QUIC_TP_PREFERRED_ADDRESS:
264 if (!server)
265 return 0;
266 if (!quic_transport_param_dec_pref_addr(&p->preferred_address, buf, *buf + len))
267 return 0;
268 p->with_preferred_address = 1;
269 break;
270 case QUIC_TP_MAX_IDLE_TIMEOUT:
271 if (!quic_dec_int(&p->max_idle_timeout, buf, end))
272 return 0;
273 break;
274 case QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
275 if (!quic_dec_int(&p->max_udp_payload_size, buf, end))
276 return 0;
277 break;
278 case QUIC_TP_INITIAL_MAX_DATA:
279 if (!quic_dec_int(&p->initial_max_data, buf, end))
280 return 0;
281 break;
282 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
283 if (!quic_dec_int(&p->initial_max_stream_data_bidi_local, buf, end))
284 return 0;
285 break;
286 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
287 if (!quic_dec_int(&p->initial_max_stream_data_bidi_remote, buf, end))
288 return 0;
289 break;
290 case QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
291 if (!quic_dec_int(&p->initial_max_stream_data_uni, buf, end))
292 return 0;
293 break;
294 case QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
295 if (!quic_dec_int(&p->initial_max_streams_bidi, buf, end))
296 return 0;
297 break;
298 case QUIC_TP_INITIAL_MAX_STREAMS_UNI:
299 if (!quic_dec_int(&p->initial_max_streams_uni, buf, end))
300 return 0;
301 break;
302 case QUIC_TP_ACK_DELAY_EXPONENT:
303 if (!quic_dec_int(&p->ack_delay_exponent, buf, end) ||
304 p->ack_delay_exponent > QUIC_TP_ACK_DELAY_EXPONENT_LIMIT)
305 return 0;
306 break;
307 case QUIC_TP_MAX_ACK_DELAY:
308 if (!quic_dec_int(&p->max_ack_delay, buf, end) ||
309 p->max_ack_delay > QUIC_TP_MAX_ACK_DELAY_LIMIT)
310 return 0;
311 break;
312 case QUIC_TP_DISABLE_ACTIVE_MIGRATION:
313 /* Zero-length parameter type. */
314 if (len != 0)
315 return 0;
316 p->disable_active_migration = 1;
317 break;
318 case QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
319 if (!quic_dec_int(&p->active_connection_id_limit, buf, end))
320 return 0;
321 break;
Frédéric Lécailleb7a406a2023-02-06 11:54:07 +0100322 case QUIC_TP_VERSION_INFORMATION:
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200323 if (!quic_transport_param_dec_version_info(&p->version_information,
324 buf, *buf + len, server))
325 return 0;
326 break;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200327 default:
328 *buf += len;
329 };
330
331 return *buf == end;
332}
333
334/* Encode <type> and <len> variable length values in <buf>.
335 * Returns 1 if succeeded, 0 if not.
336 */
337static int quic_transport_param_encode_type_len(unsigned char **buf,
338 const unsigned char *end,
339 uint64_t type, uint64_t len)
340{
341 return quic_enc_int(buf, end, type) && quic_enc_int(buf, end, len);
342}
343
344/* Decode variable length type and length values of a QUIC transport parameter
345 * into <type> and <len> found in <*buf> buffer.
346 * Returns 1 if succeeded, 0 if not.
347 */
348static int quic_transport_param_decode_type_len(uint64_t *type, uint64_t *len,
349 const unsigned char **buf,
350 const unsigned char *end)
351{
352 return quic_dec_int(type, buf, end) && quic_dec_int(len, buf, end);
353}
354
355/* Encode <param> bytes stream with <type> as type and <length> as length into buf.
356 * Returns 1 if succeeded, 0 if not.
357 */
358static int quic_transport_param_enc_mem(unsigned char **buf, const unsigned char *end,
359 uint64_t type, void *param, uint64_t length)
360{
361 if (!quic_transport_param_encode_type_len(buf, end, type, length))
362 return 0;
363
364 if (end - *buf < length)
365 return 0;
366
367 if (length)
368 memcpy(*buf, param, length);
369 *buf += length;
370
371 return 1;
372}
373
374/* Encode <val> 64-bits value as variable length integer into <buf>.
375 * Returns 1 if succeeded, 0 if not.
376 */
377static int quic_transport_param_enc_int(unsigned char **buf,
378 const unsigned char *end,
379 uint64_t type, uint64_t val)
380{
381 size_t len;
382
383 len = quic_int_getsize(val);
384
385 return len && quic_transport_param_encode_type_len(buf, end, type, len) &&
386 quic_enc_int(buf, end, val);
387}
388
389/* Returns the required length in bytes to encode <cid> QUIC connection ID. */
390static inline size_t sizeof_quic_cid(const struct tp_cid *cid)
391{
392 return sizeof cid->len + cid->len;
393}
394
395/* Encode <addr> preferred address into <buf>.
396 * Note that the IP addresses must be encoded in network byte order.
397 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained
398 * values already encoded in network byte order.
399 * Returns 1 if succeeded, 0 if not.
400 */
401static int quic_transport_param_enc_pref_addr(unsigned char **buf,
402 const unsigned char *end,
403 struct tp_preferred_address *addr)
404{
405 uint64_t addr_len = 0;
406
407 addr_len += sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
408 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
409 addr_len += sizeof_quic_cid(&addr->cid);
410 addr_len += sizeof addr->stateless_reset_token;
411
412 if (!quic_transport_param_encode_type_len(buf, end, QUIC_TP_PREFERRED_ADDRESS, addr_len))
413 return 0;
414
415 if (end - *buf < addr_len)
416 return 0;
417
418 quic_transport_param_enc_pref_addr_val(buf, end, addr);
419
420 return 1;
421}
422
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500423/* Encode version information transport parameters with <chosen_version> as chosen
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200424 * version.
425 * Return 1 if succeeded, 0 if not.
426 */
427static int quic_transport_param_enc_version_info(unsigned char **buf,
428 const unsigned char *end,
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500429 const struct quic_version *chosen_version,
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200430 int server)
431{
432 int i;
433 uint64_t tp_len;
434 uint32_t ver;
435
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500436 tp_len = sizeof chosen_version->num + quic_versions_nb * sizeof(uint32_t);
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200437 if (!quic_transport_param_encode_type_len(buf, end,
Frédéric Lécailleb7a406a2023-02-06 11:54:07 +0100438 QUIC_TP_VERSION_INFORMATION,
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200439 tp_len))
440 return 0;
441
442 if (end - *buf < tp_len)
443 return 0;
444
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500445 /* First: chosen version */
446 ver = htonl(chosen_version->num);
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200447 memcpy(*buf, &ver, sizeof ver);
448 *buf += sizeof ver;
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500449 /* For servers: all supported version, chosen included */
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200450 for (i = 0; i < quic_versions_nb; i++) {
451 ver = htonl(quic_versions[i].num);
452 memcpy(*buf, &ver, sizeof ver);
453 *buf += sizeof ver;
454 }
455
456 return 1;
457}
458
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200459/* Encode <p> transport parameter into <buf> depending on <server> value which
460 * must be set to 1 for a server (haproxy listener) or 0 for a client
461 * (connection to a haproxy server).
462 * Return the number of bytes consumed if succeeded, 0 if not.
463 */
464int quic_transport_params_encode(unsigned char *buf,
465 const unsigned char *end,
466 struct quic_transport_params *p,
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500467 const struct quic_version *chosen_version,
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200468 int server)
469{
470 unsigned char *head;
471 unsigned char *pos;
472
473 head = pos = buf;
474 if (server) {
475 if (!quic_transport_param_enc_mem(&pos, end,
476 QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID,
477 p->original_destination_connection_id.data,
478 p->original_destination_connection_id.len))
479 return 0;
480
481 if (p->retry_source_connection_id.len) {
482 if (!quic_transport_param_enc_mem(&pos, end,
483 QUIC_TP_RETRY_SOURCE_CONNECTION_ID,
484 p->retry_source_connection_id.data,
485 p->retry_source_connection_id.len))
486 return 0;
487 }
488
489 if (p->with_stateless_reset_token &&
490 !quic_transport_param_enc_mem(&pos, end, QUIC_TP_STATELESS_RESET_TOKEN,
491 p->stateless_reset_token,
492 sizeof p->stateless_reset_token))
493 return 0;
494 if (p->with_preferred_address &&
495 !quic_transport_param_enc_pref_addr(&pos, end, &p->preferred_address))
496 return 0;
497 }
498
499 if (!quic_transport_param_enc_mem(&pos, end,
500 QUIC_TP_INITIAL_SOURCE_CONNECTION_ID,
501 p->initial_source_connection_id.data,
502 p->initial_source_connection_id.len))
503 return 0;
504
505 if (p->max_idle_timeout &&
506 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_IDLE_TIMEOUT, p->max_idle_timeout))
507 return 0;
508
509 /*
510 * "max_packet_size" transport parameter must be transmitted only if different
511 * of the default value.
512 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200513 if (p->max_udp_payload_size != QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200514 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_UDP_PAYLOAD_SIZE, p->max_udp_payload_size))
515 return 0;
516
517 if (p->initial_max_data &&
518 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_DATA, p->initial_max_data))
519 return 0;
520
521 if (p->initial_max_stream_data_bidi_local &&
522 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
523 p->initial_max_stream_data_bidi_local))
524 return 0;
525
526 if (p->initial_max_stream_data_bidi_remote &&
527 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
528 p->initial_max_stream_data_bidi_remote))
529 return 0;
530
531 if (p->initial_max_stream_data_uni &&
532 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
533 p->initial_max_stream_data_uni))
534 return 0;
535
536 if (p->initial_max_streams_bidi &&
537 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
538 p->initial_max_streams_bidi))
539 return 0;
540
541 if (p->initial_max_streams_uni &&
542 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_UNI,
543 p->initial_max_streams_uni))
544 return 0;
545
546 /*
547 * "ack_delay_exponent" transport parameter must be transmitted only if different
548 * of the default value.
549 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200550 if (p->ack_delay_exponent != QUIC_TP_DFLT_ACK_DELAY_COMPONENT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200551 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACK_DELAY_EXPONENT, p->ack_delay_exponent))
552 return 0;
553
554 /*
555 * "max_ack_delay" transport parameter must be transmitted only if different
556 * of the default value.
557 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200558 if (p->max_ack_delay != QUIC_TP_DFLT_MAX_ACK_DELAY &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200559 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_ACK_DELAY, p->max_ack_delay))
560 return 0;
561
562 /* 0-length value */
563 if (p->disable_active_migration &&
564 !quic_transport_param_encode_type_len(&pos, end, QUIC_TP_DISABLE_ACTIVE_MIGRATION, 0))
565 return 0;
566
567 if (p->active_connection_id_limit &&
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200568 p->active_connection_id_limit != QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200569 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
570 p->active_connection_id_limit))
571 return 0;
572
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500573 if (!quic_transport_param_enc_version_info(&pos, end, chosen_version, server))
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200574 return 0;
575
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200576 return pos - head;
577}
578
579/* Decode transport parameters found in <buf> buffer into <p>, depending on
580 * <server> boolean value which must be set to 1 for a server (haproxy listener)
581 * or 0 for a client (connection to a haproxy server).
582 * Returns 1 if succeeded, 0 if not.
583 */
584static int quic_transport_params_decode(struct quic_transport_params *p, int server,
585 const unsigned char *buf,
586 const unsigned char *end)
587{
588 const unsigned char *pos;
Willy Tarreau33a68702022-11-24 09:16:41 +0100589 uint64_t type, len = 0;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200590
591 pos = buf;
592
593 while (pos != end) {
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200594 if (!quic_transport_param_decode_type_len(&type, &len, &pos, end))
595 return 0;
596
597 if (end - pos < len)
598 return 0;
599
600 if (!quic_transport_param_decode(p, server, type, &pos, len))
601 return 0;
602 }
603
604 /*
605 * A server MUST send original_destination_connection_id transport parameter.
606 * initial_source_connection_id must be present both for server and client.
607 */
608 if ((server && !p->original_destination_connection_id_present) ||
609 !p->initial_source_connection_id_present)
610 return 0;
611
612 return 1;
613}
614
615/* Store transport parameters found in <buf> buffer into <qc> QUIC connection
616 * depending on <server> value which must be 1 for a server (haproxy listener)
617 * or 0 for a client (connection to a haproxy server).
618 * Note that peer transport parameters are stored in the TX part of the connection:
619 * they are used to send packets to the peer with its transport parameters as
620 * limitations.
621 * Returns 1 if succeeded, 0 if not.
622 */
623int quic_transport_params_store(struct quic_conn *qc, int server,
624 const unsigned char *buf,
625 const unsigned char *end)
626{
627 struct quic_transport_params *tx_params = &qc->tx.params;
Frédéric Lécailleaf25a692023-02-01 17:56:57 +0100628 struct quic_transport_params *rx_params = &qc->rx.params;
Frédéric Lécaille0aa79952023-02-03 16:15:08 +0100629 /* Initial source connection ID */
630 struct tp_cid *iscid;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200631
632 /* initialize peer TPs to RFC default value */
633 quic_dflt_transport_params_cpy(tx_params);
634
635 if (!quic_transport_params_decode(tx_params, server, buf, end))
636 return 0;
637
Frédéric Lécailleaf25a692023-02-01 17:56:57 +0100638 /* Update the connection from transport parameters received */
639 if (tx_params->version_information.negotiated_version &&
640 tx_params->version_information.negotiated_version != qc->original_version)
641 qc->negotiated_version =
642 qc->tx.params.version_information.negotiated_version;
643
644 if (tx_params->max_ack_delay)
645 qc->max_ack_delay = tx_params->max_ack_delay;
646
647 if (tx_params->max_idle_timeout && rx_params->max_idle_timeout)
648 qc->max_idle_timeout =
649 QUIC_MIN(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
650 else
651 qc->max_idle_timeout =
652 QUIC_MAX(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
653 TRACE_PROTO("\nTX(remote) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, tx_params);
654
Frédéric Lécaille0aa79952023-02-03 16:15:08 +0100655 /* Check that the "initial_source_connection_id" transport parameter matches
656 * the SCID received which is also the DCID of the connection.
657 */
658 iscid = &tx_params->initial_source_connection_id;
659 if (qc->dcid.len != iscid->len ||
660 (qc->dcid.len && memcmp(qc->dcid.data, iscid->data, qc->dcid.len))) {
661 TRACE_PROTO("initial_source_connection_id transport parameter mismatch",
662 QUIC_EV_TRANSP_PARAMS, qc);
663 /* Kill the connection as soon as possible */
664 qc_kill_conn(qc);
665 }
666
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200667 return 1;
668}
669
670/* QUIC server (or haproxy listener) only function.
671 * Initialize the local transport parameters <rx_params> from <listener_params>
Ilya Shipitsin4a689da2022-10-29 09:34:32 +0500672 * coming from configuration and Initial packet information (destination
673 * connection ID, source connection ID, original destination connection ID) from
Frédéric Lécaillee9325e92022-08-11 17:24:38 +0200674 * client token.
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200675 * Returns 1 if succeeded, 0 if not.
676 */
677int qc_lstnr_params_init(struct quic_conn *qc,
678 const struct quic_transport_params *listener_params,
679 const unsigned char *stateless_reset_token,
680 const unsigned char *dcid, size_t dcidlen,
681 const unsigned char *scid, size_t scidlen,
Frédéric Lécaille7629f5d2022-08-11 18:54:26 +0200682 const struct quic_cid *token_odcid)
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200683{
684 struct quic_transport_params *rx_params = &qc->rx.params;
685 struct tp_cid *odcid_param = &rx_params->original_destination_connection_id;
686
687 /* Copy the transport parameters. */
688 *rx_params = *listener_params;
689 /* Copy the stateless reset token */
690 memcpy(rx_params->stateless_reset_token, stateless_reset_token,
691 sizeof rx_params->stateless_reset_token);
692 /* Copy original_destination_connection_id transport parameter. */
Amaury Denoyelle9e3026c2022-10-17 11:13:07 +0200693 if (token_odcid->len) {
Frédéric Lécaille7629f5d2022-08-11 18:54:26 +0200694 memcpy(odcid_param->data, token_odcid->data, token_odcid->len);
695 odcid_param->len = token_odcid->len;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200696 /* Copy retry_source_connection_id transport parameter. */
697 memcpy(rx_params->retry_source_connection_id.data, dcid, dcidlen);
698 rx_params->retry_source_connection_id.len = dcidlen;
699 }
700 else {
701 memcpy(odcid_param->data, dcid, dcidlen);
702 odcid_param->len = dcidlen;
703 }
704
705 /* Copy the initial source connection ID. */
706 memcpy(rx_params->initial_source_connection_id.data, scid, scidlen);
707 rx_params->initial_source_connection_id.len = scidlen;
Frédéric Lécaillec7785b52022-05-23 09:08:54 +0200708 TRACE_PROTO("\nRX(local) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, rx_params);
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200709
710 return 1;
711}
712