QUIC: ngx_quic_set_error() function.

The function sets QUIC error unless it was set before.  Previously, a new
error always reset the old error.  Now the original error stays unchanged
for logging and sending to client.
This commit is contained in:
Roman Arutyunyan 2025-05-23 13:53:33 +04:00
parent eed8765a5f
commit 77c082903e
7 changed files with 146 additions and 108 deletions

View File

@ -135,8 +135,8 @@ ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp)
if (scid.len != ctp->initial_scid.len if (scid.len != ctp->initial_scid.len
|| ngx_memcmp(scid.data, ctp->initial_scid.data, scid.len) != 0) || ngx_memcmp(scid.data, ctp->initial_scid.data, scid.len) != 0)
{ {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR,
qc->error_reason = "invalid initial_source_connection_id"; "invalid initial_source_connection_id");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic client initial_source_connection_id mismatch"); "quic client initial_source_connection_id mismatch");
@ -146,8 +146,8 @@ ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp)
if (ctp->max_udp_payload_size < NGX_QUIC_MIN_INITIAL_SIZE if (ctp->max_udp_payload_size < NGX_QUIC_MIN_INITIAL_SIZE
|| ctp->max_udp_payload_size > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) || ctp->max_udp_payload_size > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE)
{ {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR,
qc->error_reason = "invalid maximum packet size"; "invalid maximum packet size");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic maximum packet size is invalid"); "quic maximum packet size is invalid");
@ -155,8 +155,8 @@ ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp)
} }
if (ctp->active_connection_id_limit < 2) { if (ctp->active_connection_id_limit < 2) {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR,
qc->error_reason = "invalid active_connection_id_limit"; "invalid active_connection_id_limit");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic active_connection_id_limit is invalid"); "quic active_connection_id_limit is invalid");
@ -164,8 +164,8 @@ ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp)
} }
if (ctp->ack_delay_exponent > 20) { if (ctp->ack_delay_exponent > 20) {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR,
qc->error_reason = "invalid ack_delay_exponent"; "invalid ack_delay_exponent");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic ack_delay_exponent is invalid"); "quic ack_delay_exponent is invalid");
@ -173,8 +173,8 @@ ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp)
} }
if (ctp->max_ack_delay >= 16384) { if (ctp->max_ack_delay >= 16384) {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR,
qc->error_reason = "invalid max_ack_delay"; "invalid max_ack_delay");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic max_ack_delay is invalid"); "quic max_ack_delay is invalid");
@ -426,8 +426,7 @@ ngx_quic_input_handler(ngx_event_t *rev)
c->close = 0; c->close = 0;
if (!ngx_exiting || !qc->streams.initialized) { if (!ngx_exiting || !qc->streams.initialized) {
qc->error = NGX_QUIC_ERR_NO_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_NO_ERROR, "graceful shutdown");
qc->error_reason = "graceful shutdown";
ngx_quic_close_connection(c, NGX_ERROR); ngx_quic_close_connection(c, NGX_ERROR);
return; return;
} }
@ -520,9 +519,9 @@ ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc)
* to terminate the connection immediately. * to terminate the connection immediately.
*/ */
if (qc->error == 0 && rc == NGX_ERROR) { if (rc == NGX_ERROR) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR,
qc->error_app = 0; "internal server error");
} }
ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
@ -621,6 +620,25 @@ quic_done:
} }
void
ngx_quic_set_error(ngx_connection_t *c, ngx_uint_t err, const char *reason)
{
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
if (qc->error) {
return;
}
qc->error = err;
qc->error_reason = reason;
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic error c:%ui r:\"%s\"",
err, reason);
}
void void
ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err,
const char *reason) const char *reason)
@ -629,7 +647,7 @@ ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err,
qc = ngx_quic_get_connection(c); qc = ngx_quic_get_connection(c);
if (qc->closing) { if (qc->error) {
return; return;
} }
@ -637,6 +655,9 @@ ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err,
qc->error_reason = reason; qc->error_reason = reason;
qc->error_app = 1; qc->error_app = 1;
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic error app c:%ui r:\"%s\"", err, reason);
ngx_post_event(&qc->close, &ngx_posted_events); ngx_post_event(&qc->close, &ngx_posted_events);
} }
@ -764,8 +785,8 @@ ngx_quic_handle_datagram(ngx_connection_t *c, ngx_buf_t *b,
{ {
ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic flood detected"); ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic flood detected");
qc->error = NGX_QUIC_ERR_NO_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_NO_ERROR,
qc->error_reason = "QUIC flood detected"; "quic flood detected");
return NGX_ERROR; return NGX_ERROR;
} }
} }
@ -993,8 +1014,7 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
rc = ngx_quic_decrypt(pkt, &ctx->largest_pn); rc = ngx_quic_decrypt(pkt, &ctx->largest_pn);
if (rc != NGX_OK) { if (rc != NGX_OK) {
qc->error = pkt->error; ngx_quic_set_error(c, pkt->error, "failed to decrypt packet");
qc->error_reason = "failed to decrypt packet";
return rc; return rc;
} }
@ -1053,9 +1073,10 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
*/ */
qc->error_level = pkt->level; qc->error_level = pkt->level;
qc->error = NGX_QUIC_ERR_NO_ERROR;
qc->error_reason = "connection is closing, packet discarded"; ngx_quic_set_error(c, NGX_QUIC_ERR_NO_ERROR,
qc->error_app = 0; "connection is closing, packet discarded");
return ngx_quic_send_cc(c); return ngx_quic_send_cc(c);
} }
@ -1202,7 +1223,7 @@ ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt)
len = ngx_quic_parse_frame(pkt, p, end, &frame); len = ngx_quic_parse_frame(pkt, p, end, &frame);
if (len < 0) { if (len < 0) {
qc->error = pkt->error; ngx_quic_set_error(c, pkt->error, "failed to parse frame");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1405,6 +1426,9 @@ ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt)
default: default:
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic missing frame handler"); "quic missing frame handler");
ngx_quic_set_error(c, NGX_QUIC_ERR_PROTOCOL_VIOLATION,
"unexpected frame type");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1417,7 +1441,8 @@ ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt)
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic trailing garbage in payload:%ui bytes", end - p); "quic trailing garbage in payload:%ui bytes", end - p);
qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FRAME_ENCODING_ERROR,
"trailing garbage in quic payload");
return NGX_ERROR; return NGX_ERROR;
} }

View File

@ -120,7 +120,9 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
*/ */
if (ack->first_range > ack->largest) { if (ack->first_range > ack->largest) {
qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FRAME_ENCODING_ERROR,
"invalid first range in ack frame");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic invalid first range in ack frame"); "quic invalid first range in ack frame");
return NGX_ERROR; return NGX_ERROR;
@ -177,7 +179,9 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
pos += n; pos += n;
if (gap + 2 > min) { if (gap + 2 > min) {
qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FRAME_ENCODING_ERROR,
"invalid range in ack frame");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic invalid range:%ui in ack frame", i); "quic invalid range:%ui in ack frame", i);
return NGX_ERROR; return NGX_ERROR;
@ -186,7 +190,9 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
max = min - gap - 2; max = min - gap - 2;
if (range > max) { if (range > max) {
qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FRAME_ENCODING_ERROR,
"invalid range in ack frame");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic invalid range:%ui in ack frame", i); "quic invalid range:%ui in ack frame", i);
return NGX_ERROR; return NGX_ERROR;
@ -324,8 +330,8 @@ ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic ACK for the packet not sent"); "quic ACK for the packet not sent");
qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; ngx_quic_set_error(c, NGX_QUIC_ERR_PROTOCOL_VIOLATION,
qc->error_reason = "unknown packet number"; "unsent packet acknowledged");
return NGX_ERROR; return NGX_ERROR;
} }

View File

@ -309,6 +309,8 @@ struct ngx_quic_connection_s {
}; };
void ngx_quic_set_error(ngx_connection_t *c, ngx_uint_t err,
const char *reason);
ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c,
ngx_quic_tp_t *ctp); ngx_quic_tp_t *ctp);
void ngx_quic_discard_ctx(ngx_connection_t *c, ngx_uint_t level); void ngx_quic_discard_ctx(ngx_connection_t *c, ngx_uint_t level);

View File

@ -137,8 +137,9 @@ ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
* the endpoint MAY treat that receipt as a connection error * the endpoint MAY treat that receipt as a connection error
* of type PROTOCOL_VIOLATION. * of type PROTOCOL_VIOLATION.
*/ */
qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; ngx_quic_set_error(c, NGX_QUIC_ERR_PROTOCOL_VIOLATION,
qc->error_reason = "seqnum refers to different connection id/token"; "seqnum refers to different "
"connection id/token");
return NGX_ERROR; return NGX_ERROR;
} }
@ -194,8 +195,8 @@ done:
* active_connection_id_limit transport parameter, an endpoint MUST * active_connection_id_limit transport parameter, an endpoint MUST
* close the connection with an error of type CONNECTION_ID_LIMIT_ERROR. * close the connection with an error of type CONNECTION_ID_LIMIT_ERROR.
*/ */
qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR,
qc->error_reason = "too many connection ids received"; "too many connection ids received");
return NGX_ERROR; return NGX_ERROR;
} }
@ -357,8 +358,8 @@ ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
* number greater than any previously sent to the peer MUST be * number greater than any previously sent to the peer MUST be
* treated as a connection error of type PROTOCOL_VIOLATION. * treated as a connection error of type PROTOCOL_VIOLATION.
*/ */
qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; ngx_quic_set_error(c, NGX_QUIC_ERR_PROTOCOL_VIOLATION,
qc->error_reason = "sequence number of id to retire was never issued"; "sequence number of id to retire was never issued");
return NGX_ERROR; return NGX_ERROR;
} }
@ -375,9 +376,8 @@ ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
* which the frame is contained. The peer MAY treat this as a * which the frame is contained. The peer MAY treat this as a
* connection error of type PROTOCOL_VIOLATION. * connection error of type PROTOCOL_VIOLATION.
*/ */
ngx_quic_set_error(c, NGX_QUIC_ERR_PROTOCOL_VIOLATION,
qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; "sequence number of id to retire refers DCID");
qc->error_reason = "sequence number of id to retire refers DCID";
return NGX_ERROR; return NGX_ERROR;
} }

View File

@ -799,8 +799,8 @@ ngx_quic_expire_path_validation(ngx_connection_t *c, ngx_quic_path_t *path)
bkp = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP); bkp = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP);
if (bkp == NULL) { if (bkp == NULL) {
qc->error = NGX_QUIC_ERR_NO_VIABLE_PATH; ngx_quic_set_error(c, NGX_QUIC_ERR_NO_VIABLE_PATH,
qc->error_reason = "no viable path"; "no viable path");
return NGX_ERROR; return NGX_ERROR;
} }

View File

@ -88,8 +88,9 @@ ngx_quic_cbs_send(ngx_ssl_conn_t *ssl_conn,
SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len); SSL_get0_alpn_selected(ssl_conn, &alpn_data, &alpn_len);
if (alpn_len == 0) { if (alpn_len == 0) {
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL); ngx_quic_set_error(c,
qc->error_reason = "missing ALPN extension"; NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL),
"missing ALPN extension");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic missing ALPN extension"); "quic missing ALPN extension");
@ -98,8 +99,8 @@ ngx_quic_cbs_send(ngx_ssl_conn_t *ssl_conn,
if (!qc->client_tp_done) { if (!qc->client_tp_done) {
/* RFC 9001, 8.2. QUIC Transport Parameters Extension */ /* RFC 9001, 8.2. QUIC Transport Parameters Extension */
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION); ngx_quic_set_error(c, NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION),
qc->error_reason = "missing transport parameters"; "missing transport parameters");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"missing transport parameters"); "missing transport parameters");
@ -110,13 +111,13 @@ ngx_quic_cbs_send(ngx_ssl_conn_t *ssl_conn,
out = ngx_quic_copy_buffer(c, (u_char *) data, len); out = ngx_quic_copy_buffer(c, (u_char *) data, len);
if (out == NGX_CHAIN_ERROR) { if (out == NGX_CHAIN_ERROR) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "buffer error");
return 1; return 1;
} }
frame = ngx_quic_alloc_frame(c); frame = ngx_quic_alloc_frame(c);
if (frame == NULL) { if (frame == NULL) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "memory error");
return 1; return 1;
} }
@ -190,7 +191,7 @@ ngx_quic_cbs_release_rcd(ngx_ssl_conn_t *ssl_conn, size_t bytes_read, void *arg)
cl = ngx_quic_read_buffer(c, &ctx->crypto, bytes_read); cl = ngx_quic_read_buffer(c, &ctx->crypto, bytes_read);
if (cl == NGX_CHAIN_ERROR) { if (cl == NGX_CHAIN_ERROR) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "buffer error");
return 1; return 1;
} }
@ -241,7 +242,7 @@ ngx_quic_cbs_yield_secret(ngx_ssl_conn_t *ssl_conn, uint32_t ssl_level,
cipher, secret, secret_len) cipher, secret, secret_len)
!= NGX_OK) != NGX_OK)
{ {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "key error");
return 1; return 1;
} }
@ -279,9 +280,8 @@ ngx_quic_cbs_got_transport_params(ngx_ssl_conn_t *ssl_conn,
end = p + params_len; end = p + params_len;
if (ngx_quic_parse_transport_params(p, end, &ctp, c->log) != NGX_OK) { if (ngx_quic_parse_transport_params(p, end, &ctp, c->log) != NGX_OK) {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR,
qc->error_reason = "failed to process transport parameters"; "failed to process transport parameters");
return 1; return 1;
} }
@ -312,8 +312,7 @@ ngx_quic_cbs_alert(ngx_ssl_conn_t *ssl_conn, unsigned char alert, void *arg)
return 1; return 1;
} }
qc->error = NGX_QUIC_ERR_CRYPTO(alert); ngx_quic_set_error(c, NGX_QUIC_ERR_CRYPTO(alert), "handshake error");
qc->error_reason = "handshake failed";
return 1; return 1;
} }
@ -365,7 +364,7 @@ ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn,
cipher, rsecret, secret_len) cipher, rsecret, secret_len)
!= NGX_OK) != NGX_OK)
{ {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "key error");
} }
return 1; return 1;
@ -397,7 +396,7 @@ ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn,
cipher, wsecret, secret_len) cipher, wsecret, secret_len)
!= NGX_OK) != NGX_OK)
{ {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "key error");
} }
return 1; return 1;
@ -434,7 +433,7 @@ ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
cipher, rsecret, secret_len) cipher, rsecret, secret_len)
!= NGX_OK) != NGX_OK)
{ {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "key error");
return 1; return 1;
} }
@ -452,7 +451,7 @@ ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
cipher, wsecret, secret_len) cipher, wsecret, secret_len)
!= NGX_OK) != NGX_OK)
{ {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "key error");
} }
return 1; return 1;
@ -496,8 +495,9 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
if (alpn_len == 0) { if (alpn_len == 0) {
if (qc->error == 0) { if (qc->error == 0) {
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL); ngx_quic_set_error(c,
qc->error_reason = "missing ALPN extension"; NGX_QUIC_ERR_CRYPTO(SSL_AD_NO_APPLICATION_PROTOCOL),
"missing ALPN extension");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic missing ALPN extension"); "quic missing ALPN extension");
@ -517,8 +517,9 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
/* RFC 9001, 8.2. QUIC Transport Parameters Extension */ /* RFC 9001, 8.2. QUIC Transport Parameters Extension */
if (qc->error == 0) { if (qc->error == 0) {
qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION); ngx_quic_set_error(c,
qc->error_reason = "missing transport parameters"; NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION),
"missing transport parameters");
ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_log_error(NGX_LOG_INFO, c->log, 0,
"missing transport parameters"); "missing transport parameters");
@ -536,9 +537,8 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
if (ngx_quic_parse_transport_params(p, end, &ctp, c->log) if (ngx_quic_parse_transport_params(p, end, &ctp, c->log)
!= NGX_OK) != NGX_OK)
{ {
qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR,
qc->error_reason = "failed to process transport parameters"; "failed to process transport parameters");
return 1; return 1;
} }
@ -553,13 +553,13 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
out = ngx_quic_copy_buffer(c, (u_char *) data, len); out = ngx_quic_copy_buffer(c, (u_char *) data, len);
if (out == NGX_CHAIN_ERROR) { if (out == NGX_CHAIN_ERROR) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "buffer error");
return 1; return 1;
} }
frame = ngx_quic_alloc_frame(c); frame = ngx_quic_alloc_frame(c);
if (frame == NULL) { if (frame == NULL) {
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_INTERNAL_ERROR, "memory error");
return 1; return 1;
} }
@ -612,8 +612,7 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
return 1; return 1;
} }
qc->error = NGX_QUIC_ERR_CRYPTO(alert); ngx_quic_set_error(c, NGX_QUIC_ERR_CRYPTO(alert), "handshake error");
qc->error_reason = "handshake failed";
return 1; return 1;
} }
@ -643,7 +642,8 @@ ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
last = f->offset + f->length; last = f->offset + f->length;
if (last > ctx->crypto.offset + NGX_QUIC_MAX_BUFFERED) { if (last > ctx->crypto.offset + NGX_QUIC_MAX_BUFFERED) {
qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; ngx_quic_set_error(c, NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED,
"crypto buffer exceeded");
return NGX_ERROR; return NGX_ERROR;
} }

View File

@ -408,7 +408,8 @@ ngx_quic_get_stream(ngx_connection_t *c, uint64_t id)
return NGX_QUIC_STREAM_GONE; return NGX_QUIC_STREAM_GONE;
} }
qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_STATE_ERROR,
"peer attempted to open a local stream");
return NULL; return NULL;
} }
@ -417,7 +418,8 @@ ngx_quic_get_stream(ngx_connection_t *c, uint64_t id)
} }
if ((id >> 2) >= qc->streams.client_max_streams_uni) { if ((id >> 2) >= qc->streams.client_max_streams_uni) {
qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_LIMIT_ERROR,
"peer exceeded stream limit");
return NULL; return NULL;
} }
@ -432,7 +434,8 @@ ngx_quic_get_stream(ngx_connection_t *c, uint64_t id)
return NGX_QUIC_STREAM_GONE; return NGX_QUIC_STREAM_GONE;
} }
qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_STATE_ERROR,
"peer attempted to open a local stream");
return NULL; return NULL;
} }
@ -441,7 +444,8 @@ ngx_quic_get_stream(ngx_connection_t *c, uint64_t id)
} }
if ((id >> 2) >= qc->streams.client_max_streams_bidi) { if ((id >> 2) >= qc->streams.client_max_streams_bidi) {
qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_LIMIT_ERROR,
"peer exceeded stream limit");
return NULL; return NULL;
} }
@ -1096,12 +1100,14 @@ ngx_quic_stream_cleanup_handler(void *data)
{ {
ngx_connection_t *c = data; ngx_connection_t *c = data;
ngx_connection_t *pc;
ngx_quic_stream_t *qs; ngx_quic_stream_t *qs;
ngx_quic_connection_t *qc; ngx_quic_connection_t *qc;
qs = c->quic; qs = c->quic;
pc = qs->parent;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, qs->parent->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0,
"quic stream id:0x%xL cleanup", qs->id); "quic stream id:0x%xL cleanup", qs->id);
if (ngx_quic_shutdown_stream(c, NGX_RDWR_SHUTDOWN) != NGX_OK) { if (ngx_quic_shutdown_stream(c, NGX_RDWR_SHUTDOWN) != NGX_OK) {
@ -1119,8 +1125,9 @@ ngx_quic_stream_cleanup_handler(void *data)
failed: failed:
qc = ngx_quic_get_connection(qs->parent); ngx_quic_set_error(pc, NGX_QUIC_ERR_INTERNAL_ERROR, "stream cleanup error");
qc->error = NGX_QUIC_ERR_INTERNAL_ERROR;
qc = ngx_quic_get_connection(pc);
ngx_post_event(&qc->close, &ngx_posted_events); ngx_post_event(&qc->close, &ngx_posted_events);
} }
@ -1234,16 +1241,15 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
{ {
uint64_t last; uint64_t last;
ngx_quic_stream_t *qs; ngx_quic_stream_t *qs;
ngx_quic_connection_t *qc;
ngx_quic_stream_frame_t *f; ngx_quic_stream_frame_t *f;
qc = ngx_quic_get_connection(c);
f = &frame->u.stream; f = &frame->u.stream;
if ((f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL) if ((f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL)
&& (f->stream_id & NGX_QUIC_STREAM_SERVER_INITIATED)) && (f->stream_id & NGX_QUIC_STREAM_SERVER_INITIATED))
{ {
qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_STATE_ERROR,
"peer sent data on local uni stream");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1271,7 +1277,8 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
} }
if (qs->recv_final_size != (uint64_t) -1 && last > qs->recv_final_size) { if (qs->recv_final_size != (uint64_t) -1 && last > qs->recv_final_size) {
qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FINAL_SIZE_ERROR,
"peer sent data beyond stream end");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1282,12 +1289,14 @@ ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
if (f->fin) { if (f->fin) {
if (qs->recv_final_size != (uint64_t) -1 && qs->recv_final_size != last) if (qs->recv_final_size != (uint64_t) -1 && qs->recv_final_size != last)
{ {
qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FINAL_SIZE_ERROR,
"peer sent data beyond stream end");
return NGX_ERROR; return NGX_ERROR;
} }
if (qs->recv_last > last) { if (qs->recv_last > last) {
qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FINAL_SIZE_ERROR,
"peer sent data beyond stream end");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1380,15 +1389,13 @@ ngx_int_t
ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c, ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_stream_data_blocked_frame_t *f) ngx_quic_header_t *pkt, ngx_quic_stream_data_blocked_frame_t *f)
{ {
ngx_quic_stream_t *qs; ngx_quic_stream_t *qs;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL)
&& (f->id & NGX_QUIC_STREAM_SERVER_INITIATED)) && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED))
{ {
qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_STATE_ERROR,
"peer sent data blocked for local uni stream");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1410,15 +1417,13 @@ ngx_int_t
ngx_quic_handle_max_stream_data_frame(ngx_connection_t *c, ngx_quic_handle_max_stream_data_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_max_stream_data_frame_t *f) ngx_quic_header_t *pkt, ngx_quic_max_stream_data_frame_t *f)
{ {
ngx_quic_stream_t *qs; ngx_quic_stream_t *qs;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL)
&& (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0)
{ {
qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_STATE_ERROR,
"peer sent flow control for local uni stream");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1452,16 +1457,14 @@ ngx_int_t
ngx_quic_handle_reset_stream_frame(ngx_connection_t *c, ngx_quic_handle_reset_stream_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_reset_stream_frame_t *f) ngx_quic_header_t *pkt, ngx_quic_reset_stream_frame_t *f)
{ {
ngx_event_t *rev; ngx_event_t *rev;
ngx_quic_stream_t *qs; ngx_quic_stream_t *qs;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL)
&& (f->id & NGX_QUIC_STREAM_SERVER_INITIATED)) && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED))
{ {
qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_STATE_ERROR,
"peer sent reset for local uni stream");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1490,12 +1493,14 @@ ngx_quic_handle_reset_stream_frame(ngx_connection_t *c,
if (qs->recv_final_size != (uint64_t) -1 if (qs->recv_final_size != (uint64_t) -1
&& qs->recv_final_size != f->final_size) && qs->recv_final_size != f->final_size)
{ {
qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FINAL_SIZE_ERROR,
"peer sent data beyond stream end");
return NGX_ERROR; return NGX_ERROR;
} }
if (qs->recv_last > f->final_size) { if (qs->recv_last > f->final_size) {
qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_FINAL_SIZE_ERROR,
"peer sent data beyond stream end");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1522,15 +1527,13 @@ ngx_int_t
ngx_quic_handle_stop_sending_frame(ngx_connection_t *c, ngx_quic_handle_stop_sending_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_stop_sending_frame_t *f) ngx_quic_header_t *pkt, ngx_quic_stop_sending_frame_t *f)
{ {
ngx_quic_stream_t *qs; ngx_quic_stream_t *qs;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) if ((f->id & NGX_QUIC_STREAM_UNIDIRECTIONAL)
&& (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) && (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0)
{ {
qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; ngx_quic_set_error(c, NGX_QUIC_ERR_STREAM_STATE_ERROR,
"peer sent stop sending for local uni stream");
return NGX_ERROR; return NGX_ERROR;
} }
@ -1683,14 +1686,16 @@ ngx_quic_control_flow(ngx_quic_stream_t *qs, uint64_t last)
if (qs->recv_state == NGX_QUIC_STREAM_RECV_RECV if (qs->recv_state == NGX_QUIC_STREAM_RECV_RECV
&& qs->recv_last > qs->recv_max_data) && qs->recv_last > qs->recv_max_data)
{ {
qc->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; ngx_quic_set_error(pc, NGX_QUIC_ERR_FLOW_CONTROL_ERROR,
"peer sent data beyond stream flow control");
return NGX_ERROR; return NGX_ERROR;
} }
qc->streams.recv_last += len; qc->streams.recv_last += len;
if (qc->streams.recv_last > qc->streams.recv_max_data) { if (qc->streams.recv_last > qc->streams.recv_max_data) {
qc->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; ngx_quic_set_error(pc, NGX_QUIC_ERR_FLOW_CONTROL_ERROR,
"peer sent data beyond flow control");
return NGX_ERROR; return NGX_ERROR;
} }