Mercurial > hg > nginx
comparison src/event/ngx_event_quic_transport.c @ 8641:fe53def49945 quic
QUIC: refactored long header parsing.
The largely duplicate type-specific functions ngx_quic_parse_initial_header(),
ngx_quic_parse_handshake_header(), and a missing one for 0-RTT, were merged.
The new order of functions listed in ngx_event_quic_transport.c reflects this.
|_ ngx_quic_parse_long_header - version-invariant long header fields
\_ ngx_quic_supported_version - a helper to decide we can go further
\_ ngx_quic_parse_long_header_v1 - QUICv1-specific long header fields
0-RTT packets previously appeared as Handshake are now logged as appropriate:
*1 quic packet rx long flags:db version:ff00001d
*1 quic packet rx early len:870
Logging SCID/DCID is no longer duplicated as were seen with Initial packets.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Tue, 17 Nov 2020 21:32:04 +0000 |
parents | 46374c3fee3f |
children | 05b1ee464350 |
comparison
equal
deleted
inserted
replaced
8640:46374c3fee3f | 8641:fe53def49945 |
---|---|
76 | 76 |
77 static ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt, | 77 static ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt, |
78 size_t dcid_len); | 78 size_t dcid_len); |
79 static ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt); | 79 static ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt); |
80 static ngx_int_t ngx_quic_supported_version(uint32_t version); | 80 static ngx_int_t ngx_quic_supported_version(uint32_t version); |
81 static ngx_int_t ngx_quic_parse_initial_header(ngx_quic_header_t *pkt); | 81 static ngx_int_t ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt); |
82 static ngx_int_t ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt); | |
83 | 82 |
84 static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt, | 83 static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt, |
85 ngx_uint_t frame_type); | 84 ngx_uint_t frame_type); |
86 static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack); | 85 static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack); |
87 static size_t ngx_quic_create_stop_sending(u_char *p, | 86 static size_t ngx_quic_create_stop_sending(u_char *p, |
289 | 288 |
290 if (!ngx_quic_supported_version(pkt->version)) { | 289 if (!ngx_quic_supported_version(pkt->version)) { |
291 return NGX_ABORT; | 290 return NGX_ABORT; |
292 } | 291 } |
293 | 292 |
293 if (ngx_quic_parse_long_header_v1(pkt) != NGX_OK) { | |
294 return NGX_DECLINED; | |
295 } | |
296 | |
297 return NGX_OK; | |
298 } | |
299 | |
300 | |
301 static ngx_int_t | |
302 ngx_quic_parse_short_header(ngx_quic_header_t *pkt, size_t dcid_len) | |
303 { | |
304 u_char *p, *end; | |
305 | |
306 p = pkt->raw->pos; | |
307 end = pkt->data + pkt->len; | |
308 | |
309 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
310 "quic packet rx short flags:%xd", pkt->flags); | |
311 | |
312 if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) { | |
313 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set"); | |
314 return NGX_ERROR; | |
315 } | |
316 | |
317 pkt->dcid.len = dcid_len; | |
318 | |
319 p = ngx_quic_read_bytes(p, end, dcid_len, &pkt->dcid.data); | |
320 if (p == NULL) { | |
321 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
322 "quic packet is too small to read dcid"); | |
323 return NGX_ERROR; | |
324 } | |
325 | |
326 pkt->raw->pos = p; | |
327 | |
328 return NGX_OK; | |
329 } | |
330 | |
331 | |
332 static ngx_int_t | |
333 ngx_quic_parse_long_header(ngx_quic_header_t *pkt) | |
334 { | |
335 u_char *p, *end; | |
336 uint8_t idlen; | |
337 | |
338 p = pkt->raw->pos; | |
339 end = pkt->data + pkt->len; | |
340 | |
341 p = ngx_quic_read_uint32(p, end, &pkt->version); | |
342 if (p == NULL) { | |
343 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
344 "quic packet is too small to read version"); | |
345 return NGX_ERROR; | |
346 } | |
347 | |
348 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
349 "quic packet rx long flags:%xd version:%xD", | |
350 pkt->flags, pkt->version); | |
351 | |
352 if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) { | |
353 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set"); | |
354 return NGX_ERROR; | |
355 } | |
356 | |
357 p = ngx_quic_read_uint8(p, end, &idlen); | |
358 if (p == NULL) { | |
359 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
360 "quic packet is too small to read dcid len"); | |
361 return NGX_ERROR; | |
362 } | |
363 | |
364 if (idlen > NGX_QUIC_CID_LEN_MAX) { | |
365 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
366 "quic packet dcid is too long"); | |
367 return NGX_ERROR; | |
368 } | |
369 | |
370 pkt->dcid.len = idlen; | |
371 | |
372 p = ngx_quic_read_bytes(p, end, idlen, &pkt->dcid.data); | |
373 if (p == NULL) { | |
374 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
375 "quic packet is too small to read dcid"); | |
376 return NGX_ERROR; | |
377 } | |
378 | |
379 p = ngx_quic_read_uint8(p, end, &idlen); | |
380 if (p == NULL) { | |
381 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
382 "quic packet is too small to read scid len"); | |
383 return NGX_ERROR; | |
384 } | |
385 | |
386 if (idlen > NGX_QUIC_CID_LEN_MAX) { | |
387 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
388 "quic packet scid is too long"); | |
389 return NGX_ERROR; | |
390 } | |
391 | |
392 pkt->scid.len = idlen; | |
393 | |
394 p = ngx_quic_read_bytes(p, end, idlen, &pkt->scid.data); | |
395 if (p == NULL) { | |
396 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
397 "quic packet is too small to read scid"); | |
398 return NGX_ERROR; | |
399 } | |
400 | |
401 pkt->raw->pos = p; | |
402 | |
403 return NGX_OK; | |
404 } | |
405 | |
406 | |
407 static ngx_int_t | |
408 ngx_quic_supported_version(uint32_t version) | |
409 { | |
410 ngx_uint_t i; | |
411 | |
412 for (i = 0; i < NGX_QUIC_NVERSIONS; i++) { | |
413 if (ngx_quic_versions[i] == version) { | |
414 return 1; | |
415 } | |
416 } | |
417 | |
418 return 0; | |
419 } | |
420 | |
421 | |
422 static ngx_int_t | |
423 ngx_quic_parse_long_header_v1(ngx_quic_header_t *pkt) | |
424 { | |
425 u_char *p, *end; | |
426 uint64_t varint; | |
427 | |
428 p = pkt->raw->pos; | |
429 end = pkt->raw->last; | |
430 | |
431 pkt->log->action = "parsing quic long header"; | |
432 | |
294 if (ngx_quic_pkt_in(pkt->flags)) { | 433 if (ngx_quic_pkt_in(pkt->flags)) { |
295 | 434 |
296 if (pkt->len < NGX_QUIC_MIN_INITIAL_SIZE) { | 435 if (pkt->len < NGX_QUIC_MIN_INITIAL_SIZE) { |
297 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | 436 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, |
298 "quic UDP datagram is too small for initial packet"); | 437 "quic UDP datagram is too small for initial packet"); |
299 return NGX_DECLINED; | 438 return NGX_DECLINED; |
300 } | 439 } |
301 | 440 |
441 p = ngx_quic_parse_int(p, end, &varint); | |
442 if (p == NULL) { | |
443 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
444 "quic failed to parse token length"); | |
445 return NGX_ERROR; | |
446 } | |
447 | |
448 pkt->token.len = varint; | |
449 | |
450 p = ngx_quic_read_bytes(p, end, pkt->token.len, &pkt->token.data); | |
451 if (p == NULL) { | |
452 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
453 "quic packet too small to read token data"); | |
454 return NGX_ERROR; | |
455 } | |
456 | |
302 pkt->level = ssl_encryption_initial; | 457 pkt->level = ssl_encryption_initial; |
303 | |
304 if (ngx_quic_parse_initial_header(pkt) != NGX_OK) { | |
305 return NGX_DECLINED; | |
306 } | |
307 | |
308 return NGX_OK; | |
309 } | |
310 | |
311 if (ngx_quic_pkt_hs(pkt->flags)) { | |
312 pkt->level = ssl_encryption_handshake; | |
313 | 458 |
314 } else if (ngx_quic_pkt_zrtt(pkt->flags)) { | 459 } else if (ngx_quic_pkt_zrtt(pkt->flags)) { |
315 pkt->level = ssl_encryption_early_data; | 460 pkt->level = ssl_encryption_early_data; |
316 | 461 |
462 } else if (ngx_quic_pkt_hs(pkt->flags)) { | |
463 pkt->level = ssl_encryption_handshake; | |
464 | |
317 } else { | 465 } else { |
318 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | 466 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, |
319 "quic unknown long packet type"); | 467 "quic bad packet type"); |
320 return NGX_DECLINED; | 468 return NGX_DECLINED; |
321 } | |
322 | |
323 if (ngx_quic_parse_handshake_header(pkt) != NGX_OK) { | |
324 return NGX_DECLINED; | |
325 } | |
326 | |
327 return NGX_OK; | |
328 } | |
329 | |
330 | |
331 static ngx_int_t | |
332 ngx_quic_parse_short_header(ngx_quic_header_t *pkt, size_t dcid_len) | |
333 { | |
334 u_char *p, *end; | |
335 | |
336 p = pkt->raw->pos; | |
337 end = pkt->data + pkt->len; | |
338 | |
339 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
340 "quic packet rx short flags:%xd", pkt->flags); | |
341 | |
342 if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) { | |
343 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set"); | |
344 return NGX_ERROR; | |
345 } | |
346 | |
347 pkt->dcid.len = dcid_len; | |
348 | |
349 p = ngx_quic_read_bytes(p, end, dcid_len, &pkt->dcid.data); | |
350 if (p == NULL) { | |
351 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
352 "quic packet is too small to read dcid"); | |
353 return NGX_ERROR; | |
354 } | |
355 | |
356 pkt->raw->pos = p; | |
357 | |
358 return NGX_OK; | |
359 } | |
360 | |
361 | |
362 static ngx_int_t | |
363 ngx_quic_parse_long_header(ngx_quic_header_t *pkt) | |
364 { | |
365 u_char *p, *end; | |
366 uint8_t idlen; | |
367 | |
368 p = pkt->raw->pos; | |
369 end = pkt->data + pkt->len; | |
370 | |
371 p = ngx_quic_read_uint32(p, end, &pkt->version); | |
372 if (p == NULL) { | |
373 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
374 "quic packet is too small to read version"); | |
375 return NGX_ERROR; | |
376 } | |
377 | |
378 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
379 "quic packet rx long flags:%xd version:%xD", | |
380 pkt->flags, pkt->version); | |
381 | |
382 if (!(pkt->flags & NGX_QUIC_PKT_FIXED_BIT)) { | |
383 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic fixed bit is not set"); | |
384 return NGX_ERROR; | |
385 } | |
386 | |
387 p = ngx_quic_read_uint8(p, end, &idlen); | |
388 if (p == NULL) { | |
389 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
390 "quic packet is too small to read dcid len"); | |
391 return NGX_ERROR; | |
392 } | |
393 | |
394 if (idlen > NGX_QUIC_CID_LEN_MAX) { | |
395 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
396 "quic packet dcid is too long"); | |
397 return NGX_ERROR; | |
398 } | |
399 | |
400 pkt->dcid.len = idlen; | |
401 | |
402 p = ngx_quic_read_bytes(p, end, idlen, &pkt->dcid.data); | |
403 if (p == NULL) { | |
404 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
405 "quic packet is too small to read dcid"); | |
406 return NGX_ERROR; | |
407 } | |
408 | |
409 p = ngx_quic_read_uint8(p, end, &idlen); | |
410 if (p == NULL) { | |
411 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
412 "quic packet is too small to read scid len"); | |
413 return NGX_ERROR; | |
414 } | |
415 | |
416 if (idlen > NGX_QUIC_CID_LEN_MAX) { | |
417 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
418 "quic packet scid is too long"); | |
419 return NGX_ERROR; | |
420 } | |
421 | |
422 pkt->scid.len = idlen; | |
423 | |
424 p = ngx_quic_read_bytes(p, end, idlen, &pkt->scid.data); | |
425 if (p == NULL) { | |
426 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
427 "quic packet is too small to read scid"); | |
428 return NGX_ERROR; | |
429 } | |
430 | |
431 pkt->raw->pos = p; | |
432 | |
433 return NGX_OK; | |
434 } | |
435 | |
436 | |
437 static ngx_int_t | |
438 ngx_quic_supported_version(uint32_t version) | |
439 { | |
440 ngx_uint_t i; | |
441 | |
442 for (i = 0; i < NGX_QUIC_NVERSIONS; i++) { | |
443 if (ngx_quic_versions[i] == version) { | |
444 return 1; | |
445 } | |
446 } | |
447 | |
448 return 0; | |
449 } | |
450 | |
451 | |
452 static ngx_int_t | |
453 ngx_quic_parse_initial_header(ngx_quic_header_t *pkt) | |
454 { | |
455 u_char *p, *end; | |
456 uint64_t varint; | |
457 | |
458 p = pkt->raw->pos; | |
459 | |
460 end = pkt->raw->last; | |
461 | |
462 pkt->log->action = "parsing quic initial header"; | |
463 | |
464 p = ngx_quic_parse_int(p, end, &varint); | |
465 if (p == NULL) { | |
466 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
467 "quic failed to parse token length"); | |
468 return NGX_ERROR; | |
469 } | |
470 | |
471 pkt->token.len = varint; | |
472 | |
473 p = ngx_quic_read_bytes(p, end, pkt->token.len, &pkt->token.data); | |
474 if (p == NULL) { | |
475 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
476 "quic packet too small to read token data"); | |
477 return NGX_ERROR; | |
478 } | 469 } |
479 | 470 |
480 p = ngx_quic_parse_int(p, end, &varint); | 471 p = ngx_quic_parse_int(p, end, &varint); |
481 if (p == NULL) { | 472 if (p == NULL) { |
482 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic bad packet length"); | 473 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic bad packet length"); |
483 return NGX_ERROR; | 474 return NGX_ERROR; |
484 } | 475 } |
485 | 476 |
486 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | 477 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, |
487 "quic packet rx initial len:%uL", varint); | 478 "quic packet rx %s len:%uL", |
479 ngx_quic_level_name(pkt->level), varint); | |
488 | 480 |
489 if (varint > (uint64_t) ((pkt->data + pkt->len) - p)) { | 481 if (varint > (uint64_t) ((pkt->data + pkt->len) - p)) { |
490 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | 482 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic truncated %s packet", |
491 "quic truncated initial packet"); | 483 ngx_quic_level_name(pkt->level)); |
492 return NGX_ERROR; | 484 return NGX_ERROR; |
493 } | 485 } |
494 | 486 |
495 pkt->raw->pos = p; | 487 pkt->raw->pos = p; |
496 pkt->len = p + varint - pkt->data; | 488 pkt->len = p + varint - pkt->data; |
497 | |
498 #ifdef NGX_QUIC_DEBUG_PACKETS | |
499 ngx_quic_hexdump(pkt->log, "quic DCID", pkt->dcid.data, pkt->dcid.len); | |
500 ngx_quic_hexdump(pkt->log, "quic SCID", pkt->scid.data, pkt->scid.len); | |
501 ngx_quic_hexdump(pkt->log, "quic token", pkt->token.data, pkt->token.len); | |
502 #endif | |
503 | |
504 return NGX_OK; | |
505 } | |
506 | |
507 | |
508 static ngx_int_t | |
509 ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt) | |
510 { | |
511 u_char *p, *end; | |
512 uint64_t plen; | |
513 | |
514 p = pkt->raw->pos; | |
515 end = pkt->raw->last; | |
516 | |
517 pkt->log->action = "parsing quic handshake header"; | |
518 | |
519 p = ngx_quic_parse_int(p, end, &plen); | |
520 if (p == NULL) { | |
521 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic bad packet length"); | |
522 return NGX_ERROR; | |
523 } | |
524 | |
525 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pkt->log, 0, | |
526 "quic packet rx handshake len:%uL", plen); | |
527 | |
528 if (plen > (uint64_t)((pkt->data + pkt->len) - p)) { | |
529 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, | |
530 "quic truncated handshake packet"); | |
531 return NGX_ERROR; | |
532 } | |
533 | |
534 pkt->raw->pos = p; | |
535 pkt->len = p + plen - pkt->data; | |
536 | 489 |
537 return NGX_OK; | 490 return NGX_OK; |
538 } | 491 } |
539 | 492 |
540 | 493 |