comparison src/event/ngx_event_quic_transport.c @ 8240:1f002206a59b quic

Added boundaries checks into frame parser. The ngx_quic_parse_frame() functions now has new 'pkt' argument: the packet header of a currently processed frame. This allows to log errors/debug closer to reasons and perform additional checks regarding possible frame types. The handler only performs processing of good frames. A number of functions like read_uint32(), parse_int[_multi] probably should be implemented as a macro, but currently it is better to have them as functions for simpler debugging.
author Vladimir Homutov <vl@nginx.com>
date Thu, 19 Mar 2020 17:07:12 +0300
parents ff540f13d95d
children db745339e54b
comparison
equal deleted inserted replaced
8239:5ad7bffd3850 8240:1f002206a59b
49 : ((uint32_t) value) <= 16383 ? 2 \ 49 : ((uint32_t) value) <= 16383 ? 2 \
50 : ((uint64_t) value) <= 1073741823 ? 4 \ 50 : ((uint64_t) value) <= 1073741823 ? 4 \
51 : 8) 51 : 8)
52 52
53 53
54 static uint64_t ngx_quic_parse_int(u_char **pos); 54 static u_char *ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out);
55 static u_char *ngx_quic_parse_int_multi(u_char *pos, u_char *end, ...);
55 static void ngx_quic_build_int(u_char **pos, uint64_t value); 56 static void ngx_quic_build_int(u_char **pos, uint64_t value);
57
58 static u_char *ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value);
59 static u_char *ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value);
60 static u_char *ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len,
61 u_char **out);
62 static u_char *ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len,
63 u_char *dst);
56 64
57 static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack); 65 static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack);
58 static size_t ngx_quic_create_crypto(u_char *p, 66 static size_t ngx_quic_create_crypto(u_char *p,
59 ngx_quic_crypto_frame_t *crypto); 67 ngx_quic_crypto_frame_t *crypto);
60 static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf); 68 static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf);
79 "CRYPTO_BUFFER_EXCEEDED", 87 "CRYPTO_BUFFER_EXCEEDED",
80 "CRYPTO_ERROR", 88 "CRYPTO_ERROR",
81 }; 89 };
82 90
83 91
84 static uint64_t 92 static ngx_inline u_char *
85 ngx_quic_parse_int(u_char **pos) 93 ngx_quic_parse_int(u_char *pos, u_char *end, uint64_t *out)
86 { 94 {
87 u_char *p; 95 u_char *p;
88 uint64_t value; 96 uint64_t value;
89 ngx_uint_t len; 97 ngx_uint_t len;
90 98
91 p = *pos; 99 if (pos >= end) {
100 printf("OOPS >=\n");
101 return NULL;
102 }
103
104 p = pos;
92 len = 1 << ((*p & 0xc0) >> 6); 105 len = 1 << ((*p & 0xc0) >> 6);
106
93 value = *p++ & 0x3f; 107 value = *p++ & 0x3f;
108
109 if ((size_t)(end - p) < (len - 1)) {
110 printf("LEN TOO BIG: need %ld have %ld\n", len, end - p);
111 return NULL;
112 }
94 113
95 while (--len) { 114 while (--len) {
96 value = (value << 8) + *p++; 115 value = (value << 8) + *p++;
97 } 116 }
98 117
99 *pos = p; 118 *out = value;
100 return value; 119
120 return p;
121 }
122
123
124 static ngx_inline u_char *
125 ngx_quic_parse_int_multi(u_char *pos, u_char *end, ...)
126 {
127 u_char *p;
128 va_list ap;
129 uint64_t *item;
130
131 p = pos;
132
133 va_start(ap, end);
134
135 do {
136 item = va_arg(ap, uint64_t *);
137 if (item == NULL) {
138 break;
139 }
140
141 p = ngx_quic_parse_int(p, end, item);
142 if (p == NULL) {
143 return NULL;
144 }
145
146 } while (1);
147
148 va_end(ap);
149
150 return p;
151 }
152
153
154 static ngx_inline u_char *
155 ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value)
156 {
157 if ((size_t)(end - pos) < 1) {
158 return NULL;
159 }
160
161 *value = *pos;
162
163 return pos + 1;
164 }
165
166
167 static ngx_inline u_char *
168 ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value)
169 {
170 if ((size_t)(end - pos) < sizeof(uint32_t)) {
171 return NULL;
172 }
173
174 *value = ngx_quic_parse_uint32(pos);
175
176 return pos + sizeof(uint32_t);
177 }
178
179
180 static ngx_inline u_char *
181 ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len, u_char **out)
182 {
183 if ((size_t)(end - pos) < len) {
184 return NULL;
185 }
186
187 *out = pos;
188
189 return pos + len;
190 }
191
192
193 static u_char *
194 ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len, u_char *dst)
195 {
196 if ((size_t)(end - pos) < len) {
197 return NULL;
198 }
199
200 ngx_memcpy(dst, pos, len);
201
202 return pos + len;
101 } 203 }
102 204
103 205
104 static void 206 static void
105 ngx_quic_build_int(u_char **pos, uint64_t value) 207 ngx_quic_build_int(u_char **pos, uint64_t value)
139 241
140 242
141 ngx_int_t 243 ngx_int_t
142 ngx_quic_parse_long_header(ngx_quic_header_t *pkt) 244 ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
143 { 245 {
144 u_char *p; 246 u_char *p, *end;
247 uint8_t idlen;
145 248
146 p = pkt->data; 249 p = pkt->data;
250 end = pkt->data + pkt->len;
147 251
148 ngx_quic_hexdump0(pkt->log, "long input", pkt->data, pkt->len); 252 ngx_quic_hexdump0(pkt->log, "long input", pkt->data, pkt->len);
149 253
150 if (!(p[0] & NGX_QUIC_PKT_LONG)) { 254 p = ngx_quic_read_uint8(p, end, &pkt->flags);
151 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "not a long packet"); 255 if (p == NULL) {
152 return NGX_ERROR; 256 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
153 } 257 "packet is too short to read flags");
154 258 return NGX_ERROR;
155 pkt->flags = *p++; 259 }
156 260
157 pkt->version = ngx_quic_parse_uint32(p); 261 if (!(pkt->flags & NGX_QUIC_PKT_LONG)) {
158 p += sizeof(uint32_t); 262 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "not a long packet");
263 return NGX_ERROR;
264 }
265
266 p = ngx_quic_read_uint32(p, end, &pkt->version);
267 if (p == NULL) {
268 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
269 "packet is too short to read version");
270 return NGX_ERROR;
271 }
159 272
160 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, 273 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
161 "quic flags:%xi version:%xD", pkt->flags, pkt->version); 274 "quic flags:%xi version:%xD", pkt->flags, pkt->version);
162 275
163 if (pkt->version != quic_version) { 276 if (pkt->version != quic_version) {
164 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "unsupported quic version"); 277 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "unsupported quic version");
165 return NGX_ERROR; 278 return NGX_ERROR;
166 } 279 }
167 280
168 pkt->dcid.len = *p++; 281 p = ngx_quic_read_uint8(p, end, &idlen);
169 pkt->dcid.data = p; 282 if (p == NULL) {
170 p += pkt->dcid.len; 283 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
171 284 "packet is too short to read dcid len");
172 pkt->scid.len = *p++; 285 return NGX_ERROR;
173 pkt->scid.data = p; 286 }
174 p += pkt->scid.len; 287
288 pkt->dcid.len = idlen;
289
290 p = ngx_quic_read_bytes(p, end, idlen, &pkt->dcid.data);
291 if (p == NULL) {
292 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
293 "packet is too short to read dcid");
294 return NGX_ERROR;
295 }
296
297 p = ngx_quic_read_uint8(p, end, &idlen);
298 if (p == NULL) {
299 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
300 "packet is too short to read scid len");
301 return NGX_ERROR;
302 }
303
304 pkt->scid.len = idlen;
305
306 p = ngx_quic_read_bytes(p, end, idlen, &pkt->scid.data);
307 if (p == NULL) {
308 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
309 "packet is too short to read scid");
310 return NGX_ERROR;
311 }
175 312
176 pkt->raw->pos = p; 313 pkt->raw->pos = p;
177 314
178 return NGX_OK; 315 return NGX_OK;
179 } 316 }
212 349
213 350
214 ngx_int_t 351 ngx_int_t
215 ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid) 352 ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid)
216 { 353 {
217 u_char *p; 354 u_char *p, *end;
218 355
219 p = pkt->data; 356 p = pkt->data;
357 end = pkt->data + pkt->len;
220 358
221 ngx_quic_hexdump0(pkt->log, "short input", pkt->data, pkt->len); 359 ngx_quic_hexdump0(pkt->log, "short input", pkt->data, pkt->len);
222 360
223 if ((p[0] & NGX_QUIC_PKT_LONG)) { 361 p = ngx_quic_read_uint8(p, end, &pkt->flags);
224 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "not a short packet"); 362 if (p == NULL) {
225 return NGX_ERROR; 363 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
226 } 364 "packet is too short to read flags");
227 365 return NGX_ERROR;
228 pkt->flags = *p++; 366 }
367
368 if (pkt->flags & NGX_QUIC_PKT_LONG) {
369 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "not a short packet");
370 return NGX_ERROR;
371 }
229 372
230 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, 373 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
231 "quic flags:%xi", pkt->flags); 374 "quic flags:%xi", pkt->flags);
232 375
233 if (ngx_memcmp(p, dcid->data, dcid->len) != 0) { 376 if (ngx_memcmp(p, dcid->data, dcid->len) != 0) {
234 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "unexpected quic dcid"); 377 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "unexpected quic dcid");
235 return NGX_ERROR; 378 return NGX_ERROR;
236 } 379 }
237 380
238 pkt->dcid.len = dcid->len; 381 pkt->dcid.len = dcid->len;
239 pkt->dcid.data = p; 382
240 p += pkt->dcid.len; 383 p = ngx_quic_read_bytes(p, end, dcid->len, &pkt->dcid.data);
384 if (p == NULL) {
385 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
386 "packet is too short to read dcid");
387 return NGX_ERROR;
388 }
241 389
242 pkt->raw->pos = p; 390 pkt->raw->pos = p;
243 391
244 return NGX_OK; 392 return NGX_OK;
245 } 393 }
246 394
247 395
248 ngx_int_t 396 ngx_int_t
249 ngx_quic_parse_initial_header(ngx_quic_header_t *pkt) 397 ngx_quic_parse_initial_header(ngx_quic_header_t *pkt)
250 { 398 {
251 u_char *p; 399 u_char *p, *end;
252 ngx_int_t plen; 400 uint64_t plen;
253 401
254 p = pkt->raw->pos; 402 p = pkt->raw->pos;
255 403
256 pkt->token.len = ngx_quic_parse_int(&p); 404 end = pkt->raw->last;
257 pkt->token.data = p; 405
258 406 pkt->log->action = "parsing quic initial header";
259 p += pkt->token.len; 407
260 408 p = ngx_quic_parse_int(p, end, &pkt->token.len);
261 plen = ngx_quic_parse_int(&p); 409 if (p == NULL) {
410 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "failed to parse token length");
411 return NGX_ERROR;
412 }
413
414 p = ngx_quic_read_bytes(p, end, pkt->token.len, &pkt->token.data);
415 if (p == NULL) {
416 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
417 "packet too short to read token data");
418 return NGX_ERROR;
419 }
420
421 p = ngx_quic_parse_int(p, end, &plen);
422 if (p == NULL) {
423 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "bad packet length");
424 return NGX_ERROR;
425 }
262 426
263 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, 427 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
264 "quic packet length: %d", plen); 428 "quic packet length: %d", plen);
265 429
266 if (plen > pkt->data + pkt->len - p) { 430 if (plen > (uint64_t) ((pkt->data + pkt->len) - p)) {
267 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "truncated initial packet"); 431 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "truncated initial packet");
268 return NGX_ERROR; 432 return NGX_ERROR;
269 } 433 }
270 434
271 pkt->raw->pos = p; 435 pkt->raw->pos = p;
272 pkt->len = plen; 436 pkt->len = plen;
273 437
274 ngx_quic_hexdump0(pkt->log, "DCID", pkt->dcid.data, pkt->dcid.len); 438 ngx_quic_hexdump0(pkt->log, "DCID", pkt->dcid.data, pkt->dcid.len);
275 ngx_quic_hexdump0(pkt->log, "SCID", pkt->scid.data, pkt->scid.len); 439 ngx_quic_hexdump0(pkt->log, "SCID", pkt->scid.data, pkt->scid.len);
276 ngx_quic_hexdump0(pkt->log, "token", pkt->token.data, pkt->token.len); 440 ngx_quic_hexdump0(pkt->log, "token", pkt->token.data, pkt->token.len);
277 441
442 return NGX_OK;
443 }
444
445
446 ngx_int_t
447 ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt)
448 {
449 u_char *p, *end;
450 uint64_t plen;
451
452 p = pkt->raw->pos;
453 end = pkt->raw->last;
454
455 pkt->log->action = "parsing quic handshake header";
456
457 p = ngx_quic_parse_int(p, end, &plen);
458 if (p == NULL) {
459 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "bad packet length");
460 return NGX_ERROR;
461 }
462
278 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, 463 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
279 "quic packet length: %d", plen); 464 "quic packet length: %d", plen);
280 465
281 return NGX_OK; 466 if (plen > (uint64_t)((pkt->data + pkt->len) - p)) {
282 } 467 ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "truncated handshake packet");
283
284
285 ngx_int_t
286 ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt)
287 {
288 u_char *p;
289 ngx_int_t plen;
290
291 p = pkt->raw->pos;
292
293 plen = ngx_quic_parse_int(&p);
294
295 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
296 "quic packet length: %d", plen);
297
298 if (plen > pkt->data + pkt->len - p) {
299 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "truncated handshake packet");
300 return NGX_ERROR; 468 return NGX_ERROR;
301 } 469 }
302 470
303 pkt->raw->pos = p; 471 pkt->raw->pos = p;
304 pkt->len = plen; 472 pkt->len = plen;
305
306 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
307 "quic packet length: %d", plen);
308 473
309 return NGX_OK; 474 return NGX_OK;
310 } 475 }
311 476
312 477
313 #define ngx_quic_stream_bit_off(val) (((val) & 0x04) ? 1 : 0) 478 #define ngx_quic_stream_bit_off(val) (((val) & 0x04) ? 1 : 0)
314 #define ngx_quic_stream_bit_len(val) (((val) & 0x02) ? 1 : 0) 479 #define ngx_quic_stream_bit_len(val) (((val) & 0x02) ? 1 : 0)
315 #define ngx_quic_stream_bit_fin(val) (((val) & 0x01) ? 1 : 0) 480 #define ngx_quic_stream_bit_fin(val) (((val) & 0x01) ? 1 : 0)
316 481
317 ssize_t 482 ssize_t
318 ngx_quic_parse_frame(u_char *start, u_char *end, ngx_quic_frame_t *frame) 483 ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
319 { 484 ngx_quic_frame_t *f)
320 u_char *p; 485 {
321 486 u_char *p;
322 size_t npad;
323 487
324 p = start; 488 p = start;
325 489
326 frame->type = *p++; // TODO: check overflow (p < end) 490 /* TODO: add a check if frame is allowed in this type of packet */
327 491
328 switch (frame->type) { 492 p = ngx_quic_parse_int(p, end, &f->type);
493 if (p == NULL) {
494 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
495 "failed to obtain quic frame type");
496 return NGX_ERROR;
497 }
498
499 switch (f->type) {
329 500
330 case NGX_QUIC_FT_CRYPTO: 501 case NGX_QUIC_FT_CRYPTO:
331 frame->u.crypto.offset = *p++; 502
332 frame->u.crypto.len = ngx_quic_parse_int(&p); 503 p = ngx_quic_parse_int(p, end, &f->u.crypto.offset);
333 frame->u.crypto.data = p; 504 if (p == NULL) {
334 p += frame->u.crypto.len; 505 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
335 506 "failed to parse crypto frame offset");
507 return NGX_ERROR;
508 }
509
510 p = ngx_quic_parse_int(p, end, &f->u.crypto.len);
511 if (p == NULL) {
512 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
513 "failed to parse crypto frame len");
514 return NGX_ERROR;
515 }
516
517 p = ngx_quic_read_bytes(p, end, f->u.crypto.len, &f->u.crypto.data);
518 if (p == NULL) {
519 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
520 "failed to parse crypto frame data");
521 return NGX_ERROR;
522 }
523
524 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
525 "quic CRYPTO frame length: %uL off:%uL pp:%p",
526 f->u.crypto.len, f->u.crypto.offset,
527 f->u.crypto.data);
528
529 ngx_quic_hexdump0(pkt->log, "CRYPTO frame contents",
530 f->u.crypto.data, f->u.crypto.len);
336 break; 531 break;
337 532
338 case NGX_QUIC_FT_PADDING: 533 case NGX_QUIC_FT_PADDING:
339 npad = 0; 534 while (p < end && *p == NGX_QUIC_FT_PADDING) {
340 while (p < end && *p == NGX_QUIC_FT_PADDING) { // XXX 535 p++;
341 p++; npad++;
342 } 536 }
343 537
344 break; 538 break;
345 539
346 case NGX_QUIC_FT_ACK: 540 case NGX_QUIC_FT_ACK:
347 case NGX_QUIC_FT_ACK_ECN: 541 case NGX_QUIC_FT_ACK_ECN:
348 542
349 frame->u.ack.largest = ngx_quic_parse_int(&p); 543 p = ngx_quic_parse_int_multi(p, end, &f->u.ack.largest,
350 frame->u.ack.delay = ngx_quic_parse_int(&p); 544 &f->u.ack.delay, &f->u.ack.range_count,
351 frame->u.ack.range_count =ngx_quic_parse_int(&p); 545 &f->u.ack.first_range, NULL);
352 frame->u.ack.first_range =ngx_quic_parse_int(&p); 546 if (p == NULL) {
353 547 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
354 if (frame->u.ack.range_count) { 548 "failed to parse ack frame");
355 frame->u.ack.ranges[0] = ngx_quic_parse_int(&p); 549 return NGX_ERROR;
356 } 550 }
357 551
358 if (frame->type ==NGX_QUIC_FT_ACK_ECN) { 552 if (f->u.ack.range_count) {
359 return NGX_ERROR; 553 p = ngx_quic_parse_int(p, end, &f->u.ack.ranges[0]);
360 } 554 if (p == NULL) {
555 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
556 "failed to parse ack frame first range");
557 return NGX_ERROR;
558 }
559 }
560
561 if (f->type == NGX_QUIC_FT_ACK_ECN) {
562 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
563 "TODO: parse ECN ack frames");
564 /* TODO: add parsing of such frames */
565 return NGX_ERROR;
566 }
567
568 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
569 "ACK: { largest=%ui delay=%ui first=%ui count=%ui}",
570 f->u.ack.largest,
571 f->u.ack.delay,
572 f->u.ack.first_range,
573 f->u.ack.range_count);
361 574
362 break; 575 break;
363 576
364 case NGX_QUIC_FT_PING: 577 case NGX_QUIC_FT_PING:
365 break; 578 break;
366 579
367 case NGX_QUIC_FT_NEW_CONNECTION_ID: 580 case NGX_QUIC_FT_NEW_CONNECTION_ID:
368 581
369 frame->u.ncid.seqnum = ngx_quic_parse_int(&p); 582 p = ngx_quic_parse_int_multi(p, end, &f->u.ncid.seqnum,
370 frame->u.ncid.retire = ngx_quic_parse_int(&p); 583 &f->u.ncid.retire, NULL);
371 frame->u.ncid.len = *p++; 584 if (p == NULL) {
372 ngx_memcpy(frame->u.ncid.cid, p, frame->u.ncid.len); 585 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
373 p += frame->u.ncid.len; 586 "failed to parse new connection id frame");
374 587 return NGX_ERROR;
375 ngx_memcpy(frame->u.ncid.srt, p, 16); 588 }
376 p += 16; 589
377 590 p = ngx_quic_read_uint8(p, end, &f->u.ncid.len);
591 if (p == NULL) {
592 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
593 "failed to parse new connection id length");
594 return NGX_ERROR;
595 }
596
597 p = ngx_quic_copy_bytes(p, end, f->u.ncid.len, f->u.ncid.cid);
598 if (p == NULL) {
599 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
600 "failed to parse new connection id cid");
601 return NGX_ERROR;
602 }
603
604 p = ngx_quic_copy_bytes(p, end, 16, f->u.ncid.srt);
605 if (p == NULL) {
606 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
607 "failed to parse new connection id srt");
608 return NGX_ERROR;
609 }
610
611 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
612 "NCID: { seq=%ui retire=%ui len=%ui}",
613 f->u.ncid.seqnum, f->u.ncid.retire, f->u.ncid.len);
378 break; 614 break;
379 615
380 case NGX_QUIC_FT_CONNECTION_CLOSE: 616 case NGX_QUIC_FT_CONNECTION_CLOSE:
381 617
382 frame->u.close.error_code = ngx_quic_parse_int(&p); 618 p = ngx_quic_parse_int_multi(p, end, &f->u.close.error_code,
383 frame->u.close.frame_type = ngx_quic_parse_int(&p); // not in 0x1d CC 619 &f->u.close.frame_type,
384 frame->u.close.reason.len = ngx_quic_parse_int(&p); 620 &f->u.close.reason.len, NULL);
385 frame->u.close.reason.data = p; 621 if (p == NULL) {
386 p += frame->u.close.reason.len; 622 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
387 623 "failed to parse close connection frame");
388 if (frame->u.close.error_code > NGX_QUIC_ERR_LAST) { 624 return NGX_ERROR;
389 frame->u.close.error_code = NGX_QUIC_ERR_LAST; 625 }
390 } 626
627 p = ngx_quic_read_bytes(p, end, f->u.close.reason.len,
628 &f->u.close.reason.data);
629 if (p == NULL) {
630 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
631 "failed to parse close reason");
632 return NGX_ERROR;
633 }
634
635 if (f->u.close.error_code > NGX_QUIC_ERR_LAST) {
636 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
637 "unkown error code: %ui, truncated",
638 f->u.close.error_code);
639 f->u.close.error_code = NGX_QUIC_ERR_LAST;
640 }
641
642 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
643 "CONN.CLOSE: { %s (0x%xi) type=0x%xi reason='%V'}",
644 ngx_quic_error_text(f->u.close.error_code),
645 f->u.close.error_code, f->u.close.frame_type,
646 &f->u.close.reason);
647
391 break; 648 break;
392 649
393 case NGX_QUIC_FT_STREAM0: 650 case NGX_QUIC_FT_STREAM0:
394 case NGX_QUIC_FT_STREAM1: 651 case NGX_QUIC_FT_STREAM1:
395 case NGX_QUIC_FT_STREAM2: 652 case NGX_QUIC_FT_STREAM2:
397 case NGX_QUIC_FT_STREAM4: 654 case NGX_QUIC_FT_STREAM4:
398 case NGX_QUIC_FT_STREAM5: 655 case NGX_QUIC_FT_STREAM5:
399 case NGX_QUIC_FT_STREAM6: 656 case NGX_QUIC_FT_STREAM6:
400 case NGX_QUIC_FT_STREAM7: 657 case NGX_QUIC_FT_STREAM7:
401 658
402 frame->u.stream.type = frame->type; 659 f->u.stream.type = f->type;
403 660
404 frame->u.stream.off = ngx_quic_stream_bit_off(frame->type); 661 f->u.stream.off = ngx_quic_stream_bit_off(f->type);
405 frame->u.stream.len = ngx_quic_stream_bit_len(frame->type); 662 f->u.stream.len = ngx_quic_stream_bit_len(f->type);
406 frame->u.stream.fin = ngx_quic_stream_bit_fin(frame->type); 663 f->u.stream.fin = ngx_quic_stream_bit_fin(f->type);
407 664
408 frame->u.stream.stream_id = ngx_quic_parse_int(&p); 665 p = ngx_quic_parse_int(p, end, &f->u.stream.stream_id);
409 if (frame->type & 0x04) { 666 if (p == NULL) {
410 frame->u.stream.offset = ngx_quic_parse_int(&p); 667 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
668 "failed to parse stream frame id");
669 return NGX_ERROR;
670 }
671
672 if (f->type & 0x04) {
673 p = ngx_quic_parse_int(p, end, &f->u.stream.offset);
674 if (p == NULL) {
675 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
676 "failed to parse stream frame offset");
677 return NGX_ERROR;
678 }
679
411 } else { 680 } else {
412 frame->u.stream.offset = 0; 681 f->u.stream.offset = 0;
413 } 682 }
414 683
415 if (frame->type & 0x02) { 684 if (f->type & 0x02) {
416 frame->u.stream.length = ngx_quic_parse_int(&p); 685 p = ngx_quic_parse_int(p, end, &f->u.stream.length);
686 if (p == NULL) {
687 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
688 "failed to parse stream frame length");
689 return NGX_ERROR;
690 }
691
417 } else { 692 } else {
418 frame->u.stream.length = end - p; /* up to packet end */ 693 f->u.stream.length = end - p; /* up to packet end */
419 } 694 }
420 695
421 frame->u.stream.data = p; 696 p = ngx_quic_read_bytes(p, end, f->u.stream.length,
422 697 &f->u.stream.data);
423 p += frame->u.stream.length; 698 if (p == NULL) {
424 699 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
700 "failed to parse stream frame data");
701 return NGX_ERROR;
702 }
703
704 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
705 "STREAM frame { 0x%xi id 0x%xi offset 0x%xi "
706 "len 0x%xi bits:off=%d len=%d fin=%d }",
707 f->type, f->u.stream.stream_id, f->u.stream.offset,
708 f->u.stream.length, f->u.stream.off, f->u.stream.len,
709 f->u.stream.fin);
710
711 ngx_quic_hexdump0(pkt->log, "STREAM frame contents",
712 f->u.stream.data, f->u.stream.length);
425 break; 713 break;
426 714
427 case NGX_QUIC_FT_MAX_DATA: 715 case NGX_QUIC_FT_MAX_DATA:
428 frame->u.max_data.max_data = ngx_quic_parse_int(&p); 716
717 p = ngx_quic_parse_int(p, end, &f->u.max_data.max_data);
718 if (p == NULL) {
719 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
720 "failed to parse max data frame");
721 return NGX_ERROR;
722 }
723
724 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
725 "MAX_DATA frame { Maximum Data %ui }",
726 f->u.max_data.max_data);
429 break; 727 break;
430 728
431 case NGX_QUIC_FT_RESET_STREAM: 729 case NGX_QUIC_FT_RESET_STREAM:
432 frame->u.reset_stream.id = ngx_quic_parse_int(&p); 730
433 frame->u.reset_stream.error_code = ngx_quic_parse_int(&p); 731 p = ngx_quic_parse_int_multi(p, end, &f->u.reset_stream.id,
434 frame->u.reset_stream.final_size = ngx_quic_parse_int(&p); 732 &f->u.reset_stream.error_code,
733 &f->u.reset_stream.final_size, NULL);
734 if (p == NULL) {
735 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
736 "failed to parse reset stream frame");
737 return NGX_ERROR;
738 }
739
740 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
741 "RESET STREAM frame"
742 " { id 0x%xi error_code 0x%xi final_size 0x%xi }",
743 f->u.reset_stream.id, f->u.reset_stream.error_code,
744 f->u.reset_stream.final_size);
435 break; 745 break;
436 746
437 case NGX_QUIC_FT_STOP_SENDING: 747 case NGX_QUIC_FT_STOP_SENDING:
438 frame->u.stop_sending.id = ngx_quic_parse_int(&p); 748
439 frame->u.stop_sending.error_code = ngx_quic_parse_int(&p); 749 p = ngx_quic_parse_int_multi(p, end, &f->u.stop_sending.id,
750 &f->u.stop_sending.error_code, NULL);
751 if (p == NULL) {
752 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
753 "failed to parse stop sending frame");
754 return NGX_ERROR;
755 }
756
757 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
758 "STOP SENDING frame { id 0x%xi error_code 0x%xi}",
759 f->u.stop_sending.id, f->u.stop_sending.error_code);
760
440 break; 761 break;
441 762
442 case NGX_QUIC_FT_STREAMS_BLOCKED: 763 case NGX_QUIC_FT_STREAMS_BLOCKED:
443 frame->u.streams_blocked.limit = ngx_quic_parse_int(&p);
444 frame->u.streams_blocked.bidi = 1;
445 break;
446
447 case NGX_QUIC_FT_STREAMS_BLOCKED2: 764 case NGX_QUIC_FT_STREAMS_BLOCKED2:
448 frame->u.streams_blocked.limit = ngx_quic_parse_int(&p); 765
449 frame->u.streams_blocked.bidi = 0; 766 p = ngx_quic_parse_int(p, end, &f->u.streams_blocked.limit);
767 if (p == NULL) {
768 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
769 "failed to parse streams blocked frame limit");
770 return NGX_ERROR;
771 }
772
773 f->u.streams_blocked.bidi =
774 (f->type == NGX_QUIC_FT_STREAMS_BLOCKED) ? 1 : 0;
775
776 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
777 "STREAMS BLOCKED frame { limit %i bidi: %d }",
778 f->u.streams_blocked.limit,
779 f->u.streams_blocked.bidi);
780
450 break; 781 break;
451 782
452 default: 783 default:
784 ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
785 "unsupported frame type 0x%xd in packet", f->type);
786
453 return NGX_ERROR; 787 return NGX_ERROR;
454 } 788 }
455 789
456 return p - start; 790 return p - start;
457 } 791 }