Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic.c @ 7876:ffd362e87eb2 quic
Added more context to CONNECTION CLOSE frames.
Now it is possible to specify frame type that caused an error
and a human-readable reason phrase.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Fri, 22 May 2020 18:08:02 +0300 |
parents | 8bec0ac23cf9 |
children | d96ddef458cd |
comparison
equal
deleted
inserted
replaced
7875:8bec0ac23cf9 | 7876:ffd362e87eb2 |
---|---|
110 | 110 |
111 uint64_t cur_streams; | 111 uint64_t cur_streams; |
112 uint64_t max_streams; | 112 uint64_t max_streams; |
113 | 113 |
114 ngx_uint_t error; | 114 ngx_uint_t error; |
115 ngx_uint_t error_ftype; | |
116 const char *error_reason; | |
115 | 117 |
116 unsigned send_timer_set:1; | 118 unsigned send_timer_set:1; |
117 unsigned closing:1; | 119 unsigned closing:1; |
118 unsigned draining:1; | 120 unsigned draining:1; |
119 unsigned key_phase:1; | 121 unsigned key_phase:1; |
179 ngx_quic_header_t *pkt); | 181 ngx_quic_header_t *pkt); |
180 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, | 182 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, |
181 ngx_quic_header_t *pkt); | 183 ngx_quic_header_t *pkt); |
182 static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt); | 184 static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt); |
183 static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c, | 185 static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c, |
184 enum ssl_encryption_level_t level, ngx_uint_t err); | 186 enum ssl_encryption_level_t level, ngx_uint_t err, ngx_uint_t frame_type, |
187 const char *reason); | |
185 static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c); | 188 static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c); |
186 | 189 |
187 static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c, | 190 static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c, |
188 ngx_quic_header_t *pkt, ngx_quic_ack_frame_t *f); | 191 ngx_quic_header_t *pkt, ngx_quic_ack_frame_t *f); |
189 static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c, | 192 static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c, |
399 | 402 |
400 if (ngx_quic_parse_transport_params(p, end, &qc->ctp, c->log) | 403 if (ngx_quic_parse_transport_params(p, end, &qc->ctp, c->log) |
401 != NGX_OK) | 404 != NGX_OK) |
402 { | 405 { |
403 qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; | 406 qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; |
407 qc->error_reason = "failed to process transport parameters"; | |
408 | |
404 return NGX_ERROR; | 409 return NGX_ERROR; |
405 } | 410 } |
406 | 411 |
407 if (qc->ctp.max_idle_timeout > 0 | 412 if (qc->ctp.max_idle_timeout > 0 |
408 && qc->ctp.max_idle_timeout < qc->tp.max_idle_timeout) | 413 && qc->ctp.max_idle_timeout < qc->tp.max_idle_timeout) |
412 | 417 |
413 if (qc->ctp.max_packet_size < NGX_QUIC_MIN_INITIAL_SIZE | 418 if (qc->ctp.max_packet_size < NGX_QUIC_MIN_INITIAL_SIZE |
414 || qc->ctp.max_packet_size > NGX_QUIC_DEFAULT_MAX_PACKET_SIZE) | 419 || qc->ctp.max_packet_size > NGX_QUIC_DEFAULT_MAX_PACKET_SIZE) |
415 { | 420 { |
416 qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; | 421 qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; |
422 qc->error_reason = "invalid maximum packet size"; | |
423 | |
417 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 424 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
418 "quic maximum packet size is invalid"); | 425 "quic maximum packet size is invalid"); |
419 return NGX_ERROR; | 426 return NGX_ERROR; |
420 } | 427 } |
421 | 428 |
494 | 501 |
495 if (c->quic == NULL) { | 502 if (c->quic == NULL) { |
496 return 1; | 503 return 1; |
497 } | 504 } |
498 | 505 |
499 if (ngx_quic_send_cc(c, level, 0x100 + alert) != NGX_OK) { | 506 if (ngx_quic_send_cc(c, level, 0x100 + alert, 0, "TLS alert") != NGX_OK) { |
500 return 0; | 507 return 0; |
501 } | 508 } |
502 | 509 |
503 return 1; | 510 return 1; |
504 } | 511 } |
676 | 683 |
677 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | 684 ctx = ngx_quic_get_send_ctx(qc, pkt->level); |
678 | 685 |
679 if (ngx_quic_decrypt(pkt, NULL, &ctx->largest_pn) != NGX_OK) { | 686 if (ngx_quic_decrypt(pkt, NULL, &ctx->largest_pn) != NGX_OK) { |
680 qc->error = pkt->error; | 687 qc->error = pkt->error; |
688 qc->error_reason = "failed to decrypt packet"; | |
689 | |
681 return NGX_ERROR; | 690 return NGX_ERROR; |
682 } | 691 } |
683 | 692 |
684 if (ngx_quic_init_connection(c) != NGX_OK) { | 693 if (ngx_quic_init_connection(c) != NGX_OK) { |
685 return NGX_ERROR; | 694 return NGX_ERROR; |
902 | 911 |
903 /* Retry token */ | 912 /* Retry token */ |
904 | 913 |
905 if (qc->token.len) { | 914 if (qc->token.len) { |
906 if (pkt->token.len != qc->token.len) { | 915 if (pkt->token.len != qc->token.len) { |
907 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | 916 goto bad_token; |
908 return NGX_ERROR; | |
909 } | 917 } |
910 | 918 |
911 if (ngx_memcmp(pkt->token.data, qc->token.data, pkt->token.len) != 0) { | 919 if (ngx_memcmp(pkt->token.data, qc->token.data, pkt->token.len) != 0) { |
912 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | 920 goto bad_token; |
913 return NGX_ERROR; | |
914 } | 921 } |
915 | 922 |
916 return NGX_OK; | 923 return NGX_OK; |
917 } | 924 } |
918 | 925 |
924 iv_len = EVP_CIPHER_iv_length(cipher); | 931 iv_len = EVP_CIPHER_iv_length(cipher); |
925 | 932 |
926 /* sanity checks */ | 933 /* sanity checks */ |
927 | 934 |
928 if (pkt->token.len < (size_t) iv_len + EVP_CIPHER_block_size(cipher)) { | 935 if (pkt->token.len < (size_t) iv_len + EVP_CIPHER_block_size(cipher)) { |
929 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | 936 goto bad_token; |
930 return NGX_ERROR; | |
931 } | 937 } |
932 | 938 |
933 if (pkt->token.len > (size_t) iv_len + NGX_QUIC_MAX_TOKEN_SIZE) { | 939 if (pkt->token.len > (size_t) iv_len + NGX_QUIC_MAX_TOKEN_SIZE) { |
934 return NGX_ERROR; | 940 goto bad_token; |
935 } | 941 } |
936 | 942 |
937 ctx = EVP_CIPHER_CTX_new(); | 943 ctx = EVP_CIPHER_CTX_new(); |
938 if (ctx == NULL) { | 944 if (ctx == NULL) { |
939 return NGX_ERROR; | 945 return NGX_ERROR; |
947 p = pkt->token.data + iv_len; | 953 p = pkt->token.data + iv_len; |
948 len = pkt->token.len - iv_len; | 954 len = pkt->token.len - iv_len; |
949 | 955 |
950 if (EVP_DecryptUpdate(ctx, tdec, &len, p, len) != 1) { | 956 if (EVP_DecryptUpdate(ctx, tdec, &len, p, len) != 1) { |
951 EVP_CIPHER_CTX_free(ctx); | 957 EVP_CIPHER_CTX_free(ctx); |
952 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | 958 goto bad_token; |
953 return NGX_ERROR; | |
954 } | 959 } |
955 | 960 |
956 if (EVP_DecryptFinal_ex(ctx, tdec + len, &tlen) <= 0) { | 961 if (EVP_DecryptFinal_ex(ctx, tdec + len, &tlen) <= 0) { |
957 EVP_CIPHER_CTX_free(ctx); | 962 EVP_CIPHER_CTX_free(ctx); |
958 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | 963 goto bad_token; |
959 return NGX_ERROR; | |
960 } | 964 } |
961 | 965 |
962 EVP_CIPHER_CTX_free(ctx); | 966 EVP_CIPHER_CTX_free(ctx); |
963 | 967 |
964 switch (c->sockaddr->sa_family) { | 968 switch (c->sockaddr->sa_family) { |
990 | 994 |
991 break; | 995 break; |
992 } | 996 } |
993 | 997 |
994 if (ngx_memcmp(tdec, data, len) != 0) { | 998 if (ngx_memcmp(tdec, data, len) != 0) { |
995 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | 999 goto bad_token; |
996 return NGX_ERROR; | |
997 } | 1000 } |
998 | 1001 |
999 ngx_memcpy(&msec, tdec + len, sizeof(msec)); | 1002 ngx_memcpy(&msec, tdec + len, sizeof(msec)); |
1000 | 1003 |
1001 if (ngx_current_msec - msec > NGX_QUIC_RETRY_LIFETIME) { | 1004 if (ngx_current_msec - msec > NGX_QUIC_RETRY_LIFETIME) { |
1002 return NGX_DECLINED; | 1005 return NGX_DECLINED; |
1003 } | 1006 } |
1004 | 1007 |
1005 return NGX_OK; | 1008 return NGX_OK; |
1009 | |
1010 bad_token: | |
1011 | |
1012 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | |
1013 qc->error_reason = "invalid_token"; | |
1014 | |
1015 return NGX_ERROR; | |
1006 } | 1016 } |
1007 | 1017 |
1008 | 1018 |
1009 static ngx_int_t | 1019 static ngx_int_t |
1010 ngx_quic_init_connection(ngx_connection_t *c) | 1020 ngx_quic_init_connection(ngx_connection_t *c) |
1192 * terminate the connection immediately. | 1202 * terminate the connection immediately. |
1193 */ | 1203 */ |
1194 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1204 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1195 "quic immediate close, drain = %d", qc->draining); | 1205 "quic immediate close, drain = %d", qc->draining); |
1196 | 1206 |
1197 if (ngx_quic_send_cc(c, level, NGX_QUIC_ERR_NO_ERROR) == NGX_OK) { | 1207 if (ngx_quic_send_cc(c, level, NGX_QUIC_ERR_NO_ERROR, 0, NULL) |
1208 == NGX_OK) | |
1209 { | |
1198 | 1210 |
1199 qc->close.log = c->log; | 1211 qc->close.log = c->log; |
1200 qc->close.data = c; | 1212 qc->close.data = c; |
1201 qc->close.handler = ngx_quic_close_timer_handler; | 1213 qc->close.handler = ngx_quic_close_timer_handler; |
1202 qc->close.cancelable = 1; | 1214 qc->close.cancelable = 1; |
1221 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1233 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1222 "quic immediate close due to fatal error: %ui", | 1234 "quic immediate close due to fatal error: %ui", |
1223 qc->error); | 1235 qc->error); |
1224 | 1236 |
1225 err = qc->error ? qc->error : NGX_QUIC_ERR_INTERNAL_ERROR; | 1237 err = qc->error ? qc->error : NGX_QUIC_ERR_INTERNAL_ERROR; |
1226 (void) ngx_quic_send_cc(c, level, err); | 1238 (void) ngx_quic_send_cc(c, level, err, qc->error_ftype, |
1239 qc->error_reason); | |
1227 } | 1240 } |
1228 | 1241 |
1229 qc->closing = 1; | 1242 qc->closing = 1; |
1230 } | 1243 } |
1231 | 1244 |
1767 * | 1780 * |
1768 * An endpoint retains only enough information to generate | 1781 * An endpoint retains only enough information to generate |
1769 * a packet containing a CONNECTION_CLOSE frame and to identify | 1782 * a packet containing a CONNECTION_CLOSE frame and to identify |
1770 * packets as belonging to the connection. | 1783 * packets as belonging to the connection. |
1771 */ | 1784 */ |
1772 return ngx_quic_send_cc(c, pkt->level, NGX_QUIC_ERR_NO_ERROR); | 1785 return ngx_quic_send_cc(c, pkt->level, NGX_QUIC_ERR_NO_ERROR, 0, |
1786 "connection is closing, packet discarded"); | |
1773 } | 1787 } |
1774 | 1788 |
1775 p = pkt->payload.data; | 1789 p = pkt->payload.data; |
1776 end = p + pkt->payload.len; | 1790 end = p + pkt->payload.len; |
1777 | 1791 |
1959 } | 1973 } |
1960 | 1974 |
1961 | 1975 |
1962 static ngx_int_t | 1976 static ngx_int_t |
1963 ngx_quic_send_cc(ngx_connection_t *c, enum ssl_encryption_level_t level, | 1977 ngx_quic_send_cc(ngx_connection_t *c, enum ssl_encryption_level_t level, |
1964 ngx_uint_t err) | 1978 ngx_uint_t err, ngx_uint_t frame_type, const char *reason) |
1965 { | 1979 { |
1966 ngx_quic_frame_t *frame; | 1980 ngx_quic_frame_t *frame; |
1967 ngx_quic_connection_t *qc; | 1981 ngx_quic_connection_t *qc; |
1968 | 1982 |
1969 qc = c->quic; | 1983 qc = c->quic; |
1985 } | 1999 } |
1986 | 2000 |
1987 frame->level = level; | 2001 frame->level = level; |
1988 frame->type = NGX_QUIC_FT_CONNECTION_CLOSE; | 2002 frame->type = NGX_QUIC_FT_CONNECTION_CLOSE; |
1989 frame->u.close.error_code = err; | 2003 frame->u.close.error_code = err; |
1990 ngx_sprintf(frame->info, "cc from send_cc err=%ui level=%d", err, | 2004 frame->u.close.frame_type = frame_type; |
1991 frame->level); | 2005 |
2006 if (reason) { | |
2007 frame->u.close.reason.len = ngx_strlen(reason); | |
2008 frame->u.close.reason.data = (u_char *) reason; | |
2009 } | |
2010 | |
2011 ngx_snprintf(frame->info, sizeof(frame->info) - 1, | |
2012 "cc from send_cc err=%ui level=%d ft=%ui reason \"%s\"", | |
2013 err, level, frame_type, reason ? reason : "-"); | |
1992 | 2014 |
1993 ngx_quic_queue_frame(c->quic, frame); | 2015 ngx_quic_queue_frame(c->quic, frame); |
1994 | 2016 |
1995 qc->last_cc = ngx_current_msec; | 2017 qc->last_cc = ngx_current_msec; |
1996 | 2018 |
2150 | 2172 |
2151 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 2173 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
2152 "quic ACK for the packet not in sent queue "); | 2174 "quic ACK for the packet not in sent queue "); |
2153 | 2175 |
2154 qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; | 2176 qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; |
2177 qc->error_ftype = NGX_QUIC_FT_ACK; | |
2178 qc->error_reason = "unknown packet number"; | |
2155 | 2179 |
2156 return NGX_ERROR; | 2180 return NGX_ERROR; |
2157 } | 2181 } |
2158 | 2182 |
2159 if (!qc->push.timer_set) { | 2183 if (!qc->push.timer_set) { |