summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/event/ngx_event_quic.c84
-rw-r--r--src/event/ngx_event_quic_transport.c6
-rw-r--r--src/event/ngx_event_quic_transport.h1
3 files changed, 58 insertions, 33 deletions
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
index 6bb348892..bbe1e79c3 100644
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -34,6 +34,7 @@
typedef enum {
+ NGX_QUIC_ST_UNAVAIL, /* connection not ready */
NGX_QUIC_ST_INITIAL, /* connection just created */
NGX_QUIC_ST_HANDSHAKE, /* handshake started */
NGX_QUIC_ST_EARLY_DATA, /* handshake in progress */
@@ -119,6 +120,8 @@ struct ngx_quic_connection_s {
uint64_t cur_streams;
uint64_t max_streams;
+ ngx_uint_t error;
+
unsigned send_timer_set:1;
unsigned closing:1;
unsigned draining:1;
@@ -405,6 +408,7 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
if (ngx_quic_parse_transport_params(p, end, &qc->ctp, c->log)
!= NGX_OK)
{
+ qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR;
return NGX_ERROR;
}
@@ -417,6 +421,7 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
if (qc->ctp.max_packet_size < NGX_QUIC_MIN_INITIAL_SIZE
|| qc->ctp.max_packet_size > NGX_QUIC_DEFAULT_MAX_PACKET_SIZE)
{
+ qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic maximum packet size is invalid");
return NGX_ERROR;
@@ -580,8 +585,6 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
return NGX_ERROR;
}
- qc->state = NGX_QUIC_ST_INITIAL;
-
ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel,
ngx_quic_rbtree_insert_stream);
@@ -608,6 +611,7 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
qc->push.cancelable = 1;
c->quic = qc;
+ qc->state = NGX_QUIC_ST_UNAVAIL;
qc->ssl = ssl;
qc->tp = *tp;
qc->streams.handler = handler;
@@ -644,6 +648,8 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
return NGX_ERROR;
}
+ qc->state = NGX_QUIC_ST_INITIAL;
+
if (pkt->token.len) {
rc = ngx_quic_validate_token(c, pkt);
@@ -896,10 +902,12 @@ ngx_quic_validate_token(ngx_connection_t *c, ngx_quic_header_t *pkt)
if (qc->token.len) {
if (pkt->token.len != qc->token.len) {
+ qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
return NGX_ERROR;
}
if (ngx_memcmp(pkt->token.data, qc->token.data, pkt->token.len) != 0) {
+ qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
return NGX_ERROR;
}
@@ -916,6 +924,7 @@ ngx_quic_validate_token(ngx_connection_t *c, ngx_quic_header_t *pkt)
/* sanity checks */
if (pkt->token.len < (size_t) iv_len + EVP_CIPHER_block_size(cipher)) {
+ qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
return NGX_ERROR;
}
@@ -938,11 +947,13 @@ ngx_quic_validate_token(ngx_connection_t *c, ngx_quic_header_t *pkt)
if (EVP_DecryptUpdate(ctx, tdec, &len, p, len) != 1) {
EVP_CIPHER_CTX_free(ctx);
+ qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
return NGX_ERROR;
}
if (EVP_DecryptFinal_ex(ctx, tdec + len, &tlen) <= 0) {
EVP_CIPHER_CTX_free(ctx);
+ qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
return NGX_ERROR;
}
@@ -979,6 +990,7 @@ ngx_quic_validate_token(ngx_connection_t *c, ngx_quic_header_t *pkt)
}
if (ngx_memcmp(tdec, data, len) != 0) {
+ qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
return NGX_ERROR;
}
@@ -1116,7 +1128,7 @@ ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_close_connection, rc: %i", rc);
- if (!c->quic) {
+ if (!c->quic || c->quic->state == NGX_QUIC_ST_UNAVAIL) {
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic close connection early error");
@@ -1149,7 +1161,7 @@ ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc)
static ngx_int_t
ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc)
{
- ngx_uint_t i;
+ ngx_uint_t i, err;
ngx_quic_connection_t *qc;
enum ssl_encryption_level_t level;
@@ -1157,6 +1169,20 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc)
if (!qc->closing) {
+ switch (qc->state) {
+ case NGX_QUIC_ST_INITIAL:
+ level = ssl_encryption_initial;
+ break;
+
+ case NGX_QUIC_ST_HANDSHAKE:
+ level = ssl_encryption_handshake;
+ break;
+
+ default: /* NGX_QUIC_ST_APPLICATION/EARLY_DATA */
+ level = ssl_encryption_application;
+ break;
+ }
+
if (rc == NGX_OK) {
/*
@@ -1168,20 +1194,6 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic immediate close, drain = %d", qc->draining);
- switch (qc->state) {
- case NGX_QUIC_ST_INITIAL:
- level = ssl_encryption_initial;
- break;
-
- case NGX_QUIC_ST_HANDSHAKE:
- level = ssl_encryption_handshake;
- break;
-
- default: /* NGX_QUIC_ST_APPLICATION/EARLY_DATA */
- level = ssl_encryption_application;
- break;
- }
-
if (ngx_quic_send_cc(c, level, NGX_QUIC_ERR_NO_ERROR) == NGX_OK) {
qc->close.log = c->log;
@@ -1206,8 +1218,12 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc)
qc->draining ? "drained" : "idle");
} else {
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic immediate close due to fatal error");
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "quic immediate close due to fatal error: %ui",
+ qc->error);
+
+ err = qc->error ? qc->error : NGX_QUIC_ERR_INTERNAL_ERROR;
+ (void) ngx_quic_send_cc(c, level, err);
}
qc->closing = 1;
@@ -1749,14 +1765,8 @@ ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
len = ngx_quic_parse_frame(pkt, p, end, &frame);
- if (len == NGX_DECLINED) {
- /* TODO: handle protocol violation:
- * such frame not allowed in this packet
- */
- return NGX_ERROR;
- }
-
if (len < 0) {
+ qc->error = pkt->error;
return NGX_ERROR;
}
@@ -1887,6 +1897,8 @@ ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
if (p != end) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic trailing garbage in payload: %ui bytes", end - p);
+
+ qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
return NGX_ERROR;
}
@@ -2012,12 +2024,13 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
"quic ngx_quic_handle_ack_frame level %d", pkt->level);
/*
- * TODO: If any computed packet number is negative, an endpoint MUST
- * generate a connection error of type FRAME_ENCODING_ERROR.
- * (19.3.1)
+ * If any computed packet number is negative, an endpoint MUST
+ * generate a connection error of type FRAME_ENCODING_ERROR.
+ * (19.3.1)
*/
if (ack->first_range > ack->largest) {
+ c->quic->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic invalid first range in ack frame");
return NGX_ERROR;
@@ -2049,6 +2062,7 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
pos += n;
if (gap >= min) {
+ c->quic->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic invalid range %ui in ack frame", i);
return NGX_ERROR;
@@ -2057,6 +2071,7 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
max = min - 1 - gap;
if (range > max + 1) {
+ c->quic->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"quic invalid range %ui in ack frame", i);
return NGX_ERROR;
@@ -2116,7 +2131,9 @@ 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,
"quic ACK for the packet not in sent queue ");
- /* TODO: handle error properly: PROTOCOL VIOLATION */
+
+ qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION;
+
return NGX_ERROR;
}
@@ -2978,6 +2995,7 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_queue_t *frames)
ngx_msec_t now;
ngx_str_t out, res;
ngx_queue_t *q;
+ ngx_ssl_conn_t *ssl_conn;
ngx_quic_frame_t *f, *start;
ngx_quic_header_t pkt;
ngx_quic_secrets_t *keys;
@@ -2990,6 +3008,8 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_queue_t *frames)
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic ngx_quic_send_frames");
+ ssl_conn = c->ssl ? c->ssl->connection : NULL;
+
q = ngx_queue_head(frames);
start = ngx_queue_data(q, ngx_quic_frame_t, queue);
@@ -3077,7 +3097,7 @@ ngx_quic_send_frames(ngx_connection_t *c, ngx_queue_t *frames)
out.len, start->level, pkt.need_ack, pkt.number,
pkt.num_len, pkt.trunc);
- if (ngx_quic_encrypt(&pkt, c->ssl->connection, &res) != NGX_OK) {
+ if (ngx_quic_encrypt(&pkt, ssl_conn, &res) != NGX_OK) {
return NGX_ERROR;
}
diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c
index ddf99a3bc..4dcb78abd 100644
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -568,6 +568,7 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
p = ngx_quic_parse_int(p, end, &varint);
if (p == NULL) {
+ pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
"quic failed to obtain quic frame type");
return NGX_ERROR;
@@ -576,7 +577,8 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
f->type = varint;
if (ngx_quic_frame_allowed(pkt, f->type) != NGX_OK) {
- return NGX_DECLINED;
+ pkt->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION;
+ return NGX_ERROR;
}
switch (f->type) {
@@ -1003,6 +1005,8 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
error:
+ pkt->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
+
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
"quic failed to parse frame type 0x%xi", f->type);
diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h
index 1ff70f97b..364f827ac 100644
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -278,6 +278,7 @@ typedef struct {
uint32_t version;
ngx_str_t token;
enum ssl_encryption_level_t level;
+ ngx_uint_t error;
/* filled in by parser */
ngx_buf_t *raw; /* udp datagram */