aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/event/quic/ngx_event_quic.c66
-rw-r--r--src/event/quic/ngx_event_quic_connection.h20
-rw-r--r--src/event/quic/ngx_event_quic_connid.c231
-rw-r--r--src/event/quic/ngx_event_quic_connid.h5
-rw-r--r--src/event/quic/ngx_event_quic_migration.c402
-rw-r--r--src/event/quic/ngx_event_quic_migration.h30
-rw-r--r--src/event/quic/ngx_event_quic_output.c45
-rw-r--r--src/event/quic/ngx_event_quic_socket.c101
-rw-r--r--src/event/quic/ngx_event_quic_socket.h4
-rw-r--r--src/event/quic/ngx_event_quic_ssl.c9
-rw-r--r--src/event/quic/ngx_event_quic_transport.h2
11 files changed, 351 insertions, 564 deletions
diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c
index 96488c6a7..d47d0bc4e 100644
--- a/src/event/quic/ngx_event_quic.c
+++ b/src/event/quic/ngx_event_quic.c
@@ -131,8 +131,8 @@ ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp)
qc = ngx_quic_get_connection(c);
- scid.data = qc->socket->cid->id;
- scid.len = qc->socket->cid->len;
+ scid.data = qc->path->cid->id;
+ scid.len = qc->path->cid->len;
if (scid.len != ctp->initial_scid.len
|| ngx_memcmp(scid.data, ctp->initial_scid.data, scid.len) != 0)
@@ -373,7 +373,7 @@ ngx_quic_handle_stateless_reset(ngx_connection_t *c, ngx_quic_header_t *pkt)
{
cid = ngx_queue_data(q, ngx_quic_client_id_t, queue);
- if (cid->seqnum == 0 || cid->refcnt == 0) {
+ if (cid->seqnum == 0 || !cid->used) {
/*
* No stateless reset token in initial connection id.
* Don't accept a token from an unused connection id.
@@ -673,10 +673,12 @@ ngx_quic_handle_datagram(ngx_connection_t *c, ngx_buf_t *b,
u_char *p, *start;
ngx_int_t rc;
ngx_uint_t good;
+ ngx_quic_path_t *path;
ngx_quic_header_t pkt;
ngx_quic_connection_t *qc;
good = 0;
+ path = NULL;
size = b->last - b->pos;
@@ -690,6 +692,7 @@ ngx_quic_handle_datagram(ngx_connection_t *c, ngx_buf_t *b,
pkt.len = b->last - p;
pkt.log = c->log;
pkt.first = (p == start) ? 1 : 0;
+ pkt.path = path;
pkt.flags = p[0];
pkt.raw->pos++;
@@ -720,6 +723,8 @@ ngx_quic_handle_datagram(ngx_connection_t *c, ngx_buf_t *b,
good = 1;
}
+ path = pkt.path; /* preserve packet path from 1st packet */
+
/* NGX_OK || NGX_DECLINED */
/*
@@ -825,14 +830,15 @@ ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf,
}
if (pkt->first) {
- if (ngx_quic_find_path(c, c->udp->dgram->sockaddr,
- c->udp->dgram->socklen)
- == NULL)
+ if (ngx_cmp_sockaddr(c->udp->dgram->sockaddr,
+ c->udp->dgram->socklen,
+ qc->path->sockaddr, qc->path->socklen, 1)
+ != NGX_OK)
{
/* packet comes from unknown path, possibly migration */
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic too early migration attempt");
- return NGX_DECLINED;
+ return NGX_DONE;
}
}
@@ -991,9 +997,12 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
pkt->decrypted = 1;
- if (pkt->first) {
- if (ngx_quic_update_paths(c, pkt) != NGX_OK) {
- return NGX_ERROR;
+ c->log->action = "handling decrypted packet";
+
+ if (pkt->path == NULL) {
+ rc = ngx_quic_set_path(c, pkt);
+ if (rc != NGX_OK) {
+ return rc;
}
}
@@ -1012,9 +1021,10 @@ ngx_quic_handle_payload(ngx_connection_t *c, ngx_quic_header_t *pkt)
*/
ngx_quic_discard_ctx(c, ssl_encryption_initial);
- if (qc->socket->path->state != NGX_QUIC_PATH_VALIDATED) {
- qc->socket->path->state = NGX_QUIC_PATH_VALIDATED;
- qc->socket->path->limited = 0;
+ if (!qc->path->validated) {
+ qc->path->validated = 1;
+ qc->path->limited = 0;
+ ngx_quic_path_dbg(c, "in handshake", qc->path);
ngx_post_event(&qc->push, &ngx_posted_events);
}
}
@@ -1153,7 +1163,6 @@ ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt)
ngx_uint_t do_close, nonprobing;
ngx_chain_t chain;
ngx_quic_frame_t frame;
- ngx_quic_socket_t *qsock;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
@@ -1335,7 +1344,8 @@ ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt)
case NGX_QUIC_FT_PATH_CHALLENGE:
- if (ngx_quic_handle_path_challenge_frame(c, &frame.u.path_challenge)
+ if (ngx_quic_handle_path_challenge_frame(c, pkt,
+ &frame.u.path_challenge)
!= NGX_OK)
{
return NGX_ERROR;
@@ -1394,26 +1404,18 @@ ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt)
ngx_quic_close_connection(c, NGX_OK);
}
- qsock = ngx_quic_get_socket(c);
+ if (pkt->path != qc->path && nonprobing) {
- if (qsock != qc->socket) {
-
- if (qsock->path != qc->socket->path && nonprobing) {
- /*
- * RFC 9000, 9.2. Initiating Connection Migration
- *
- * An endpoint can migrate a connection to a new local
- * address by sending packets containing non-probing frames
- * from that address.
- */
- if (ngx_quic_handle_migration(c, pkt) != NGX_OK) {
- return NGX_ERROR;
- }
- }
/*
- * else: packet arrived via non-default socket;
- * no reason to change active path
+ * RFC 9000, 9.2. Initiating Connection Migration
+ *
+ * An endpoint can migrate a connection to a new local
+ * address by sending packets containing non-probing frames
+ * from that address.
*/
+ if (ngx_quic_handle_migration(c, pkt) != NGX_OK) {
+ return NGX_ERROR;
+ }
}
if (ngx_quic_ack_packet(c, pkt) != NGX_OK) {
diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h
index dfd29fce5..173af10d1 100644
--- a/src/event/quic/ngx_event_quic_connection.h
+++ b/src/event/quic/ngx_event_quic_connection.h
@@ -69,7 +69,7 @@ struct ngx_quic_client_id_s {
size_t len;
u_char id[NGX_QUIC_CID_LEN_MAX];
u_char sr_token[NGX_QUIC_SR_TOKEN_LEN];
- ngx_uint_t refcnt;
+ ngx_uint_t used; /* unsigned used:1; */
};
@@ -83,20 +83,22 @@ struct ngx_quic_server_id_s {
struct ngx_quic_path_s {
ngx_queue_t queue;
struct sockaddr *sockaddr;
+ ngx_sockaddr_t sa;
socklen_t socklen;
- ngx_uint_t state;
- ngx_uint_t limited; /* unsigned limited:1; */
+ ngx_quic_client_id_t *cid;
ngx_msec_t expires;
- ngx_msec_t last_seen;
ngx_uint_t tries;
+ ngx_uint_t tag;
off_t sent;
off_t received;
u_char challenge1[8];
u_char challenge2[8];
- ngx_uint_t refcnt;
uint64_t seqnum;
ngx_str_t addr_text;
u_char text[NGX_SOCKADDR_STRLEN];
+ unsigned validated:1;
+ unsigned validating:1;
+ unsigned limited:1;
};
@@ -104,11 +106,8 @@ struct ngx_quic_socket_s {
ngx_udp_connection_t udp;
ngx_quic_connection_t *quic;
ngx_queue_t queue;
-
ngx_quic_server_id_t sid;
-
- ngx_quic_path_t *path;
- ngx_quic_client_id_t *cid;
+ ngx_uint_t used; /* unsigned used:1; */
};
@@ -184,8 +183,7 @@ struct ngx_quic_send_ctx_s {
struct ngx_quic_connection_s {
uint32_t version;
- ngx_quic_socket_t *socket;
- ngx_quic_socket_t *backup;
+ ngx_quic_path_t *path;
ngx_queue_t sockets;
ngx_queue_t paths;
diff --git a/src/event/quic/ngx_event_quic_connid.c b/src/event/quic/ngx_event_quic_connid.c
index 9f2f7ab33..32926a022 100644
--- a/src/event/quic/ngx_event_quic_connid.c
+++ b/src/event/quic/ngx_event_quic_connid.c
@@ -15,13 +15,10 @@
#if (NGX_QUIC_BPF)
static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id);
#endif
-static ngx_int_t ngx_quic_send_retire_connection_id(ngx_connection_t *c,
- uint64_t seqnum);
-
+static ngx_int_t ngx_quic_retire_client_id(ngx_connection_t *c,
+ ngx_quic_client_id_t *cid);
static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c,
ngx_quic_connection_t *qc);
-static ngx_int_t ngx_quic_replace_retired_client_id(ngx_connection_t *c,
- ngx_quic_client_id_t *retired_cid);
static ngx_int_t ngx_quic_send_server_id(ngx_connection_t *c,
ngx_quic_server_id_t *sid);
@@ -77,9 +74,9 @@ ngx_int_t
ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
ngx_quic_new_conn_id_frame_t *f)
{
- uint64_t seq;
ngx_str_t id;
ngx_queue_t *q;
+ ngx_quic_frame_t *frame;
ngx_quic_client_id_t *cid, *item;
ngx_quic_connection_t *qc;
@@ -97,10 +94,17 @@ ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
* done so for that sequence number.
*/
- if (ngx_quic_send_retire_connection_id(c, f->seqnum) != NGX_OK) {
+ frame = ngx_quic_alloc_frame(c);
+ if (frame == NULL) {
return NGX_ERROR;
}
+ frame->level = ssl_encryption_application;
+ frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID;
+ frame->u.retire_cid.sequence_number = f->seqnum;
+
+ ngx_quic_queue_frame(qc, frame);
+
goto retire;
}
@@ -173,20 +177,7 @@ retire:
continue;
}
- /* this connection id must be retired */
- seq = cid->seqnum;
-
- if (cid->refcnt) {
- /* we are going to retire client id which is in use */
- if (ngx_quic_replace_retired_client_id(c, cid) != NGX_OK) {
- return NGX_ERROR;
- }
-
- } else {
- ngx_quic_unref_client_id(c, cid);
- }
-
- if (ngx_quic_send_retire_connection_id(c, seq) != NGX_OK) {
+ if (ngx_quic_retire_client_id(c, cid) != NGX_OK) {
return NGX_ERROR;
}
}
@@ -213,25 +204,47 @@ done:
static ngx_int_t
-ngx_quic_send_retire_connection_id(ngx_connection_t *c, uint64_t seqnum)
+ngx_quic_retire_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid)
{
- ngx_quic_frame_t *frame;
+ ngx_queue_t *q;
+ ngx_quic_path_t *path;
+ ngx_quic_client_id_t *new_cid;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
- frame = ngx_quic_alloc_frame(c);
- if (frame == NULL) {
- return NGX_ERROR;
+ if (!cid->used) {
+ return ngx_quic_free_client_id(c, cid);
}
- frame->level = ssl_encryption_application;
- frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID;
- frame->u.retire_cid.sequence_number = seqnum;
+ /* we are going to retire client id which is in use */
- ngx_quic_queue_frame(qc, frame);
+ q = ngx_queue_head(&qc->paths);
- /* we are no longer going to use this client id */
+ while (q != ngx_queue_sentinel(&qc->paths)) {
+
+ path = ngx_queue_data(q, ngx_quic_path_t, queue);
+ q = ngx_queue_next(q);
+
+ if (path->cid != cid) {
+ continue;
+ }
+
+ if (path == qc->path) {
+ /* this is the active path: update it with new CID */
+ new_cid = ngx_quic_next_client_id(c);
+ if (new_cid == NULL) {
+ return NGX_ERROR;
+ }
+
+ qc->path->cid = new_cid;
+ new_cid->used = 1;
+
+ return ngx_quic_free_client_id(c, cid);
+ }
+
+ return ngx_quic_free_path(c, path);
+ }
return NGX_OK;
}
@@ -318,7 +331,7 @@ ngx_quic_next_client_id(ngx_connection_t *c)
{
cid = ngx_queue_data(q, ngx_quic_client_id_t, queue);
- if (cid->refcnt == 0) {
+ if (!cid->used) {
return cid;
}
}
@@ -327,42 +340,11 @@ ngx_quic_next_client_id(ngx_connection_t *c)
}
-ngx_quic_client_id_t *
-ngx_quic_used_client_id(ngx_connection_t *c, ngx_quic_path_t *path)
-{
- ngx_queue_t *q;
- ngx_quic_socket_t *qsock;
- ngx_quic_connection_t *qc;
-
- qc = ngx_quic_get_connection(c);
-
- /* best guess: cid used by active path is good for us */
- if (qc->socket->path == path) {
- return qc->socket->cid;
- }
-
- for (q = ngx_queue_head(&qc->sockets);
- q != ngx_queue_sentinel(&qc->sockets);
- q = ngx_queue_next(q))
- {
- qsock = ngx_queue_data(q, ngx_quic_socket_t, queue);
-
- if (qsock->path && qsock->path == path) {
- return qsock->cid;
- }
- }
-
- return NULL;
-}
-
-
ngx_int_t
ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
ngx_quic_retire_cid_frame_t *f)
{
- ngx_quic_path_t *path;
- ngx_quic_socket_t *qsock, **tmp;
- ngx_quic_client_id_t *cid;
+ ngx_quic_socket_t *qsock;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
@@ -408,76 +390,14 @@ ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic socket #%uL is retired", qsock->sid.seqnum);
- /* check if client is willing to retire sid we have in use */
- if (qsock->sid.seqnum == qc->socket->sid.seqnum) {
- tmp = &qc->socket;
-
- } else if (qc->backup && qsock->sid.seqnum == qc->backup->sid.seqnum) {
- tmp = &qc->backup;
-
- } else {
-
- ngx_quic_close_socket(c, qsock);
-
- /* restore socket count up to a limit after deletion */
- if (ngx_quic_create_sockets(c) != NGX_OK) {
- return NGX_ERROR;
- }
-
- return NGX_OK;
- }
-
- /* preserve path/cid from retired socket */
- path = qsock->path;
- cid = qsock->cid;
-
- /* ensure that closing_socket will not drop path and cid */
- path->refcnt++;
- cid->refcnt++;
-
ngx_quic_close_socket(c, qsock);
- /* restore original values */
- path->refcnt--;
- cid->refcnt--;
-
/* restore socket count up to a limit after deletion */
if (ngx_quic_create_sockets(c) != NGX_OK) {
- goto failed;
- }
-
- qsock = ngx_quic_get_unconnected_socket(c);
- if (qsock == NULL) {
- qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR;
- qc->error_reason = "not enough server IDs";
- goto failed;
+ return NGX_ERROR;
}
- ngx_quic_connect(c, qsock, path, cid);
-
- ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic %s socket is now #%uL:%uL:%uL (%s)",
- (*tmp) == qc->socket ? "active" : "backup",
- qsock->sid.seqnum, qsock->cid->seqnum,
- qsock->path->seqnum,
- ngx_quic_path_state_str(qsock->path));
-
- /* restore active/backup pointer in quic connection */
- *tmp = qsock;
-
return NGX_OK;
-
-failed:
-
- /*
- * socket was closed, path and cid were preserved artifically
- * to be reused, but it didn't happen, thus unref here
- */
-
- ngx_quic_unref_path(c, path);
- ngx_quic_unref_client_id(c, cid);
-
- return NGX_ERROR;
}
@@ -552,62 +472,31 @@ ngx_quic_send_server_id(ngx_connection_t *c, ngx_quic_server_id_t *sid)
}
-static ngx_int_t
-ngx_quic_replace_retired_client_id(ngx_connection_t *c,
- ngx_quic_client_id_t *retired_cid)
+ngx_int_t
+ngx_quic_free_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid)
{
- ngx_queue_t *q;
- ngx_quic_socket_t *qsock;
- ngx_quic_client_id_t *cid;
+ ngx_quic_frame_t *frame;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
- for (q = ngx_queue_head(&qc->sockets);
- q != ngx_queue_sentinel(&qc->sockets);
- q = ngx_queue_next(q))
- {
- qsock = ngx_queue_data(q, ngx_quic_socket_t, queue);
-
- if (qsock->cid == retired_cid) {
-
- cid = ngx_quic_next_client_id(c);
- if (cid == NULL) {
- return NGX_ERROR;
- }
-
- qsock->cid = cid;
- cid->refcnt++;
-
- ngx_quic_unref_client_id(c, retired_cid);
-
- if (retired_cid->refcnt == 0) {
- return NGX_OK;
- }
- }
+ frame = ngx_quic_alloc_frame(c);
+ if (frame == NULL) {
+ return NGX_ERROR;
}
- return NGX_OK;
-}
-
-
-void
-ngx_quic_unref_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid)
-{
- ngx_quic_connection_t *qc;
-
- if (cid->refcnt) {
- cid->refcnt--;
- } /* else: unused client id */
+ frame->level = ssl_encryption_application;
+ frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID;
+ frame->u.retire_cid.sequence_number = cid->seqnum;
- if (cid->refcnt) {
- return;
- }
+ ngx_quic_queue_frame(qc, frame);
- qc = ngx_quic_get_connection(c);
+ /* we are no longer going to use this client id */
ngx_queue_remove(&cid->queue);
ngx_queue_insert_head(&qc->free_client_ids, &cid->queue);
qc->nclient_ids--;
+
+ return NGX_OK;
}
diff --git a/src/event/quic/ngx_event_quic_connid.h b/src/event/quic/ngx_event_quic_connid.h
index f823e84dc..33e9c65b9 100644
--- a/src/event/quic/ngx_event_quic_connid.h
+++ b/src/event/quic/ngx_event_quic_connid.h
@@ -23,8 +23,7 @@ ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id);
ngx_quic_client_id_t *ngx_quic_create_client_id(ngx_connection_t *c,
ngx_str_t *id, uint64_t seqnum, u_char *token);
ngx_quic_client_id_t *ngx_quic_next_client_id(ngx_connection_t *c);
-ngx_quic_client_id_t *ngx_quic_used_client_id(ngx_connection_t *c,
- ngx_quic_path_t *path);
-void ngx_quic_unref_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid);
+ngx_int_t ngx_quic_free_client_id(ngx_connection_t *c,
+ ngx_quic_client_id_t *cid);
#endif /* _NGX_EVENT_QUIC_CONNID_H_INCLUDED_ */
diff --git a/src/event/quic/ngx_event_quic_migration.c b/src/event/quic/ngx_event_quic_migration.c
index ac787e31d..e66a402c8 100644
--- a/src/event/quic/ngx_event_quic_migration.c
+++ b/src/event/quic/ngx_event_quic_migration.c
@@ -16,17 +16,14 @@ static ngx_int_t ngx_quic_validate_path(ngx_connection_t *c,
ngx_quic_path_t *path);
static ngx_int_t ngx_quic_send_path_challenge(ngx_connection_t *c,
ngx_quic_path_t *path);
-static ngx_int_t ngx_quic_path_restore(ngx_connection_t *c);
-static ngx_quic_path_t *ngx_quic_alloc_path(ngx_connection_t *c);
+static ngx_quic_path_t *ngx_quic_get_path(ngx_connection_t *c, ngx_uint_t tag);
ngx_int_t
ngx_quic_handle_path_challenge_frame(ngx_connection_t *c,
- ngx_quic_path_challenge_frame_t *f)
+ ngx_quic_header_t *pkt, ngx_quic_path_challenge_frame_t *f)
{
- ngx_quic_path_t *path;
ngx_quic_frame_t frame, *fp;
- ngx_quic_socket_t *qsock;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
@@ -43,18 +40,16 @@ ngx_quic_handle_path_challenge_frame(ngx_connection_t *c,
* A PATH_RESPONSE frame MUST be sent on the network path where the
* PATH_CHALLENGE frame was received.
*/
- qsock = ngx_quic_get_socket(c);
- path = qsock->path;
/*
* An endpoint MUST expand datagrams that contain a PATH_RESPONSE frame
* to at least the smallest allowed maximum datagram size of 1200 bytes.
*/
- if (ngx_quic_frame_sendto(c, &frame, 1200, path) != NGX_OK) {
+ if (ngx_quic_frame_sendto(c, &frame, 1200, pkt->path) != NGX_OK) {
return NGX_ERROR;
}
- if (qsock == qc->socket) {
+ if (pkt->path == qc->path) {
/*
* RFC 9000, 9.3.3. Off-Path Packet Forwarding
*
@@ -101,7 +96,7 @@ ngx_quic_handle_path_response_frame(ngx_connection_t *c,
{
path = ngx_queue_data(q, ngx_quic_path_t, queue);
- if (path->state != NGX_QUIC_PATH_VALIDATING) {
+ if (!path->validating) {
continue;
}
@@ -112,7 +107,7 @@ ngx_quic_handle_path_response_frame(ngx_connection_t *c,
}
}
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic stale PATH_RESPONSE ignored");
return NGX_OK;
@@ -130,8 +125,9 @@ valid:
rst = 1;
- if (qc->backup) {
- prev = qc->backup->path;
+ prev = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP);
+
+ if (prev != NULL) {
if (ngx_cmp_sockaddr(prev->sockaddr, prev->socklen,
path->sockaddr, path->socklen, 0)
@@ -164,20 +160,24 @@ valid:
}
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic path #%uL successfully validated", path->seqnum);
+ "quic path #%uL addr:%V successfully validated",
+ path->seqnum, &path->addr_text);
+
+ ngx_quic_path_dbg(c, "is validated", path);
- path->state = NGX_QUIC_PATH_VALIDATED;
+ path->validated = 1;
+ path->validating = 0;
path->limited = 0;
return NGX_OK;
}
-static ngx_quic_path_t *
-ngx_quic_alloc_path(ngx_connection_t *c)
+ngx_quic_path_t *
+ngx_quic_new_path(ngx_connection_t *c,
+ struct sockaddr *sockaddr, socklen_t socklen, ngx_quic_client_id_t *cid)
{
ngx_queue_t *q;
- struct sockaddr *sa;
ngx_quic_path_t *path;
ngx_quic_connection_t *qc;
@@ -190,9 +190,7 @@ ngx_quic_alloc_path(ngx_connection_t *c)
ngx_queue_remove(&path->queue);
- sa = path->sockaddr;
ngx_memzero(path, sizeof(ngx_quic_path_t));
- path->sockaddr = sa;
} else {
@@ -200,37 +198,18 @@ ngx_quic_alloc_path(ngx_connection_t *c)
if (path == NULL) {
return NULL;
}
-
- path->sockaddr = ngx_palloc(c->pool, NGX_SOCKADDRLEN);
- if (path->sockaddr == NULL) {
- return NULL;
- }
}
- return path;
-}
-
-
-ngx_quic_path_t *
-ngx_quic_add_path(ngx_connection_t *c, struct sockaddr *sockaddr,
- socklen_t socklen)
-{
- ngx_quic_path_t *path;
- ngx_quic_connection_t *qc;
-
- qc = ngx_quic_get_connection(c);
+ ngx_queue_insert_tail(&qc->paths, &path->queue);
- path = ngx_quic_alloc_path(c);
- if (path == NULL) {
- return NULL;
- }
+ path->cid = cid;
+ cid->used = 1;
- path->state = NGX_QUIC_PATH_NEW;
path->limited = 1;
path->seqnum = qc->path_seqnum++;
- path->last_seen = ngx_current_msec;
+ path->sockaddr = &path->sa.sockaddr;
path->socklen = socklen;
ngx_memcpy(path->sockaddr, sockaddr, socklen);
@@ -238,19 +217,15 @@ ngx_quic_add_path(ngx_connection_t *c, struct sockaddr *sockaddr,
path->addr_text.len = ngx_sock_ntop(sockaddr, socklen, path->text,
NGX_SOCKADDR_STRLEN, 1);
- ngx_queue_insert_tail(&qc->paths, &path->queue);
-
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic path #%uL created src:%V",
+ "quic path #%uL created addr:%V",
path->seqnum, &path->addr_text);
-
return path;
}
-ngx_quic_path_t *
-ngx_quic_find_path(ngx_connection_t *c, struct sockaddr *sockaddr,
- socklen_t socklen)
+static ngx_quic_path_t *
+ngx_quic_get_path(ngx_connection_t *c, ngx_uint_t tag)
{
ngx_queue_t *q;
ngx_quic_path_t *path;
@@ -264,10 +239,7 @@ ngx_quic_find_path(ngx_connection_t *c, struct sockaddr *sockaddr,
{
path = ngx_queue_data(q, ngx_quic_path_t, queue);
- if (ngx_cmp_sockaddr(sockaddr, socklen,
- path->sockaddr, path->socklen, 1)
- == NGX_OK)
- {
+ if (path->tag == tag) {
return path;
}
}
@@ -277,10 +249,11 @@ ngx_quic_find_path(ngx_connection_t *c, struct sockaddr *sockaddr,
ngx_int_t
-ngx_quic_update_paths(ngx_connection_t *c, ngx_quic_header_t *pkt)
+ngx_quic_set_path(ngx_connection_t *c, ngx_quic_header_t *pkt)
{
off_t len;
- ngx_quic_path_t *path;
+ ngx_queue_t *q;
+ ngx_quic_path_t *path, *probe;
ngx_quic_socket_t *qsock;
ngx_quic_client_id_t *cid;
ngx_quic_connection_t *qc;
@@ -288,72 +261,69 @@ ngx_quic_update_paths(ngx_connection_t *c, ngx_quic_header_t *pkt)
qc = ngx_quic_get_connection(c);
qsock = ngx_quic_get_socket(c);
+ len = pkt->raw->last - pkt->raw->start;
+
if (c->udp->dgram == NULL) {
- /* 1st ever packet in connection, path already exists */
- path = qsock->path;
+ /* first ever packet in connection, path already exists */
+ path = qc->path;
goto update;
}
- path = ngx_quic_find_path(c, c->udp->dgram->sockaddr,
- c->udp->dgram->socklen);
-
- if (path == NULL) {
- path = ngx_quic_add_path(c, c->udp->dgram->sockaddr,
- c->udp->dgram->socklen);
- if (path == NULL) {
- return NGX_ERROR;
- }
-
- if (qsock->path) {
- /* NAT rebinding case: packet to same CID, but from new address */
+ probe = NULL;
- ngx_quic_unref_path(c, qsock->path);
-
- qsock->path = path;
- path->refcnt++;
+ for (q = ngx_queue_head(&qc->paths);
+ q != ngx_queue_sentinel(&qc->paths);
+ q = ngx_queue_next(q))
+ {
+ path = ngx_queue_data(q, ngx_quic_path_t, queue);
+ if (ngx_cmp_sockaddr(c->udp->dgram->sockaddr, c->udp->dgram->socklen,
+ path->sockaddr, path->socklen, 1)
+ == NGX_OK)
+ {
goto update;
}
- } else if (qsock->path) {
- goto update;
+ if (path->tag == NGX_QUIC_PATH_PROBE) {
+ probe = path;
+ }
}
- /* prefer unused client IDs if available */
- cid = ngx_quic_next_client_id(c);
- if (cid == NULL) {
-
- /* try to reuse connection ID used on the same path */
- cid = ngx_quic_used_client_id(c, path);
- if (cid == NULL) {
-
- qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR;
- qc->error_reason = "no available client ids for new path";
+ /* packet from new path, drop current probe, if any */
- ngx_log_error(NGX_LOG_ERR, c->log, 0,
- "no available client ids for new path");
+ if (probe && ngx_quic_free_path(c, probe) != NGX_OK) {
+ return NGX_ERROR;
+ }
- return NGX_ERROR;
- }
+ /* new path requires new client id */
+ cid = ngx_quic_next_client_id(c);
+ if (cid == NULL) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "quic no available client ids for new path");
+ /* stop processing of this datagram */
+ return NGX_DONE;
}
- ngx_quic_connect(c, qsock, path, cid);
+ path = ngx_quic_new_path(c, c->udp->dgram->sockaddr,
+ c->udp->dgram->socklen, cid);
+ if (path == NULL) {
+ return NGX_ERROR;
+ }
-update:
+ path->tag = NGX_QUIC_PATH_PROBE;
- if (path->state != NGX_QUIC_PATH_NEW) {
- /* force limits/revalidation for paths that were not seen recently */
- if (ngx_current_msec - path->last_seen > qc->tp.max_idle_timeout) {
- path->state = NGX_QUIC_PATH_NEW;
- path->limited = 1;
- path->sent = 0;
- path->received = 0;
- }
+ /*
+ * client arrived using new path and previously seen DCID,
+ * this indicates NAT rebinding (or bad client)
+ */
+ if (qsock->used) {
+ pkt->rebound = 1;
}
- path->last_seen = ngx_current_msec;
+update:
- len = pkt->raw->last - pkt->raw->start;
+ qsock->used = 1;
+ pkt->path = path;
/* TODO: this may be too late in some cases;
* for example, if error happens during decrypt(), we cannot
@@ -364,11 +334,38 @@ update:
*/
path->received += len;
- ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic packet via #%uL:%uL:%uL"
- " size:%O path recvd:%O sent:%O limited:%ui",
- qsock->sid.seqnum, qsock->cid->seqnum, path->seqnum,
- len, path->received, path->sent, path->limited);
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "quic packet len:%O via sock#%uL path#%uL",
+ len, qsock->sid.seqnum, path->seqnum);
+ ngx_quic_path_dbg(c, "status", path);
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_quic_free_path(ngx_connection_t *c, ngx_quic_path_t *path)
+{
+ ngx_quic_connection_t *qc;
+
+ qc = ngx_quic_get_connection(c);
+
+ ngx_queue_remove(&path->queue);
+ ngx_queue_insert_head(&qc->free_paths, &path->queue);
+
+ /*
+ * invalidate CID that is no longer usable for any other path;
+ * this also requests new CIDs from client
+ */
+ if (path->cid) {
+ if (ngx_quic_free_client_id(c, path->cid) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "quic path #%uL addr:%V retired",
+ path->seqnum, &path->addr_text);
return NGX_OK;
}
@@ -398,35 +395,14 @@ ngx_quic_set_connection_path(ngx_connection_t *c, ngx_quic_path_t *path)
ngx_int_t
ngx_quic_handle_migration(ngx_connection_t *c, ngx_quic_header_t *pkt)
{
- ngx_quic_path_t *next;
- ngx_quic_socket_t *qsock;
+ ngx_quic_path_t *next, *bkp;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
- /* got non-probing packet via non-active socket with different path */
+ /* got non-probing packet via non-active path */
qc = ngx_quic_get_connection(c);
- /* current socket, different from active */
- qsock = ngx_quic_get_socket(c);
-
- next = qsock->path; /* going to migrate to this path... */
-
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic migration from #%uL:%uL:%uL (%s)"
- " to #%uL:%uL:%uL (%s)",
- qc->socket->sid.seqnum, qc->socket->cid->seqnum,
- qc->socket->path->seqnum,
- ngx_quic_path_state_str(qc->socket->path),
- qsock->sid.seqnum, qsock->cid->seqnum, next->seqnum,
- ngx_quic_path_state_str(next));
-
- if (next->state == NGX_QUIC_PATH_NEW) {
- if (ngx_quic_validate_path(c, qsock->path) != NGX_OK) {
- return NGX_ERROR;
- }
- }
-
ctx = ngx_quic_get_send_ctx(qc, pkt->level);
/*
@@ -439,39 +415,59 @@ ngx_quic_handle_migration(ngx_connection_t *c, ngx_quic_header_t *pkt)
return NGX_OK;
}
- /* switching connection to new path */
-
- ngx_quic_set_connection_path(c, next);
+ next = pkt->path;
/*
- * RFC 9000, 9.5. Privacy Implications of Connection Migration
+ * RFC 9000, 9.3.3:
*
- * An endpoint MUST NOT reuse a connection ID when sending to
- * more than one destination address.
+ * In response to an apparent migration, endpoints MUST validate the
+ * previously active path using a PATH_CHALLENGE frame.
*/
+ if (pkt->rebound) {
+
+ /* NAT rebinding: client uses new path with old SID */
+ if (ngx_quic_validate_path(c, qc->path) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ if (qc->path->validated) {
- /* preserve valid path we are migrating from */
- if (qc->socket->path->state == NGX_QUIC_PATH_VALIDATED) {
+ if (next->tag != NGX_QUIC_PATH_BACKUP) {
+ /* can delete backup path, if any */
+ bkp = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP);
- if (qc->backup) {
- ngx_quic_close_socket(c, qc->backup);
+ if (bkp && ngx_quic_free_path(c, bkp) != NGX_OK) {
+ return NGX_ERROR;
+ }
}
- qc->backup = qc->socket;
+ qc->path->tag = NGX_QUIC_PATH_BACKUP;
+ ngx_quic_path_dbg(c, "is now backup", qc->path);
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic backup socket is now #%uL:%uL:%uL (%s)",
- qc->backup->sid.seqnum, qc->backup->cid->seqnum,
- qc->backup->path->seqnum,
- ngx_quic_path_state_str(qc->backup->path));
+ } else {
+ if (ngx_quic_free_path(c, qc->path) != NGX_OK) {
+ return NGX_ERROR;
+ }
}
- qc->socket = qsock;
+ /* switch active path to migrated */
+ qc->path = next;
+ qc->path->tag = NGX_QUIC_PATH_ACTIVE;
+
+ ngx_quic_set_connection_path(c, next);
+
+ if (!next->validated && !next->validating) {
+ if (ngx_quic_validate_path(c, next) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic active socket is now #%uL:%uL:%uL (%s)",
- qsock->sid.seqnum, qsock->cid->seqnum,
- qsock->path->seqnum, ngx_quic_path_state_str(qsock->path));
+ "quic migrated to path#%uL addr:%V",
+ qc->path->seqnum, &qc->path->addr_text);
+
+ ngx_quic_path_dbg(c, "is now active", qc->path);
return NGX_OK;
}
@@ -487,10 +483,9 @@ ngx_quic_validate_path(ngx_connection_t *c, ngx_quic_path_t *path)
qc = ngx_quic_get_connection(c);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic initiated validation of new path #%uL",
- path->seqnum);
+ "quic initiated validation of path #%uL", path->seqnum);
- path->state = NGX_QUIC_PATH_VALIDATING;
+ path->validating = 1;
if (RAND_bytes(path->challenge1, 8) != 1) {
return NGX_ERROR;
@@ -524,7 +519,7 @@ ngx_quic_send_path_challenge(ngx_connection_t *c, ngx_quic_path_t *path)
ngx_quic_frame_t frame;
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic path #%uL send path challenge tries:%ui",
+ "quic path #%uL send path_challenge tries:%ui",
path->seqnum, path->tries);
ngx_memzero(&frame, sizeof(ngx_quic_frame_t));
@@ -564,7 +559,7 @@ ngx_quic_path_validation_handler(ngx_event_t *ev)
ngx_msec_t now;
ngx_queue_t *q;
ngx_msec_int_t left, next, pto;
- ngx_quic_path_t *path;
+ ngx_quic_path_t *path, *bkp;
ngx_connection_t *c;
ngx_quic_send_ctx_t *ctx;
ngx_quic_connection_t *qc;
@@ -578,13 +573,14 @@ ngx_quic_path_validation_handler(ngx_event_t *ev)
next = -1;
now = ngx_current_msec;
- for (q = ngx_queue_head(&qc->paths);
- q != ngx_queue_sentinel(&qc->paths);
- q = ngx_queue_next(q))
- {
+ q = ngx_queue_head(&qc->paths);
+
+ while (q != ngx_queue_sentinel(&qc->paths)) {
+
path = ngx_queue_data(q, ngx_quic_path_t, queue);
+ q = ngx_queue_next(q);
- if (path->state != NGX_QUIC_PATH_VALIDATING) {
+ if (!path->validating) {
continue;
}
@@ -593,7 +589,7 @@ ngx_quic_path_validation_handler(ngx_event_t *ev)
if (left > 0) {
if (next == -1 || left < next) {
- next = path->expires;
+ next = left;
}
continue;
@@ -617,26 +613,43 @@ ngx_quic_path_validation_handler(ngx_event_t *ev)
/* found expired path */
- path->state = NGX_QUIC_PATH_NEW;
+ path->validated = 0;
+ path->validating = 0;
path->limited = 1;
- /*
- * RFC 9000, 9.4. Loss Detection and Congestion Control
+
+ /* RFC 9000, 9.3.2. On-Path Address Spoofing
*
- * If the timer fires before the PATH_RESPONSE is received, the
- * endpoint might send a new PATH_CHALLENGE and restart the timer for
- * a longer period of time. This timer SHOULD be set as described in
- * Section 6.2.1 of [QUIC-RECOVERY] and MUST NOT be more aggressive.
+ * To protect the connection from failing due to such a spurious
+ * migration, an endpoint MUST revert to using the last validated
+ * peer address when validation of a new peer address fails.
*/
- if (qc->socket->path != path) {
- /* the path was not actually used */
- continue;
+ if (qc->path == path) {
+ /* active path validation failed */
+
+ bkp = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP);
+
+ if (bkp == NULL) {
+ qc->error = NGX_QUIC_ERR_NO_VIABLE_PATH;
+ qc->error_reason = "no viable path";
+ ngx_quic_close_connection(c, NGX_ERROR);
+ return;
+ }
+
+ qc->path = bkp;
+ qc->path->tag = NGX_QUIC_PATH_ACTIVE;
+
+ ngx_quic_set_connection_path(c, qc->path);
+
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "quic path #%uL addr:%V is restored from backup",
+ qc->path->seqnum, &qc->path->addr_text);
+
+ ngx_quic_path_dbg(c, "is active", qc->path);
}
- if (ngx_quic_path_restore(c) != NGX_OK) {
- qc->error = NGX_QUIC_ERR_NO_VIABLE_PATH;
- qc->error_reason = "no viable path";
+ if (ngx_quic_free_path(c, path) != NGX_OK) {
ngx_quic_close_connection(c, NGX_ERROR);
return;
}
@@ -646,44 +659,3 @@ ngx_quic_path_validation_handler(ngx_event_t *ev)
ngx_add_timer(&qc->path_validation, next);
}
}
-
-
-static ngx_int_t
-ngx_quic_path_restore(ngx_connection_t *c)
-{
- ngx_quic_socket_t *qsock;
- ngx_quic_connection_t *qc;
-
- qc = ngx_quic_get_connection(c);
-
- /*
- * RFC 9000, 9.1. Probing a New Path
- *
- * Failure to validate a path does not cause the connection to end
- *
- * RFC 9000, 9.3.2. On-Path Address Spoofing
- *
- * To protect the connection from failing due to such a spurious
- * migration, an endpoint MUST revert to using the last validated
- * peer address when validation of a new peer address fails.
- */
-
- if (qc->backup == NULL) {
- return NGX_ERROR;
- }
-
- qc->socket = qc->backup;
- qc->backup = NULL;
-
- qsock = qc->socket;
-
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "quic active socket is restored to #%uL:%uL:%uL"
- " (%s), no backup",
- qsock->sid.seqnum, qsock->cid->seqnum, qsock->path->seqnum,
- ngx_quic_path_state_str(qsock->path));
-
- ngx_quic_set_connection_path(c, qsock->path);
-
- return NGX_OK;
-}
diff --git a/src/event/quic/ngx_event_quic_migration.h b/src/event/quic/ngx_event_quic_migration.h
index 4bb5a2a1a..a446d10a5 100644
--- a/src/event/quic/ngx_event_quic_migration.h
+++ b/src/event/quic/ngx_event_quic_migration.h
@@ -11,29 +11,29 @@
#include <ngx_config.h>
#include <ngx_core.h>
-#define NGX_QUIC_PATH_RETRIES 3
+#define NGX_QUIC_PATH_RETRIES 3
-#define NGX_QUIC_PATH_NEW 0
-#define NGX_QUIC_PATH_VALIDATING 1
-#define NGX_QUIC_PATH_VALIDATED 2
-
-
-#define ngx_quic_path_state_str(p) \
- ((p)->state == NGX_QUIC_PATH_NEW) ? "new" : \
- (((p)->state == NGX_QUIC_PATH_VALIDATED) ? "validated" : "validating")
+#define NGX_QUIC_PATH_PROBE 0
+#define NGX_QUIC_PATH_ACTIVE 1
+#define NGX_QUIC_PATH_BACKUP 2
+#define ngx_quic_path_dbg(c, msg, path) \
+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, \
+ "quic path#%uL %s sent:%O recvd:%O state:%s%s%s", \
+ path->seqnum, msg, path->sent, path->received, \
+ path->limited ? "L" : "", path->validated ? "V": "N", \
+ path->validating ? "R": "");
ngx_int_t ngx_quic_handle_path_challenge_frame(ngx_connection_t *c,
- ngx_quic_path_challenge_frame_t *f);
+ ngx_quic_header_t *pkt, ngx_quic_path_challenge_frame_t *f);
ngx_int_t ngx_quic_handle_path_response_frame(ngx_connection_t *c,
ngx_quic_path_challenge_frame_t *f);
-ngx_quic_path_t *ngx_quic_find_path(ngx_connection_t *c,
- struct sockaddr *sockaddr, socklen_t socklen);
-ngx_quic_path_t *ngx_quic_add_path(ngx_connection_t *c,
- struct sockaddr *sockaddr, socklen_t socklen);
+ngx_quic_path_t *ngx_quic_new_path(ngx_connection_t *c,
+ struct sockaddr *sockaddr, socklen_t socklen, ngx_quic_client_id_t *cid);
+ngx_int_t ngx_quic_free_path(ngx_connection_t *c, ngx_quic_path_t *path);
-ngx_int_t ngx_quic_update_paths(ngx_connection_t *c, ngx_quic_header_t *pkt);
+ngx_int_t ngx_quic_set_path(ngx_connection_t *c, ngx_quic_header_t *pkt);
ngx_int_t ngx_quic_handle_migration(ngx_connection_t *c,
ngx_quic_header_t *pkt);
diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c
index 5599cdeb1..d4b079125 100644
--- a/src/event/quic/ngx_event_quic_output.c
+++ b/src/event/quic/ngx_event_quic_output.c
@@ -51,7 +51,7 @@ static ssize_t ngx_quic_send_segments(ngx_connection_t *c, u_char *buf,
static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min);
static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
- ngx_quic_header_t *pkt);
+ ngx_quic_header_t *pkt, ngx_quic_path_t *path);
static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
struct sockaddr *sockaddr, socklen_t socklen);
@@ -131,7 +131,7 @@ ngx_quic_create_datagrams(ngx_connection_t *c)
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
- path = qc->socket->path;
+ path = qc->path;
while (cg->in_flight < cg->window) {
@@ -269,7 +269,7 @@ ngx_quic_allow_segmentation(ngx_connection_t *c)
return 0;
}
- if (qc->socket->path->limited) {
+ if (qc->path->limited) {
/* don't even try to be faster on non-validated paths */
return 0;
}
@@ -325,7 +325,7 @@ ngx_quic_create_segments(ngx_connection_t *c)
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
- path = qc->socket->path;
+ path = qc->path;
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
@@ -505,17 +505,18 @@ static ssize_t
ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
u_char *data, size_t max, size_t min)
{
- size_t len, pad, min_payload, max_payload;
- u_char *p;
- ssize_t flen;
- ngx_str_t res;
- ngx_int_t rc;
- ngx_uint_t nframes, expand;
- ngx_msec_t now;
- ngx_queue_t *q;
- ngx_quic_frame_t *f;
- ngx_quic_header_t pkt;
- static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
+ size_t len, pad, min_payload, max_payload;
+ u_char *p;
+ ssize_t flen;
+ ngx_str_t res;
+ ngx_int_t rc;
+ ngx_uint_t nframes, expand;
+ ngx_msec_t now;
+ ngx_queue_t *q;
+ ngx_quic_frame_t *f;
+ ngx_quic_header_t pkt;
+ ngx_quic_connection_t *qc;
+ static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
if (ngx_queue_empty(&ctx->frames)) {
return 0;
@@ -525,7 +526,9 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
"quic output %s packet max:%uz min:%uz",
ngx_quic_level_name(ctx->level), max, min);
- ngx_quic_init_packet(c, ctx, &pkt);
+ qc = ngx_quic_get_connection(c);
+
+ ngx_quic_init_packet(c, ctx, &pkt, qc->path);
min_payload = ngx_quic_payload_size(&pkt, min);
max_payload = ngx_quic_payload_size(&pkt, max);
@@ -668,14 +671,14 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
static void
ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
- ngx_quic_header_t *pkt)
+ ngx_quic_header_t *pkt, ngx_quic_path_t *path)
{
ngx_quic_socket_t *qsock;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
- qsock = qc->socket;
+ qsock = ngx_quic_get_socket(c);
ngx_memzero(pkt, sizeof(ngx_quic_header_t));
@@ -693,8 +696,8 @@ ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
}
}
- pkt->dcid.data = qsock->cid->id;
- pkt->dcid.len = qsock->cid->len;
+ pkt->dcid.data = path->cid->id;
+ pkt->dcid.len = path->cid->len;
pkt->scid.data = qsock->sid.id;
pkt->scid.len = qsock->sid.len;
@@ -1202,7 +1205,7 @@ ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
- ngx_quic_init_packet(c, ctx, &pkt);
+ ngx_quic_init_packet(c, ctx, &pkt, path);
min = ngx_quic_path_limit(c, path, min);
diff --git a/src/event/quic/ngx_event_quic_socket.c b/src/event/quic/ngx_event_quic_socket.c
index 426e1ebae..b5d168a7a 100644
--- a/src/event/quic/ngx_event_quic_socket.c
+++ b/src/event/quic/ngx_event_quic_socket.c
@@ -14,11 +14,12 @@ ngx_int_t
ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc,
ngx_quic_header_t *pkt)
{
- ngx_quic_path_t *path;
ngx_quic_socket_t *qsock, *tmp;
ngx_quic_client_id_t *cid;
/*
+ * qc->path = NULL
+ *
* qc->nclient_ids = 0
* qc->nsockets = 0
* qc->max_retired_seqnum = 0
@@ -51,6 +52,8 @@ ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc,
return NGX_ERROR;
}
+ qsock->used = 1;
+
qc->tp.initial_scid.len = qsock->sid.len;
qc->tp.initial_scid.data = ngx_pnalloc(c->pool, qsock->sid.len);
if (qc->tp.initial_scid.data == NULL) {
@@ -69,19 +72,20 @@ ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc,
goto failed;
}
- /* the client arrived from this path */
- path = ngx_quic_add_path(c, c->sockaddr, c->socklen);
- if (path == NULL) {
+ /* path of the first packet is our initial active path */
+ qc->path = ngx_quic_new_path(c, c->sockaddr, c->socklen, cid);
+ if (qc->path == NULL) {
goto failed;
}
+ qc->path->tag = NGX_QUIC_PATH_ACTIVE;
+
if (pkt->validated) {
- path->state = NGX_QUIC_PATH_VALIDATED;
- path->limited = 0;
+ qc->path->validated = 1;
+ qc->path->limited = 0;
}
- /* now bind socket to client and path */
- ngx_quic_connect(c, qsock, path, cid);
+ ngx_quic_path_dbg(c, "set active", qc->path);
tmp = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t));
if (tmp == NULL) {
@@ -97,16 +101,6 @@ ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc,
goto failed;
}
- ngx_quic_connect(c, tmp, path, cid);
-
- /* use this socket as default destination */
- qc->socket = qsock;
-
- ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic active socket is #%uL:%uL:%uL (%s)",
- qsock->sid.seqnum, qsock->cid->seqnum, qsock->path->seqnum,
- ngx_quic_path_state_str(qsock->path));
-
return NGX_OK;
failed:
@@ -165,42 +159,12 @@ ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock)
ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node);
qc->nsockets--;
- if (qsock->path) {
- ngx_quic_unref_path(c, qsock->path);
- }
-
- if (qsock->cid) {
- ngx_quic_unref_client_id(c, qsock->cid);
- }
-
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic socket #%L closed nsock:%ui",
(int64_t) qsock->sid.seqnum, qc->nsockets);
}
-void
-ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path)
-{
- ngx_quic_connection_t *qc;
-
- path->refcnt--;
-
- if (path->refcnt) {
- return;
- }
-
- qc = ngx_quic_get_connection(c);
-
- ngx_queue_remove(&path->queue);
- ngx_queue_insert_head(&qc->free_paths, &path->queue);
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic path #%uL addr:%V removed",
- path->seqnum, &path->addr_text);
-}
-
-
ngx_int_t
ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc,
ngx_quic_socket_t *qsock)
@@ -229,23 +193,6 @@ ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc,
void
-ngx_quic_connect(ngx_connection_t *c, ngx_quic_socket_t *sock,
- ngx_quic_path_t *path, ngx_quic_client_id_t *cid)
-{
- sock->path = path;
- path->refcnt++;
-
- sock->cid = cid;
- cid->refcnt++;
-
- ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic socket #%L connected to cid #%uL path:%uL",
- (int64_t) sock->sid.seqnum,
- sock->cid->seqnum, path->seqnum);
-}
-
-
-void
ngx_quic_close_sockets(ngx_connection_t *c)
{
ngx_queue_t *q;
@@ -285,27 +232,3 @@ ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum)
return NULL;
}
-
-
-ngx_quic_socket_t *
-ngx_quic_get_unconnected_socket(ngx_connection_t *c)
-{
- ngx_queue_t *q;
- ngx_quic_socket_t *sock;
- ngx_quic_connection_t *qc;
-
- qc = ngx_quic_get_connection(c);
-
- for (q = ngx_queue_head(&qc->sockets);
- q != ngx_queue_sentinel(&qc->sockets);
- q = ngx_queue_next(q))
- {
- sock = ngx_queue_data(q, ngx_quic_socket_t, queue);
-
- if (sock->cid == NULL) {
- return sock;
- }
- }
-
- return NULL;
-}
diff --git a/src/event/quic/ngx_event_quic_socket.h b/src/event/quic/ngx_event_quic_socket.h
index 51f01a1fa..e15996883 100644
--- a/src/event/quic/ngx_event_quic_socket.h
+++ b/src/event/quic/ngx_event_quic_socket.h
@@ -22,10 +22,6 @@ ngx_int_t ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc,
ngx_quic_socket_t *qsock);
void ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock);
-void ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path);
-void ngx_quic_connect(ngx_connection_t *c, ngx_quic_socket_t *qsock,
- ngx_quic_path_t *path, ngx_quic_client_id_t *cid);
-
ngx_quic_socket_t *ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum);
ngx_quic_socket_t *ngx_quic_get_unconnected_socket(ngx_connection_t *c);
diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c
index e5e3ffcab..41806b252 100644
--- a/src/event/quic/ngx_event_quic_ssl.c
+++ b/src/event/quic/ngx_event_quic_ssl.c
@@ -497,7 +497,7 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data)
ngx_quic_queue_frame(qc, frame);
if (qc->conf->retry) {
- if (ngx_quic_send_new_token(c, qc->socket->path) != NGX_OK) {
+ if (ngx_quic_send_new_token(c, qc->path) != NGX_OK) {
return NGX_ERROR;
}
}
@@ -541,6 +541,7 @@ ngx_quic_init_connection(ngx_connection_t *c)
ssize_t len;
ngx_str_t dcid;
ngx_ssl_conn_t *ssl_conn;
+ ngx_quic_socket_t *qsock;
ngx_quic_connection_t *qc;
qc = ngx_quic_get_connection(c);
@@ -569,8 +570,10 @@ ngx_quic_init_connection(ngx_connection_t *c)
SSL_set_quic_use_legacy_codepoint(ssl_conn, qc->version != 1);
#endif
- dcid.data = qc->socket->sid.id;
- dcid.len = qc->socket->sid.len;
+ qsock = ngx_quic_get_socket(c);
+
+ dcid.data = qsock->sid.id;
+ dcid.len = qsock->sid.len;
if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key, qc->tp.sr_token)
!= NGX_OK)
diff --git a/src/event/quic/ngx_event_quic_transport.h b/src/event/quic/ngx_event_quic_transport.h
index 64ebfa979..a512ad802 100644
--- a/src/event/quic/ngx_event_quic_transport.h
+++ b/src/event/quic/ngx_event_quic_transport.h
@@ -300,6 +300,7 @@ struct ngx_quic_frame_s {
typedef struct {
ngx_log_t *log;
+ ngx_quic_path_t *path;
ngx_quic_keys_t *keys;
@@ -335,6 +336,7 @@ typedef struct {
unsigned validated:1;
unsigned retried:1;
unsigned first:1;
+ unsigned rebound:1;
} ngx_quic_header_t;