blob: f7f8d7ddd622b5cd276da6f97ca90ee303e141ce [file] [log] [blame]
Frédéric Lécaille748ece62022-05-21 23:58:40 +02001#include <haproxy/global.h>
2#include <haproxy/ncbuf-t.h>
3#include <haproxy/net_helper.h>
4#include <haproxy/quic_enc.h>
5#include <haproxy/quic_tp.h>
Frédéric Lécaillec7785b52022-05-23 09:08:54 +02006#include <haproxy/trace.h>
Frédéric Lécaille748ece62022-05-21 23:58:40 +02007#include <haproxy/xprt_quic-t.h>
8
9#define QUIC_MAX_UDP_PAYLOAD_SIZE 2048
10
Frédéric Lécaillec7785b52022-05-23 09:08:54 +020011#define TRACE_SOURCE &trace_quic
12
Frédéric Lécaille748ece62022-05-21 23:58:40 +020013/* This is the values of some QUIC transport parameters when absent.
14 * Should be used to initialize any transport parameters (local or remote)
15 * before updating them with customized values.
16 */
17struct quic_transport_params quic_dflt_transport_params = {
Frédéric Lécailleaee67572022-05-23 18:29:39 +020018 .max_udp_payload_size = QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE,
19 .ack_delay_exponent = QUIC_TP_DFLT_ACK_DELAY_COMPONENT,
20 .max_ack_delay = QUIC_TP_DFLT_MAX_ACK_DELAY,
21 .active_connection_id_limit = QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT,
Frédéric Lécaille748ece62022-05-21 23:58:40 +020022};
23
24/* Initialize <dst> transport parameters with default values (when absent)
25 * from <quic_dflt_transport_params>.
26 * Never fails.
27 */
28static void quic_dflt_transport_params_cpy(struct quic_transport_params *dst)
29{
30 dst->max_udp_payload_size = quic_dflt_transport_params.max_udp_payload_size;
31 dst->ack_delay_exponent = quic_dflt_transport_params.ack_delay_exponent;
32 dst->max_ack_delay = quic_dflt_transport_params.max_ack_delay;
33 dst->active_connection_id_limit = quic_dflt_transport_params.active_connection_id_limit;
34}
35
36/* Initialize <p> transport parameters. <server> is a boolean, set if TPs are
37 * used by a server (haproxy frontend) else this is for a client (haproxy
38 * backend).
39 *
40 * This must only be used for haproxy local parameters. To initialize peer
41 * parameters, see quic_dflt_transport_params_cpy().
42 *
43 * Never fails.
44 */
45void quic_transport_params_init(struct quic_transport_params *p, int server)
46{
47 const uint64_t ncb_size = global.tune.bufsize - NCB_RESERVED_SZ;
Frédéric Lécaille26740982022-05-23 17:28:01 +020048 const int max_streams_bidi = global.tune.quic_frontend_max_streams_bidi;
Frédéric Lécaille748ece62022-05-21 23:58:40 +020049 const int max_streams_uni = 3;
50
51 /* Set RFC default values for unspecified parameters. */
52 quic_dflt_transport_params_cpy(p);
53
Frédéric Lécailleaee67572022-05-23 18:29:39 +020054 /* Set the max_udp_payload_size value. If not would equal to
55 * QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE
56 */
57 p->max_udp_payload_size = QUIC_MAX_UDP_PAYLOAD_SIZE;
Frédéric Lécaille1d96d6e2022-05-23 16:38:14 +020058 if (server)
59 p->max_idle_timeout = global.tune.quic_frontend_max_idle_timeout;
60 else
61 p->max_idle_timeout = global.tune.quic_backend_max_idle_timeout;
Frédéric Lécaille748ece62022-05-21 23:58:40 +020062
63 p->initial_max_streams_bidi = max_streams_bidi;
64 p->initial_max_streams_uni = max_streams_uni;
65 p->initial_max_stream_data_bidi_local = ncb_size;
66 p->initial_max_stream_data_bidi_remote = ncb_size;
67 p->initial_max_stream_data_uni = ncb_size;
68 p->initial_max_data = (max_streams_bidi + max_streams_uni) * ncb_size;
69
70 if (server)
71 p->with_stateless_reset_token = 1;
72
73 p->active_connection_id_limit = 8;
74
75 p->retry_source_connection_id.len = 0;
76}
77
78/* Encode <addr> preferred address transport parameter in <buf> without its
79 * "type+len" prefix. Note that the IP addresses must be encoded in network byte
80 * order.
81 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained values
82 * already encoded in network byte order.
83 * It is the responsibility of the caller to check there is enough room in <buf> to encode
84 * this address.
85 * Never fails.
86 */
87static void quic_transport_param_enc_pref_addr_val(unsigned char **buf,
88 const unsigned char *end,
89 struct tp_preferred_address *addr)
90{
91 write_n16(*buf, addr->ipv4_port);
92 *buf += sizeof addr->ipv4_port;
93
94 memcpy(*buf, addr->ipv4_addr, sizeof addr->ipv4_addr);
95 *buf += sizeof addr->ipv4_addr;
96
97 write_n16(*buf, addr->ipv6_port);
98 *buf += sizeof addr->ipv6_port;
99
100 memcpy(*buf, addr->ipv6_addr, sizeof addr->ipv6_addr);
101 *buf += sizeof addr->ipv6_addr;
102
103 *(*buf)++ = addr->cid.len;
104 if (addr->cid.len) {
105 memcpy(*buf, addr->cid.data, addr->cid.len);
106 *buf += addr->cid.len;
107 }
108
109 memcpy(*buf, addr->stateless_reset_token, sizeof addr->stateless_reset_token);
110 *buf += sizeof addr->stateless_reset_token;
111}
112
113/* Decode into <addr> preferred address transport parameter found in <*buf> buffer.
114 * Returns 1 if succeeded, 0 if not.
115 */
116static int quic_transport_param_dec_pref_addr(struct tp_preferred_address *addr,
117 const unsigned char **buf,
118 const unsigned char *end)
119{
120 ssize_t addr_len;
121
122 addr_len = sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
123 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
124 addr_len += sizeof addr->cid.len;
125
126 if (end - *buf < addr_len)
127 return 0;
128
129 addr->ipv4_port = read_n16(*buf);
130 *buf += sizeof addr->ipv4_port;
131
132 memcpy(addr->ipv4_addr, *buf, sizeof addr->ipv4_addr);
133 *buf += sizeof addr->ipv4_addr;
134
135 addr->ipv6_port = read_n16(*buf);
136 *buf += sizeof addr->ipv6_port;
137
138 memcpy(addr->ipv6_addr, *buf, sizeof addr->ipv6_addr);
139 *buf += sizeof addr->ipv6_addr;
140
141 addr->cid.len = *(*buf)++;
142 if (addr->cid.len) {
143 if (end - *buf > addr->cid.len || addr->cid.len > sizeof addr->cid.data)
144 return 0;
145 memcpy(addr->cid.data, *buf, addr->cid.len);
146 *buf += addr->cid.len;
147 }
148
149 if (end - *buf != sizeof addr->stateless_reset_token)
150 return 0;
151
152 memcpy(addr->stateless_reset_token, *buf, end - *buf);
153 *buf += sizeof addr->stateless_reset_token;
154
155 return *buf == end;
156}
157
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200158/* Decode into <v> version information received transport parameters from <*buf>
159 * buffer. <server> must be set to 1 for QUIC clients which receive server
160 * transport parameters, and 0 for QUIC servers which receive client transport
161 * parameters.
162 * Also set the QUIC negotiated version into <tp>.
163 * Return 1 if succeeded, 0 if not.
164 */
165static int quic_transport_param_dec_version_info(struct tp_version_information *tp,
166 const unsigned char **buf,
167 const unsigned char *end, int server)
168{
169 size_t tp_len = end - *buf;
170 const uint32_t *ver;
171
172 /* <tp_len> must be a multiple of sizeof(uint32_t) */
173 if (tp_len < sizeof tp->choosen || (tp_len & 0x3))
174 return 0;
175
176 tp->choosen = ntohl(*(uint32_t *)*buf);
177 /* Must not be null */
178 if (!tp->choosen)
179 return 0;
180
181 *buf += sizeof tp->choosen;
182 tp->others = (const uint32_t *)*buf;
183
184 /* Others versions must not be null */
185 for (ver = tp->others; ver < (const uint32_t *)end; ver++) {
186 if (!*ver)
187 return 0;
188 }
189
190 if (server)
191 /* TODO: not supported */
192 return 0;
193
194 for (ver = tp->others; ver < (const uint32_t *)end; ver++) {
195 if (!tp->negotiated_version) {
196 int i;
197
198 for (i = 0; i < quic_versions_nb; i++) {
199 if (ntohl(*ver) == quic_versions[i].num) {
200 tp->negotiated_version = &quic_versions[i];
201 break;
202 }
203 }
204 }
205
206 if (preferred_version && ntohl(*ver) == preferred_version->num) {
207 tp->negotiated_version = preferred_version;
208 goto out;
209 }
210 }
211
212 out:
213 *buf = end;
214
215 return 1;
216}
217
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200218/* Decode into <p> struct a transport parameter found in <*buf> buffer with
219 * <type> as type and <len> as length, depending on <server> boolean value which
220 * must be set to 1 for a server (haproxy listener) or 0 for a client (connection
221 * to an haproxy server).
222 */
223static int quic_transport_param_decode(struct quic_transport_params *p,
224 int server, uint64_t type,
225 const unsigned char **buf, size_t len)
226{
227 const unsigned char *end = *buf + len;
228
229 switch (type) {
230 case QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID:
231 if (!server || len > sizeof p->original_destination_connection_id.data)
232 return 0;
233
234 if (len)
235 memcpy(p->original_destination_connection_id.data, *buf, len);
236 p->original_destination_connection_id.len = len;
237 *buf += len;
238 p->original_destination_connection_id_present = 1;
239 break;
240 case QUIC_TP_INITIAL_SOURCE_CONNECTION_ID:
241 if (len > sizeof p->initial_source_connection_id.data)
242 return 0;
243
244 if (len)
245 memcpy(p->initial_source_connection_id.data, *buf, len);
246 p->initial_source_connection_id.len = len;
247 *buf += len;
248 p->initial_source_connection_id_present = 1;
249 break;
250 case QUIC_TP_STATELESS_RESET_TOKEN:
251 if (!server || len != sizeof p->stateless_reset_token)
252 return 0;
253 memcpy(p->stateless_reset_token, *buf, len);
254 *buf += len;
255 p->with_stateless_reset_token = 1;
256 break;
257 case QUIC_TP_PREFERRED_ADDRESS:
258 if (!server)
259 return 0;
260 if (!quic_transport_param_dec_pref_addr(&p->preferred_address, buf, *buf + len))
261 return 0;
262 p->with_preferred_address = 1;
263 break;
264 case QUIC_TP_MAX_IDLE_TIMEOUT:
265 if (!quic_dec_int(&p->max_idle_timeout, buf, end))
266 return 0;
267 break;
268 case QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
269 if (!quic_dec_int(&p->max_udp_payload_size, buf, end))
270 return 0;
271 break;
272 case QUIC_TP_INITIAL_MAX_DATA:
273 if (!quic_dec_int(&p->initial_max_data, buf, end))
274 return 0;
275 break;
276 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
277 if (!quic_dec_int(&p->initial_max_stream_data_bidi_local, buf, end))
278 return 0;
279 break;
280 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
281 if (!quic_dec_int(&p->initial_max_stream_data_bidi_remote, buf, end))
282 return 0;
283 break;
284 case QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
285 if (!quic_dec_int(&p->initial_max_stream_data_uni, buf, end))
286 return 0;
287 break;
288 case QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
289 if (!quic_dec_int(&p->initial_max_streams_bidi, buf, end))
290 return 0;
291 break;
292 case QUIC_TP_INITIAL_MAX_STREAMS_UNI:
293 if (!quic_dec_int(&p->initial_max_streams_uni, buf, end))
294 return 0;
295 break;
296 case QUIC_TP_ACK_DELAY_EXPONENT:
297 if (!quic_dec_int(&p->ack_delay_exponent, buf, end) ||
298 p->ack_delay_exponent > QUIC_TP_ACK_DELAY_EXPONENT_LIMIT)
299 return 0;
300 break;
301 case QUIC_TP_MAX_ACK_DELAY:
302 if (!quic_dec_int(&p->max_ack_delay, buf, end) ||
303 p->max_ack_delay > QUIC_TP_MAX_ACK_DELAY_LIMIT)
304 return 0;
305 break;
306 case QUIC_TP_DISABLE_ACTIVE_MIGRATION:
307 /* Zero-length parameter type. */
308 if (len != 0)
309 return 0;
310 p->disable_active_migration = 1;
311 break;
312 case QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
313 if (!quic_dec_int(&p->active_connection_id_limit, buf, end))
314 return 0;
315 break;
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200316 case QUIC_TP_DRAFT_VERSION_INFORMATION:
317 if (!quic_transport_param_dec_version_info(&p->version_information,
318 buf, *buf + len, server))
319 return 0;
320 break;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200321 default:
322 *buf += len;
323 };
324
325 return *buf == end;
326}
327
328/* Encode <type> and <len> variable length values in <buf>.
329 * Returns 1 if succeeded, 0 if not.
330 */
331static int quic_transport_param_encode_type_len(unsigned char **buf,
332 const unsigned char *end,
333 uint64_t type, uint64_t len)
334{
335 return quic_enc_int(buf, end, type) && quic_enc_int(buf, end, len);
336}
337
338/* Decode variable length type and length values of a QUIC transport parameter
339 * into <type> and <len> found in <*buf> buffer.
340 * Returns 1 if succeeded, 0 if not.
341 */
342static int quic_transport_param_decode_type_len(uint64_t *type, uint64_t *len,
343 const unsigned char **buf,
344 const unsigned char *end)
345{
346 return quic_dec_int(type, buf, end) && quic_dec_int(len, buf, end);
347}
348
349/* Encode <param> bytes stream with <type> as type and <length> as length into buf.
350 * Returns 1 if succeeded, 0 if not.
351 */
352static int quic_transport_param_enc_mem(unsigned char **buf, const unsigned char *end,
353 uint64_t type, void *param, uint64_t length)
354{
355 if (!quic_transport_param_encode_type_len(buf, end, type, length))
356 return 0;
357
358 if (end - *buf < length)
359 return 0;
360
361 if (length)
362 memcpy(*buf, param, length);
363 *buf += length;
364
365 return 1;
366}
367
368/* Encode <val> 64-bits value as variable length integer into <buf>.
369 * Returns 1 if succeeded, 0 if not.
370 */
371static int quic_transport_param_enc_int(unsigned char **buf,
372 const unsigned char *end,
373 uint64_t type, uint64_t val)
374{
375 size_t len;
376
377 len = quic_int_getsize(val);
378
379 return len && quic_transport_param_encode_type_len(buf, end, type, len) &&
380 quic_enc_int(buf, end, val);
381}
382
383/* Returns the required length in bytes to encode <cid> QUIC connection ID. */
384static inline size_t sizeof_quic_cid(const struct tp_cid *cid)
385{
386 return sizeof cid->len + cid->len;
387}
388
389/* Encode <addr> preferred address into <buf>.
390 * Note that the IP addresses must be encoded in network byte order.
391 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained
392 * values already encoded in network byte order.
393 * Returns 1 if succeeded, 0 if not.
394 */
395static int quic_transport_param_enc_pref_addr(unsigned char **buf,
396 const unsigned char *end,
397 struct tp_preferred_address *addr)
398{
399 uint64_t addr_len = 0;
400
401 addr_len += sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
402 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
403 addr_len += sizeof_quic_cid(&addr->cid);
404 addr_len += sizeof addr->stateless_reset_token;
405
406 if (!quic_transport_param_encode_type_len(buf, end, QUIC_TP_PREFERRED_ADDRESS, addr_len))
407 return 0;
408
409 if (end - *buf < addr_len)
410 return 0;
411
412 quic_transport_param_enc_pref_addr_val(buf, end, addr);
413
414 return 1;
415}
416
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200417/* Encode version information transport parameters with <choosen_version> as choosen
418 * version.
419 * Return 1 if succeeded, 0 if not.
420 */
421static int quic_transport_param_enc_version_info(unsigned char **buf,
422 const unsigned char *end,
423 const struct quic_version *choosen_version,
424 int server)
425{
426 int i;
427 uint64_t tp_len;
428 uint32_t ver;
429
430 tp_len = sizeof choosen_version->num + quic_versions_nb * sizeof(uint32_t);
431 if (!quic_transport_param_encode_type_len(buf, end,
432 QUIC_TP_DRAFT_VERSION_INFORMATION,
433 tp_len))
434 return 0;
435
436 if (end - *buf < tp_len)
437 return 0;
438
439 /* First: choosen version */
440 ver = htonl(choosen_version->num);
441 memcpy(*buf, &ver, sizeof ver);
442 *buf += sizeof ver;
443 /* For servers: all supported version, choosen included */
444 for (i = 0; i < quic_versions_nb; i++) {
445 ver = htonl(quic_versions[i].num);
446 memcpy(*buf, &ver, sizeof ver);
447 *buf += sizeof ver;
448 }
449
450 return 1;
451}
452
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200453/* Encode <p> transport parameter into <buf> depending on <server> value which
454 * must be set to 1 for a server (haproxy listener) or 0 for a client
455 * (connection to a haproxy server).
456 * Return the number of bytes consumed if succeeded, 0 if not.
457 */
458int quic_transport_params_encode(unsigned char *buf,
459 const unsigned char *end,
460 struct quic_transport_params *p,
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200461 const struct quic_version *choosen_version,
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200462 int server)
463{
464 unsigned char *head;
465 unsigned char *pos;
466
467 head = pos = buf;
468 if (server) {
469 if (!quic_transport_param_enc_mem(&pos, end,
470 QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID,
471 p->original_destination_connection_id.data,
472 p->original_destination_connection_id.len))
473 return 0;
474
475 if (p->retry_source_connection_id.len) {
476 if (!quic_transport_param_enc_mem(&pos, end,
477 QUIC_TP_RETRY_SOURCE_CONNECTION_ID,
478 p->retry_source_connection_id.data,
479 p->retry_source_connection_id.len))
480 return 0;
481 }
482
483 if (p->with_stateless_reset_token &&
484 !quic_transport_param_enc_mem(&pos, end, QUIC_TP_STATELESS_RESET_TOKEN,
485 p->stateless_reset_token,
486 sizeof p->stateless_reset_token))
487 return 0;
488 if (p->with_preferred_address &&
489 !quic_transport_param_enc_pref_addr(&pos, end, &p->preferred_address))
490 return 0;
491 }
492
493 if (!quic_transport_param_enc_mem(&pos, end,
494 QUIC_TP_INITIAL_SOURCE_CONNECTION_ID,
495 p->initial_source_connection_id.data,
496 p->initial_source_connection_id.len))
497 return 0;
498
499 if (p->max_idle_timeout &&
500 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_IDLE_TIMEOUT, p->max_idle_timeout))
501 return 0;
502
503 /*
504 * "max_packet_size" transport parameter must be transmitted only if different
505 * of the default value.
506 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200507 if (p->max_udp_payload_size != QUIC_TP_DFLT_MAX_UDP_PAYLOAD_SIZE &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200508 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_UDP_PAYLOAD_SIZE, p->max_udp_payload_size))
509 return 0;
510
511 if (p->initial_max_data &&
512 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_DATA, p->initial_max_data))
513 return 0;
514
515 if (p->initial_max_stream_data_bidi_local &&
516 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
517 p->initial_max_stream_data_bidi_local))
518 return 0;
519
520 if (p->initial_max_stream_data_bidi_remote &&
521 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
522 p->initial_max_stream_data_bidi_remote))
523 return 0;
524
525 if (p->initial_max_stream_data_uni &&
526 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
527 p->initial_max_stream_data_uni))
528 return 0;
529
530 if (p->initial_max_streams_bidi &&
531 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
532 p->initial_max_streams_bidi))
533 return 0;
534
535 if (p->initial_max_streams_uni &&
536 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_UNI,
537 p->initial_max_streams_uni))
538 return 0;
539
540 /*
541 * "ack_delay_exponent" transport parameter must be transmitted only if different
542 * of the default value.
543 */
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200544 if (p->ack_delay_exponent != QUIC_TP_DFLT_ACK_DELAY_COMPONENT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200545 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACK_DELAY_EXPONENT, p->ack_delay_exponent))
546 return 0;
547
548 /*
549 * "max_ack_delay" 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->max_ack_delay != QUIC_TP_DFLT_MAX_ACK_DELAY &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200553 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_ACK_DELAY, p->max_ack_delay))
554 return 0;
555
556 /* 0-length value */
557 if (p->disable_active_migration &&
558 !quic_transport_param_encode_type_len(&pos, end, QUIC_TP_DISABLE_ACTIVE_MIGRATION, 0))
559 return 0;
560
561 if (p->active_connection_id_limit &&
Frédéric Lécailleaee67572022-05-23 18:29:39 +0200562 p->active_connection_id_limit != QUIC_TP_DFLT_ACTIVE_CONNECTION_ID_LIMIT &&
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200563 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
564 p->active_connection_id_limit))
565 return 0;
566
Frédéric Lécaille301425b2022-06-14 17:40:39 +0200567 if (!quic_transport_param_enc_version_info(&pos, end, choosen_version, server))
568 return 0;
569
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200570 return pos - head;
571}
572
573/* Decode transport parameters found in <buf> buffer into <p>, depending on
574 * <server> boolean value which must be set to 1 for a server (haproxy listener)
575 * or 0 for a client (connection to a haproxy server).
576 * Returns 1 if succeeded, 0 if not.
577 */
578static int quic_transport_params_decode(struct quic_transport_params *p, int server,
579 const unsigned char *buf,
580 const unsigned char *end)
581{
582 const unsigned char *pos;
583
584 pos = buf;
585
586 while (pos != end) {
587 uint64_t type, len;
588
589 if (!quic_transport_param_decode_type_len(&type, &len, &pos, end))
590 return 0;
591
592 if (end - pos < len)
593 return 0;
594
595 if (!quic_transport_param_decode(p, server, type, &pos, len))
596 return 0;
597 }
598
599 /*
600 * A server MUST send original_destination_connection_id transport parameter.
601 * initial_source_connection_id must be present both for server and client.
602 */
603 if ((server && !p->original_destination_connection_id_present) ||
604 !p->initial_source_connection_id_present)
605 return 0;
606
607 return 1;
608}
609
610/* Store transport parameters found in <buf> buffer into <qc> QUIC connection
611 * depending on <server> value which must be 1 for a server (haproxy listener)
612 * or 0 for a client (connection to a haproxy server).
613 * Note that peer transport parameters are stored in the TX part of the connection:
614 * they are used to send packets to the peer with its transport parameters as
615 * limitations.
616 * Returns 1 if succeeded, 0 if not.
617 */
618int quic_transport_params_store(struct quic_conn *qc, int server,
619 const unsigned char *buf,
620 const unsigned char *end)
621{
622 struct quic_transport_params *tx_params = &qc->tx.params;
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200623
624 /* initialize peer TPs to RFC default value */
625 quic_dflt_transport_params_cpy(tx_params);
626
627 if (!quic_transport_params_decode(tx_params, server, buf, end))
628 return 0;
629
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200630 return 1;
631}
632
633/* QUIC server (or haproxy listener) only function.
634 * Initialize the local transport parameters <rx_params> from <listener_params>
635 * coming from configuration and Initial packet information (destintation
636 * connection ID, source connection ID, original destination connection ID,
637 * and if a token was present denoted by <token> boolean value.
638 * Returns 1 if succeeded, 0 if not.
639 */
640int qc_lstnr_params_init(struct quic_conn *qc,
641 const struct quic_transport_params *listener_params,
642 const unsigned char *stateless_reset_token,
643 const unsigned char *dcid, size_t dcidlen,
644 const unsigned char *scid, size_t scidlen,
645 const unsigned char *odcid, size_t odcidlen, int token)
646{
647 struct quic_transport_params *rx_params = &qc->rx.params;
648 struct tp_cid *odcid_param = &rx_params->original_destination_connection_id;
649
650 /* Copy the transport parameters. */
651 *rx_params = *listener_params;
652 /* Copy the stateless reset token */
653 memcpy(rx_params->stateless_reset_token, stateless_reset_token,
654 sizeof rx_params->stateless_reset_token);
655 /* Copy original_destination_connection_id transport parameter. */
656 if (token) {
657 memcpy(odcid_param->data, odcid, odcidlen);
658 odcid_param->len = odcidlen;
659 /* Copy retry_source_connection_id transport parameter. */
660 memcpy(rx_params->retry_source_connection_id.data, dcid, dcidlen);
661 rx_params->retry_source_connection_id.len = dcidlen;
662 }
663 else {
664 memcpy(odcid_param->data, dcid, dcidlen);
665 odcid_param->len = dcidlen;
666 }
667
668 /* Copy the initial source connection ID. */
669 memcpy(rx_params->initial_source_connection_id.data, scid, scidlen);
670 rx_params->initial_source_connection_id.len = scidlen;
Frédéric Lécaillec7785b52022-05-23 09:08:54 +0200671 TRACE_PROTO("\nRX(local) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, rx_params);
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200672
673 return 1;
674}
675