comparison src/event/quic/ngx_event_quic_output.c @ 8971:1e2f4e9c8195 quic

QUIC: reworked migration handling. The quic connection now holds active, backup and probe paths instead of sockets. The number of migration paths is now limited and cannot be inflated by a bad client or an attacker. The client id is now associated with path rather than socket. This allows to simplify processing of output and connection ids handling. New migration abandons any previously started migrations. This allows to free consumed client ids and request new for use in future migrations and make progress in case when connection id limit is hit during migration. A path now can be revalidated without losing its state. The patch also fixes various issues with NAT rebinding case handling: - paths are now validated (previously, there was no validation and paths were left in limited state) - attempt to reuse id on different path is now again verified (this was broken in 40445fc7c403) - former path is now validated in case of apparent migration
author Vladimir Homutov <vl@nginx.com>
date Wed, 19 Jan 2022 22:39:24 +0300
parents 19e063e955bf
children e5509ff0dfd2
comparison
equal deleted inserted replaced
8970:7106a918a277 8971:1e2f4e9c8195
49 size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment); 49 size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment);
50 #endif 50 #endif
51 static ssize_t ngx_quic_output_packet(ngx_connection_t *c, 51 static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
52 ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min); 52 ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min);
53 static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, 53 static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
54 ngx_quic_header_t *pkt); 54 ngx_quic_header_t *pkt, ngx_quic_path_t *path);
55 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c); 55 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
56 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len, 56 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
57 struct sockaddr *sockaddr, socklen_t socklen); 57 struct sockaddr *sockaddr, socklen_t socklen);
58 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, 58 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt,
59 ngx_quic_send_ctx_t *ctx); 59 ngx_quic_send_ctx_t *ctx);
129 ngx_quic_connection_t *qc; 129 ngx_quic_connection_t *qc;
130 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; 130 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
131 131
132 qc = ngx_quic_get_connection(c); 132 qc = ngx_quic_get_connection(c);
133 cg = &qc->congestion; 133 cg = &qc->congestion;
134 path = qc->socket->path; 134 path = qc->path;
135 135
136 while (cg->in_flight < cg->window) { 136 while (cg->in_flight < cg->window) {
137 137
138 p = dst; 138 p = dst;
139 139
267 267
268 if (!qc->conf->gso_enabled) { 268 if (!qc->conf->gso_enabled) {
269 return 0; 269 return 0;
270 } 270 }
271 271
272 if (qc->socket->path->limited) { 272 if (qc->path->limited) {
273 /* don't even try to be faster on non-validated paths */ 273 /* don't even try to be faster on non-validated paths */
274 return 0; 274 return 0;
275 } 275 }
276 276
277 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); 277 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial);
323 ngx_quic_connection_t *qc; 323 ngx_quic_connection_t *qc;
324 static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF]; 324 static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF];
325 325
326 qc = ngx_quic_get_connection(c); 326 qc = ngx_quic_get_connection(c);
327 cg = &qc->congestion; 327 cg = &qc->congestion;
328 path = qc->socket->path; 328 path = qc->path;
329 329
330 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); 330 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
331 331
332 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { 332 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) {
333 return NGX_ERROR; 333 return NGX_ERROR;
503 503
504 static ssize_t 504 static ssize_t
505 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, 505 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
506 u_char *data, size_t max, size_t min) 506 u_char *data, size_t max, size_t min)
507 { 507 {
508 size_t len, pad, min_payload, max_payload; 508 size_t len, pad, min_payload, max_payload;
509 u_char *p; 509 u_char *p;
510 ssize_t flen; 510 ssize_t flen;
511 ngx_str_t res; 511 ngx_str_t res;
512 ngx_int_t rc; 512 ngx_int_t rc;
513 ngx_uint_t nframes, expand; 513 ngx_uint_t nframes, expand;
514 ngx_msec_t now; 514 ngx_msec_t now;
515 ngx_queue_t *q; 515 ngx_queue_t *q;
516 ngx_quic_frame_t *f; 516 ngx_quic_frame_t *f;
517 ngx_quic_header_t pkt; 517 ngx_quic_header_t pkt;
518 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; 518 ngx_quic_connection_t *qc;
519 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
519 520
520 if (ngx_queue_empty(&ctx->frames)) { 521 if (ngx_queue_empty(&ctx->frames)) {
521 return 0; 522 return 0;
522 } 523 }
523 524
524 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, 525 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
525 "quic output %s packet max:%uz min:%uz", 526 "quic output %s packet max:%uz min:%uz",
526 ngx_quic_level_name(ctx->level), max, min); 527 ngx_quic_level_name(ctx->level), max, min);
527 528
528 ngx_quic_init_packet(c, ctx, &pkt); 529 qc = ngx_quic_get_connection(c);
530
531 ngx_quic_init_packet(c, ctx, &pkt, qc->path);
529 532
530 min_payload = ngx_quic_payload_size(&pkt, min); 533 min_payload = ngx_quic_payload_size(&pkt, min);
531 max_payload = ngx_quic_payload_size(&pkt, max); 534 max_payload = ngx_quic_payload_size(&pkt, max);
532 535
533 /* RFC 9001, 5.4.2. Header Protection Sample */ 536 /* RFC 9001, 5.4.2. Header Protection Sample */
666 } 669 }
667 670
668 671
669 static void 672 static void
670 ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, 673 ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
671 ngx_quic_header_t *pkt) 674 ngx_quic_header_t *pkt, ngx_quic_path_t *path)
672 { 675 {
673 ngx_quic_socket_t *qsock; 676 ngx_quic_socket_t *qsock;
674 ngx_quic_connection_t *qc; 677 ngx_quic_connection_t *qc;
675 678
676 qc = ngx_quic_get_connection(c); 679 qc = ngx_quic_get_connection(c);
677 680
678 qsock = qc->socket; 681 qsock = ngx_quic_get_socket(c);
679 682
680 ngx_memzero(pkt, sizeof(ngx_quic_header_t)); 683 ngx_memzero(pkt, sizeof(ngx_quic_header_t));
681 684
682 pkt->flags = NGX_QUIC_PKT_FIXED_BIT; 685 pkt->flags = NGX_QUIC_PKT_FIXED_BIT;
683 686
691 if (qc->key_phase) { 694 if (qc->key_phase) {
692 pkt->flags |= NGX_QUIC_PKT_KPHASE; 695 pkt->flags |= NGX_QUIC_PKT_KPHASE;
693 } 696 }
694 } 697 }
695 698
696 pkt->dcid.data = qsock->cid->id; 699 pkt->dcid.data = path->cid->id;
697 pkt->dcid.len = qsock->cid->len; 700 pkt->dcid.len = path->cid->len;
698 701
699 pkt->scid.data = qsock->sid.id; 702 pkt->scid.data = qsock->sid.id;
700 pkt->scid.len = qsock->sid.len; 703 pkt->scid.len = qsock->sid.len;
701 704
702 pkt->version = qc->version; 705 pkt->version = qc->version;
1200 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; 1203 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
1201 1204
1202 qc = ngx_quic_get_connection(c); 1205 qc = ngx_quic_get_connection(c);
1203 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); 1206 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
1204 1207
1205 ngx_quic_init_packet(c, ctx, &pkt); 1208 ngx_quic_init_packet(c, ctx, &pkt, path);
1206 1209
1207 min = ngx_quic_path_limit(c, path, min); 1210 min = ngx_quic_path_limit(c, path, min);
1208 1211
1209 min_payload = min ? ngx_quic_payload_size(&pkt, min) : 0; 1212 min_payload = min ? ngx_quic_payload_size(&pkt, min) : 0;
1210 1213