Mercurial > hg > nginx
comparison src/event/ngx_event_quic.c @ 8224:ae35ccba7aa6 quic
Extracted transport part of the code into separate file.
All code dealing with serializing/deserializing
is moved int srv/event/ngx_event_quic_transport.c/h file.
All macros for dealing with data are internal to source file.
The header file exposes frame types and error codes.
The exported functions are currently packet header parsers and writers
and frames parser/writer.
The ngx_quic_header_t structure is updated with 'log' member. This avoids
passing extra argument to parsing functions that need to report errors.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 18 Mar 2020 12:58:27 +0300 |
parents | 61f9b873e2e7 |
children | 714a19dba6af |
comparison
equal
deleted
inserted
replaced
8223:61f9b873e2e7 | 8224:ae35ccba7aa6 |
---|---|
5 | 5 |
6 | 6 |
7 #include <ngx_config.h> | 7 #include <ngx_config.h> |
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_event.h> | 9 #include <ngx_event.h> |
10 | |
11 | |
12 /* 12.4. Frames and Frame Types */ | |
13 #define NGX_QUIC_FT_PADDING 0x00 | |
14 #define NGX_QUIC_FT_PING 0x01 | |
15 #define NGX_QUIC_FT_ACK 0x02 | |
16 #define NGX_QUIC_FT_ACK_ECN 0x03 | |
17 #define NGX_QUIC_FT_RESET_STREAM 0x04 | |
18 #define NGX_QUIC_FT_STOP_SENDING 0x05 | |
19 #define NGX_QUIC_FT_CRYPTO 0x06 | |
20 #define NGX_QUIC_FT_NEW_TOKEN 0x07 | |
21 #define NGX_QUIC_FT_STREAM0 0x08 | |
22 #define NGX_QUIC_FT_STREAM1 0x09 | |
23 #define NGX_QUIC_FT_STREAM2 0x0A | |
24 #define NGX_QUIC_FT_STREAM3 0x0B | |
25 #define NGX_QUIC_FT_STREAM4 0x0C | |
26 #define NGX_QUIC_FT_STREAM5 0x0D | |
27 #define NGX_QUIC_FT_STREAM6 0x0E | |
28 #define NGX_QUIC_FT_STREAM7 0x0F | |
29 #define NGX_QUIC_FT_MAX_DATA 0x10 | |
30 #define NGX_QUIC_FT_MAX_STREAM_DATA 0x11 | |
31 #define NGX_QUIC_FT_MAX_STREAMS 0x12 | |
32 #define NGX_QUIC_FT_MAX_STREAMS2 0x13 // XXX | |
33 #define NGX_QUIC_FT_DATA_BLOCKED 0x14 | |
34 #define NGX_QUIC_FT_STREAM_DATA_BLOCKED 0x15 | |
35 #define NGX_QUIC_FT_STREAMS_BLOCKED 0x16 | |
36 #define NGX_QUIC_FT_STREAMS_BLOCKED2 0x17 // XXX | |
37 #define NGX_QUIC_FT_NEW_CONNECTION_ID 0x18 | |
38 #define NGX_QUIC_FT_RETIRE_CONNECTION_ID 0x19 | |
39 #define NGX_QUIC_FT_PATH_CHALLENGE 0x1a | |
40 #define NGX_QUIC_FT_PATH_RESPONSE 0x1b | |
41 #define NGX_QUIC_FT_CONNECTION_CLOSE 0x1c | |
42 #define NGX_QUIC_FT_CONNECTION_CLOSE2 0x1d // XXX | |
43 #define NGX_QUIC_FT_HANDSHAKE_DONE 0x1e | |
44 | |
45 #define ngx_quic_stream_bit_off(val) (((val) & 0x04) ? 1 : 0) | |
46 #define ngx_quic_stream_bit_len(val) (((val) & 0x02) ? 1 : 0) | |
47 #define ngx_quic_stream_bit_fin(val) (((val) & 0x01) ? 1 : 0) | |
48 | |
49 | |
50 #define NGX_QUIC_ERR_NO_ERROR 0x0 | |
51 #define NGX_QUIC_ERR_INTERNAL_ERROR 0x1 | |
52 #define NGX_QUIC_ERR_SERVER_BUSY 0x2 | |
53 #define NGX_QUIC_ERR_FLOW_CONTROL_ERROR 0x3 | |
54 #define NGX_QUIC_ERR_STREAM_LIMIT_ERROR 0x4 | |
55 #define NGX_QUIC_ERR_STREAM_STATE_ERROR 0x5 | |
56 #define NGX_QUIC_ERR_FINAL_SIZE_ERROR 0x6 | |
57 #define NGX_QUIC_ERR_FRAME_ENCODING_ERROR 0x7 | |
58 #define NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR 0x8 | |
59 #define NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR 0x9 | |
60 #define NGX_QUIC_ERR_PROTOCOL_VIOLATION 0xA | |
61 #define NGX_QUIC_ERR_INVALID_TOKEN 0xB | |
62 /* 0xC is not defined */ | |
63 #define NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED 0xD | |
64 #define NGX_QUIC_ERR_CRYPTO_ERROR 0x10 | |
65 | |
66 #define NGX_QUIC_ERR_LAST NGX_QUIC_ERR_CRYPTO_ERROR | |
67 | |
68 /* literal errors indexed by corresponding value */ | |
69 static char *ngx_quic_errors[] = { | |
70 "NO_ERROR", | |
71 "INTERNAL_ERROR", | |
72 "SERVER_BUSY", | |
73 "FLOW_CONTROL_ERROR", | |
74 "STREAM_LIMIT_ERROR", | |
75 "STREAM_STATE_ERROR", | |
76 "FINAL_SIZE_ERROR", | |
77 "FRAME_ENCODING_ERROR", | |
78 "TRANSPORT_PARAMETER_ERROR", | |
79 "CONNECTION_ID_LIMIT_ERROR", | |
80 "PROTOCOL_VIOLATION", | |
81 "INVALID_TOKEN", | |
82 "", | |
83 "CRYPTO_BUFFER_EXCEEDED", | |
84 "CRYPTO_ERROR", | |
85 }; | |
86 | 10 |
87 | 11 |
88 /* TODO: real states, these are stubs */ | 12 /* TODO: real states, these are stubs */ |
89 typedef enum { | 13 typedef enum { |
90 NGX_QUIC_ST_INITIAL, | 14 NGX_QUIC_ST_INITIAL, |
91 NGX_QUIC_ST_HANDSHAKE, | 15 NGX_QUIC_ST_HANDSHAKE, |
92 NGX_QUIC_ST_APP_DATA | 16 NGX_QUIC_ST_APP_DATA |
93 } ngx_quic_state_t; | 17 } ngx_quic_state_t; |
94 | |
95 | |
96 typedef struct ngx_quic_frame_s ngx_quic_frame_t; | |
97 | |
98 typedef struct { | |
99 ngx_uint_t pn; | |
100 | |
101 // input | |
102 uint64_t largest; | |
103 uint64_t delay; | |
104 uint64_t range_count; | |
105 uint64_t first_range; | |
106 uint64_t ranges[20]; | |
107 /* ecn counts */ | |
108 } ngx_quic_ack_frame_t; | |
109 | |
110 typedef struct { | |
111 size_t offset; | |
112 size_t len; | |
113 u_char *data; | |
114 } ngx_quic_crypto_frame_t; | |
115 | |
116 | |
117 typedef struct { | |
118 uint64_t seqnum; | |
119 uint64_t retire; | |
120 uint64_t len; | |
121 u_char cid[20]; | |
122 u_char srt[16]; | |
123 } ngx_quic_ncid_t; | |
124 | |
125 | |
126 typedef struct { | |
127 uint8_t type; | |
128 uint64_t stream_id; | |
129 uint64_t offset; | |
130 uint64_t length; | |
131 u_char *data; | |
132 } ngx_quic_stream_frame_t; | |
133 | |
134 | |
135 typedef struct { | |
136 uint64_t error_code; | |
137 uint64_t frame_type; | |
138 ngx_str_t reason; | |
139 } ngx_quic_close_frame_t; | |
140 | |
141 | |
142 struct ngx_quic_frame_s { | |
143 ngx_uint_t type; | |
144 ngx_quic_level_t level; | |
145 ngx_quic_frame_t *next; | |
146 union { | |
147 ngx_quic_crypto_frame_t crypto; | |
148 ngx_quic_ack_frame_t ack; | |
149 ngx_quic_ncid_t ncid; | |
150 ngx_quic_stream_frame_t stream; | |
151 ngx_quic_close_frame_t close; | |
152 // more frames | |
153 } u; | |
154 | |
155 u_char info[128]; // for debug purposes | |
156 }; | |
157 | 18 |
158 | 19 |
159 struct ngx_quic_connection_s { | 20 struct ngx_quic_connection_s { |
160 | 21 |
161 ngx_quic_state_t state; | 22 ngx_quic_state_t state; |
227 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); | 88 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); |
228 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); | 89 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); |
229 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, | 90 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, |
230 enum ssl_encryption_level_t level, uint8_t alert); | 91 enum ssl_encryption_level_t level, uint8_t alert); |
231 | 92 |
232 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c, | |
233 ngx_quic_header_t *pkt); | |
234 static ngx_int_t ngx_quic_process_short_header(ngx_connection_t *c, | |
235 ngx_quic_header_t *pkt); | |
236 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c, | |
237 ngx_quic_header_t *pkt); | |
238 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c, | |
239 ngx_quic_header_t *pkt); | |
240 | |
241 static uint64_t ngx_quic_parse_int(u_char **pos); | |
242 | 93 |
243 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, | 94 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, |
244 size_t size); | 95 size_t size); |
245 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, | 96 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, |
246 size_t size); | 97 size_t size); |
280 | 131 |
281 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | 132 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); |
282 | 133 |
283 b = c->buffer; | 134 b = c->buffer; |
284 | 135 |
136 pkt.log = c->log; | |
285 pkt.raw = b; | 137 pkt.raw = b; |
286 pkt.data = b->start; | 138 pkt.data = b->start; |
287 pkt.len = b->last - b->start; | 139 pkt.len = b->last - b->start; |
288 | 140 |
289 if (ngx_quic_new_connection(c, ssl, &pkt) != NGX_OK) { | 141 if (ngx_quic_new_connection(c, ssl, &pkt) != NGX_OK) { |
405 do { | 257 do { |
406 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | 258 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); |
407 pkt.raw = b; | 259 pkt.raw = b; |
408 pkt.data = p; | 260 pkt.data = p; |
409 pkt.len = b->last - p; | 261 pkt.len = b->last - p; |
262 pkt.log = c->log; | |
410 | 263 |
411 if (p[0] == 0) { | 264 if (p[0] == 0) { |
412 /* XXX: no idea WTF is this, just ignore */ | 265 /* XXX: no idea WTF is this, just ignore */ |
413 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "FIREFOX: ZEROES"); | 266 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "FIREFOX: ZEROES"); |
414 break; | 267 break; |
446 return NGX_OK; | 299 return NGX_OK; |
447 } | 300 } |
448 | 301 |
449 static ngx_int_t | 302 static ngx_int_t |
450 ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc, | 303 ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc, |
451 ngx_quic_level_t level, ngx_str_t *payload) | 304 enum ssl_encryption_level_t level, ngx_str_t *payload) |
452 { | 305 { |
453 ngx_str_t res; | 306 ngx_str_t res; |
454 ngx_quic_header_t pkt; | 307 ngx_quic_header_t pkt; |
308 | |
309 pkt.log = c->log; | |
455 | 310 |
456 static ngx_str_t initial_token = ngx_null_string; | 311 static ngx_str_t initial_token = ngx_null_string; |
457 | 312 |
458 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | 313 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); |
459 ngx_quic_hexdump0(c->log, "payload", payload->data, payload->len); | 314 ngx_quic_hexdump0(c->log, "payload", payload->data, payload->len); |
492 | 347 |
493 return NGX_OK; | 348 return NGX_OK; |
494 } | 349 } |
495 | 350 |
496 | 351 |
497 static size_t | |
498 ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack) | |
499 { | |
500 size_t len; | |
501 | |
502 /* minimal ACK packet */ | |
503 | |
504 if (p == NULL) { | |
505 len = ngx_quic_varint_len(NGX_QUIC_FT_ACK); | |
506 len += ngx_quic_varint_len(ack->pn); | |
507 len += ngx_quic_varint_len(0); | |
508 len += ngx_quic_varint_len(0); | |
509 len += ngx_quic_varint_len(ack->pn); | |
510 | |
511 return len; | |
512 } | |
513 | |
514 ngx_quic_build_int(&p, NGX_QUIC_FT_ACK); | |
515 ngx_quic_build_int(&p, ack->pn); | |
516 ngx_quic_build_int(&p, 0); | |
517 ngx_quic_build_int(&p, 0); | |
518 ngx_quic_build_int(&p, ack->pn); | |
519 | |
520 return 5; | |
521 } | |
522 | |
523 | |
524 static size_t | |
525 ngx_quic_create_crypto(u_char *p, ngx_quic_crypto_frame_t *crypto) | |
526 { | |
527 size_t len; | |
528 u_char *start; | |
529 | |
530 if (p == NULL) { | |
531 len = ngx_quic_varint_len(NGX_QUIC_FT_CRYPTO); | |
532 len += ngx_quic_varint_len(crypto->offset); | |
533 len += ngx_quic_varint_len(crypto->len); | |
534 len += crypto->len; | |
535 | |
536 return len; | |
537 } | |
538 | |
539 start = p; | |
540 | |
541 ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO); | |
542 ngx_quic_build_int(&p, crypto->offset); | |
543 ngx_quic_build_int(&p, crypto->len); | |
544 p = ngx_cpymem(p, crypto->data, crypto->len); | |
545 | |
546 return p - start; | |
547 } | |
548 | |
549 | |
550 static size_t | |
551 ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf) | |
552 { | |
553 size_t len; | |
554 u_char *start; | |
555 | |
556 if (!ngx_quic_stream_bit_len(sf->type)) { | |
557 #if 0 | |
558 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
559 "attempt to generate a stream frame without length"); | |
560 #endif | |
561 // XXX: handle error in caller | |
562 return NGX_ERROR; | |
563 } | |
564 | |
565 if (p == NULL) { | |
566 len = ngx_quic_varint_len(sf->type); | |
567 | |
568 if (ngx_quic_stream_bit_off(sf->type)) { | |
569 len += ngx_quic_varint_len(sf->offset); | |
570 } | |
571 | |
572 len += ngx_quic_varint_len(sf->stream_id); | |
573 | |
574 /* length is always present in generated frames */ | |
575 len += ngx_quic_varint_len(sf->length); | |
576 | |
577 len += sf->length; | |
578 | |
579 return len; | |
580 } | |
581 | |
582 start = p; | |
583 | |
584 ngx_quic_build_int(&p, sf->type); | |
585 ngx_quic_build_int(&p, sf->stream_id); | |
586 | |
587 if (ngx_quic_stream_bit_off(sf->type)) { | |
588 ngx_quic_build_int(&p, sf->offset); | |
589 } | |
590 | |
591 /* length is always present in generated frames */ | |
592 ngx_quic_build_int(&p, sf->length); | |
593 | |
594 p = ngx_cpymem(p, sf->data, sf->length); | |
595 | |
596 return p - start; | |
597 } | |
598 | |
599 | |
600 size_t | |
601 ngx_quic_frame_len(ngx_quic_frame_t *frame) | |
602 { | |
603 switch (frame->type) { | |
604 case NGX_QUIC_FT_ACK: | |
605 return ngx_quic_create_ack(NULL, &frame->u.ack); | |
606 case NGX_QUIC_FT_CRYPTO: | |
607 return ngx_quic_create_crypto(NULL, &frame->u.crypto); | |
608 | |
609 case NGX_QUIC_FT_STREAM0: | |
610 case NGX_QUIC_FT_STREAM1: | |
611 case NGX_QUIC_FT_STREAM2: | |
612 case NGX_QUIC_FT_STREAM3: | |
613 case NGX_QUIC_FT_STREAM4: | |
614 case NGX_QUIC_FT_STREAM5: | |
615 case NGX_QUIC_FT_STREAM6: | |
616 case NGX_QUIC_FT_STREAM7: | |
617 return ngx_quic_create_stream(NULL, &frame->u.stream); | |
618 default: | |
619 /* BUG: unsupported frame type generated */ | |
620 return 0; | |
621 } | |
622 } | |
623 | |
624 | |
625 /* pack a group of frames [start; end) into memory p and send as single packet */ | 352 /* pack a group of frames [start; end) into memory p and send as single packet */ |
626 ngx_int_t | 353 ngx_int_t |
627 ngx_quic_frames_send(ngx_connection_t *c, ngx_quic_frame_t *start, | 354 ngx_quic_frames_send(ngx_connection_t *c, ngx_quic_frame_t *start, |
628 ngx_quic_frame_t *end, size_t total) | 355 ngx_quic_frame_t *end, size_t total) |
629 { | 356 { |
357 ssize_t len; | |
630 u_char *p; | 358 u_char *p; |
631 ngx_str_t out; | 359 ngx_str_t out; |
632 ngx_quic_frame_t *f; | 360 ngx_quic_frame_t *f; |
633 | 361 |
634 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 362 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
643 | 371 |
644 for (f = start; f != end; f = f->next) { | 372 for (f = start; f != end; f = f->next) { |
645 | 373 |
646 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "frame: %s", f->info); | 374 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "frame: %s", f->info); |
647 | 375 |
648 switch (f->type) { | 376 len = ngx_quic_create_frame(p, p + total, f); |
649 case NGX_QUIC_FT_ACK: | 377 if (len == -1) { |
650 p += ngx_quic_create_ack(p, &f->u.ack); | |
651 break; | |
652 | |
653 case NGX_QUIC_FT_CRYPTO: | |
654 p += ngx_quic_create_crypto(p, &f->u.crypto); | |
655 break; | |
656 | |
657 case NGX_QUIC_FT_STREAM0: | |
658 case NGX_QUIC_FT_STREAM1: | |
659 case NGX_QUIC_FT_STREAM2: | |
660 case NGX_QUIC_FT_STREAM3: | |
661 case NGX_QUIC_FT_STREAM4: | |
662 case NGX_QUIC_FT_STREAM5: | |
663 case NGX_QUIC_FT_STREAM6: | |
664 case NGX_QUIC_FT_STREAM7: | |
665 p += ngx_quic_create_stream(p, &f->u.stream); | |
666 break; | |
667 | |
668 default: | |
669 /* BUG: unsupported frame type generated */ | |
670 return NGX_ERROR; | 378 return NGX_ERROR; |
671 } | 379 } |
380 | |
381 p += len; | |
672 } | 382 } |
673 | 383 |
674 out.len = p - out.data; | 384 out.len = p - out.data; |
675 | 385 |
676 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 386 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
889 (int) level, (int) alert); | 599 (int) level, (int) alert); |
890 | 600 |
891 return 1; | 601 return 1; |
892 } | 602 } |
893 | 603 |
894 | |
895 static ngx_int_t | |
896 ngx_quic_process_short_header(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
897 { | |
898 u_char *p; | |
899 | |
900 p = pkt->data; | |
901 | |
902 ngx_quic_hexdump0(c->log, "short input", pkt->data, pkt->len); | |
903 | |
904 if ((p[0] & NGX_QUIC_PKT_LONG)) { | |
905 ngx_log_error(NGX_LOG_INFO, c->log, 0, "not a short packet"); | |
906 return NGX_ERROR; | |
907 } | |
908 | |
909 pkt->flags = *p++; | |
910 | |
911 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
912 "quic flags:%xi", pkt->flags); | |
913 | |
914 if (ngx_memcmp(p, c->quic->dcid.data, c->quic->dcid.len) != 0) { | |
915 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid"); | |
916 return NGX_ERROR; | |
917 } | |
918 | |
919 pkt->dcid.len = c->quic->dcid.len; | |
920 pkt->dcid.data = p; | |
921 p += pkt->dcid.len; | |
922 | |
923 pkt->raw->pos = p; | |
924 | |
925 return NGX_OK; | |
926 } | |
927 | |
928 | |
929 static ngx_int_t | |
930 ngx_quic_process_long_header(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
931 { | |
932 u_char *p; | |
933 | |
934 p = pkt->data; | |
935 | |
936 ngx_quic_hexdump0(c->log, "long input", pkt->data, pkt->len); | |
937 | |
938 if (!(p[0] & NGX_QUIC_PKT_LONG)) { | |
939 ngx_log_error(NGX_LOG_INFO, c->log, 0, "not a long packet"); | |
940 return NGX_ERROR; | |
941 } | |
942 | |
943 pkt->flags = *p++; | |
944 | |
945 pkt->version = ngx_quic_parse_uint32(p); | |
946 p += sizeof(uint32_t); | |
947 | |
948 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
949 "quic flags:%xi version:%xD", pkt->flags, pkt->version); | |
950 | |
951 if (pkt->version != quic_version) { | |
952 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unsupported quic version"); | |
953 return NGX_ERROR; | |
954 } | |
955 | |
956 pkt->dcid.len = *p++; | |
957 pkt->dcid.data = p; | |
958 p += pkt->dcid.len; | |
959 | |
960 pkt->scid.len = *p++; | |
961 pkt->scid.data = p; | |
962 p += pkt->scid.len; | |
963 | |
964 pkt->raw->pos = p; | |
965 | |
966 return NGX_OK; | |
967 } | |
968 | |
969 | |
970 static ngx_int_t | |
971 ngx_quic_process_initial_header(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
972 { | |
973 u_char *p; | |
974 ngx_int_t plen; | |
975 | |
976 p = pkt->raw->pos; | |
977 | |
978 pkt->token.len = ngx_quic_parse_int(&p); | |
979 pkt->token.data = p; | |
980 | |
981 p += pkt->token.len; | |
982 | |
983 plen = ngx_quic_parse_int(&p); | |
984 | |
985 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
986 "quic packet length: %d", plen); | |
987 | |
988 if (plen > pkt->data + pkt->len - p) { | |
989 ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated initial packet"); | |
990 return NGX_ERROR; | |
991 } | |
992 | |
993 pkt->raw->pos = p; | |
994 pkt->len = plen; | |
995 | |
996 ngx_quic_hexdump0(c->log, "DCID", pkt->dcid.data, pkt->dcid.len); | |
997 ngx_quic_hexdump0(c->log, "SCID", pkt->scid.data, pkt->scid.len); | |
998 ngx_quic_hexdump0(c->log, "token", pkt->token.data, pkt->token.len); | |
999 | |
1000 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1001 "quic packet length: %d", plen); | |
1002 | |
1003 return NGX_OK; | |
1004 } | |
1005 | |
1006 static ngx_int_t | |
1007 ngx_quic_process_handshake_header(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
1008 { | |
1009 u_char *p; | |
1010 ngx_int_t plen; | |
1011 | |
1012 p = pkt->raw->pos; | |
1013 | |
1014 plen = ngx_quic_parse_int(&p); | |
1015 | |
1016 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1017 "quic packet length: %d", plen); | |
1018 | |
1019 if (plen > pkt->data + pkt->len - p) { | |
1020 ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated handshake packet"); | |
1021 return NGX_ERROR; | |
1022 } | |
1023 | |
1024 pkt->raw->pos = p; | |
1025 pkt->len = plen; | |
1026 | |
1027 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1028 "quic packet length: %d", plen); | |
1029 | |
1030 return NGX_OK; | |
1031 } | |
1032 | |
1033 | |
1034 ssize_t | |
1035 ngx_quic_read_frame(ngx_connection_t *c, u_char *start, u_char *end, | |
1036 ngx_quic_frame_t *frame) | |
1037 { | |
1038 u_char *p; | |
1039 | |
1040 size_t npad; | |
1041 | |
1042 p = start; | |
1043 | |
1044 frame->type = *p++; // TODO: check overflow (p < end) | |
1045 | |
1046 switch (frame->type) { | |
1047 | |
1048 case NGX_QUIC_FT_CRYPTO: | |
1049 frame->u.crypto.offset = *p++; | |
1050 frame->u.crypto.len = ngx_quic_parse_int(&p); | |
1051 frame->u.crypto.data = p; | |
1052 p += frame->u.crypto.len; | |
1053 | |
1054 ngx_quic_hexdump0(c->log, "CRYPTO frame", | |
1055 frame->u.crypto.data, frame->u.crypto.len); | |
1056 | |
1057 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1058 "quic CRYPTO frame length: %uL off:%uL pp:%p", | |
1059 frame->u.crypto.len, frame->u.crypto.offset, | |
1060 frame->u.crypto.data); | |
1061 break; | |
1062 | |
1063 case NGX_QUIC_FT_PADDING: | |
1064 npad = 0; | |
1065 while (p < end && *p == NGX_QUIC_FT_PADDING) { // XXX | |
1066 p++; npad++; | |
1067 } | |
1068 | |
1069 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1070 "PADDING frame length %uL", npad); | |
1071 | |
1072 break; | |
1073 | |
1074 case NGX_QUIC_FT_ACK: | |
1075 case NGX_QUIC_FT_ACK_ECN: | |
1076 | |
1077 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ACK frame"); | |
1078 | |
1079 frame->u.ack.largest = ngx_quic_parse_int(&p); | |
1080 frame->u.ack.delay = ngx_quic_parse_int(&p); | |
1081 frame->u.ack.range_count =ngx_quic_parse_int(&p); | |
1082 frame->u.ack.first_range =ngx_quic_parse_int(&p); | |
1083 | |
1084 if (frame->u.ack.range_count) { | |
1085 frame->u.ack.ranges[0] = ngx_quic_parse_int(&p); | |
1086 } | |
1087 | |
1088 if (frame->type ==NGX_QUIC_FT_ACK_ECN) { | |
1089 return NGX_ERROR; | |
1090 } | |
1091 | |
1092 break; | |
1093 | |
1094 case NGX_QUIC_FT_PING: | |
1095 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "PING frame"); | |
1096 break; | |
1097 | |
1098 case NGX_QUIC_FT_NEW_CONNECTION_ID: | |
1099 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "NCID frame"); | |
1100 | |
1101 frame->u.ncid.seqnum = ngx_quic_parse_int(&p); | |
1102 frame->u.ncid.retire = ngx_quic_parse_int(&p); | |
1103 frame->u.ncid.len = *p++; | |
1104 ngx_memcpy(frame->u.ncid.cid, p, frame->u.ncid.len); | |
1105 p += frame->u.ncid.len; | |
1106 | |
1107 ngx_memcpy(frame->u.ncid.srt, p, 16); | |
1108 p += 16; | |
1109 | |
1110 break; | |
1111 | |
1112 case NGX_QUIC_FT_CONNECTION_CLOSE: | |
1113 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "connection close frame"); | |
1114 | |
1115 frame->u.close.error_code = ngx_quic_parse_int(&p); | |
1116 frame->u.close.frame_type = ngx_quic_parse_int(&p); // not in 0x1d CC | |
1117 frame->u.close.reason.len = ngx_quic_parse_int(&p); | |
1118 frame->u.close.reason.data = p; | |
1119 p += frame->u.close.reason.len; | |
1120 | |
1121 if (frame->u.close.error_code > NGX_QUIC_ERR_LAST) { | |
1122 frame->u.close.error_code = NGX_QUIC_ERR_LAST; | |
1123 } | |
1124 break; | |
1125 | |
1126 case NGX_QUIC_FT_STREAM0: | |
1127 case NGX_QUIC_FT_STREAM1: | |
1128 case NGX_QUIC_FT_STREAM2: | |
1129 case NGX_QUIC_FT_STREAM3: | |
1130 case NGX_QUIC_FT_STREAM4: | |
1131 case NGX_QUIC_FT_STREAM5: | |
1132 case NGX_QUIC_FT_STREAM6: | |
1133 case NGX_QUIC_FT_STREAM7: | |
1134 | |
1135 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1136 "STREAM frame, type: 0x%xi", frame->type); | |
1137 | |
1138 frame->u.stream.type = frame->type; | |
1139 | |
1140 frame->u.stream.stream_id = ngx_quic_parse_int(&p); | |
1141 if (frame->type & 0x04) { | |
1142 frame->u.stream.offset = ngx_quic_parse_int(&p); | |
1143 } else { | |
1144 frame->u.stream.offset = 0; | |
1145 } | |
1146 | |
1147 if (frame->type & 0x02) { | |
1148 frame->u.stream.length = ngx_quic_parse_int(&p); | |
1149 } else { | |
1150 frame->u.stream.length = end - p; /* up to packet end */ | |
1151 } | |
1152 | |
1153 frame->u.stream.data = p; | |
1154 | |
1155 p += frame->u.stream.length; | |
1156 | |
1157 break; | |
1158 | |
1159 default: | |
1160 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1161 "unknown frame type %xi", frame->type); | |
1162 return NGX_ERROR; | |
1163 } | |
1164 | |
1165 return p - start; | |
1166 } | |
1167 | 604 |
1168 | 605 |
1169 static ngx_int_t | 606 static ngx_int_t |
1170 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, | 607 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, |
1171 ngx_quic_frame_t *frame) | 608 ngx_quic_frame_t *frame) |
1347 | 784 |
1348 ngx_memcpy(p, buf, size); | 785 ngx_memcpy(p, buf, size); |
1349 | 786 |
1350 frame->level = ssl_encryption_application; | 787 frame->level = ssl_encryption_application; |
1351 frame->type = NGX_QUIC_FT_STREAM6; /* OFF=1 LEN=1 FIN=0 */ | 788 frame->type = NGX_QUIC_FT_STREAM6; /* OFF=1 LEN=1 FIN=0 */ |
789 frame->u.stream.off = 1; | |
790 frame->u.stream.len = 1; | |
791 frame->u.stream.fin = 0; | |
1352 | 792 |
1353 frame->u.stream.type = frame->type; | 793 frame->u.stream.type = frame->type; |
1354 frame->u.stream.stream_id = qs->id; | 794 frame->u.stream.stream_id = qs->id; |
1355 frame->u.stream.offset = c->sent; | 795 frame->u.stream.offset = c->sent; |
1356 frame->u.stream.length = size; | 796 frame->u.stream.length = size; |
1431 ack_this = 0; | 871 ack_this = 0; |
1432 do_close = 0; | 872 do_close = 0; |
1433 | 873 |
1434 while (p < end) { | 874 while (p < end) { |
1435 | 875 |
1436 len = ngx_quic_read_frame(c, p, end, &frame); | 876 len = ngx_quic_parse_frame(p, end, &frame); |
1437 if (len < 0) { | 877 if (len < 0) { |
878 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
879 "unknown frame type %xi", frame.type); | |
880 // XXX: log here | |
1438 return NGX_ERROR; | 881 return NGX_ERROR; |
1439 } | 882 } |
1440 | 883 |
1441 p += len; | 884 p += len; |
1442 | 885 |
1454 frame.u.ack.range_count); | 897 frame.u.ack.range_count); |
1455 | 898 |
1456 break; | 899 break; |
1457 | 900 |
1458 case NGX_QUIC_FT_CRYPTO: | 901 case NGX_QUIC_FT_CRYPTO: |
902 ngx_quic_hexdump0(c->log, "CRYPTO frame", | |
903 frame.u.crypto.data, frame.u.crypto.len); | |
904 | |
905 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
906 "quic CRYPTO frame length: %uL off:%uL pp:%p", | |
907 frame.u.crypto.len, frame.u.crypto.offset, | |
908 frame.u.crypto.data); | |
1459 | 909 |
1460 if (frame.u.crypto.offset != 0x0) { | 910 if (frame.u.crypto.offset != 0x0) { |
1461 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 911 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1462 "crypto frame with non-zero offset"); | 912 "crypto frame with non-zero offset"); |
1463 // TODO: support packet spanning with offsets | 913 // TODO: support packet spanning with offsets |
1489 continue; | 939 continue; |
1490 | 940 |
1491 case NGX_QUIC_FT_CONNECTION_CLOSE: | 941 case NGX_QUIC_FT_CONNECTION_CLOSE: |
1492 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | 942 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1493 "CONN.CLOSE: { %s (0x%xi) type=0x%xi reason='%V'}", | 943 "CONN.CLOSE: { %s (0x%xi) type=0x%xi reason='%V'}", |
1494 ngx_quic_errors[frame.u.close.error_code], | 944 ngx_quic_error_text(frame.u.close.error_code), |
1495 frame.u.close.error_code, | 945 frame.u.close.error_code, |
1496 frame.u.close.frame_type, | 946 frame.u.close.frame_type, |
1497 &frame.u.close.reason); | 947 &frame.u.close.reason); |
1498 | 948 |
1499 do_close = 1; | 949 do_close = 1; |
1514 "STREAM frame 0x%xi id 0x%xi offset 0x%xi len 0x%xi bits:off=%d len=%d fin=%d", | 964 "STREAM frame 0x%xi id 0x%xi offset 0x%xi len 0x%xi bits:off=%d len=%d fin=%d", |
1515 frame.type, | 965 frame.type, |
1516 frame.u.stream.stream_id, | 966 frame.u.stream.stream_id, |
1517 frame.u.stream.offset, | 967 frame.u.stream.offset, |
1518 frame.u.stream.length, | 968 frame.u.stream.length, |
1519 ngx_quic_stream_bit_off(frame.u.stream.type), | 969 frame.u.stream.off, |
1520 ngx_quic_stream_bit_len(frame.u.stream.type), | 970 frame.u.stream.len, |
1521 ngx_quic_stream_bit_fin(frame.u.stream.type)); | 971 frame.u.stream.fin); |
1522 | |
1523 | 972 |
1524 sn = ngx_quic_stream_lookup(&qc->stree, frame.u.stream.stream_id); | 973 sn = ngx_quic_stream_lookup(&qc->stree, frame.u.stream.stream_id); |
1525 if (sn == NULL) { | 974 if (sn == NULL) { |
1526 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "stream is new"); | 975 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "stream is new"); |
1527 | 976 |
1725 if (ngx_buf_size(pkt->raw) < 1200) { | 1174 if (ngx_buf_size(pkt->raw) < 1200) { |
1726 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram"); | 1175 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram"); |
1727 return NGX_ERROR; | 1176 return NGX_ERROR; |
1728 } | 1177 } |
1729 | 1178 |
1730 if (ngx_quic_process_long_header(c, pkt) != NGX_OK) { | 1179 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { |
1731 return NGX_ERROR; | 1180 return NGX_ERROR; |
1732 } | 1181 } |
1733 | 1182 |
1734 if ((pkt->flags & 0xf0) != NGX_QUIC_PKT_INITIAL) { | 1183 if ((pkt->flags & 0xf0) != NGX_QUIC_PKT_INITIAL) { |
1735 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1184 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1736 "invalid initial packet: 0x%xi", pkt->flags); | 1185 "invalid initial packet: 0x%xi", pkt->flags); |
1737 return NGX_ERROR; | 1186 return NGX_ERROR; |
1738 } | 1187 } |
1739 | 1188 |
1740 if (ngx_quic_process_initial_header(c, pkt) != NGX_OK) { | 1189 if (ngx_quic_parse_initial_header(pkt) != NGX_OK) { |
1741 return NGX_ERROR; | 1190 return NGX_ERROR; |
1742 } | 1191 } |
1743 | 1192 |
1744 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); | 1193 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); |
1745 if (qc == NULL) { | 1194 if (qc == NULL) { |
1802 ngx_quic_connection_t *qc; | 1251 ngx_quic_connection_t *qc; |
1803 | 1252 |
1804 qc = c->quic; | 1253 qc = c->quic; |
1805 ssl_conn = c->ssl->connection; | 1254 ssl_conn = c->ssl->connection; |
1806 | 1255 |
1807 if (ngx_quic_process_long_header(c, pkt) != NGX_OK) { | 1256 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { |
1808 return NGX_ERROR; | 1257 return NGX_ERROR; |
1809 } | 1258 } |
1810 | 1259 |
1811 if (ngx_quic_process_initial_header(c, pkt) != NGX_OK) { | 1260 if (ngx_quic_parse_initial_header(pkt) != NGX_OK) { |
1812 return NGX_ERROR; | 1261 return NGX_ERROR; |
1813 } | 1262 } |
1814 | 1263 |
1815 pkt->secret = &qc->secrets.client.in; | 1264 pkt->secret = &qc->secrets.client.in; |
1816 pkt->level = ssl_encryption_initial; | 1265 pkt->level = ssl_encryption_initial; |
1831 | 1280 |
1832 qc = c->quic; | 1281 qc = c->quic; |
1833 ssl_conn = c->ssl->connection; | 1282 ssl_conn = c->ssl->connection; |
1834 | 1283 |
1835 /* extract cleartext data into pkt */ | 1284 /* extract cleartext data into pkt */ |
1836 if (ngx_quic_process_long_header(c, pkt) != NGX_OK) { | 1285 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { |
1837 return NGX_ERROR; | 1286 return NGX_ERROR; |
1838 } | 1287 } |
1839 | 1288 |
1840 if (pkt->dcid.len != qc->dcid.len) { | 1289 if (pkt->dcid.len != qc->dcid.len) { |
1841 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl"); | 1290 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl"); |
1861 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1310 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1862 "invalid packet type: 0x%xi", pkt->flags); | 1311 "invalid packet type: 0x%xi", pkt->flags); |
1863 return NGX_ERROR; | 1312 return NGX_ERROR; |
1864 } | 1313 } |
1865 | 1314 |
1866 if (ngx_quic_process_handshake_header(c, pkt) != NGX_OK) { | 1315 if (ngx_quic_parse_handshake_header(pkt) != NGX_OK) { |
1867 return NGX_ERROR; | 1316 return NGX_ERROR; |
1868 } | 1317 } |
1869 | 1318 |
1870 pkt->secret = &qc->secrets.client.hs; | 1319 pkt->secret = &qc->secrets.client.hs; |
1871 pkt->level = ssl_encryption_handshake; | 1320 pkt->level = ssl_encryption_handshake; |
1889 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1338 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1890 "no read keys yet, packet ignored"); | 1339 "no read keys yet, packet ignored"); |
1891 return NGX_DECLINED; | 1340 return NGX_DECLINED; |
1892 } | 1341 } |
1893 | 1342 |
1894 if (ngx_quic_process_short_header(c, pkt) != NGX_OK) { | 1343 if (ngx_quic_parse_short_header(pkt, &qc->dcid) != NGX_OK) { |
1895 return NGX_ERROR; | 1344 return NGX_ERROR; |
1896 } | 1345 } |
1897 | 1346 |
1898 pkt->secret = &qc->secrets.client.ad; | 1347 pkt->secret = &qc->secrets.client.ad; |
1899 pkt->level = ssl_encryption_application; | 1348 pkt->level = ssl_encryption_application; |
1904 | 1353 |
1905 return ngx_quic_payload_handler(c, pkt); | 1354 return ngx_quic_payload_handler(c, pkt); |
1906 } | 1355 } |
1907 | 1356 |
1908 | 1357 |
1909 uint64_t | |
1910 ngx_quic_parse_int(u_char **pos) | |
1911 { | |
1912 u_char *p; | |
1913 uint64_t value; | |
1914 ngx_uint_t len; | |
1915 | |
1916 p = *pos; | |
1917 len = 1 << ((*p & 0xc0) >> 6); | |
1918 value = *p++ & 0x3f; | |
1919 | |
1920 while (--len) { | |
1921 value = (value << 8) + *p++; | |
1922 } | |
1923 | |
1924 *pos = p; | |
1925 return value; | |
1926 } | |
1927 | |
1928 | |
1929 void | |
1930 ngx_quic_build_int(u_char **pos, uint64_t value) | |
1931 { | |
1932 u_char *p; | |
1933 ngx_uint_t len;//, len2; | |
1934 | |
1935 p = *pos; | |
1936 len = 0; | |
1937 | |
1938 while (value >> ((1 << len) * 8 - 2)) { | |
1939 len++; | |
1940 } | |
1941 | |
1942 *p = len << 6; | |
1943 | |
1944 // len2 = | |
1945 len = (1 << len); | |
1946 len--; | |
1947 *p |= value >> (len * 8); | |
1948 p++; | |
1949 | |
1950 while (len) { | |
1951 *p++ = value >> ((len-- - 1) * 8); | |
1952 } | |
1953 | |
1954 *pos = p; | |
1955 // return len2; | |
1956 } | |
1957 |