Mercurial > hg > nginx
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); |