blob: 23a1ff72552b85eccd6ccd1c8eda2710088b1809 [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 = {
18 .max_udp_payload_size = QUIC_MAX_UDP_PAYLOAD_SIZE,
19 .ack_delay_exponent = QUIC_DFLT_ACK_DELAY_COMPONENT,
20 .max_ack_delay = QUIC_DFLT_MAX_ACK_DELAY,
21 .active_connection_id_limit = QUIC_ACTIVE_CONNECTION_ID_LIMIT,
22};
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;
48 const int max_streams_bidi = 100;
49 const int max_streams_uni = 3;
50
51 /* Set RFC default values for unspecified parameters. */
52 quic_dflt_transport_params_cpy(p);
53
54 p->max_idle_timeout = 30000;
55
56 p->initial_max_streams_bidi = max_streams_bidi;
57 p->initial_max_streams_uni = max_streams_uni;
58 p->initial_max_stream_data_bidi_local = ncb_size;
59 p->initial_max_stream_data_bidi_remote = ncb_size;
60 p->initial_max_stream_data_uni = ncb_size;
61 p->initial_max_data = (max_streams_bidi + max_streams_uni) * ncb_size;
62
63 if (server)
64 p->with_stateless_reset_token = 1;
65
66 p->active_connection_id_limit = 8;
67
68 p->retry_source_connection_id.len = 0;
69}
70
71/* Encode <addr> preferred address transport parameter in <buf> without its
72 * "type+len" prefix. Note that the IP addresses must be encoded in network byte
73 * order.
74 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained values
75 * already encoded in network byte order.
76 * It is the responsibility of the caller to check there is enough room in <buf> to encode
77 * this address.
78 * Never fails.
79 */
80static void quic_transport_param_enc_pref_addr_val(unsigned char **buf,
81 const unsigned char *end,
82 struct tp_preferred_address *addr)
83{
84 write_n16(*buf, addr->ipv4_port);
85 *buf += sizeof addr->ipv4_port;
86
87 memcpy(*buf, addr->ipv4_addr, sizeof addr->ipv4_addr);
88 *buf += sizeof addr->ipv4_addr;
89
90 write_n16(*buf, addr->ipv6_port);
91 *buf += sizeof addr->ipv6_port;
92
93 memcpy(*buf, addr->ipv6_addr, sizeof addr->ipv6_addr);
94 *buf += sizeof addr->ipv6_addr;
95
96 *(*buf)++ = addr->cid.len;
97 if (addr->cid.len) {
98 memcpy(*buf, addr->cid.data, addr->cid.len);
99 *buf += addr->cid.len;
100 }
101
102 memcpy(*buf, addr->stateless_reset_token, sizeof addr->stateless_reset_token);
103 *buf += sizeof addr->stateless_reset_token;
104}
105
106/* Decode into <addr> preferred address transport parameter found in <*buf> buffer.
107 * Returns 1 if succeeded, 0 if not.
108 */
109static int quic_transport_param_dec_pref_addr(struct tp_preferred_address *addr,
110 const unsigned char **buf,
111 const unsigned char *end)
112{
113 ssize_t addr_len;
114
115 addr_len = sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
116 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
117 addr_len += sizeof addr->cid.len;
118
119 if (end - *buf < addr_len)
120 return 0;
121
122 addr->ipv4_port = read_n16(*buf);
123 *buf += sizeof addr->ipv4_port;
124
125 memcpy(addr->ipv4_addr, *buf, sizeof addr->ipv4_addr);
126 *buf += sizeof addr->ipv4_addr;
127
128 addr->ipv6_port = read_n16(*buf);
129 *buf += sizeof addr->ipv6_port;
130
131 memcpy(addr->ipv6_addr, *buf, sizeof addr->ipv6_addr);
132 *buf += sizeof addr->ipv6_addr;
133
134 addr->cid.len = *(*buf)++;
135 if (addr->cid.len) {
136 if (end - *buf > addr->cid.len || addr->cid.len > sizeof addr->cid.data)
137 return 0;
138 memcpy(addr->cid.data, *buf, addr->cid.len);
139 *buf += addr->cid.len;
140 }
141
142 if (end - *buf != sizeof addr->stateless_reset_token)
143 return 0;
144
145 memcpy(addr->stateless_reset_token, *buf, end - *buf);
146 *buf += sizeof addr->stateless_reset_token;
147
148 return *buf == end;
149}
150
151/* Decode into <p> struct a transport parameter found in <*buf> buffer with
152 * <type> as type and <len> as length, depending on <server> boolean value which
153 * must be set to 1 for a server (haproxy listener) or 0 for a client (connection
154 * to an haproxy server).
155 */
156static int quic_transport_param_decode(struct quic_transport_params *p,
157 int server, uint64_t type,
158 const unsigned char **buf, size_t len)
159{
160 const unsigned char *end = *buf + len;
161
162 switch (type) {
163 case QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID:
164 if (!server || len > sizeof p->original_destination_connection_id.data)
165 return 0;
166
167 if (len)
168 memcpy(p->original_destination_connection_id.data, *buf, len);
169 p->original_destination_connection_id.len = len;
170 *buf += len;
171 p->original_destination_connection_id_present = 1;
172 break;
173 case QUIC_TP_INITIAL_SOURCE_CONNECTION_ID:
174 if (len > sizeof p->initial_source_connection_id.data)
175 return 0;
176
177 if (len)
178 memcpy(p->initial_source_connection_id.data, *buf, len);
179 p->initial_source_connection_id.len = len;
180 *buf += len;
181 p->initial_source_connection_id_present = 1;
182 break;
183 case QUIC_TP_STATELESS_RESET_TOKEN:
184 if (!server || len != sizeof p->stateless_reset_token)
185 return 0;
186 memcpy(p->stateless_reset_token, *buf, len);
187 *buf += len;
188 p->with_stateless_reset_token = 1;
189 break;
190 case QUIC_TP_PREFERRED_ADDRESS:
191 if (!server)
192 return 0;
193 if (!quic_transport_param_dec_pref_addr(&p->preferred_address, buf, *buf + len))
194 return 0;
195 p->with_preferred_address = 1;
196 break;
197 case QUIC_TP_MAX_IDLE_TIMEOUT:
198 if (!quic_dec_int(&p->max_idle_timeout, buf, end))
199 return 0;
200 break;
201 case QUIC_TP_MAX_UDP_PAYLOAD_SIZE:
202 if (!quic_dec_int(&p->max_udp_payload_size, buf, end))
203 return 0;
204 break;
205 case QUIC_TP_INITIAL_MAX_DATA:
206 if (!quic_dec_int(&p->initial_max_data, buf, end))
207 return 0;
208 break;
209 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
210 if (!quic_dec_int(&p->initial_max_stream_data_bidi_local, buf, end))
211 return 0;
212 break;
213 case QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
214 if (!quic_dec_int(&p->initial_max_stream_data_bidi_remote, buf, end))
215 return 0;
216 break;
217 case QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
218 if (!quic_dec_int(&p->initial_max_stream_data_uni, buf, end))
219 return 0;
220 break;
221 case QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
222 if (!quic_dec_int(&p->initial_max_streams_bidi, buf, end))
223 return 0;
224 break;
225 case QUIC_TP_INITIAL_MAX_STREAMS_UNI:
226 if (!quic_dec_int(&p->initial_max_streams_uni, buf, end))
227 return 0;
228 break;
229 case QUIC_TP_ACK_DELAY_EXPONENT:
230 if (!quic_dec_int(&p->ack_delay_exponent, buf, end) ||
231 p->ack_delay_exponent > QUIC_TP_ACK_DELAY_EXPONENT_LIMIT)
232 return 0;
233 break;
234 case QUIC_TP_MAX_ACK_DELAY:
235 if (!quic_dec_int(&p->max_ack_delay, buf, end) ||
236 p->max_ack_delay > QUIC_TP_MAX_ACK_DELAY_LIMIT)
237 return 0;
238 break;
239 case QUIC_TP_DISABLE_ACTIVE_MIGRATION:
240 /* Zero-length parameter type. */
241 if (len != 0)
242 return 0;
243 p->disable_active_migration = 1;
244 break;
245 case QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
246 if (!quic_dec_int(&p->active_connection_id_limit, buf, end))
247 return 0;
248 break;
249 default:
250 *buf += len;
251 };
252
253 return *buf == end;
254}
255
256/* Encode <type> and <len> variable length values in <buf>.
257 * Returns 1 if succeeded, 0 if not.
258 */
259static int quic_transport_param_encode_type_len(unsigned char **buf,
260 const unsigned char *end,
261 uint64_t type, uint64_t len)
262{
263 return quic_enc_int(buf, end, type) && quic_enc_int(buf, end, len);
264}
265
266/* Decode variable length type and length values of a QUIC transport parameter
267 * into <type> and <len> found in <*buf> buffer.
268 * Returns 1 if succeeded, 0 if not.
269 */
270static int quic_transport_param_decode_type_len(uint64_t *type, uint64_t *len,
271 const unsigned char **buf,
272 const unsigned char *end)
273{
274 return quic_dec_int(type, buf, end) && quic_dec_int(len, buf, end);
275}
276
277/* Encode <param> bytes stream with <type> as type and <length> as length into buf.
278 * Returns 1 if succeeded, 0 if not.
279 */
280static int quic_transport_param_enc_mem(unsigned char **buf, const unsigned char *end,
281 uint64_t type, void *param, uint64_t length)
282{
283 if (!quic_transport_param_encode_type_len(buf, end, type, length))
284 return 0;
285
286 if (end - *buf < length)
287 return 0;
288
289 if (length)
290 memcpy(*buf, param, length);
291 *buf += length;
292
293 return 1;
294}
295
296/* Encode <val> 64-bits value as variable length integer into <buf>.
297 * Returns 1 if succeeded, 0 if not.
298 */
299static int quic_transport_param_enc_int(unsigned char **buf,
300 const unsigned char *end,
301 uint64_t type, uint64_t val)
302{
303 size_t len;
304
305 len = quic_int_getsize(val);
306
307 return len && quic_transport_param_encode_type_len(buf, end, type, len) &&
308 quic_enc_int(buf, end, val);
309}
310
311/* Returns the required length in bytes to encode <cid> QUIC connection ID. */
312static inline size_t sizeof_quic_cid(const struct tp_cid *cid)
313{
314 return sizeof cid->len + cid->len;
315}
316
317/* Encode <addr> preferred address into <buf>.
318 * Note that the IP addresses must be encoded in network byte order.
319 * So ->ipv4_addr and ->ipv6_addr, which are buffers, must contained
320 * values already encoded in network byte order.
321 * Returns 1 if succeeded, 0 if not.
322 */
323static int quic_transport_param_enc_pref_addr(unsigned char **buf,
324 const unsigned char *end,
325 struct tp_preferred_address *addr)
326{
327 uint64_t addr_len = 0;
328
329 addr_len += sizeof addr->ipv4_port + sizeof addr->ipv4_addr;
330 addr_len += sizeof addr->ipv6_port + sizeof addr->ipv6_addr;
331 addr_len += sizeof_quic_cid(&addr->cid);
332 addr_len += sizeof addr->stateless_reset_token;
333
334 if (!quic_transport_param_encode_type_len(buf, end, QUIC_TP_PREFERRED_ADDRESS, addr_len))
335 return 0;
336
337 if (end - *buf < addr_len)
338 return 0;
339
340 quic_transport_param_enc_pref_addr_val(buf, end, addr);
341
342 return 1;
343}
344
345/* Encode <p> transport parameter into <buf> depending on <server> value which
346 * must be set to 1 for a server (haproxy listener) or 0 for a client
347 * (connection to a haproxy server).
348 * Return the number of bytes consumed if succeeded, 0 if not.
349 */
350int quic_transport_params_encode(unsigned char *buf,
351 const unsigned char *end,
352 struct quic_transport_params *p,
353 int server)
354{
355 unsigned char *head;
356 unsigned char *pos;
357
358 head = pos = buf;
359 if (server) {
360 if (!quic_transport_param_enc_mem(&pos, end,
361 QUIC_TP_ORIGINAL_DESTINATION_CONNECTION_ID,
362 p->original_destination_connection_id.data,
363 p->original_destination_connection_id.len))
364 return 0;
365
366 if (p->retry_source_connection_id.len) {
367 if (!quic_transport_param_enc_mem(&pos, end,
368 QUIC_TP_RETRY_SOURCE_CONNECTION_ID,
369 p->retry_source_connection_id.data,
370 p->retry_source_connection_id.len))
371 return 0;
372 }
373
374 if (p->with_stateless_reset_token &&
375 !quic_transport_param_enc_mem(&pos, end, QUIC_TP_STATELESS_RESET_TOKEN,
376 p->stateless_reset_token,
377 sizeof p->stateless_reset_token))
378 return 0;
379 if (p->with_preferred_address &&
380 !quic_transport_param_enc_pref_addr(&pos, end, &p->preferred_address))
381 return 0;
382 }
383
384 if (!quic_transport_param_enc_mem(&pos, end,
385 QUIC_TP_INITIAL_SOURCE_CONNECTION_ID,
386 p->initial_source_connection_id.data,
387 p->initial_source_connection_id.len))
388 return 0;
389
390 if (p->max_idle_timeout &&
391 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_IDLE_TIMEOUT, p->max_idle_timeout))
392 return 0;
393
394 /*
395 * "max_packet_size" transport parameter must be transmitted only if different
396 * of the default value.
397 */
398 if (p->max_udp_payload_size != QUIC_DFLT_MAX_UDP_PAYLOAD_SIZE &&
399 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_UDP_PAYLOAD_SIZE, p->max_udp_payload_size))
400 return 0;
401
402 if (p->initial_max_data &&
403 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_DATA, p->initial_max_data))
404 return 0;
405
406 if (p->initial_max_stream_data_bidi_local &&
407 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
408 p->initial_max_stream_data_bidi_local))
409 return 0;
410
411 if (p->initial_max_stream_data_bidi_remote &&
412 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
413 p->initial_max_stream_data_bidi_remote))
414 return 0;
415
416 if (p->initial_max_stream_data_uni &&
417 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI,
418 p->initial_max_stream_data_uni))
419 return 0;
420
421 if (p->initial_max_streams_bidi &&
422 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_BIDI,
423 p->initial_max_streams_bidi))
424 return 0;
425
426 if (p->initial_max_streams_uni &&
427 !quic_transport_param_enc_int(&pos, end, QUIC_TP_INITIAL_MAX_STREAMS_UNI,
428 p->initial_max_streams_uni))
429 return 0;
430
431 /*
432 * "ack_delay_exponent" transport parameter must be transmitted only if different
433 * of the default value.
434 */
435 if (p->ack_delay_exponent != QUIC_DFLT_ACK_DELAY_COMPONENT &&
436 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACK_DELAY_EXPONENT, p->ack_delay_exponent))
437 return 0;
438
439 /*
440 * "max_ack_delay" transport parameter must be transmitted only if different
441 * of the default value.
442 */
443 if (p->max_ack_delay != QUIC_DFLT_MAX_ACK_DELAY &&
444 !quic_transport_param_enc_int(&pos, end, QUIC_TP_MAX_ACK_DELAY, p->max_ack_delay))
445 return 0;
446
447 /* 0-length value */
448 if (p->disable_active_migration &&
449 !quic_transport_param_encode_type_len(&pos, end, QUIC_TP_DISABLE_ACTIVE_MIGRATION, 0))
450 return 0;
451
452 if (p->active_connection_id_limit &&
453 p->active_connection_id_limit != QUIC_ACTIVE_CONNECTION_ID_LIMIT &&
454 !quic_transport_param_enc_int(&pos, end, QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT,
455 p->active_connection_id_limit))
456 return 0;
457
458 return pos - head;
459}
460
461/* Decode transport parameters found in <buf> buffer into <p>, depending on
462 * <server> boolean value which must be set to 1 for a server (haproxy listener)
463 * or 0 for a client (connection to a haproxy server).
464 * Returns 1 if succeeded, 0 if not.
465 */
466static int quic_transport_params_decode(struct quic_transport_params *p, int server,
467 const unsigned char *buf,
468 const unsigned char *end)
469{
470 const unsigned char *pos;
471
472 pos = buf;
473
474 while (pos != end) {
475 uint64_t type, len;
476
477 if (!quic_transport_param_decode_type_len(&type, &len, &pos, end))
478 return 0;
479
480 if (end - pos < len)
481 return 0;
482
483 if (!quic_transport_param_decode(p, server, type, &pos, len))
484 return 0;
485 }
486
487 /*
488 * A server MUST send original_destination_connection_id transport parameter.
489 * initial_source_connection_id must be present both for server and client.
490 */
491 if ((server && !p->original_destination_connection_id_present) ||
492 !p->initial_source_connection_id_present)
493 return 0;
494
495 return 1;
496}
497
498/* Store transport parameters found in <buf> buffer into <qc> QUIC connection
499 * depending on <server> value which must be 1 for a server (haproxy listener)
500 * or 0 for a client (connection to a haproxy server).
501 * Note that peer transport parameters are stored in the TX part of the connection:
502 * they are used to send packets to the peer with its transport parameters as
503 * limitations.
504 * Returns 1 if succeeded, 0 if not.
505 */
506int quic_transport_params_store(struct quic_conn *qc, int server,
507 const unsigned char *buf,
508 const unsigned char *end)
509{
510 struct quic_transport_params *tx_params = &qc->tx.params;
511 struct quic_transport_params *rx_params = &qc->rx.params;
512
513 /* initialize peer TPs to RFC default value */
514 quic_dflt_transport_params_cpy(tx_params);
515
516 if (!quic_transport_params_decode(tx_params, server, buf, end))
517 return 0;
518
519 if (tx_params->max_ack_delay)
520 qc->max_ack_delay = tx_params->max_ack_delay;
521
522 if (tx_params->max_idle_timeout && rx_params->max_idle_timeout)
523 qc->max_idle_timeout =
524 QUIC_MIN(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
525 else
526 qc->max_idle_timeout =
527 QUIC_MAX(tx_params->max_idle_timeout, rx_params->max_idle_timeout);
528
Frédéric Lécaillec7785b52022-05-23 09:08:54 +0200529 TRACE_PROTO("\nTX(remote) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, tx_params);
530
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200531 return 1;
532}
533
534/* QUIC server (or haproxy listener) only function.
535 * Initialize the local transport parameters <rx_params> from <listener_params>
536 * coming from configuration and Initial packet information (destintation
537 * connection ID, source connection ID, original destination connection ID,
538 * and if a token was present denoted by <token> boolean value.
539 * Returns 1 if succeeded, 0 if not.
540 */
541int qc_lstnr_params_init(struct quic_conn *qc,
542 const struct quic_transport_params *listener_params,
543 const unsigned char *stateless_reset_token,
544 const unsigned char *dcid, size_t dcidlen,
545 const unsigned char *scid, size_t scidlen,
546 const unsigned char *odcid, size_t odcidlen, int token)
547{
548 struct quic_transport_params *rx_params = &qc->rx.params;
549 struct tp_cid *odcid_param = &rx_params->original_destination_connection_id;
550
551 /* Copy the transport parameters. */
552 *rx_params = *listener_params;
553 /* Copy the stateless reset token */
554 memcpy(rx_params->stateless_reset_token, stateless_reset_token,
555 sizeof rx_params->stateless_reset_token);
556 /* Copy original_destination_connection_id transport parameter. */
557 if (token) {
558 memcpy(odcid_param->data, odcid, odcidlen);
559 odcid_param->len = odcidlen;
560 /* Copy retry_source_connection_id transport parameter. */
561 memcpy(rx_params->retry_source_connection_id.data, dcid, dcidlen);
562 rx_params->retry_source_connection_id.len = dcidlen;
563 }
564 else {
565 memcpy(odcid_param->data, dcid, dcidlen);
566 odcid_param->len = dcidlen;
567 }
568
569 /* Copy the initial source connection ID. */
570 memcpy(rx_params->initial_source_connection_id.data, scid, scidlen);
571 rx_params->initial_source_connection_id.len = scidlen;
Frédéric Lécaillec7785b52022-05-23 09:08:54 +0200572 TRACE_PROTO("\nRX(local) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, rx_params);
Frédéric Lécaille748ece62022-05-21 23:58:40 +0200573
574 return 1;
575}
576