comparison src/event/quic/ngx_event_quic_output.c @ 8763:4117aa7fa38e quic

QUIC: connection migration. The patch adds proper transitions between multiple networking addresses that can be used by a single quic connection. New networking paths are validated using PATH_CHALLENGE/PATH_RESPONSE frames.
author Vladimir Homutov <vl@nginx.com>
date Thu, 29 Apr 2021 15:35:02 +0300
parents bc910a5ec737
children 4715f3e669f1
comparison
equal deleted inserted replaced
8762:12f18e0bca09 8763:4117aa7fa38e
33 #define NGX_QUIC_MAX_SR_PACKET 1200 33 #define NGX_QUIC_MAX_SR_PACKET 1200
34 34
35 #define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */ 35 #define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */
36 36
37 37
38 static ngx_int_t ngx_quic_socket_output(ngx_connection_t *c,
39 ngx_quic_socket_t *qsock);
38 static ssize_t ngx_quic_output_packet(ngx_connection_t *c, 40 static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
39 ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min); 41 ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min,
42 ngx_quic_socket_t *qsock);
40 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c); 43 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
41 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len); 44 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
45 struct sockaddr *sockaddr, socklen_t socklen);
42 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, 46 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt,
43 ngx_quic_send_ctx_t *ctx); 47 ngx_quic_send_ctx_t *ctx);
44 48
45 49
46 size_t 50 size_t
58 } 62 }
59 63
60 64
61 ngx_int_t 65 ngx_int_t
62 ngx_quic_output(ngx_connection_t *c) 66 ngx_quic_output(ngx_connection_t *c)
67 {
68 ngx_quic_connection_t *qc;
69
70 qc = ngx_quic_get_connection(c);
71
72 if (ngx_quic_socket_output(c, qc->socket) != NGX_OK) {
73 return NGX_ERROR;
74 }
75
76 ngx_quic_set_lost_timer(c);
77
78 return NGX_OK;
79 }
80
81
82 static ngx_int_t
83 ngx_quic_socket_output(ngx_connection_t *c, ngx_quic_socket_t *qsock)
63 { 84 {
64 off_t max; 85 off_t max;
65 size_t len, min, in_flight; 86 size_t len, min, in_flight;
66 ssize_t n; 87 ssize_t n;
67 u_char *p; 88 u_char *p;
68 ngx_uint_t i, pad; 89 ngx_uint_t i, pad;
90 ngx_quic_path_t *path;
69 ngx_quic_send_ctx_t *ctx; 91 ngx_quic_send_ctx_t *ctx;
70 ngx_quic_congestion_t *cg; 92 ngx_quic_congestion_t *cg;
71 ngx_quic_connection_t *qc; 93 ngx_quic_connection_t *qc;
72 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; 94 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
73 95
76 qc = ngx_quic_get_connection(c); 98 qc = ngx_quic_get_connection(c);
77 cg = &qc->congestion; 99 cg = &qc->congestion;
78 100
79 in_flight = cg->in_flight; 101 in_flight = cg->in_flight;
80 102
103 path = qsock->path;
104
81 for ( ;; ) { 105 for ( ;; ) {
82 p = dst; 106 p = dst;
83 107
84 len = ngx_min(qc->ctp.max_udp_payload_size, 108 len = ngx_min(qc->ctp.max_udp_payload_size,
85 NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); 109 NGX_QUIC_MAX_UDP_PAYLOAD_SIZE);
86 110
87 if (!qc->validated) { 111 if (path->state != NGX_QUIC_PATH_VALIDATED) {
88 max = qc->received * 3; 112 max = path->received * 3;
89 max = (c->sent >= max) ? 0 : max - c->sent; 113 max = (path->sent >= max) ? 0 : max - path->sent;
114
90 len = ngx_min(len, (size_t) max); 115 len = ngx_min(len, (size_t) max);
91 } 116 }
92 117
93 pad = ngx_quic_get_padding_level(c); 118 pad = ngx_quic_get_padding_level(c);
94 119
101 } 126 }
102 127
103 min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE) 128 min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE)
104 ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0; 129 ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0;
105 130
106 n = ngx_quic_output_packet(c, ctx, p, len, min); 131 n = ngx_quic_output_packet(c, ctx, p, len, min, qsock);
107 if (n == NGX_ERROR) { 132 if (n == NGX_ERROR) {
108 return NGX_ERROR; 133 return NGX_ERROR;
109 } 134 }
110 135
111 p += n; 136 p += n;
115 len = p - dst; 140 len = p - dst;
116 if (len == 0) { 141 if (len == 0) {
117 break; 142 break;
118 } 143 }
119 144
120 n = ngx_quic_send(c, dst, len); 145 n = ngx_quic_send(c, dst, len, path->sockaddr, path->socklen);
146
121 if (n == NGX_ERROR) { 147 if (n == NGX_ERROR) {
122 return NGX_ERROR; 148 return NGX_ERROR;
123 } 149 }
150
151 path->sent += len;
124 } 152 }
125 153
126 if (in_flight != cg->in_flight && !qc->send_timer_set && !qc->closing) { 154 if (in_flight != cg->in_flight && !qc->send_timer_set && !qc->closing) {
127 qc->send_timer_set = 1; 155 qc->send_timer_set = 1;
128 ngx_add_timer(c->read, qc->tp.max_idle_timeout); 156 ngx_add_timer(c->read, qc->tp.max_idle_timeout);
129 } 157 }
130 158
131 ngx_quic_set_lost_timer(c);
132 159
133 return NGX_OK; 160 return NGX_OK;
134 } 161 }
135 162
136 163
174 } 201 }
175 202
176 203
177 static ssize_t 204 static ssize_t
178 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, 205 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
179 u_char *data, size_t max, size_t min) 206 u_char *data, size_t max, size_t min, ngx_quic_socket_t *qsock)
180 { 207 {
181 size_t len, hlen, pad_len; 208 size_t len, hlen, pad_len;
182 u_char *p; 209 u_char *p;
183 ssize_t flen; 210 ssize_t flen;
184 ngx_str_t out, res; 211 ngx_str_t out, res;
185 ngx_int_t rc; 212 ngx_int_t rc;
186 ngx_uint_t nframes; 213 ngx_uint_t nframes, has_pr;
187 ngx_msec_t now; 214 ngx_msec_t now;
188 ngx_queue_t *q; 215 ngx_queue_t *q;
189 ngx_quic_frame_t *f; 216 ngx_quic_frame_t *f;
190 ngx_quic_header_t pkt; 217 ngx_quic_header_t pkt;
191 ngx_quic_congestion_t *cg; 218 ngx_quic_congestion_t *cg;
194 221
195 if (ngx_queue_empty(&ctx->frames)) { 222 if (ngx_queue_empty(&ctx->frames)) {
196 return 0; 223 return 0;
197 } 224 }
198 225
199 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, 226 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
200 "quic output %s packet max:%uz min:%uz", 227 "quic output sock #%uL %s packet max:%uz min:%uz",
201 ngx_quic_level_name(ctx->level), max, min); 228 qsock->sid.seqnum, ngx_quic_level_name(ctx->level),
229 max, min);
202 230
203 qc = ngx_quic_get_connection(c); 231 qc = ngx_quic_get_connection(c);
204 cg = &qc->congestion; 232 cg = &qc->congestion;
205 233
206 hlen = (ctx->level == ssl_encryption_application) 234 hlen = (ctx->level == ssl_encryption_application)
207 ? NGX_QUIC_MAX_SHORT_HEADER 235 ? NGX_QUIC_MAX_SHORT_HEADER
208 : NGX_QUIC_MAX_LONG_HEADER; 236 : NGX_QUIC_MAX_LONG_HEADER;
209 237
210 hlen += EVP_GCM_TLS_TAG_LEN; 238 hlen += EVP_GCM_TLS_TAG_LEN;
211 hlen -= NGX_QUIC_MAX_CID_LEN - qc->scid.len; 239 hlen -= NGX_QUIC_MAX_CID_LEN - qsock->cid->len;
212 240
213 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); 241 ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
214 242
215 now = ngx_current_msec; 243 now = ngx_current_msec;
216 nframes = 0; 244 nframes = 0;
217 p = src; 245 p = src;
218 len = 0; 246 len = 0;
247 has_pr = 0;
219 248
220 for (q = ngx_queue_head(&ctx->frames); 249 for (q = ngx_queue_head(&ctx->frames);
221 q != ngx_queue_sentinel(&ctx->frames); 250 q != ngx_queue_sentinel(&ctx->frames);
222 q = ngx_queue_next(q)) 251 q = ngx_queue_next(q))
223 { 252 {
225 254
226 if (!pkt.need_ack && f->need_ack && max > cg->window) { 255 if (!pkt.need_ack && f->need_ack && max > cg->window) {
227 max = cg->window; 256 max = cg->window;
228 } 257 }
229 258
259 if (f->type == NGX_QUIC_FT_PATH_RESPONSE
260 || f->type == NGX_QUIC_FT_PATH_CHALLENGE)
261 {
262 has_pr = 1;
263 }
264
230 if (hlen + len >= max) { 265 if (hlen + len >= max) {
231 break; 266 break;
232 } 267 }
233 268
234 if (hlen + len + f->len > max) { 269 if (hlen + len + f->len > max) {
294 ngx_quic_set_packet_number(&pkt, ctx); 329 ngx_quic_set_packet_number(&pkt, ctx);
295 330
296 pkt.version = qc->version; 331 pkt.version = qc->version;
297 pkt.log = c->log; 332 pkt.log = c->log;
298 pkt.level = ctx->level; 333 pkt.level = ctx->level;
299 pkt.dcid = qc->scid; 334
300 pkt.scid = qc->dcid; 335 pkt.dcid.data = qsock->cid->id;
336 pkt.dcid.len = qsock->cid->len;
337
338 pkt.scid.data = qsock->sid.id;
339 pkt.scid.len = qsock->sid.len;
301 340
302 pad_len = 4; 341 pad_len = 4;
303 342
304 if (min) { 343 if (min || has_pr) {
305 hlen = EVP_GCM_TLS_TAG_LEN 344 hlen = EVP_GCM_TLS_TAG_LEN
306 + ngx_quic_create_header(&pkt, NULL, out.len, NULL); 345 + ngx_quic_create_header(&pkt, NULL, out.len, NULL);
346
347 /*
348 * An endpoint MUST expand datagrams that contain a
349 * PATH_CHALLENGE frame to at least the smallest allowed
350 * maximum datagram size of 1200 bytes, unless the
351 * anti-amplification limit for the path does not permit
352 * sending a datagram of this size.
353 *
354 * (same applies to PATH_RESPONSE frames)
355 */
356
357 if (has_pr) {
358 min = ngx_max(1200, min);
359 }
307 360
308 if (min > hlen + pad_len) { 361 if (min > hlen + pad_len) {
309 pad_len = min - hlen; 362 pad_len = min - hlen;
310 } 363 }
311 } 364 }
362 415
363 return res.len; 416 return res.len;
364 } 417 }
365 418
366 419
367 ssize_t 420 static ssize_t
368 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len) 421 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
369 { 422 struct sockaddr *sockaddr, socklen_t socklen)
370 ngx_buf_t b; 423 {
371 ngx_chain_t cl, *res; 424 ngx_buf_t b;
425 socklen_t orig_socklen;
426 ngx_chain_t cl, *res;
427 struct sockaddr *orig_sockaddr;
372 428
373 ngx_memzero(&b, sizeof(ngx_buf_t)); 429 ngx_memzero(&b, sizeof(ngx_buf_t));
374 430
375 b.pos = b.start = buf; 431 b.pos = b.start = buf;
376 b.last = b.end = buf + len; 432 b.last = b.end = buf + len;
378 b.temporary = 1; 434 b.temporary = 1;
379 435
380 cl.buf = &b; 436 cl.buf = &b;
381 cl.next= NULL; 437 cl.next= NULL;
382 438
439 orig_socklen = c->socklen;
440 orig_sockaddr = c->sockaddr;
441
442 c->sockaddr = sockaddr;
443 c->socklen = socklen;
444
383 res = c->send_chain(c, &cl, 0); 445 res = c->send_chain(c, &cl, 0);
446
447 c->sockaddr = orig_sockaddr;
448 c->socklen = orig_socklen;
449
384 if (res == NGX_CHAIN_ERROR) { 450 if (res == NGX_CHAIN_ERROR) {
385 return NGX_ERROR; 451 return NGX_ERROR;
386 } 452 }
387 453
388 return len; 454 return len;
439 #ifdef NGX_QUIC_DEBUG_PACKETS 505 #ifdef NGX_QUIC_DEBUG_PACKETS
440 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, 506 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
441 "quic vnego packet to send len:%uz %*xs", len, len, buf); 507 "quic vnego packet to send len:%uz %*xs", len, len, buf);
442 #endif 508 #endif
443 509
444 (void) ngx_quic_send(c, buf, len); 510 (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen);
445 511
446 return NGX_ERROR; 512 return NGX_ERROR;
447 } 513 }
448 514
449 515
522 != NGX_OK) 588 != NGX_OK)
523 { 589 {
524 return NGX_ERROR; 590 return NGX_ERROR;
525 } 591 }
526 592
527 (void) ngx_quic_send(c, buf, len); 593 (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen);
528 594
529 return NGX_DECLINED; 595 return NGX_DECLINED;
530 } 596 }
531 597
532 598
640 706
641 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { 707 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
642 return NGX_ERROR; 708 return NGX_ERROR;
643 } 709 }
644 710
645 if (ngx_quic_send(c, res.data, res.len) == NGX_ERROR) { 711 if (ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen)
712 == NGX_ERROR)
713 {
646 return NGX_ERROR; 714 return NGX_ERROR;
647 } 715 }
648 716
649 return NGX_OK; 717 return NGX_OK;
650 } 718 }
662 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; 730 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE];
663 u_char dcid[NGX_QUIC_SERVER_CID_LEN]; 731 u_char dcid[NGX_QUIC_SERVER_CID_LEN];
664 732
665 expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME; 733 expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME;
666 734
667 if (ngx_quic_new_token(c, conf->av_token_key, &token, &inpkt->dcid, 735 if (ngx_quic_new_token(c, c->sockaddr, c->socklen, conf->av_token_key,
668 expires, 1) 736 &token, &inpkt->dcid, expires, 1)
669 != NGX_OK) 737 != NGX_OK)
670 { 738 {
671 return NGX_ERROR; 739 return NGX_ERROR;
672 } 740 }
673 741
698 #ifdef NGX_QUIC_DEBUG_PACKETS 766 #ifdef NGX_QUIC_DEBUG_PACKETS
699 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, 767 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
700 "quic packet to send len:%uz %xV", res.len, &res); 768 "quic packet to send len:%uz %xV", res.len, &res);
701 #endif 769 #endif
702 770
703 len = ngx_quic_send(c, res.data, res.len); 771 len = ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen);
704 if (len == NGX_ERROR) { 772 if (len == NGX_ERROR) {
705 return NGX_ERROR; 773 return NGX_ERROR;
706 } 774 }
707 775
708 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, 776 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
716 return NGX_DONE; 784 return NGX_DONE;
717 } 785 }
718 786
719 787
720 ngx_int_t 788 ngx_int_t
721 ngx_quic_send_new_token(ngx_connection_t *c) 789 ngx_quic_send_new_token(ngx_connection_t *c, ngx_quic_path_t *path)
722 { 790 {
723 time_t expires; 791 time_t expires;
724 ngx_str_t token; 792 ngx_str_t token;
725 ngx_quic_frame_t *frame; 793 ngx_quic_frame_t *frame;
726 ngx_quic_connection_t *qc; 794 ngx_quic_connection_t *qc;
727 795
728 qc = ngx_quic_get_connection(c); 796 qc = ngx_quic_get_connection(c);
729 797
730 if (!qc->conf->retry) {
731 return NGX_OK;
732 }
733
734 expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME; 798 expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME;
735 799
736 if (ngx_quic_new_token(c, qc->conf->av_token_key, &token, NULL, expires, 0) 800 if (ngx_quic_new_token(c, path->sockaddr, path->socklen,
801 qc->conf->av_token_key, &token, NULL, expires, 0)
737 != NGX_OK) 802 != NGX_OK)
738 { 803 {
739 return NGX_ERROR; 804 return NGX_ERROR;
740 } 805 }
741 806
847 912
848 ngx_quic_queue_frame(qc, frame); 913 ngx_quic_queue_frame(qc, frame);
849 914
850 return NGX_OK; 915 return NGX_OK;
851 } 916 }
917
918
919 ssize_t
920 ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
921 size_t min, struct sockaddr *sockaddr, socklen_t socklen)
922 {
923 ssize_t len;
924 ngx_str_t res;
925 ngx_quic_header_t pkt;
926 ngx_quic_send_ctx_t *ctx;
927 ngx_quic_connection_t *qc;
928
929 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
930 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
931
932 qc = ngx_quic_get_connection(c);
933
934 ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
935
936 len = ngx_quic_create_frame(NULL, frame);
937 if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) {
938 return -1;
939 }
940
941 ngx_quic_log_frame(c->log, frame, 1);
942
943 len = ngx_quic_create_frame(src, frame);
944 if (len == -1) {
945 return -1;
946 }
947
948 if (len < (ssize_t) min) {
949 ngx_memset(src + len, NGX_QUIC_FT_PADDING, min - len);
950 len = min;
951 }
952
953 pkt.keys = qc->keys;
954 pkt.flags = NGX_QUIC_PKT_FIXED_BIT;
955
956 if (qc->key_phase) {
957 pkt.flags |= NGX_QUIC_PKT_KPHASE;
958 }
959
960 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
961
962 ngx_quic_set_packet_number(&pkt, ctx);
963
964 pkt.version = qc->version;
965 pkt.log = c->log;
966 pkt.level = ctx->level;
967
968 pkt.dcid.data = qc->socket->cid->id;
969 pkt.dcid.len = qc->socket->cid->len;
970
971 pkt.scid.data = qc->socket->sid.id;
972 pkt.scid.len = qc->socket->sid.len;
973
974 pkt.payload.data = src;
975 pkt.payload.len = len;
976
977 res.data = dst;
978
979 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
980 return -1;
981 }
982
983 ctx->pnum++;
984
985 len = ngx_quic_send(c, res.data, res.len, sockaddr, socklen);
986
987 return len;
988 }