blob: 9879828417e580d4ac563e4731eec14c4ac12dde [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;
Frédéric Lécailleb9716962023-05-10 13:06:31 +0200175 const uint32_t *ver, *others;
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200176
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écailleb9716962023-05-10 13:06:31 +0200187 others = (const uint32_t *)*buf;
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200188
189 /* Others versions must not be null */
Frédéric Lécailleb9716962023-05-10 13:06:31 +0200190 for (ver = others; ver < (const uint32_t *)end; ver++) {
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200191 if (!*ver)
192 return 0;
193 }
194
195 if (server)
196 /* TODO: not supported */
197 return 0;
198
Frédéric Lécailleb9716962023-05-10 13:06:31 +0200199 for (ver = others; ver < (const uint32_t *)end; ver++) {
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200200 if (!tp->negotiated_version) {
201 int i;
202
203 for (i = 0; i < quic_versions_nb; i++) {
204 if (ntohl(*ver) == quic_versions[i].num) {
205 tp->negotiated_version = &quic_versions[i];
206 break;
207 }
208 }
209 }
210
211 if (preferred_version && ntohl(*ver) == preferred_version->num) {
212 tp->negotiated_version = preferred_version;
213 goto out;
214 }
215 }
216
217 out:
218 *buf = end;
219
220 return 1;
221}
222
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200223/* Decode into <p> struct a transport parameter found in <*buf> buffer with
224 * <type> as type and <len> as length, depending on <server> boolean value which
225 * must be set to 1 for a server (haproxy listener) or 0 for a client (connection
226 * to an haproxy server).
227 */
228static int quic_transport_param_decode(struct quic_transport_params *p,
229 int server, uint64_t type,
230 const unsigned char **buf, size_t len)
231{
232 const unsigned char *end = *buf + len;
233
234 switch (type) {
235 case QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID:
236 if (!server || len > sizeof p->original_destination_connection_id.data)
237 return 0;
238
239 if (len)
240 memcpy(p->original_destination_connection_id.data, *buf, len);
241 p->original_destination_connection_id.len = len;
242 *buf += len;
243 p->original_destination_connection_id_present = 1;
244 break;
245 case QUIC_TP_INITIAL_SOURCE_CONNECTION_ID:
246 if (len > sizeof p->initial_source_connection_id.data)
247 return 0;
248
249 if (len)
250 memcpy(p->initial_source_connection_id.data, *buf, len);
251 p->initial_source_connection_id.len = len;
252 *buf += len;
253 p->initial_source_connection_id_present = 1;
254 break;
255 case QUIC_TP_STATELESS_RESET_TOKEN:
256 if (!server || len != sizeof p->stateless_reset_token)
257 return 0;
258 memcpy(p->stateless_reset_token, *buf, len);
259 *buf += len;
260 p->with_stateless_reset_token = 1;
261 break;
262 case QUIC_TP_PREFERRED_ADDRESS:
263 if (!server)
264 return 0;
265 if (!quic_transport_param_dec_pref_addr(&p->preferred_address, buf, *buf + len))
266 return 0;
267 p->with_preferred_address = 1;
268 break;
269 case QUIC_TP_MAX_IDLE_TIMEOUT:
270 if (!quic_dec_int(&p->max_idle_timeout, buf, end))
271 return 0;
272 break;
273 case QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
274 if (!quic_dec_int(&p->max_udp_payload_size, buf, end))
275 return 0;
276 break;
277 case QUIC_TP_INITIAL_MAX_DATA:
278 if (!quic_dec_int(&p->initial_max_data, buf, end))
279 return 0;
280 break;
281 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
282 if (!quic_dec_int(&p->initial_max_stream_data_bidi_local, buf, end))
283 return 0;
284 break;
285 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
286 if (!quic_dec_int(&p->initial_max_stream_data_bidi_remote, buf, end))
287 return 0;
288 break;
289 case QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
290 if (!quic_dec_int(&p->initial_max_stream_data_uni, buf, end))
291 return 0;
292 break;
293 case QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
294 if (!quic_dec_int(&p->initial_max_streams_bidi, buf, end))
295 return 0;
296 break;
297 case QUIC_TP_INITIAL_MAX_STREAMS_UNI:
298 if (!quic_dec_int(&p->initial_max_streams_uni, buf, end))
299 return 0;
300 break;
301 case QUIC_TP_ACK_DELAY_EXPONENT:
302 if (!quic_dec_int(&p->ack_delay_exponent, buf, end) ||
303 p->ack_delay_exponent > QUIC_TP_ACK_DELAY_EXPONENT_LIMIT)
304 return 0;
305 break;
306 case QUIC_TP_MAX_ACK_DELAY:
307 if (!quic_dec_int(&p->max_ack_delay, buf, end) ||
308 p->max_ack_delay > QUIC_TP_MAX_ACK_DELAY_LIMIT)
309 return 0;
310 break;
311 case QUIC_TP_DISABLE_ACTIVE_MIGRATION:
312 /* Zero-length parameter type. */
313 if (len != 0)
314 return 0;
315 p->disable_active_migration = 1;
316 break;
317 case QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
318 if (!quic_dec_int(&p->active_connection_id_limit, buf, end))
319 return 0;
320 break;
Frédéric Lécailleb7a406a2023-02-06 11:54:07 +0100321 case QUIC_TP_VERSION_INFORMATION:
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200322 if (!quic_transport_param_dec_version_info(&p->version_information,
323 buf, *buf + len, server))
324 return 0;
325 break;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200326 default:
327 *buf += len;
328 };
329
330 return *buf == end;
331}
332
333/* Encode <type> and <len> variable length values in <buf>.
334 * Returns 1 if succeeded, 0 if not.
335 */
336static int quic_transport_param_encode_type_len(unsigned char **buf,
337 const unsigned char *end,
338 uint64_t type, uint64_t len)
339{
340 return quic_enc_int(buf, end, type) && quic_enc_int(buf, end, len);
341}
342
343/* Decode variable length type and length values of a QUIC transport parameter
344 * into <type> and <len> found in <*buf> buffer.
345 * Returns 1 if succeeded, 0 if not.
346 */
347static int quic_transport_param_decode_type_len(uint64_t *type, uint64_t *len,
348 const unsigned char **buf,
349 const unsigned char *end)
350{
351 return quic_dec_int(type, buf, end) && quic_dec_int(len, buf, end);
352}
353
354/* Encode <param> bytes stream with <type> as type and <length> as length into buf.
355 * Returns 1 if succeeded, 0 if not.
356 */
357static int quic_transport_param_enc_mem(unsigned char **buf, const unsigned char *end,
358 uint64_t type, void *param, uint64_t length)
359{
360 if (!quic_transport_param_encode_type_len(buf, end, type, length))
361 return 0;
362
363 if (end - *buf < length)
364 return 0;
365
366 if (length)
367 memcpy(*buf, param, length);
368 *buf += length;
369
370 return 1;
371}
372
373/* Encode <val> 64-bits value as variable length integer into <buf>.
374 * Returns 1 if succeeded, 0 if not.
375 */
376static int quic_transport_param_enc_int(unsigned char **buf,
377 const unsigned char *end,
378 uint64_t type, uint64_t val)
379{
380 size_t len;
381
382 len = quic_int_getsize(val);
383
384 return len && quic_transport_param_encode_type_len(buf, end, type, len) &&
385 quic_enc_int(buf, end, val);
386}
387
388/* Returns the required length in bytes to encode <cid> QUIC connection ID. */
389static inline size_t sizeof_quic_cid(const struct tp_cid *cid)
390{
391 return sizeof cid->len + cid->len;
392}
393
394/* Encode <addr> preferred address into <buf>.
395 * Note that the IP addresses must be encoded in network byte order.
396 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained
397 * values already encoded in network byte order.
398 * Returns 1 if succeeded, 0 if not.
399 */
400static int quic_transport_param_enc_pref_addr(unsigned char **buf,
401 const unsigned char *end,
402 struct tp_preferred_address *addr)
403{
404 uint64_t addr_len = 0;
405
406 addr_len += sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
407 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
408 addr_len += sizeof_quic_cid(&addr->cid);
409 addr_len += sizeof addr->stateless_reset_token;
410
411 if (!quic_transport_param_encode_type_len(buf, end, QUIC_TP_PREFERRED_ADDRESS, addr_len))
412 return 0;
413
414 if (end - *buf < addr_len)
415 return 0;
416
417 quic_transport_param_enc_pref_addr_val(buf, end, addr);
418
419 return 1;
420}
421
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500422/* Encode version information transport parameters with <chosen_version> as chosen
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200423 * version.
424 * Return 1 if succeeded, 0 if not.
425 */
426static int quic_transport_param_enc_version_info(unsigned char **buf,
427 const unsigned char *end,
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500428 const struct quic_version *chosen_version,
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200429 int server)
430{
431 int i;
432 uint64_t tp_len;
433 uint32_t ver;
434
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500435 tp_len = sizeof chosen_version->num + quic_versions_nb * sizeof(uint32_t);
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200436 if (!quic_transport_param_encode_type_len(buf, end,
Frédéric Lécailleb7a406a2023-02-06 11:54:07 +0100437 QUIC_TP_VERSION_INFORMATION,
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200438 tp_len))
439 return 0;
440
441 if (end - *buf < tp_len)
442 return 0;
443
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500444 /* First: chosen version */
445 ver = htonl(chosen_version->num);
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200446 memcpy(*buf, &ver, sizeof ver);
447 *buf += sizeof ver;
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500448 /* For servers: all supported version, chosen included */
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200449 for (i = 0; i < quic_versions_nb; i++) {
450 ver = htonl(quic_versions[i].num);
451 memcpy(*buf, &ver, sizeof ver);
452 *buf += sizeof ver;
453 }
454
455 return 1;
456}
457
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200458/* Encode <p> transport parameter into <buf> depending on <server> value which
459 * must be set to 1 for a server (haproxy listener) or 0 for a client
460 * (connection to a haproxy server).
461 * Return the number of bytes consumed if succeeded, 0 if not.
462 */
463int quic_transport_params_encode(unsigned char *buf,
464 const unsigned char *end,
465 struct quic_transport_params *p,
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500466 const struct quic_version *chosen_version,
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200467 int server)
468{
469 unsigned char *head;
470 unsigned char *pos;
471
472 head = pos = buf;
473 if (server) {
474 if (!quic_transport_param_enc_mem(&pos, end,
475 QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID,
476 p->original_destination_connection_id.data,
477 p->original_destination_connection_id.len))
478 return 0;
479
480 if (p->retry_source_connection_id.len) {
481 if (!quic_transport_param_enc_mem(&pos, end,
482 QUIC_TP_RETRY_SOURCE_CONNECTION_ID,
483 p->retry_source_connection_id.data,
484 p->retry_source_connection_id.len))
485 return 0;
486 }
487
488 if (p->with_stateless_reset_token &&
489 !quic_transport_param_enc_mem(&pos, end, QUIC_TP_STATELESS_RESET_TOKEN,
490 p->stateless_reset_token,
491 sizeof p->stateless_reset_token))
492 return 0;
493 if (p->with_preferred_address &&
494 !quic_transport_param_enc_pref_addr(&pos, end, &p->preferred_address))
495 return 0;
496 }
497
498 if (!quic_transport_param_enc_mem(&pos, end,
499 QUIC_TP_INITIAL_SOURCE_CONNECTION_ID,
500 p->initial_source_connection_id.data,
501 p->initial_source_connection_id.len))
502 return 0;
503
504 if (p->max_idle_timeout &&
505 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_IDLE_TIMEOUT, p->max_idle_timeout))
506 return 0;
507
508 /*
509 * "max_packet_size" transport parameter must be transmitted only if different
510 * of the default value.
511 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200512 if (p->max_udp_payload_size != QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200513 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_UDP_PAYLOAD_SIZE, p->max_udp_payload_size))
514 return 0;
515
516 if (p->initial_max_data &&
517 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_DATA, p->initial_max_data))
518 return 0;
519
520 if (p->initial_max_stream_data_bidi_local &&
521 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
522 p->initial_max_stream_data_bidi_local))
523 return 0;
524
525 if (p->initial_max_stream_data_bidi_remote &&
526 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
527 p->initial_max_stream_data_bidi_remote))
528 return 0;
529
530 if (p->initial_max_stream_data_uni &&
531 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
532 p->initial_max_stream_data_uni))
533 return 0;
534
535 if (p->initial_max_streams_bidi &&
536 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
537 p->initial_max_streams_bidi))
538 return 0;
539
540 if (p->initial_max_streams_uni &&
541 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_UNI,
542 p->initial_max_streams_uni))
543 return 0;
544
545 /*
546 * "ack_delay_exponent" transport parameter must be transmitted only if different
547 * of the default value.
548 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200549 if (p->ack_delay_exponent != QUIC_TP_DFLT_ACK_DELAY_COMPONENT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200550 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACK_DELAY_EXPONENT, p->ack_delay_exponent))
551 return 0;
552
553 /*
554 * "max_ack_delay" transport parameter must be transmitted only if different
555 * of the default value.
556 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200557 if (p->max_ack_delay != QUIC_TP_DFLT_MAX_ACK_DELAY &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200558 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_ACK_DELAY, p->max_ack_delay))
559 return 0;
560
561 /* 0-length value */
562 if (p->disable_active_migration &&
563 !quic_transport_param_encode_type_len(&pos, end, QUIC_TP_DISABLE_ACTIVE_MIGRATION, 0))
564 return 0;
565
566 if (p->active_connection_id_limit &&
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200567 p->active_connection_id_limit != QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200568 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
569 p->active_connection_id_limit))
570 return 0;
571
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500572 if (!quic_transport_param_enc_version_info(&pos, end, chosen_version, server))
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200573 return 0;
574
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200575 return pos - head;
576}
577
578/* Decode transport parameters found in <buf> buffer into <p>, depending on
579 * <server> boolean value which must be set to 1 for a server (haproxy listener)
580 * or 0 for a client (connection to a haproxy server).
581 * Returns 1 if succeeded, 0 if not.
582 */
583static int quic_transport_params_decode(struct quic_transport_params *p, int server,
584 const unsigned char *buf,
585 const unsigned char *end)
586{
587 const unsigned char *pos;
Willy Tarreau33a68702022-11-24 09:16:41 +0100588 uint64_t type, len = 0;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200589
590 pos = buf;
591
592 while (pos != end) {
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200593 if (!quic_transport_param_decode_type_len(&type, &len, &pos, end))
594 return 0;
595
596 if (end - pos < len)
597 return 0;
598
599 if (!quic_transport_param_decode(p, server, type, &pos, len))
600 return 0;
601 }
602
603 /*
604 * A server MUST send original_destination_connection_id transport parameter.
605 * initial_source_connection_id must be present both for server and client.
606 */
607 if ((server && !p->original_destination_connection_id_present) ||
608 !p->initial_source_connection_id_present)
609 return 0;
610
Frédéric Lécaille4afbca62023-03-06 13:57:40 +0100611 /* Note that if not received by the peer, active_connection_id_limit will
612 * have QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT as default value. This
613 * is also the minimum value for this transport parameter.
614 */
615 if (p->active_connection_id_limit < QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT)
616 return 0;
617
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200618 return 1;
619}
620
621/* Store transport parameters found in <buf> buffer into <qc> QUIC connection
622 * depending on <server> value which must be 1 for a server (haproxy listener)
623 * or 0 for a client (connection to a haproxy server).
624 * Note that peer transport parameters are stored in the TX part of the connection:
625 * they are used to send packets to the peer with its transport parameters as
626 * limitations.
627 * Returns 1 if succeeded, 0 if not.
628 */
629int quic_transport_params_store(struct quic_conn *qc, int server,
630 const unsigned char *buf,
631 const unsigned char *end)
632{
633 struct quic_transport_params *tx_params = &qc->tx.params;
Frédéric Lécailleaf25a692023-02-01 17:56:57 +0100634 struct quic_transport_params *rx_params = &qc->rx.params;
Frédéric Lécaille0aa79952023-02-03 16:15:08 +0100635 /* Initial source connection ID */
636 struct tp_cid *iscid;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200637
638 /* initialize peer TPs to RFC default value */
639 quic_dflt_transport_params_cpy(tx_params);
640
641 if (!quic_transport_params_decode(tx_params, server, buf, end))
642 return 0;
643
Frédéric Lécailleaf25a692023-02-01 17:56:57 +0100644 /* Update the connection from transport parameters received */
645 if (tx_params->version_information.negotiated_version &&
646 tx_params->version_information.negotiated_version != qc->original_version)
647 qc->negotiated_version =
648 qc->tx.params.version_information.negotiated_version;
649
650 if (tx_params->max_ack_delay)
651 qc->max_ack_delay = tx_params->max_ack_delay;
652
653 if (tx_params->max_idle_timeout && rx_params->max_idle_timeout)
654 qc->max_idle_timeout =
655 QUIC_MIN(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
656 else
657 qc->max_idle_timeout =
658 QUIC_MAX(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
659 TRACE_PROTO("\nTX(remote) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, tx_params);
660
Frédéric Lécaille0aa79952023-02-03 16:15:08 +0100661 /* Check that the "initial_source_connection_id" transport parameter matches
662 * the SCID received which is also the DCID of the connection.
663 */
664 iscid = &tx_params->initial_source_connection_id;
665 if (qc->dcid.len != iscid->len ||
666 (qc->dcid.len && memcmp(qc->dcid.data, iscid->data, qc->dcid.len))) {
667 TRACE_PROTO("initial_source_connection_id transport parameter mismatch",
668 QUIC_EV_TRANSP_PARAMS, qc);
669 /* Kill the connection as soon as possible */
670 qc_kill_conn(qc);
671 }
672
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200673 return 1;
674}
675
676/* QUIC server (or haproxy listener) only function.
677 * Initialize the local transport parameters <rx_params> from <listener_params>
Ilya Shipitsin4a689da2022-10-29 09:34:32 +0500678 * coming from configuration and Initial packet information (destination
679 * connection ID, source connection ID, original destination connection ID) from
Frédéric Lécaillee9325e92022-08-11 17:24:38 +0200680 * client token.
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200681 * Returns 1 if succeeded, 0 if not.
682 */
683int qc_lstnr_params_init(struct quic_conn *qc,
684 const struct quic_transport_params *listener_params,
685 const unsigned char *stateless_reset_token,
686 const unsigned char *dcid, size_t dcidlen,
687 const unsigned char *scid, size_t scidlen,
Frédéric Lécaille7629f5d2022-08-11 18:54:26 +0200688 const struct quic_cid *token_odcid)
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200689{
690 struct quic_transport_params *rx_params = &qc->rx.params;
691 struct tp_cid *odcid_param = &rx_params->original_destination_connection_id;
692
693 /* Copy the transport parameters. */
694 *rx_params = *listener_params;
695 /* Copy the stateless reset token */
696 memcpy(rx_params->stateless_reset_token, stateless_reset_token,
697 sizeof rx_params->stateless_reset_token);
698 /* Copy original_destination_connection_id transport parameter. */
Amaury Denoyelle9e3026c2022-10-17 11:13:07 +0200699 if (token_odcid->len) {
Frédéric Lécaille7629f5d2022-08-11 18:54:26 +0200700 memcpy(odcid_param->data, token_odcid->data, token_odcid->len);
701 odcid_param->len = token_odcid->len;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200702 /* Copy retry_source_connection_id transport parameter. */
703 memcpy(rx_params->retry_source_connection_id.data, dcid, dcidlen);
704 rx_params->retry_source_connection_id.len = dcidlen;
705 }
706 else {
707 memcpy(odcid_param->data, dcid, dcidlen);
708 odcid_param->len = dcidlen;
709 }
710
711 /* Copy the initial source connection ID. */
712 memcpy(rx_params->initial_source_connection_id.data, scid, scidlen);
713 rx_params->initial_source_connection_id.len = scidlen;
Frédéric Lécaillec7785b52022-05-23 09:08:54 +0200714 TRACE_PROTO("\nRX(local) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, rx_params);
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200715
716 return 1;
717}
718