blob: d2468c0c3277e73651d3c96373eb9bf5474bc3e0 [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
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200134 memcpy(addr->ipv4_addr, *buf, sizeof addr->ipv4_addr);
135 *buf += sizeof addr->ipv4_addr;
136
Amaury Denoyelle2778ddc2023-11-30 14:01:51 +0100137 addr->ipv4_port = read_n16(*buf);
138 *buf += sizeof addr->ipv4_port;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200139
140 memcpy(addr->ipv6_addr, *buf, sizeof addr->ipv6_addr);
141 *buf += sizeof addr->ipv6_addr;
142
Amaury Denoyelle2778ddc2023-11-30 14:01:51 +0100143 addr->ipv6_port = read_n16(*buf);
144 *buf += sizeof addr->ipv6_port;
145
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200146 addr->cid.len = *(*buf)++;
147 if (addr->cid.len) {
Amaury Denoyelle2778ddc2023-11-30 14:01:51 +0100148 if (end - sizeof(addr->stateless_reset_token) - *buf > addr->cid.len ||
149 addr->cid.len > sizeof(addr->cid.data)) {
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200150 return 0;
Amaury Denoyelle2778ddc2023-11-30 14:01:51 +0100151 }
152
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200153 memcpy(addr->cid.data, *buf, addr->cid.len);
154 *buf += addr->cid.len;
155 }
156
Amaury Denoyelle2778ddc2023-11-30 14:01:51 +0100157 if (end - *buf != sizeof(addr->stateless_reset_token))
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200158 return 0;
159
160 memcpy(addr->stateless_reset_token, *buf, end - *buf);
161 *buf += sizeof addr->stateless_reset_token;
162
163 return *buf == end;
164}
165
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200166/* Decode into <v> version information received transport parameters from <*buf>
167 * buffer. <server> must be set to 1 for QUIC clients which receive server
168 * transport parameters, and 0 for QUIC servers which receive client transport
169 * parameters.
170 * Also set the QUIC negotiated version into <tp>.
171 * Return 1 if succeeded, 0 if not.
172 */
173static int quic_transport_param_dec_version_info(struct tp_version_information *tp,
174 const unsigned char **buf,
175 const unsigned char *end, int server)
176{
177 size_t tp_len = end - *buf;
Willy Tarreaub4cf4ba2024-04-05 23:54:17 +0200178 const unsigned char *ver, *others;
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200179
180 /* <tp_len> must be a multiple of sizeof(uint32_t) */
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500181 if (tp_len < sizeof tp->chosen || (tp_len & 0x3))
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200182 return 0;
183
Willy Tarreaub4cf4ba2024-04-05 23:54:17 +0200184 tp->chosen = ntohl(read_u32(*buf));
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200185 /* Must not be null */
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500186 if (!tp->chosen)
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200187 return 0;
188
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500189 *buf += sizeof tp->chosen;
Willy Tarreaub4cf4ba2024-04-05 23:54:17 +0200190 others = *buf;
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200191
192 /* Others versions must not be null */
Willy Tarreaub4cf4ba2024-04-05 23:54:17 +0200193 for (ver = others; ver < end; ver += 4) {
194 if (!read_u32(ver))
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200195 return 0;
196 }
197
198 if (server)
199 /* TODO: not supported */
200 return 0;
201
Willy Tarreaub4cf4ba2024-04-05 23:54:17 +0200202 for (ver = others; ver < end; ver += 4) {
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200203 if (!tp->negotiated_version) {
204 int i;
205
206 for (i = 0; i < quic_versions_nb; i++) {
Willy Tarreaub4cf4ba2024-04-05 23:54:17 +0200207 if (ntohl(read_u32(ver)) == quic_versions[i].num) {
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200208 tp->negotiated_version = &quic_versions[i];
209 break;
210 }
211 }
212 }
213
Willy Tarreaub4cf4ba2024-04-05 23:54:17 +0200214 if (preferred_version && ntohl(read_u32(ver)) == preferred_version->num) {
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200215 tp->negotiated_version = preferred_version;
216 goto out;
217 }
218 }
219
220 out:
221 *buf = end;
222
223 return 1;
224}
225
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200226/* Decode into <p> struct a transport parameter found in <*buf> buffer with
227 * <type> as type and <len> as length, depending on <server> boolean value which
228 * must be set to 1 for a server (haproxy listener) or 0 for a client (connection
229 * to an haproxy server).
230 */
231static int quic_transport_param_decode(struct quic_transport_params *p,
232 int server, uint64_t type,
233 const unsigned char **buf, size_t len)
234{
235 const unsigned char *end = *buf + len;
236
237 switch (type) {
238 case QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID:
239 if (!server || len > sizeof p->original_destination_connection_id.data)
240 return 0;
241
242 if (len)
243 memcpy(p->original_destination_connection_id.data, *buf, len);
244 p->original_destination_connection_id.len = len;
245 *buf += len;
246 p->original_destination_connection_id_present = 1;
247 break;
248 case QUIC_TP_INITIAL_SOURCE_CONNECTION_ID:
249 if (len > sizeof p->initial_source_connection_id.data)
250 return 0;
251
252 if (len)
253 memcpy(p->initial_source_connection_id.data, *buf, len);
254 p->initial_source_connection_id.len = len;
255 *buf += len;
256 p->initial_source_connection_id_present = 1;
257 break;
258 case QUIC_TP_STATELESS_RESET_TOKEN:
259 if (!server || len != sizeof p->stateless_reset_token)
260 return 0;
261 memcpy(p->stateless_reset_token, *buf, len);
262 *buf += len;
263 p->with_stateless_reset_token = 1;
264 break;
265 case QUIC_TP_PREFERRED_ADDRESS:
266 if (!server)
267 return 0;
268 if (!quic_transport_param_dec_pref_addr(&p->preferred_address, buf, *buf + len))
269 return 0;
270 p->with_preferred_address = 1;
271 break;
272 case QUIC_TP_MAX_IDLE_TIMEOUT:
273 if (!quic_dec_int(&p->max_idle_timeout, buf, end))
274 return 0;
275 break;
276 case QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
277 if (!quic_dec_int(&p->max_udp_payload_size, buf, end))
278 return 0;
279 break;
280 case QUIC_TP_INITIAL_MAX_DATA:
281 if (!quic_dec_int(&p->initial_max_data, buf, end))
282 return 0;
283 break;
284 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
285 if (!quic_dec_int(&p->initial_max_stream_data_bidi_local, buf, end))
286 return 0;
287 break;
288 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
289 if (!quic_dec_int(&p->initial_max_stream_data_bidi_remote, buf, end))
290 return 0;
291 break;
292 case QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
293 if (!quic_dec_int(&p->initial_max_stream_data_uni, buf, end))
294 return 0;
295 break;
296 case QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
297 if (!quic_dec_int(&p->initial_max_streams_bidi, buf, end))
298 return 0;
299 break;
300 case QUIC_TP_INITIAL_MAX_STREAMS_UNI:
301 if (!quic_dec_int(&p->initial_max_streams_uni, buf, end))
302 return 0;
303 break;
304 case QUIC_TP_ACK_DELAY_EXPONENT:
305 if (!quic_dec_int(&p->ack_delay_exponent, buf, end) ||
306 p->ack_delay_exponent > QUIC_TP_ACK_DELAY_EXPONENT_LIMIT)
307 return 0;
308 break;
309 case QUIC_TP_MAX_ACK_DELAY:
310 if (!quic_dec_int(&p->max_ack_delay, buf, end) ||
311 p->max_ack_delay > QUIC_TP_MAX_ACK_DELAY_LIMIT)
312 return 0;
313 break;
314 case QUIC_TP_DISABLE_ACTIVE_MIGRATION:
315 /* Zero-length parameter type. */
316 if (len != 0)
317 return 0;
318 p->disable_active_migration = 1;
319 break;
320 case QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
321 if (!quic_dec_int(&p->active_connection_id_limit, buf, end))
322 return 0;
323 break;
Frédéric Lécailleb7a406a2023-02-06 11:54:07 +0100324 case QUIC_TP_VERSION_INFORMATION:
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200325 if (!quic_transport_param_dec_version_info(&p->version_information,
326 buf, *buf + len, server))
327 return 0;
328 break;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200329 default:
330 *buf += len;
331 };
332
333 return *buf == end;
334}
335
336/* Encode <type> and <len> variable length values in <buf>.
337 * Returns 1 if succeeded, 0 if not.
338 */
339static int quic_transport_param_encode_type_len(unsigned char **buf,
340 const unsigned char *end,
341 uint64_t type, uint64_t len)
342{
343 return quic_enc_int(buf, end, type) && quic_enc_int(buf, end, len);
344}
345
346/* Decode variable length type and length values of a QUIC transport parameter
347 * into <type> and <len> found in <*buf> buffer.
348 * Returns 1 if succeeded, 0 if not.
349 */
350static int quic_transport_param_decode_type_len(uint64_t *type, uint64_t *len,
351 const unsigned char **buf,
352 const unsigned char *end)
353{
354 return quic_dec_int(type, buf, end) && quic_dec_int(len, buf, end);
355}
356
357/* Encode <param> bytes stream with <type> as type and <length> as length into buf.
358 * Returns 1 if succeeded, 0 if not.
359 */
360static int quic_transport_param_enc_mem(unsigned char **buf, const unsigned char *end,
361 uint64_t type, void *param, uint64_t length)
362{
363 if (!quic_transport_param_encode_type_len(buf, end, type, length))
364 return 0;
365
366 if (end - *buf < length)
367 return 0;
368
369 if (length)
370 memcpy(*buf, param, length);
371 *buf += length;
372
373 return 1;
374}
375
376/* Encode <val> 64-bits value as variable length integer into <buf>.
377 * Returns 1 if succeeded, 0 if not.
378 */
379static int quic_transport_param_enc_int(unsigned char **buf,
380 const unsigned char *end,
381 uint64_t type, uint64_t val)
382{
383 size_t len;
384
385 len = quic_int_getsize(val);
386
387 return len && quic_transport_param_encode_type_len(buf, end, type, len) &&
388 quic_enc_int(buf, end, val);
389}
390
391/* Returns the required length in bytes to encode <cid> QUIC connection ID. */
392static inline size_t sizeof_quic_cid(const struct tp_cid *cid)
393{
394 return sizeof cid->len + cid->len;
395}
396
397/* Encode <addr> preferred address into <buf>.
398 * Note that the IP addresses must be encoded in network byte order.
399 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained
400 * values already encoded in network byte order.
401 * Returns 1 if succeeded, 0 if not.
402 */
403static int quic_transport_param_enc_pref_addr(unsigned char **buf,
404 const unsigned char *end,
405 struct tp_preferred_address *addr)
406{
407 uint64_t addr_len = 0;
408
409 addr_len += sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
410 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
411 addr_len += sizeof_quic_cid(&addr->cid);
412 addr_len += sizeof addr->stateless_reset_token;
413
414 if (!quic_transport_param_encode_type_len(buf, end, QUIC_TP_PREFERRED_ADDRESS, addr_len))
415 return 0;
416
417 if (end - *buf < addr_len)
418 return 0;
419
420 quic_transport_param_enc_pref_addr_val(buf, end, addr);
421
422 return 1;
423}
424
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500425/* Encode version information transport parameters with <chosen_version> as chosen
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200426 * version.
427 * Return 1 if succeeded, 0 if not.
428 */
429static int quic_transport_param_enc_version_info(unsigned char **buf,
430 const unsigned char *end,
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500431 const struct quic_version *chosen_version,
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200432 int server)
433{
434 int i;
435 uint64_t tp_len;
436 uint32_t ver;
437
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500438 tp_len = sizeof chosen_version->num + quic_versions_nb * sizeof(uint32_t);
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200439 if (!quic_transport_param_encode_type_len(buf, end,
Frédéric Lécailleb7a406a2023-02-06 11:54:07 +0100440 QUIC_TP_VERSION_INFORMATION,
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200441 tp_len))
442 return 0;
443
444 if (end - *buf < tp_len)
445 return 0;
446
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500447 /* First: chosen version */
448 ver = htonl(chosen_version->num);
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200449 memcpy(*buf, &ver, sizeof ver);
450 *buf += sizeof ver;
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500451 /* For servers: all supported version, chosen included */
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200452 for (i = 0; i < quic_versions_nb; i++) {
453 ver = htonl(quic_versions[i].num);
454 memcpy(*buf, &ver, sizeof ver);
455 *buf += sizeof ver;
456 }
457
458 return 1;
459}
460
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200461/* Encode <p> transport parameter into <buf> depending on <server> value which
462 * must be set to 1 for a server (haproxy listener) or 0 for a client
463 * (connection to a haproxy server).
464 * Return the number of bytes consumed if succeeded, 0 if not.
465 */
466int quic_transport_params_encode(unsigned char *buf,
467 const unsigned char *end,
468 struct quic_transport_params *p,
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500469 const struct quic_version *chosen_version,
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200470 int server)
471{
472 unsigned char *head;
473 unsigned char *pos;
474
475 head = pos = buf;
476 if (server) {
477 if (!quic_transport_param_enc_mem(&pos, end,
478 QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID,
479 p->original_destination_connection_id.data,
480 p->original_destination_connection_id.len))
481 return 0;
482
483 if (p->retry_source_connection_id.len) {
484 if (!quic_transport_param_enc_mem(&pos, end,
485 QUIC_TP_RETRY_SOURCE_CONNECTION_ID,
486 p->retry_source_connection_id.data,
487 p->retry_source_connection_id.len))
488 return 0;
489 }
490
491 if (p->with_stateless_reset_token &&
492 !quic_transport_param_enc_mem(&pos, end, QUIC_TP_STATELESS_RESET_TOKEN,
493 p->stateless_reset_token,
494 sizeof p->stateless_reset_token))
495 return 0;
496 if (p->with_preferred_address &&
497 !quic_transport_param_enc_pref_addr(&pos, end, &p->preferred_address))
498 return 0;
499 }
500
501 if (!quic_transport_param_enc_mem(&pos, end,
502 QUIC_TP_INITIAL_SOURCE_CONNECTION_ID,
503 p->initial_source_connection_id.data,
504 p->initial_source_connection_id.len))
505 return 0;
506
507 if (p->max_idle_timeout &&
508 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_IDLE_TIMEOUT, p->max_idle_timeout))
509 return 0;
510
511 /*
512 * "max_packet_size" transport parameter must be transmitted only if different
513 * of the default value.
514 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200515 if (p->max_udp_payload_size != QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200516 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_UDP_PAYLOAD_SIZE, p->max_udp_payload_size))
517 return 0;
518
519 if (p->initial_max_data &&
520 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_DATA, p->initial_max_data))
521 return 0;
522
523 if (p->initial_max_stream_data_bidi_local &&
524 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
525 p->initial_max_stream_data_bidi_local))
526 return 0;
527
528 if (p->initial_max_stream_data_bidi_remote &&
529 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
530 p->initial_max_stream_data_bidi_remote))
531 return 0;
532
533 if (p->initial_max_stream_data_uni &&
534 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
535 p->initial_max_stream_data_uni))
536 return 0;
537
538 if (p->initial_max_streams_bidi &&
539 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
540 p->initial_max_streams_bidi))
541 return 0;
542
543 if (p->initial_max_streams_uni &&
544 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_UNI,
545 p->initial_max_streams_uni))
546 return 0;
547
548 /*
549 * "ack_delay_exponent" transport parameter must be transmitted only if different
550 * of the default value.
551 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200552 if (p->ack_delay_exponent != QUIC_TP_DFLT_ACK_DELAY_COMPONENT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200553 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACK_DELAY_EXPONENT, p->ack_delay_exponent))
554 return 0;
555
556 /*
557 * "max_ack_delay" transport parameter must be transmitted only if different
558 * of the default value.
559 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200560 if (p->max_ack_delay != QUIC_TP_DFLT_MAX_ACK_DELAY &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200561 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_ACK_DELAY, p->max_ack_delay))
562 return 0;
563
564 /* 0-length value */
565 if (p->disable_active_migration &&
566 !quic_transport_param_encode_type_len(&pos, end, QUIC_TP_DISABLE_ACTIVE_MIGRATION, 0))
567 return 0;
568
569 if (p->active_connection_id_limit &&
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200570 p->active_connection_id_limit != QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200571 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
572 p->active_connection_id_limit))
573 return 0;
574
Ilya Shipitsinace3da82022-11-01 15:46:39 +0500575 if (!quic_transport_param_enc_version_info(&pos, end, chosen_version, server))
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200576 return 0;
577
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200578 return pos - head;
579}
580
581/* Decode transport parameters found in <buf> buffer into <p>, depending on
582 * <server> boolean value which must be set to 1 for a server (haproxy listener)
583 * or 0 for a client (connection to a haproxy server).
584 * Returns 1 if succeeded, 0 if not.
585 */
586static int quic_transport_params_decode(struct quic_transport_params *p, int server,
587 const unsigned char *buf,
588 const unsigned char *end)
589{
590 const unsigned char *pos;
Willy Tarreau33a68702022-11-24 09:16:41 +0100591 uint64_t type, len = 0;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200592
593 pos = buf;
594
595 while (pos != end) {
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200596 if (!quic_transport_param_decode_type_len(&type, &len, &pos, end))
597 return 0;
598
599 if (end - pos < len)
600 return 0;
601
602 if (!quic_transport_param_decode(p, server, type, &pos, len))
603 return 0;
604 }
605
606 /*
607 * A server MUST send original_destination_connection_id transport parameter.
608 * initial_source_connection_id must be present both for server and client.
609 */
610 if ((server && !p->original_destination_connection_id_present) ||
611 !p->initial_source_connection_id_present)
612 return 0;
613
Frédéric Lécaille4afbca62023-03-06 13:57:40 +0100614 /* Note that if not received by the peer, active_connection_id_limit will
615 * have QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT as default value. This
616 * is also the minimum value for this transport parameter.
617 */
618 if (p->active_connection_id_limit < QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT)
619 return 0;
620
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200621 return 1;
622}
623
624/* Store transport parameters found in <buf> buffer into <qc> QUIC connection
625 * depending on <server> value which must be 1 for a server (haproxy listener)
626 * or 0 for a client (connection to a haproxy server).
627 * Note that peer transport parameters are stored in the TX part of the connection:
628 * they are used to send packets to the peer with its transport parameters as
629 * limitations.
630 * Returns 1 if succeeded, 0 if not.
631 */
632int quic_transport_params_store(struct quic_conn *qc, int server,
633 const unsigned char *buf,
634 const unsigned char *end)
635{
636 struct quic_transport_params *tx_params = &qc->tx.params;
Frédéric Lécailleaf25a692023-02-01 17:56:57 +0100637 struct quic_transport_params *rx_params = &qc->rx.params;
Frédéric Lécaille0aa79952023-02-03 16:15:08 +0100638 /* Initial source connection ID */
639 struct tp_cid *iscid;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200640
641 /* initialize peer TPs to RFC default value */
642 quic_dflt_transport_params_cpy(tx_params);
643
644 if (!quic_transport_params_decode(tx_params, server, buf, end))
645 return 0;
646
Frédéric Lécailleaf25a692023-02-01 17:56:57 +0100647 /* Update the connection from transport parameters received */
648 if (tx_params->version_information.negotiated_version &&
649 tx_params->version_information.negotiated_version != qc->original_version)
650 qc->negotiated_version =
651 qc->tx.params.version_information.negotiated_version;
652
653 if (tx_params->max_ack_delay)
654 qc->max_ack_delay = tx_params->max_ack_delay;
655
656 if (tx_params->max_idle_timeout && rx_params->max_idle_timeout)
657 qc->max_idle_timeout =
658 QUIC_MIN(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
659 else
660 qc->max_idle_timeout =
661 QUIC_MAX(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
662 TRACE_PROTO("\nTX(remote) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, tx_params);
663
Frédéric Lécaille0aa79952023-02-03 16:15:08 +0100664 /* Check that the "initial_source_connection_id" transport parameter matches
665 * the SCID received which is also the DCID of the connection.
666 */
667 iscid = &tx_params->initial_source_connection_id;
668 if (qc->dcid.len != iscid->len ||
669 (qc->dcid.len && memcmp(qc->dcid.data, iscid->data, qc->dcid.len))) {
670 TRACE_PROTO("initial_source_connection_id transport parameter mismatch",
671 QUIC_EV_TRANSP_PARAMS, qc);
672 /* Kill the connection as soon as possible */
673 qc_kill_conn(qc);
674 }
675
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200676 return 1;
677}
678
679/* QUIC server (or haproxy listener) only function.
680 * Initialize the local transport parameters <rx_params> from <listener_params>
Ilya Shipitsin4a689da2022-10-29 09:34:32 +0500681 * coming from configuration and Initial packet information (destination
682 * connection ID, source connection ID, original destination connection ID) from
Frédéric Lécaillee9325e92022-08-11 17:24:38 +0200683 * client token.
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200684 * Returns 1 if succeeded, 0 if not.
685 */
686int qc_lstnr_params_init(struct quic_conn *qc,
687 const struct quic_transport_params *listener_params,
688 const unsigned char *stateless_reset_token,
689 const unsigned char *dcid, size_t dcidlen,
690 const unsigned char *scid, size_t scidlen,
Frédéric Lécaille7629f5d2022-08-11 18:54:26 +0200691 const struct quic_cid *token_odcid)
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200692{
693 struct quic_transport_params *rx_params = &qc->rx.params;
694 struct tp_cid *odcid_param = &rx_params->original_destination_connection_id;
695
696 /* Copy the transport parameters. */
697 *rx_params = *listener_params;
698 /* Copy the stateless reset token */
699 memcpy(rx_params->stateless_reset_token, stateless_reset_token,
700 sizeof rx_params->stateless_reset_token);
701 /* Copy original_destination_connection_id transport parameter. */
Amaury Denoyelle9e3026c2022-10-17 11:13:07 +0200702 if (token_odcid->len) {
Frédéric Lécaille7629f5d2022-08-11 18:54:26 +0200703 memcpy(odcid_param->data, token_odcid->data, token_odcid->len);
704 odcid_param->len = token_odcid->len;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200705 /* Copy retry_source_connection_id transport parameter. */
706 memcpy(rx_params->retry_source_connection_id.data, dcid, dcidlen);
707 rx_params->retry_source_connection_id.len = dcidlen;
708 }
709 else {
710 memcpy(odcid_param->data, dcid, dcidlen);
711 odcid_param->len = dcidlen;
712 }
713
714 /* Copy the initial source connection ID. */
715 memcpy(rx_params->initial_source_connection_id.data, scid, scidlen);
716 rx_params->initial_source_connection_id.len = scidlen;
Frédéric Lécaillec7785b52022-05-23 09:08:54 +0200717 TRACE_PROTO("\nRX(local) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, rx_params);
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200718
719 return 1;
720}
721