comparison src/event/ngx_event_quic.c @ 8561:b4ef79ef1c23 quic

QUIC: refined the "c->quic->initialized" flag usage. The flag is tied to the initial secret creation. The presence of c->quic pointer is sufficient to enable execution of ngx_quic_close_quic(). The ngx_quic_new_connection() function now returns the allocated quic connection object and the c->quic pointer is set by the caller. If an early error occurs before secrets initialization (i.e. in cases of invalid retry token or nginx exiting), it is still possible to generate an error response by trying to initialize secrets directly in the ngx_quic_send_cc() function. Before the change such early errors failed to send proper connection close message and logged an error. An auxilliary ngx_quic_init_secrets() function is introduced to avoid verbose call to ngx_quic_set_initial_secret() requiring local variable.
author Vladimir Homutov <vl@nginx.com>
date Wed, 30 Sep 2020 21:27:52 +0300
parents d0d3fc0697a0
children b31c02454539
comparison
equal deleted inserted replaced
8560:d0d3fc0697a0 8561:b4ef79ef1c23
180 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); 180 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn);
181 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, 181 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
182 enum ssl_encryption_level_t level, uint8_t alert); 182 enum ssl_encryption_level_t level, uint8_t alert);
183 183
184 184
185 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, 185 static ngx_quic_connection_t *ngx_quic_new_connection(ngx_connection_t *c,
186 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); 186 ngx_ssl_t *ssl, ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
187 static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c, 187 static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c,
188 ngx_quic_header_t *inpkt); 188 ngx_quic_header_t *inpkt);
189 static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid); 189 static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c,
190 ngx_quic_connection_t *qc, ngx_str_t *odcid);
190 static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c); 191 static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c);
191 static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token); 192 static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token);
192 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, 193 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c,
193 ngx_quic_header_t *pkt); 194 ngx_quic_header_t *pkt);
194 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); 195 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c);
203 204
204 static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b, 205 static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b,
205 ngx_ssl_t *ssl, ngx_quic_conf_t *conf); 206 ngx_ssl_t *ssl, ngx_quic_conf_t *conf);
206 static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c, ngx_ssl_t *ssl, 207 static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c, ngx_ssl_t *ssl,
207 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); 208 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
209 static ngx_int_t ngx_quic_init_secrets(ngx_connection_t *c);
208 static void ngx_quic_discard_ctx(ngx_connection_t *c, 210 static void ngx_quic_discard_ctx(ngx_connection_t *c,
209 enum ssl_encryption_level_t level); 211 enum ssl_encryption_level_t level);
210 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc, 212 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc,
211 ngx_quic_header_t *pkt); 213 ngx_quic_header_t *pkt);
212 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, 214 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c,
264 ngx_quic_header_t *pkt, ngx_quic_path_challenge_frame_t *f); 266 ngx_quic_header_t *pkt, ngx_quic_path_challenge_frame_t *f);
265 static ngx_int_t ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, 267 static ngx_int_t ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
266 ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f); 268 ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f);
267 static ngx_int_t ngx_quic_retire_connection_id(ngx_connection_t *c, 269 static ngx_int_t ngx_quic_retire_connection_id(ngx_connection_t *c,
268 enum ssl_encryption_level_t level, uint64_t seqnum); 270 enum ssl_encryption_level_t level, uint64_t seqnum);
269 static ngx_quic_client_id_t *ngx_quic_alloc_connection_id(ngx_connection_t *c); 271 static ngx_quic_client_id_t *ngx_quic_alloc_connection_id(ngx_connection_t *c,
272 ngx_quic_connection_t *qc);
270 273
271 static void ngx_quic_queue_frame(ngx_quic_connection_t *qc, 274 static void ngx_quic_queue_frame(ngx_quic_connection_t *qc,
272 ngx_quic_frame_t *frame); 275 ngx_quic_frame_t *frame);
273 276
274 static ngx_int_t ngx_quic_output(ngx_connection_t *c); 277 static ngx_int_t ngx_quic_output(ngx_connection_t *c);
643 646
644 return; 647 return;
645 } 648 }
646 649
647 650
648 static ngx_int_t 651 static ngx_quic_connection_t *
649 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, 652 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
650 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt) 653 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt)
651 { 654 {
652 ngx_uint_t i; 655 ngx_uint_t i;
653 ngx_quic_tp_t *ctp; 656 ngx_quic_tp_t *ctp;
656 659
657 c->log->action = "creating new quic connection"; 660 c->log->action = "creating new quic connection";
658 661
659 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); 662 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
660 if (qc == NULL) { 663 if (qc == NULL) {
661 return NGX_ERROR; 664 return NULL;
662 } 665 }
663 666
664 ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel, 667 ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel,
665 ngx_quic_rbtree_insert_stream); 668 ngx_quic_rbtree_insert_stream);
666 669
699 qc->push.log = c->log; 702 qc->push.log = c->log;
700 qc->push.data = c; 703 qc->push.data = c;
701 qc->push.handler = ngx_quic_push_handler; 704 qc->push.handler = ngx_quic_push_handler;
702 qc->push.cancelable = 1; 705 qc->push.cancelable = 1;
703 706
704 c->quic = qc;
705 qc->ssl = ssl; 707 qc->ssl = ssl;
706 qc->conf = conf; 708 qc->conf = conf;
707 qc->tp = conf->tp; 709 qc->tp = conf->tp;
708 710
709 ctp = &qc->ctp; 711 ctp = &qc->ctp;
720 ngx_max(2 * qc->tp.max_udp_payload_size, 722 ngx_max(2 * qc->tp.max_udp_payload_size,
721 14720)); 723 14720));
722 qc->congestion.ssthresh = NGX_MAX_SIZE_T_VALUE; 724 qc->congestion.ssthresh = NGX_MAX_SIZE_T_VALUE;
723 qc->congestion.recovery_start = ngx_current_msec; 725 qc->congestion.recovery_start = ngx_current_msec;
724 726
725 if (ngx_quic_new_dcid(c, &pkt->dcid) != NGX_OK) { 727 if (ngx_quic_new_dcid(c, qc, &pkt->dcid) != NGX_OK) {
726 return NGX_ERROR; 728 return NULL;
727 } 729 }
728 730
729 #if (NGX_QUIC_DRAFT_VERSION >= 28) 731 #if (NGX_QUIC_DRAFT_VERSION >= 28)
730 qc->tp.original_dcid = c->quic->odcid; 732 qc->tp.original_dcid = qc->odcid;
731 #endif 733 #endif
732 qc->tp.initial_scid = c->quic->dcid; 734 qc->tp.initial_scid = qc->dcid;
733 735
734 qc->scid.len = pkt->scid.len; 736 qc->scid.len = pkt->scid.len;
735 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len); 737 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
736 if (qc->scid.data == NULL) { 738 if (qc->scid.data == NULL) {
737 return NGX_ERROR; 739 return NULL;
738 } 740 }
739 ngx_memcpy(qc->scid.data, pkt->scid.data, qc->scid.len); 741 ngx_memcpy(qc->scid.data, pkt->scid.data, qc->scid.len);
740 742
741 cid = ngx_quic_alloc_connection_id(c); 743 cid = ngx_quic_alloc_connection_id(c, qc);
742 if (cid == NULL) { 744 if (cid == NULL) {
743 return NGX_ERROR; 745 return NULL;
744 } 746 }
745 747
746 cid->seqnum = 0; 748 cid->seqnum = 0;
747 cid->len = pkt->scid.len; 749 cid->len = pkt->scid.len;
748 ngx_memcpy(cid->id, pkt->scid.data, pkt->scid.len); 750 ngx_memcpy(cid->id, pkt->scid.data, pkt->scid.len);
749 751
750 ngx_queue_insert_tail(&qc->client_ids, &cid->queue); 752 ngx_queue_insert_tail(&qc->client_ids, &cid->queue);
751 qc->nclient_ids++; 753 qc->nclient_ids++;
752 qc->curr_seqnum = 0; 754 qc->curr_seqnum = 0;
753 755
754 qc->initialized = 1; 756 return qc;
755
756 if (ngx_terminate || ngx_exiting) {
757 qc->error = NGX_QUIC_ERR_CONNECTION_REFUSED;
758 return NGX_ERROR;
759 }
760
761 return NGX_OK;
762 } 757 }
763 758
764 759
765 static ngx_int_t 760 static ngx_int_t
766 ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt) 761 ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt)
790 return NGX_ERROR; 785 return NGX_ERROR;
791 } 786 }
792 787
793 788
794 static ngx_int_t 789 static ngx_int_t
795 ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid) 790 ngx_quic_new_dcid(ngx_connection_t *c, ngx_quic_connection_t *qc,
796 { 791 ngx_str_t *odcid)
797 ngx_quic_connection_t *qc; 792 {
798
799 qc = c->quic;
800
801 qc->dcid.len = NGX_QUIC_SERVER_CID_LEN; 793 qc->dcid.len = NGX_QUIC_SERVER_CID_LEN;
802 qc->dcid.data = ngx_pnalloc(c->pool, NGX_QUIC_SERVER_CID_LEN); 794 qc->dcid.data = ngx_pnalloc(c->pool, NGX_QUIC_SERVER_CID_LEN);
803 if (qc->dcid.data == NULL) { 795 if (qc->dcid.data == NULL) {
804 return NGX_ERROR; 796 return NGX_ERROR;
805 } 797 }
1250 ngx_pool_t *pool; 1242 ngx_pool_t *pool;
1251 1243
1252 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, 1244 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1253 "quic ngx_quic_close_connection, rc: %i", rc); 1245 "quic ngx_quic_close_connection, rc: %i", rc);
1254 1246
1255 if (!c->quic || !c->quic->initialized) { 1247 if (!c->quic) {
1256 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, 1248 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
1257 "quic close connection early error"); 1249 "quic close connection early error");
1258 1250
1259 } else if (ngx_quic_close_quic(c, rc) == NGX_AGAIN) { 1251 } else if (ngx_quic_close_quic(c, rc) == NGX_AGAIN) {
1260 return; 1252 return;
1601 1593
1602 if (!pkt->token.len) { 1594 if (!pkt->token.len) {
1603 return NGX_DECLINED; 1595 return NGX_DECLINED;
1604 } 1596 }
1605 1597
1606 if (ngx_quic_new_dcid(c, &pkt->dcid) != NGX_OK) { 1598 if (ngx_quic_new_dcid(c, qc, &pkt->dcid) != NGX_OK) {
1607 return NGX_ERROR; 1599 return NGX_ERROR;
1608 } 1600 }
1609 1601
1610 qc->tp.initial_scid = qc->dcid; 1602 qc->tp.initial_scid = qc->dcid;
1611 qc->in_retry = 0; 1603 qc->in_retry = 0;
1612 1604
1613 keys = &qc->keys[ssl_encryption_initial]; 1605 if (ngx_quic_init_secrets(c) != NGX_OK) {
1614
1615 if (ngx_quic_set_initial_secret(c->pool, &keys->client,
1616 &keys->server, &qc->odcid)
1617 != NGX_OK)
1618 {
1619 return NGX_ERROR; 1606 return NGX_ERROR;
1620 } 1607 }
1621 1608
1622 if (ngx_quic_validate_token(c, pkt) != NGX_OK) { 1609 if (ngx_quic_validate_token(c, pkt) != NGX_OK) {
1623 return NGX_ERROR; 1610 return NGX_ERROR;
1640 "quic too short dcid in initial" 1627 "quic too short dcid in initial"
1641 " packet: length %i", pkt->dcid.len); 1628 " packet: length %i", pkt->dcid.len);
1642 return NGX_ERROR; 1629 return NGX_ERROR;
1643 } 1630 }
1644 1631
1645 rc = ngx_quic_new_connection(c, ssl, conf, pkt); 1632 qc = ngx_quic_new_connection(c, ssl, conf, pkt);
1646 if (rc != NGX_OK) { 1633 if (qc == NULL) {
1647 return rc; 1634 return NGX_ERROR;
1635 }
1636
1637 c->quic = qc;
1638
1639 if (ngx_terminate || ngx_exiting) {
1640 qc->error = NGX_QUIC_ERR_CONNECTION_REFUSED;
1641 return NGX_ERROR;
1648 } 1642 }
1649 1643
1650 if (pkt->token.len) { 1644 if (pkt->token.len) {
1651 if (ngx_quic_validate_token(c, pkt) != NGX_OK) { 1645 if (ngx_quic_validate_token(c, pkt) != NGX_OK) {
1652 return NGX_ERROR; 1646 return NGX_ERROR;
1654 1648
1655 } else if (conf->retry) { 1649 } else if (conf->retry) {
1656 return ngx_quic_send_retry(c); 1650 return ngx_quic_send_retry(c);
1657 } 1651 }
1658 1652
1659 qc = c->quic; 1653 if (ngx_quic_init_secrets(c) != NGX_OK) {
1660
1661 keys = &qc->keys[ssl_encryption_initial];
1662
1663 if (ngx_quic_set_initial_secret(c->pool, &keys->client,
1664 &keys->server, &qc->odcid)
1665 != NGX_OK)
1666 {
1667 return NGX_ERROR; 1654 return NGX_ERROR;
1668 } 1655 }
1669 1656
1670 } else if (pkt->level == ssl_encryption_application) { 1657 } else if (pkt->level == ssl_encryption_application) {
1671 return NGX_DECLINED; 1658 return NGX_DECLINED;
1742 if (pkt->key_update) { 1729 if (pkt->key_update) {
1743 if (ngx_quic_key_update(c, keys, next) != NGX_OK) { 1730 if (ngx_quic_key_update(c, keys, next) != NGX_OK) {
1744 return NGX_ERROR; 1731 return NGX_ERROR;
1745 } 1732 }
1746 } 1733 }
1734
1735 return NGX_OK;
1736 }
1737
1738
1739 static ngx_int_t
1740 ngx_quic_init_secrets(ngx_connection_t *c)
1741 {
1742 ngx_quic_secrets_t *keys;
1743 ngx_quic_connection_t *qc;
1744
1745 qc =c->quic;
1746 keys = &qc->keys[ssl_encryption_initial];
1747
1748 if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server,
1749 &qc->odcid)
1750 != NGX_OK)
1751 {
1752 return NGX_ERROR;
1753 }
1754
1755 qc->initialized = 1;
1747 1756
1748 return NGX_OK; 1757 return NGX_OK;
1749 } 1758 }
1750 1759
1751 1760
2133 2142
2134 qc = c->quic; 2143 qc = c->quic;
2135 2144
2136 if (qc->draining) { 2145 if (qc->draining) {
2137 return NGX_OK; 2146 return NGX_OK;
2147 }
2148
2149 if (!qc->initialized) {
2150 /* try to initialize secrets to send an early error */
2151 if (ngx_quic_init_secrets(c) != NGX_OK) {
2152 return NGX_OK;
2153 }
2138 } 2154 }
2139 2155
2140 if (qc->closing 2156 if (qc->closing
2141 && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL) 2157 && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL)
2142 { 2158 {
3333 return NGX_ERROR; 3349 return NGX_ERROR;
3334 } 3350 }
3335 3351
3336 } else { 3352 } else {
3337 3353
3338 cid = ngx_quic_alloc_connection_id(c); 3354 cid = ngx_quic_alloc_connection_id(c, qc);
3339 if (cid == NULL) { 3355 if (cid == NULL) {
3340 return NGX_ERROR; 3356 return NGX_ERROR;
3341 } 3357 }
3342 3358
3343 cid->seqnum = f->seqnum; 3359 cid->seqnum = f->seqnum;
3437 return NGX_OK; 3453 return NGX_OK;
3438 } 3454 }
3439 3455
3440 3456
3441 static ngx_quic_client_id_t * 3457 static ngx_quic_client_id_t *
3442 ngx_quic_alloc_connection_id(ngx_connection_t *c) 3458 ngx_quic_alloc_connection_id(ngx_connection_t *c, ngx_quic_connection_t *qc)
3443 { 3459 {
3444 ngx_queue_t *q; 3460 ngx_queue_t *q;
3445 ngx_quic_client_id_t *cid; 3461 ngx_quic_client_id_t *cid;
3446 ngx_quic_connection_t *qc;
3447
3448 qc = c->quic;
3449 3462
3450 if (!ngx_queue_empty(&qc->free_client_ids)) { 3463 if (!ngx_queue_empty(&qc->free_client_ids)) {
3451 3464
3452 q = ngx_queue_head(&qc->free_client_ids); 3465 q = ngx_queue_head(&qc->free_client_ids);
3453 cid = ngx_queue_data(q, ngx_quic_client_id_t, queue); 3466 cid = ngx_queue_data(q, ngx_quic_client_id_t, queue);