comparison src/event/quic/ngx_event_quic.c @ 9156:36b59521a41c

QUIC: refined sending CONNECTION_CLOSE in various packet types. As per RFC 9000, section 10.2.3, to ensure that peer successfully removed packet protection, CONNECTION_CLOSE can be sent in multiple packets using different packet protection levels. Now it is sent in all protection levels available. This roughly corresponds to the following paragraph: * Prior to confirming the handshake, a peer might be unable to process 1-RTT packets, so an endpoint SHOULD send a CONNECTION_CLOSE frame in both Handshake and 1-RTT packets. A server SHOULD also send a CONNECTION_CLOSE frame in an Initial packet. In practice, this change allows to avoid sending an Initial packet when we know the client has handshake keys, by checking if we have discarded initial keys. Also, this fixes sending CONNECTION_CLOSE when using QuicTLS with old QUIC API, where TLS stack releases application read keys before handshake confirmation; it is fixed by sending CONNECTION_CLOSE additionally in a Handshake packet.
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 01 Sep 2023 20:31:46 +0400
parents 8f7e6d8c061e
children daf8f5ba23d8
comparison
equal deleted inserted replaced
9155:35bb47f65cab 9156:36b59521a41c
507 * 507 *
508 * An endpoint sends a CONNECTION_CLOSE frame (Section 19.19) 508 * An endpoint sends a CONNECTION_CLOSE frame (Section 19.19)
509 * to terminate the connection immediately. 509 * to terminate the connection immediately.
510 */ 510 */
511 511
512 qc->error_level = c->ssl ? SSL_quic_read_level(c->ssl->connection)
513 : ssl_encryption_initial;
514
515 if (qc->error == (ngx_uint_t) -1) { 512 if (qc->error == (ngx_uint_t) -1) {
516 qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; 513 qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
517 qc->error_app = 0; 514 qc->error_app = 0;
518 } 515 }
519 516
522 "%serror:%ui \"%s\"", 519 "%serror:%ui \"%s\"",
523 rc == NGX_ERROR ? 1 : 0, qc->draining, 520 rc == NGX_ERROR ? 1 : 0, qc->draining,
524 qc->error_app ? "app " : "", qc->error, 521 qc->error_app ? "app " : "", qc->error,
525 qc->error_reason ? qc->error_reason : ""); 522 qc->error_reason ? qc->error_reason : "");
526 523
527 if (rc == NGX_OK) { 524 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
528 ctx = ngx_quic_get_send_ctx(qc, qc->error_level); 525 ctx = &qc->send_ctx[i];
529 ngx_add_timer(&qc->close, 3 * ngx_quic_pto(c, ctx)); 526
530 } 527 if (!ngx_quic_keys_available(qc->keys, ctx->level)) {
531 528 continue;
532 (void) ngx_quic_send_cc(c); 529 }
533 530
534 if (qc->error_level == ssl_encryption_handshake) { 531 qc->error_level = ctx->level;
535 /* for clients that might not have handshake keys */
536 qc->error_level = ssl_encryption_initial;
537 (void) ngx_quic_send_cc(c); 532 (void) ngx_quic_send_cc(c);
533
534 if (rc == NGX_OK && !qc->close.timer_set) {
535 ngx_add_timer(&qc->close, 3 * ngx_quic_pto(c, ctx));
536 }
538 } 537 }
539 } 538 }
540 539
541 qc->closing = 1; 540 qc->closing = 1;
542 } 541 }