aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVladimir Homutov <vl@nginx.com>2020-09-30 15:14:09 +0300
committerVladimir Homutov <vl@nginx.com>2020-09-30 15:14:09 +0300
commit99d4f2399dc466c52bcb30433c6ecc1613130ab8 (patch)
treeec604358332777821e487b0004af4432e3099fb2 /src
parentfe626bda8426fe7f0a9a9e4930eba30eb2b2f109 (diff)
downloadnginx-99d4f2399dc466c52bcb30433c6ecc1613130ab8.tar.gz
nginx-99d4f2399dc466c52bcb30433c6ecc1613130ab8.zip
QUIC: packet processing refactoring.
All packet header parsing is now performed by ngx_quic_parse_packet() function, located in the ngx_quic_transport.c file. The packet processing is centralized in the ngx_quic_process_packet() function which decides if the packet should be accepted, ignored or connection should be closed, depending on the connection state. As a result of refactoring, behavior has changed in some places: - minimal size of Initial packet is now always tested - connection IDs are always tested in existing connections - old keys are discarded on encryption level switch
Diffstat (limited to 'src')
-rw-r--r--src/event/ngx_event_quic.c637
-rw-r--r--src/event/ngx_event_quic_transport.c69
-rw-r--r--src/event/ngx_event_quic_transport.h8
3 files changed, 239 insertions, 475 deletions
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
index 04fe56deb..184afd8e1 100644
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -187,7 +187,7 @@ static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c,
ngx_quic_header_t *inpkt);
static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid);
-static ngx_int_t ngx_quic_retry(ngx_connection_t *c);
+static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c);
static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token);
static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c,
ngx_quic_header_t *pkt);
@@ -201,20 +201,14 @@ static void ngx_quic_close_timer_handler(ngx_event_t *ev);
static ngx_int_t ngx_quic_close_streams(ngx_connection_t *c,
ngx_quic_connection_t *qc);
-static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b);
-static ngx_inline u_char *ngx_quic_skip_zero_padding(ngx_buf_t *b);
-static ngx_int_t ngx_quic_retry_input(ngx_connection_t *c,
- ngx_quic_header_t *pkt);
-static ngx_int_t ngx_quic_initial_input(ngx_connection_t *c,
- ngx_quic_header_t *pkt);
-static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c,
- ngx_quic_header_t *pkt);
-static ngx_int_t ngx_quic_early_input(ngx_connection_t *c,
- ngx_quic_header_t *pkt);
+static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b,
+ ngx_ssl_t *ssl, ngx_quic_conf_t *conf);
+static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c, ngx_ssl_t *ssl,
+ ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
+static void ngx_quic_discard_ctx(ngx_connection_t *c,
+ enum ssl_encryption_level_t level);
static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc,
ngx_quic_header_t *pkt);
-static ngx_int_t ngx_quic_app_input(ngx_connection_t *c,
- ngx_quic_header_t *pkt);
static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c,
ngx_quic_header_t *pkt);
static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt);
@@ -630,24 +624,13 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level,
void
ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_conf_t *conf)
{
- ngx_int_t rc;
- ngx_buf_t *b;
- ngx_quic_header_t pkt;
+ ngx_int_t rc;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic run");
c->log->action = "QUIC initialization";
- ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
-
- b = c->buffer;
-
- pkt.log = c->log;
- pkt.raw = b;
- pkt.data = b->start;
- pkt.len = b->last - b->start;
-
- rc = ngx_quic_new_connection(c, ssl, conf, &pkt);
+ rc = ngx_quic_input(c, c->buffer, ssl, conf);
if (rc != NGX_OK) {
ngx_quic_close_connection(c, rc == NGX_DECLINED ? NGX_DONE : NGX_ERROR);
return;
@@ -666,46 +649,10 @@ static ngx_int_t
ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt)
{
- ngx_int_t rc;
ngx_uint_t i;
ngx_quic_tp_t *ctp;
- ngx_quic_secrets_t *keys;
- ngx_quic_send_ctx_t *ctx;
ngx_quic_client_id_t *cid;
ngx_quic_connection_t *qc;
- static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
-
- if (ngx_buf_size(pkt->raw) < NGX_QUIC_MIN_INITIAL_SIZE) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic UDP datagram is too small for initial packet");
- return NGX_ERROR;
- }
-
- if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
- return NGX_ERROR;
- }
-
- if (pkt->version != NGX_QUIC_VERSION) {
- return ngx_quic_negotiate_version(c, pkt);
- }
-
- if (!ngx_quic_pkt_in(pkt->flags)) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic invalid initial packet: 0x%xd", pkt->flags);
- return NGX_ERROR;
- }
-
- if (ngx_quic_parse_initial_header(pkt) != NGX_OK) {
- return NGX_ERROR;
- }
-
- if (pkt->dcid.len < NGX_QUIC_CID_LEN_MIN) {
- /* 7.2. Negotiating Connection IDs */
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic too short dcid in initial packet: length %i",
- pkt->dcid.len);
- return NGX_ERROR;
- }
c->log->action = "creating new quic connection";
@@ -804,15 +751,6 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
qc->nclient_ids++;
qc->curr_seqnum = 0;
- keys = &c->quic->keys[ssl_encryption_initial];
-
- if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server,
- &qc->odcid)
- != NGX_OK)
- {
- return NGX_ERROR;
- }
-
qc->initialized = 1;
if (ngx_terminate || ngx_exiting) {
@@ -820,60 +758,6 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
return NGX_ERROR;
}
- if (pkt->token.len) {
- rc = ngx_quic_validate_token(c, pkt);
-
- if (rc == NGX_ERROR) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token");
- return NGX_ERROR;
- }
-
- if (rc == NGX_DECLINED) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token");
- return ngx_quic_retry(c);
- }
-
- /* NGX_OK */
- qc->validated = 1;
-
- } else if (conf->retry) {
- return ngx_quic_retry(c);
- }
-
- pkt->secret = &keys->client;
- pkt->level = ssl_encryption_initial;
- pkt->plaintext = buf;
-
- ctx = ngx_quic_get_send_ctx(qc, pkt->level);
-
- rc = ngx_quic_decrypt(pkt, NULL, &ctx->largest_pn);
- if (rc != NGX_OK) {
- qc->error = pkt->error;
- qc->error_reason = "failed to decrypt packet";
- return rc;
- }
-
- if (ngx_quic_init_connection(c) != NGX_OK) {
- return NGX_ERROR;
- }
-
- if (ngx_quic_payload_handler(c, pkt) != NGX_OK) {
- return NGX_ERROR;
- }
-
- /* pos is at header end, adjust by actual packet length */
- pkt->raw->pos += pkt->len;
-
- (void) ngx_quic_skip_zero_padding(pkt->raw);
-
- rc = ngx_quic_input(c, pkt->raw);
-
- if (rc == NGX_ERROR) {
- return NGX_ERROR;
- }
-
- /* rc == NGX_OK || rc == NGX_DECLINED */
-
return NGX_OK;
}
@@ -939,7 +823,7 @@ ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid)
static ngx_int_t
-ngx_quic_retry(ngx_connection_t *c)
+ngx_quic_send_retry(ngx_connection_t *c)
{
ssize_t len;
ngx_str_t res, token;
@@ -1194,6 +1078,7 @@ ngx_quic_validate_token(ngx_connection_t *c, ngx_quic_header_t *pkt)
ngx_memcpy(&msec, tdec + len, sizeof(msec));
if (ngx_current_msec - msec > NGX_QUIC_RETRY_LIFETIME) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token");
return NGX_DECLINED;
}
@@ -1201,6 +1086,8 @@ ngx_quic_validate_token(ngx_connection_t *c, ngx_quic_header_t *pkt)
bad_token:
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token");
+
qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
qc->error_reason = "invalid_token";
@@ -1339,7 +1226,7 @@ ngx_quic_input_handler(ngx_event_t *rev)
b.last += n;
qc->received += n;
- rc = ngx_quic_input(c, &b);
+ rc = ngx_quic_input(c, &b, NULL, NULL);
if (rc == NGX_ERROR) {
ngx_quic_close_connection(c, NGX_ERROR);
@@ -1603,7 +1490,8 @@ ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc)
static ngx_int_t
-ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b)
+ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b, ngx_ssl_t *ssl,
+ ngx_quic_conf_t *conf)
{
u_char *p;
ngx_int_t rc;
@@ -1625,29 +1513,7 @@ ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b)
pkt.flags = p[0];
pkt.raw->pos++;
- if (c->quic->in_retry) {
- rc = ngx_quic_retry_input(c, &pkt);
-
- } else if (ngx_quic_long_pkt(pkt.flags)) {
-
- if (ngx_quic_pkt_in(pkt.flags)) {
- rc = ngx_quic_initial_input(c, &pkt);
-
- } else if (ngx_quic_pkt_hs(pkt.flags)) {
- rc = ngx_quic_handshake_input(c, &pkt);
-
- } else if (ngx_quic_pkt_zrtt(pkt.flags)) {
- rc = ngx_quic_early_input(c, &pkt);
-
- } else {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic unknown long packet type");
- rc = NGX_DECLINED;
- }
-
- } else {
- rc = ngx_quic_app_input(c, &pkt);
- }
+ rc = ngx_quic_process_packet(c, ssl, conf, &pkt);
if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -1678,164 +1544,156 @@ ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b)
/* b->pos is at header end, adjust by actual packet length */
b->pos = pkt.data + pkt.len;
- p = ngx_quic_skip_zero_padding(b);
- }
-
- return good ? NGX_OK : NGX_DECLINED;
-}
+ /* firefox workaround: skip zero padding at the end of quic packet */
+ while (b->pos < b->last && *(b->pos) == 0) {
+ b->pos++;
+ }
-/* firefox workaround: skip zero padding at the end of quic packet */
-static ngx_inline u_char *
-ngx_quic_skip_zero_padding(ngx_buf_t *b)
-{
- while (b->pos < b->last && *(b->pos) == 0) {
- b->pos++;
+ p = b->pos;
}
- return b->pos;
+ return good ? NGX_OK : NGX_DECLINED;
}
static ngx_int_t
-ngx_quic_retry_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
+ngx_quic_process_packet(ngx_connection_t *c, ngx_ssl_t *ssl,
+ ngx_quic_conf_t *conf, ngx_quic_header_t *pkt)
{
ngx_int_t rc;
- ngx_quic_secrets_t *keys;
+ ngx_ssl_conn_t *ssl_conn;
+ ngx_quic_secrets_t *keys, *next, tmp;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
- static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
- c->log->action = "retrying quic connection";
+ static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
- if (ngx_buf_size(pkt->raw) < NGX_QUIC_MIN_INITIAL_SIZE) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic UDP datagram is too small for initial packet");
- return NGX_DECLINED;
- }
+ rc = ngx_quic_parse_packet(pkt);
- if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
- return NGX_DECLINED;
+ if (rc == NGX_DECLINED || rc == NGX_ERROR) {
+ return rc;
}
- if (pkt->version != NGX_QUIC_VERSION) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic unsupported version: 0x%xD", pkt->version);
- return NGX_DECLINED;
- }
+ qc = c->quic;
- if (ngx_quic_pkt_zrtt(pkt->flags)) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic discard inflight 0-RTT packet");
- return NGX_DECLINED;
- }
+ if (qc) {
- if (!ngx_quic_pkt_in(pkt->flags)) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic invalid initial packet: 0x%xd", pkt->flags);
- return NGX_DECLINED;
- }
+ if (rc == NGX_ABORT) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "quic unsupported version: 0x%xD", pkt->version);
+ return NGX_DECLINED;
+ }
- if (ngx_quic_parse_initial_header(pkt) != NGX_OK) {
- return NGX_DECLINED;
- }
+ if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
+ return NGX_DECLINED;
+ }
- if (!pkt->token.len) {
- return NGX_DECLINED;
- }
+ if (qc->in_retry) {
- if (ngx_quic_new_dcid(c, &pkt->dcid) != NGX_OK) {
- return NGX_ERROR;
- }
+ c->log->action = "retrying quic connection";
- qc = c->quic;
- qc->tp.initial_scid = c->quic->dcid;
+ if (pkt->level != ssl_encryption_initial) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "quic discard late retry packet");
+ return NGX_DECLINED;
+ }
- keys = &c->quic->keys[ssl_encryption_initial];
+ if (!pkt->token.len) {
+ return NGX_DECLINED;
+ }
- if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server,
- &qc->odcid)
- != NGX_OK)
- {
- return NGX_ERROR;
- }
+ if (ngx_quic_new_dcid(c, &pkt->dcid) != NGX_OK) {
+ return NGX_ERROR;
+ }
- c->quic->in_retry = 0;
+ qc->tp.initial_scid = qc->dcid;
+ qc->in_retry = 0;
- if (ngx_quic_validate_token(c, pkt) != NGX_OK) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token");
- return NGX_ERROR;
- }
+ keys = &qc->keys[ssl_encryption_initial];
- qc->validated = 1;
+ if (ngx_quic_set_initial_secret(c->pool, &keys->client,
+ &keys->server, &qc->odcid)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
- pkt->secret = &keys->client;
- pkt->level = ssl_encryption_initial;
- pkt->plaintext = buf;
+ if (ngx_quic_validate_token(c, pkt) != NGX_OK) {
+ return NGX_ERROR;
+ }
- ctx = ngx_quic_get_send_ctx(qc, pkt->level);
+ qc->validated = 1;
+ }
- rc = ngx_quic_decrypt(pkt, NULL, &ctx->largest_pn);
- if (rc != NGX_OK) {
- qc->error = pkt->error;
- qc->error_reason = "failed to decrypt packet";
- return rc;
- }
+ } else {
- if (ngx_quic_init_connection(c) != NGX_OK) {
- return NGX_ERROR;
- }
+ if (rc == NGX_ABORT) {
+ return ngx_quic_negotiate_version(c, pkt);
+ }
- if (ngx_quic_payload_handler(c, pkt) != NGX_OK) {
- return NGX_ERROR;
- }
+ if (pkt->level == ssl_encryption_initial) {
- return NGX_OK;
-}
+ if (pkt->dcid.len < NGX_QUIC_CID_LEN_MIN) {
+ /* 7.2. Negotiating Connection IDs */
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "quic too short dcid in initial"
+ " packet: length %i", pkt->dcid.len);
+ return NGX_ERROR;
+ }
+ rc = ngx_quic_new_connection(c, ssl, conf, pkt);
+ if (rc != NGX_OK) {
+ return rc;
+ }
-static ngx_int_t
-ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
-{
- ngx_int_t rc;
- ngx_ssl_conn_t *ssl_conn;
- ngx_quic_secrets_t *keys;
- ngx_quic_send_ctx_t *ctx;
- ngx_quic_connection_t *qc;
- static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
+ if (pkt->token.len) {
+ if (ngx_quic_validate_token(c, pkt) != NGX_OK) {
+ return NGX_ERROR;
+ }
- c->log->action = "processing initial quic packet";
+ } else if (conf->retry) {
+ return ngx_quic_send_retry(c);
+ }
- ssl_conn = c->ssl->connection;
+ qc = c->quic;
- if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
- return NGX_DECLINED;
- }
+ keys = &qc->keys[ssl_encryption_initial];
- if (pkt->version != NGX_QUIC_VERSION) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic unsupported version: 0x%xD", pkt->version);
- return NGX_DECLINED;
- }
+ if (ngx_quic_set_initial_secret(c->pool, &keys->client,
+ &keys->server, &qc->odcid)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
- qc = c->quic;
+ } else if (pkt->level == ssl_encryption_application) {
+ return NGX_DECLINED;
- if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
- return NGX_DECLINED;
+ } else {
+ return NGX_ERROR;
+ }
}
- if (ngx_quic_parse_initial_header(pkt) != NGX_OK) {
+ keys = &qc->keys[pkt->level];
+
+ if (keys->client.key.len == 0) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "quic no level %d keys yet, ignoring packet", pkt->level);
return NGX_DECLINED;
}
- keys = &qc->keys[ssl_encryption_initial];
+ next = &qc->next_key;
pkt->secret = &keys->client;
- pkt->level = ssl_encryption_initial;
+ pkt->next = &next->client;
+ pkt->key_phase = qc->key_phase;
pkt->plaintext = buf;
ctx = ngx_quic_get_send_ctx(qc, pkt->level);
+ ssl_conn = c->ssl ? c->ssl->connection : NULL;
+
rc = ngx_quic_decrypt(pkt, ssl_conn, &ctx->largest_pn);
if (rc != NGX_OK) {
qc->error = pkt->error;
@@ -1843,167 +1701,115 @@ ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
return rc;
}
- return ngx_quic_payload_handler(c, pkt);
-}
-
-
-static ngx_int_t
-ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
-{
- ngx_int_t rc;
- ngx_queue_t *q;
- ngx_quic_frame_t *f;
- ngx_quic_secrets_t *keys;
- ngx_quic_send_ctx_t *ctx;
- ngx_quic_connection_t *qc;
- static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
-
- c->log->action = "processing handshake quic packet";
-
- qc = c->quic;
-
- keys = &c->quic->keys[ssl_encryption_handshake];
-
- if (keys->client.key.len == 0) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic no read keys yet, packet ignored");
- return NGX_DECLINED;
+ if (c->ssl == NULL) {
+ if (ngx_quic_init_connection(c) != NGX_OK) {
+ return NGX_ERROR;
+ }
}
- /* extract cleartext data into pkt */
- if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
- return NGX_DECLINED;
+ if (pkt->level == ssl_encryption_handshake) {
+ /*
+ * 4.10.1. The successful use of Handshake packets indicates
+ * that no more Initial packets need to be exchanged
+ */
+ ngx_quic_discard_ctx(c, ssl_encryption_initial);
+ qc->validated = 1;
}
- if (pkt->version != NGX_QUIC_VERSION) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic unsupported version: 0x%xD", pkt->version);
- return NGX_DECLINED;
+ if (pkt->level != ssl_encryption_application) {
+ return ngx_quic_payload_handler(c, pkt);
}
- if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
- return NGX_DECLINED;
- }
+ ngx_gettimeofday(&pkt->received);
- if (ngx_quic_parse_handshake_header(pkt) != NGX_OK) {
- return NGX_DECLINED;
- }
+ /* switch keys on Key Phase change */
- pkt->secret = &keys->client;
- pkt->level = ssl_encryption_handshake;
- pkt->plaintext = buf;
+ if (pkt->key_update) {
+ qc->key_phase ^= 1;
- ctx = ngx_quic_get_send_ctx(qc, pkt->level);
+ tmp = *keys;
+ *keys = *next;
+ *next = tmp;
+ }
- rc = ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn);
+ rc = ngx_quic_payload_handler(c, pkt);
if (rc != NGX_OK) {
- qc->error = pkt->error;
- qc->error_reason = "failed to decrypt packet";
return rc;
}
- /*
- * 4.10.1. The successful use of Handshake packets indicates
- * that no more Initial packets need to be exchanged
- */
- ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_initial);
-
- while (!ngx_queue_empty(&ctx->sent)) {
- q = ngx_queue_head(&ctx->sent);
- ngx_queue_remove(q);
+ /* generate next keys */
- f = ngx_queue_data(q, ngx_quic_frame_t, queue);
- ngx_quic_congestion_ack(c, f);
- ngx_quic_free_frame(c, f);
+ if (pkt->key_update) {
+ if (ngx_quic_key_update(c, keys, next) != NGX_OK) {
+ return NGX_ERROR;
+ }
}
- qc->validated = 1;
- qc->pto_count = 0;
-
- return ngx_quic_payload_handler(c, pkt);
+ return NGX_OK;
}
-static ngx_int_t
-ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
+static void
+ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level)
{
- ngx_int_t rc;
- ngx_quic_secrets_t *keys;
+ ngx_queue_t *q;
+ ngx_quic_frame_t *f;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
- static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
-
- c->log->action = "processing early data quic packet";
qc = c->quic;
- /* extract cleartext data into pkt */
- if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
- return NGX_DECLINED;
- }
-
- if (pkt->version != NGX_QUIC_VERSION) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic unsupported version: 0x%xD", pkt->version);
- return NGX_DECLINED;
- }
-
- if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
- return NGX_DECLINED;
- }
-
- if (ngx_quic_parse_handshake_header(pkt) != NGX_OK) {
- return NGX_DECLINED;
- }
-
- keys = &c->quic->keys[ssl_encryption_early_data];
-
- if (keys->client.key.len == 0) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic no 0-RTT keys yet, packet ignored");
- return NGX_DECLINED;
+ if (qc->keys[level].client.key.len == 0) {
+ return;
}
+ qc->keys[level].client.key.len = 0;
+ qc->pto_count = 0;
- pkt->secret = &keys->client;
- pkt->level = ssl_encryption_early_data;
- pkt->plaintext = buf;
+ ctx = ngx_quic_get_send_ctx(qc, level);
- ctx = ngx_quic_get_send_ctx(qc, pkt->level);
+ while (!ngx_queue_empty(&ctx->sent)) {
+ q = ngx_queue_head(&ctx->sent);
+ ngx_queue_remove(q);
- rc = ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn);
- if (rc != NGX_OK) {
- qc->error = pkt->error;
- qc->error_reason = "failed to decrypt packet";
- return rc;
+ f = ngx_queue_data(q, ngx_quic_frame_t, queue);
+ ngx_quic_congestion_ack(c, f);
+ ngx_quic_free_frame(c, f);
}
-
- return ngx_quic_payload_handler(c, pkt);
}
static ngx_int_t
ngx_quic_check_peer(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt)
{
+ ngx_str_t *dcid;
ngx_queue_t *q;
ngx_quic_send_ctx_t *ctx;
ngx_quic_client_id_t *cid;
- ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial);
+ dcid = (pkt->level == ssl_encryption_early_data) ? &qc->odcid : &qc->dcid;
- if (ngx_quic_pkt_zrtt(pkt->flags)
- || (ngx_quic_pkt_in(pkt->flags) && ctx->largest_ack == (uint64_t) -1))
+ if (pkt->dcid.len == dcid->len
+ && ngx_memcmp(pkt->dcid.data, dcid->data, dcid->len) == 0)
{
- if (pkt->dcid.len == qc->odcid.len
- && ngx_memcmp(pkt->dcid.data, qc->odcid.data, qc->odcid.len) == 0)
- {
- goto found;
+ if (pkt->level == ssl_encryption_application) {
+ return NGX_OK;
}
+
+ goto found;
}
- if (!ngx_quic_pkt_zrtt(pkt->flags)) {
- if (pkt->dcid.len == qc->dcid.len
- && ngx_memcmp(pkt->dcid.data, qc->dcid.data, qc->dcid.len) == 0)
+ /*
+ * a packet sent in response to an initial client packet might be lost,
+ * thus check also for old dcid
+ */
+ ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial);
+
+ if (pkt->level == ssl_encryption_initial
+ && ctx->largest_ack == (uint64_t) -1)
+ {
+ if (pkt->dcid.len == qc->odcid.len
+ && ngx_memcmp(pkt->dcid.data, qc->odcid.data, qc->odcid.len) == 0)
{
goto found;
}
@@ -2027,80 +1833,8 @@ found:
}
}
-
- ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic unexpected quic scid");
- return NGX_ERROR;
-}
-
-
-static ngx_int_t
-ngx_quic_app_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
-{
- ngx_int_t rc;
- ngx_quic_secrets_t *keys, *next, tmp;
- ngx_quic_send_ctx_t *ctx;
- ngx_quic_connection_t *qc;
- static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
-
- c->log->action = "processing application data quic packet";
-
- qc = c->quic;
-
- keys = &c->quic->keys[ssl_encryption_application];
- next = &c->quic->next_key;
-
- if (keys->client.key.len == 0) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic no read keys yet, packet ignored");
- return NGX_DECLINED;
- }
-
- if (ngx_quic_parse_short_header(pkt, &qc->dcid) != NGX_OK) {
- return NGX_DECLINED;
- }
-
- pkt->secret = &keys->client;
- pkt->next = &next->client;
- pkt->key_phase = c->quic->key_phase;
- pkt->level = ssl_encryption_application;
- pkt->plaintext = buf;
-
- ctx = ngx_quic_get_send_ctx(qc, pkt->level);
-
- rc = ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn);
- if (rc != NGX_OK) {
- qc->error = pkt->error;
- qc->error_reason = "failed to decrypt packet";
- return rc;
- }
-
- ngx_gettimeofday(&pkt->received);
-
- /* switch keys on Key Phase change */
-
- if (pkt->key_update) {
- c->quic->key_phase ^= 1;
-
- tmp = *keys;
- *keys = *next;
- *next = tmp;
- }
-
- rc = ngx_quic_payload_handler(c, pkt);
-
- if (rc == NGX_ERROR) {
- return NGX_ERROR;
- }
-
- /* generate next keys */
-
- if (pkt->key_update) {
- if (ngx_quic_key_update(c, keys, next) != NGX_OK) {
- return NGX_ERROR;
- }
- }
-
- return rc;
+ ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic unexpected quic scid");
+ return NGX_ERROR;
}
@@ -2981,9 +2715,7 @@ static ngx_int_t
ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
{
int n, sslerr;
- ngx_queue_t *q;
ngx_ssl_conn_t *ssl_conn;
- ngx_quic_send_ctx_t *ctx;
ngx_quic_crypto_frame_t *f;
f = &frame->u.crypto;
@@ -3060,18 +2792,7 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
* 4.10.2 An endpoint MUST discard its handshake keys
* when the TLS handshake is confirmed
*/
- ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_handshake);
-
- while (!ngx_queue_empty(&ctx->sent)) {
- q = ngx_queue_head(&ctx->sent);
- ngx_queue_remove(q);
-
- frame = ngx_queue_data(q, ngx_quic_frame_t, queue);
- ngx_quic_congestion_ack(c, frame);
- ngx_quic_free_frame(c, frame);
- }
-
- c->quic->pto_count = 0;
+ ngx_quic_discard_ctx(c, ssl_encryption_handshake);
}
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c
index 182b93f61..0dd56abd9 100644
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -67,6 +67,12 @@ static u_char *ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len,
static u_char *ngx_quic_copy_bytes(u_char *pos, u_char *end, size_t len,
u_char *dst);
+static ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt);
+static ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt,
+ size_t dcid_len);
+static ngx_int_t ngx_quic_parse_initial_header(ngx_quic_header_t *pkt);
+static ngx_int_t ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt);
+
static ngx_int_t ngx_quic_frame_allowed(ngx_quic_header_t *pkt,
ngx_uint_t frame_type);
static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack);
@@ -245,6 +251,52 @@ ngx_quic_error_text(uint64_t error_code)
ngx_int_t
+ngx_quic_parse_packet(ngx_quic_header_t *pkt)
+{
+ if (!ngx_quic_long_pkt(pkt->flags)) {
+ pkt->level = ssl_encryption_application;
+
+ return ngx_quic_parse_short_header(pkt, NGX_QUIC_SERVER_CID_LEN);
+ }
+
+ if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
+ return NGX_DECLINED;
+ }
+
+ if (pkt->version != NGX_QUIC_VERSION) {
+ return NGX_ABORT;
+ }
+
+ if (ngx_quic_pkt_in(pkt->flags)) {
+
+ if (pkt->len < NGX_QUIC_MIN_INITIAL_SIZE) {
+ ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
+ "quic UDP datagram is too small for initial packet");
+ return NGX_DECLINED;
+ }
+
+ pkt->level = ssl_encryption_initial;
+
+ return ngx_quic_parse_initial_header(pkt);
+ }
+
+ if (ngx_quic_pkt_hs(pkt->flags)) {
+ pkt->level = ssl_encryption_handshake;
+
+ } else if (ngx_quic_pkt_zrtt(pkt->flags)) {
+ pkt->level = ssl_encryption_early_data;
+
+ } else {
+ ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
+ "quic unknown long packet type");
+ return NGX_DECLINED;
+ }
+
+ return ngx_quic_parse_handshake_header(pkt);
+}
+
+
+static ngx_int_t
ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
{
u_char *p, *end;
@@ -456,8 +508,8 @@ ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out,
}
-ngx_int_t
-ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid)
+static ngx_int_t
+ngx_quic_parse_short_header(ngx_quic_header_t *pkt, size_t dcid_len)
{
u_char *p, *end;
@@ -472,14 +524,9 @@ ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid)
return NGX_ERROR;
}
- if (ngx_memcmp(p, dcid->data, dcid->len) != 0) {
- ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "unexpected quic dcid");
- return NGX_ERROR;
- }
-
- pkt->dcid.len = dcid->len;
+ pkt->dcid.len = dcid_len;
- p = ngx_quic_read_bytes(p, end, dcid->len, &pkt->dcid.data);
+ p = ngx_quic_read_bytes(p, end, dcid_len, &pkt->dcid.data);
if (p == NULL) {
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
"quic packet is too small to read dcid");
@@ -492,7 +539,7 @@ ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid)
}
-ngx_int_t
+static ngx_int_t
ngx_quic_parse_initial_header(ngx_quic_header_t *pkt)
{
u_char *p, *end;
@@ -548,7 +595,7 @@ ngx_quic_parse_initial_header(ngx_quic_header_t *pkt)
}
-ngx_int_t
+static ngx_int_t
ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt)
{
u_char *p, *end;
diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h
index 63c6a2191..5417c664b 100644
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -319,23 +319,19 @@ typedef struct {
u_char *ngx_quic_error_text(uint64_t error_code);
+ngx_int_t ngx_quic_parse_packet(ngx_quic_header_t *pkt);
+
size_t ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out);
-ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt);
size_t ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
size_t pkt_len, u_char **pnp);
-ngx_int_t ngx_quic_parse_short_header(ngx_quic_header_t *pkt,
- ngx_str_t *dcid);
size_t ngx_quic_create_short_header(ngx_quic_header_t *pkt, u_char *out,
size_t pkt_len, u_char **pnp);
size_t ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out,
u_char **start);
-ngx_int_t ngx_quic_parse_initial_header(ngx_quic_header_t *pkt);
-ngx_int_t ngx_quic_parse_handshake_header(ngx_quic_header_t *pkt);
-
ssize_t ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
ngx_quic_frame_t *frame);
ssize_t ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f);