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; + return NGX_ERROR; } - 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; - } - - 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; -} + frame->level = ssl_encryption_application; + frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID; + frame->u.retire_cid.sequence_number = cid->seqnum; + ngx_quic_queue_frame(qc, frame); -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 */ - - if (cid->refcnt) { - return; - } - - 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); - path->state = NGX_QUIC_PATH_VALIDATED; + ngx_quic_path_dbg(c, "is validated", path); + + 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_queue_insert_tail(&qc->paths, &path->queue); + path->cid = cid; + cid->used = 1; -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); - - path = ngx_quic_alloc_path(c); - if (path == NULL) { - return NULL; - } - - 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); + probe = NULL; - 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 */ - - 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; - } - - /* 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"; - - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no available client ids for new path"); - - return NGX_ERROR; + if (path->tag == NGX_QUIC_PATH_PROBE) { + probe = path; } } - ngx_quic_connect(c, qsock, path, cid); + /* packet from new path, drop current probe, if any */ + + if (probe && ngx_quic_free_path(c, probe) != NGX_OK) { + 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; + } + + path = ngx_quic_new_path(c, c->udp->dgram->sockaddr, + c->udp->dgram->socklen, cid); + if (path == NULL) { + return NGX_ERROR; + } + + path->tag = NGX_QUIC_PATH_PROBE; + + /* + * client arrived using new path and previously seen DCID, + * this indicates NAT rebinding (or bad client) + */ + if (qsock->used) { + pkt->rebound = 1; + } update: - 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; - } - } - - path->last_seen = ngx_current_msec; - - 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 */ + next = pkt->path; + + /* + * RFC 9000, 9.3.3: + * + * 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) { + + if (next->tag != NGX_QUIC_PATH_BACKUP) { + /* can delete backup path, if any */ + bkp = ngx_quic_get_path(c, NGX_QUIC_PATH_BACKUP); + + if (bkp && ngx_quic_free_path(c, bkp) != NGX_OK) { + return NGX_ERROR; + } + } + + qc->path->tag = NGX_QUIC_PATH_BACKUP; + ngx_quic_path_dbg(c, "is now backup", qc->path); + + } else { + if (ngx_quic_free_path(c, qc->path) != NGX_OK) { + return NGX_ERROR; + } + } + + /* switch active path to migrated */ + qc->path = next; + qc->path->tag = NGX_QUIC_PATH_ACTIVE; ngx_quic_set_connection_path(c, next); - /* - * RFC 9000, 9.5. Privacy Implications of Connection Migration - * - * An endpoint MUST NOT reuse a connection ID when sending to - * more than one destination address. - */ - - /* preserve valid path we are migrating from */ - if (qc->socket->path->state == NGX_QUIC_PATH_VALIDATED) { - - if (qc->backup) { - ngx_quic_close_socket(c, qc->backup); + if (!next->validated && !next->validating) { + if (ngx_quic_validate_path(c, next) != NGX_OK) { + return NGX_ERROR; } - - qc->backup = qc->socket; - - 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)); } - qc->socket = qsock; - 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)) - { - path = ngx_queue_data(q, ngx_quic_path_t, queue); + q = ngx_queue_head(&qc->paths); - if (path->state != NGX_QUIC_PATH_VALIDATING) { + while (q != ngx_queue_sentinel(&qc->paths)) { + + path = ngx_queue_data(q, ngx_quic_path_t, queue); + q = ngx_queue_next(q); + + 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 #include -#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) @@ -228,23 +192,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) { @@ -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;