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) {