mirror of
https://github.com/nginx/nginx.git
synced 2025-02-25 18:55:26 -06:00
QUIC: separate files for connection id related processing.
This commit is contained in:
parent
232fcba34b
commit
118775761c
@ -1343,10 +1343,12 @@ if [ $USE_OPENSSL$USE_OPENSSL_QUIC = YESYES ]; then
|
|||||||
src/event/quic/ngx_event_quic_transport.h \
|
src/event/quic/ngx_event_quic_transport.h \
|
||||||
src/event/quic/ngx_event_quic_protection.h \
|
src/event/quic/ngx_event_quic_protection.h \
|
||||||
src/event/quic/ngx_event_quic_connection.h \
|
src/event/quic/ngx_event_quic_connection.h \
|
||||||
|
src/event/quic/ngx_event_quic_connid.h \
|
||||||
src/event/quic/ngx_event_quic_migration.h"
|
src/event/quic/ngx_event_quic_migration.h"
|
||||||
ngx_module_srcs="src/event/quic/ngx_event_quic.c \
|
ngx_module_srcs="src/event/quic/ngx_event_quic.c \
|
||||||
src/event/quic/ngx_event_quic_transport.c \
|
src/event/quic/ngx_event_quic_transport.c \
|
||||||
src/event/quic/ngx_event_quic_protection.c \
|
src/event/quic/ngx_event_quic_protection.c \
|
||||||
|
src/event/quic/ngx_event_quic_connid.c \
|
||||||
src/event/quic/ngx_event_quic_migration.c"
|
src/event/quic/ngx_event_quic_migration.c"
|
||||||
|
|
||||||
ngx_module_libs=
|
ngx_module_libs=
|
||||||
|
@ -23,8 +23,6 @@
|
|||||||
|
|
||||||
#define NGX_QUIC_STREAM_GONE (void *) -1
|
#define NGX_QUIC_STREAM_GONE (void *) -1
|
||||||
|
|
||||||
#define NGX_QUIC_UNSET_PN (uint64_t) -1
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Endpoints MUST discard packets that are too small to be valid QUIC
|
* Endpoints MUST discard packets that are too small to be valid QUIC
|
||||||
* packets. With the set of AEAD functions defined in [QUIC-TLS],
|
* packets. With the set of AEAD functions defined in [QUIC-TLS],
|
||||||
@ -66,20 +64,12 @@ static ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c,
|
|||||||
ngx_quic_tp_t *ctp);
|
ngx_quic_tp_t *ctp);
|
||||||
static ngx_quic_connection_t *ngx_quic_new_connection(ngx_connection_t *c,
|
static ngx_quic_connection_t *ngx_quic_new_connection(ngx_connection_t *c,
|
||||||
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
||||||
static ngx_int_t ngx_quic_setup_connection_ids(ngx_connection_t *c,
|
|
||||||
ngx_quic_connection_t *qc, ngx_quic_header_t *pkt);
|
|
||||||
static ngx_int_t ngx_quic_send_stateless_reset(ngx_connection_t *c,
|
static ngx_int_t ngx_quic_send_stateless_reset(ngx_connection_t *c,
|
||||||
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
||||||
static ngx_int_t ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid,
|
|
||||||
u_char *secret, u_char *token);
|
|
||||||
static ngx_int_t ngx_quic_process_stateless_reset(ngx_connection_t *c,
|
static ngx_int_t ngx_quic_process_stateless_reset(ngx_connection_t *c,
|
||||||
ngx_quic_header_t *pkt);
|
ngx_quic_header_t *pkt);
|
||||||
static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c,
|
static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c,
|
||||||
ngx_quic_header_t *inpkt);
|
ngx_quic_header_t *inpkt);
|
||||||
static ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id);
|
|
||||||
#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_retry(ngx_connection_t *c,
|
static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c,
|
||||||
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
||||||
static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, u_char *key,
|
static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, u_char *key,
|
||||||
@ -163,20 +153,6 @@ static ngx_int_t ngx_quic_handle_stop_sending_frame(ngx_connection_t *c,
|
|||||||
ngx_quic_header_t *pkt, ngx_quic_stop_sending_frame_t *f);
|
ngx_quic_header_t *pkt, ngx_quic_stop_sending_frame_t *f);
|
||||||
static ngx_int_t ngx_quic_handle_max_streams_frame(ngx_connection_t *c,
|
static ngx_int_t ngx_quic_handle_max_streams_frame(ngx_connection_t *c,
|
||||||
ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f);
|
ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f);
|
||||||
static ngx_int_t ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
|
|
||||||
ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f);
|
|
||||||
static ngx_int_t ngx_quic_retire_connection_id(ngx_connection_t *c,
|
|
||||||
enum ssl_encryption_level_t level, uint64_t seqnum);
|
|
||||||
static ngx_int_t ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
|
|
||||||
ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f);
|
|
||||||
static ngx_int_t ngx_quic_issue_server_ids(ngx_connection_t *c);
|
|
||||||
static void ngx_quic_clear_temp_server_ids(ngx_connection_t *c);
|
|
||||||
static ngx_quic_server_id_t *ngx_quic_insert_server_id(ngx_connection_t *c,
|
|
||||||
ngx_quic_connection_t *qc, ngx_str_t *id);
|
|
||||||
static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c,
|
|
||||||
ngx_quic_connection_t *qc);
|
|
||||||
static ngx_quic_server_id_t *ngx_quic_alloc_server_id(ngx_connection_t *c,
|
|
||||||
ngx_quic_connection_t *qc);
|
|
||||||
|
|
||||||
static ngx_int_t ngx_quic_output(ngx_connection_t *c);
|
static ngx_int_t ngx_quic_output(ngx_connection_t *c);
|
||||||
static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
|
static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
|
||||||
@ -1035,84 +1011,6 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
|
||||||
ngx_quic_setup_connection_ids(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
|
||||||
ngx_quic_header_t *pkt)
|
|
||||||
{
|
|
||||||
ngx_quic_server_id_t *sid, *osid;
|
|
||||||
ngx_quic_client_id_t *cid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* qc->nclient_ids = 0
|
|
||||||
* qc->nserver_ids = 0
|
|
||||||
* qc->max_retired_seqnum = 0
|
|
||||||
*/
|
|
||||||
|
|
||||||
ngx_queue_init(&qc->client_ids);
|
|
||||||
ngx_queue_init(&qc->server_ids);
|
|
||||||
ngx_queue_init(&qc->free_client_ids);
|
|
||||||
ngx_queue_init(&qc->free_server_ids);
|
|
||||||
|
|
||||||
qc->odcid.len = pkt->odcid.len;
|
|
||||||
qc->odcid.data = ngx_pstrdup(c->pool, &pkt->odcid);
|
|
||||||
if (qc->odcid.data == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
qc->tp.original_dcid = qc->odcid;
|
|
||||||
|
|
||||||
qc->scid.len = pkt->scid.len;
|
|
||||||
qc->scid.data = ngx_pstrdup(c->pool, &pkt->scid);
|
|
||||||
if (qc->scid.data == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
qc->dcid.len = NGX_QUIC_SERVER_CID_LEN;
|
|
||||||
qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len);
|
|
||||||
if (qc->dcid.data == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ngx_quic_create_server_id(c, qc->dcid.data) != NGX_OK) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
qc->tp.initial_scid = qc->dcid;
|
|
||||||
|
|
||||||
cid = ngx_quic_alloc_client_id(c, qc);
|
|
||||||
if (cid == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
cid->seqnum = 0;
|
|
||||||
cid->len = pkt->scid.len;
|
|
||||||
ngx_memcpy(cid->id, pkt->scid.data, pkt->scid.len);
|
|
||||||
|
|
||||||
ngx_queue_insert_tail(&qc->client_ids, &cid->queue);
|
|
||||||
qc->nclient_ids++;
|
|
||||||
qc->client_seqnum = 0;
|
|
||||||
|
|
||||||
qc->server_seqnum = NGX_QUIC_UNSET_PN;
|
|
||||||
|
|
||||||
osid = ngx_quic_insert_server_id(c, qc, &qc->odcid);
|
|
||||||
if (osid == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
qc->server_seqnum = 0;
|
|
||||||
|
|
||||||
sid = ngx_quic_insert_server_id(c, qc, &qc->dcid);
|
|
||||||
if (sid == NULL) {
|
|
||||||
ngx_rbtree_delete(&c->listening->rbtree, &osid->udp.node);
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->udp = &sid->udp;
|
|
||||||
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
||||||
ngx_quic_header_t *pkt)
|
ngx_quic_header_t *pkt)
|
||||||
@ -1164,7 +1062,7 @@ ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
ngx_int_t
|
||||||
ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, u_char *secret,
|
ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, u_char *secret,
|
||||||
u_char *token)
|
u_char *token)
|
||||||
{
|
{
|
||||||
@ -1262,56 +1160,6 @@ ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
|
||||||
ngx_quic_create_server_id(ngx_connection_t *c, u_char *id)
|
|
||||||
{
|
|
||||||
if (RAND_bytes(id, NGX_QUIC_SERVER_CID_LEN) != 1) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (NGX_QUIC_BPF)
|
|
||||||
if (ngx_quic_bpf_attach_id(c, id) != NGX_OK) {
|
|
||||||
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
|
||||||
"quic bpf failed to generate socket key");
|
|
||||||
/* ignore error, things still may work */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
||||||
"quic create server id %*xs",
|
|
||||||
(size_t) NGX_QUIC_SERVER_CID_LEN, id);
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if (NGX_QUIC_BPF)
|
|
||||||
|
|
||||||
static ngx_int_t
|
|
||||||
ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
uint64_t cookie;
|
|
||||||
socklen_t optlen;
|
|
||||||
|
|
||||||
fd = c->listening->fd;
|
|
||||||
|
|
||||||
optlen = sizeof(cookie);
|
|
||||||
|
|
||||||
if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &optlen) == -1) {
|
|
||||||
ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno,
|
|
||||||
"quic getsockopt(SO_COOKIE) failed");
|
|
||||||
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_quic_dcid_encode_key(id, cookie);
|
|
||||||
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
|
||||||
ngx_quic_header_t *inpkt)
|
ngx_quic_header_t *inpkt)
|
||||||
@ -4390,381 +4238,6 @@ ngx_quic_handle_max_streams_frame(ngx_connection_t *c,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
|
||||||
ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
|
|
||||||
ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f)
|
|
||||||
{
|
|
||||||
ngx_queue_t *q;
|
|
||||||
ngx_quic_client_id_t *cid, *item;
|
|
||||||
ngx_quic_connection_t *qc;
|
|
||||||
|
|
||||||
qc = ngx_quic_get_connection(c);
|
|
||||||
|
|
||||||
if (f->seqnum < qc->max_retired_seqnum) {
|
|
||||||
/*
|
|
||||||
* An endpoint that receives a NEW_CONNECTION_ID frame with
|
|
||||||
* a sequence number smaller than the Retire Prior To field
|
|
||||||
* of a previously received NEW_CONNECTION_ID frame MUST send
|
|
||||||
* a corresponding RETIRE_CONNECTION_ID frame that retires
|
|
||||||
* the newly received connection ID, unless it has already
|
|
||||||
* done so for that sequence number.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (ngx_quic_retire_connection_id(c, pkt->level, f->seqnum) != NGX_OK) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto retire;
|
|
||||||
}
|
|
||||||
|
|
||||||
cid = NULL;
|
|
||||||
|
|
||||||
for (q = ngx_queue_head(&qc->client_ids);
|
|
||||||
q != ngx_queue_sentinel(&qc->client_ids);
|
|
||||||
q = ngx_queue_next(q))
|
|
||||||
{
|
|
||||||
item = ngx_queue_data(q, ngx_quic_client_id_t, queue);
|
|
||||||
|
|
||||||
if (item->seqnum == f->seqnum) {
|
|
||||||
cid = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cid) {
|
|
||||||
/*
|
|
||||||
* Transmission errors, timeouts and retransmissions might cause the
|
|
||||||
* same NEW_CONNECTION_ID frame to be received multiple times
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (cid->len != f->len
|
|
||||||
|| ngx_strncmp(cid->id, f->cid, f->len) != 0
|
|
||||||
|| ngx_strncmp(cid->sr_token, f->srt, NGX_QUIC_SR_TOKEN_LEN) != 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* ..a sequence number is used for different connection IDs,
|
|
||||||
* the endpoint MAY treat that receipt as a connection error
|
|
||||||
* of type PROTOCOL_VIOLATION.
|
|
||||||
*/
|
|
||||||
qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION;
|
|
||||||
qc->error_reason = "seqnum refers to different connection id/token";
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
cid = ngx_quic_alloc_client_id(c, qc);
|
|
||||||
if (cid == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
cid->seqnum = f->seqnum;
|
|
||||||
cid->len = f->len;
|
|
||||||
ngx_memcpy(cid->id, f->cid, f->len);
|
|
||||||
|
|
||||||
ngx_memcpy(cid->sr_token, f->srt, NGX_QUIC_SR_TOKEN_LEN);
|
|
||||||
|
|
||||||
ngx_queue_insert_tail(&qc->client_ids, &cid->queue);
|
|
||||||
qc->nclient_ids++;
|
|
||||||
|
|
||||||
/* always use latest available connection id */
|
|
||||||
if (f->seqnum > qc->client_seqnum) {
|
|
||||||
qc->scid.len = cid->len;
|
|
||||||
qc->scid.data = cid->id;
|
|
||||||
qc->client_seqnum = f->seqnum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
retire:
|
|
||||||
|
|
||||||
if (qc->max_retired_seqnum && f->retire <= qc->max_retired_seqnum) {
|
|
||||||
/*
|
|
||||||
* Once a sender indicates a Retire Prior To value, smaller values sent
|
|
||||||
* in subsequent NEW_CONNECTION_ID frames have no effect. A receiver
|
|
||||||
* MUST ignore any Retire Prior To fields that do not increase the
|
|
||||||
* largest received Retire Prior To value.
|
|
||||||
*/
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
qc->max_retired_seqnum = f->retire;
|
|
||||||
|
|
||||||
q = ngx_queue_head(&qc->client_ids);
|
|
||||||
|
|
||||||
while (q != ngx_queue_sentinel(&qc->client_ids)) {
|
|
||||||
|
|
||||||
cid = ngx_queue_data(q, ngx_quic_client_id_t, queue);
|
|
||||||
q = ngx_queue_next(q);
|
|
||||||
|
|
||||||
if (cid->seqnum >= f->retire) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this connection id must be retired */
|
|
||||||
|
|
||||||
if (ngx_quic_retire_connection_id(c, pkt->level, cid->seqnum)
|
|
||||||
!= NGX_OK)
|
|
||||||
{
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_queue_remove(&cid->queue);
|
|
||||||
ngx_queue_insert_head(&qc->free_client_ids, &cid->queue);
|
|
||||||
qc->nclient_ids--;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
|
|
||||||
if (qc->nclient_ids > qc->tp.active_connection_id_limit) {
|
|
||||||
/*
|
|
||||||
* After processing a NEW_CONNECTION_ID frame and
|
|
||||||
* adding and retiring active connection IDs, if the number of active
|
|
||||||
* connection IDs exceeds the value advertised in its
|
|
||||||
* active_connection_id_limit transport parameter, an endpoint MUST
|
|
||||||
* close the connection with an error of type CONNECTION_ID_LIMIT_ERROR.
|
|
||||||
*/
|
|
||||||
qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR;
|
|
||||||
qc->error_reason = "too many connection ids received";
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
|
||||||
ngx_quic_retire_connection_id(ngx_connection_t *c,
|
|
||||||
enum ssl_encryption_level_t level, uint64_t seqnum)
|
|
||||||
{
|
|
||||||
ngx_quic_frame_t *frame;
|
|
||||||
ngx_quic_connection_t *qc;
|
|
||||||
|
|
||||||
qc = ngx_quic_get_connection(c);
|
|
||||||
|
|
||||||
frame = ngx_quic_alloc_frame(c);
|
|
||||||
if (frame == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame->level = level;
|
|
||||||
frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID;
|
|
||||||
frame->u.retire_cid.sequence_number = seqnum;
|
|
||||||
|
|
||||||
ngx_quic_queue_frame(qc, frame);
|
|
||||||
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
|
||||||
ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
|
|
||||||
ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f)
|
|
||||||
{
|
|
||||||
ngx_queue_t *q;
|
|
||||||
ngx_quic_server_id_t *sid;
|
|
||||||
ngx_quic_connection_t *qc;
|
|
||||||
|
|
||||||
qc = ngx_quic_get_connection(c);
|
|
||||||
|
|
||||||
for (q = ngx_queue_head(&qc->server_ids);
|
|
||||||
q != ngx_queue_sentinel(&qc->server_ids);
|
|
||||||
q = ngx_queue_next(q))
|
|
||||||
{
|
|
||||||
sid = ngx_queue_data(q, ngx_quic_server_id_t, queue);
|
|
||||||
|
|
||||||
if (sid->seqnum == f->sequence_number) {
|
|
||||||
ngx_queue_remove(q);
|
|
||||||
ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue);
|
|
||||||
ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node);
|
|
||||||
qc->nserver_ids--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ngx_quic_issue_server_ids(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
|
||||||
ngx_quic_issue_server_ids(ngx_connection_t *c)
|
|
||||||
{
|
|
||||||
ngx_str_t dcid;
|
|
||||||
ngx_uint_t n;
|
|
||||||
ngx_quic_frame_t *frame;
|
|
||||||
ngx_quic_server_id_t *sid;
|
|
||||||
ngx_quic_connection_t *qc;
|
|
||||||
u_char id[NGX_QUIC_SERVER_CID_LEN];
|
|
||||||
|
|
||||||
qc = ngx_quic_get_connection(c);
|
|
||||||
|
|
||||||
n = ngx_min(NGX_QUIC_MAX_SERVER_IDS, qc->ctp.active_connection_id_limit);
|
|
||||||
|
|
||||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
||||||
"quic issue server ids has:%ui max:%ui", qc->nserver_ids, n);
|
|
||||||
|
|
||||||
while (qc->nserver_ids < n) {
|
|
||||||
if (ngx_quic_create_server_id(c, id) != NGX_OK) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
dcid.len = NGX_QUIC_SERVER_CID_LEN;
|
|
||||||
dcid.data = id;
|
|
||||||
|
|
||||||
sid = ngx_quic_insert_server_id(c, qc, &dcid);
|
|
||||||
if (sid == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame = ngx_quic_alloc_frame(c);
|
|
||||||
if (frame == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame->level = ssl_encryption_application;
|
|
||||||
frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID;
|
|
||||||
frame->u.ncid.seqnum = sid->seqnum;
|
|
||||||
frame->u.ncid.retire = 0;
|
|
||||||
frame->u.ncid.len = NGX_QUIC_SERVER_CID_LEN;
|
|
||||||
ngx_memcpy(frame->u.ncid.cid, id, NGX_QUIC_SERVER_CID_LEN);
|
|
||||||
|
|
||||||
if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key,
|
|
||||||
frame->u.ncid.srt)
|
|
||||||
!= NGX_OK)
|
|
||||||
{
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_quic_queue_frame(qc, frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
ngx_quic_clear_temp_server_ids(ngx_connection_t *c)
|
|
||||||
{
|
|
||||||
ngx_queue_t *q, *next;
|
|
||||||
ngx_quic_server_id_t *sid;
|
|
||||||
ngx_quic_connection_t *qc;
|
|
||||||
|
|
||||||
qc = ngx_quic_get_connection(c);
|
|
||||||
|
|
||||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
||||||
"quic clear temp server ids");
|
|
||||||
|
|
||||||
for (q = ngx_queue_head(&qc->server_ids);
|
|
||||||
q != ngx_queue_sentinel(&qc->server_ids);
|
|
||||||
q = next)
|
|
||||||
{
|
|
||||||
next = ngx_queue_next(q);
|
|
||||||
sid = ngx_queue_data(q, ngx_quic_server_id_t, queue);
|
|
||||||
|
|
||||||
if (sid->seqnum != NGX_QUIC_UNSET_PN) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_queue_remove(q);
|
|
||||||
ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue);
|
|
||||||
ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node);
|
|
||||||
qc->nserver_ids--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_quic_server_id_t *
|
|
||||||
ngx_quic_insert_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
|
||||||
ngx_str_t *id)
|
|
||||||
{
|
|
||||||
ngx_str_t dcid;
|
|
||||||
ngx_quic_server_id_t *sid;
|
|
||||||
|
|
||||||
sid = ngx_quic_alloc_server_id(c, qc);
|
|
||||||
if (sid == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sid->quic = qc;
|
|
||||||
|
|
||||||
sid->seqnum = qc->server_seqnum;
|
|
||||||
|
|
||||||
if (qc->server_seqnum != NGX_QUIC_UNSET_PN) {
|
|
||||||
qc->server_seqnum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
sid->len = id->len;
|
|
||||||
ngx_memcpy(sid->id, id->data, id->len);
|
|
||||||
|
|
||||||
ngx_queue_insert_tail(&qc->server_ids, &sid->queue);
|
|
||||||
qc->nserver_ids++;
|
|
||||||
|
|
||||||
dcid.data = sid->id;
|
|
||||||
dcid.len = sid->len;
|
|
||||||
|
|
||||||
ngx_insert_udp_connection(c, &sid->udp, &dcid);
|
|
||||||
|
|
||||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
||||||
"quic insert server id seqnum:%uL id len:%uz %xV",
|
|
||||||
sid->seqnum, id->len, id);
|
|
||||||
|
|
||||||
return sid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_quic_client_id_t *
|
|
||||||
ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc)
|
|
||||||
{
|
|
||||||
ngx_queue_t *q;
|
|
||||||
ngx_quic_client_id_t *cid;
|
|
||||||
|
|
||||||
if (!ngx_queue_empty(&qc->free_client_ids)) {
|
|
||||||
|
|
||||||
q = ngx_queue_head(&qc->free_client_ids);
|
|
||||||
cid = ngx_queue_data(q, ngx_quic_client_id_t, queue);
|
|
||||||
|
|
||||||
ngx_queue_remove(&cid->queue);
|
|
||||||
|
|
||||||
ngx_memzero(cid, sizeof(ngx_quic_client_id_t));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
cid = ngx_pcalloc(c->pool, sizeof(ngx_quic_client_id_t));
|
|
||||||
if (cid == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static ngx_quic_server_id_t *
|
|
||||||
ngx_quic_alloc_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc)
|
|
||||||
{
|
|
||||||
ngx_queue_t *q;
|
|
||||||
ngx_quic_server_id_t *sid;
|
|
||||||
|
|
||||||
if (!ngx_queue_empty(&qc->free_server_ids)) {
|
|
||||||
|
|
||||||
q = ngx_queue_head(&qc->free_server_ids);
|
|
||||||
sid = ngx_queue_data(q, ngx_quic_server_id_t, queue);
|
|
||||||
|
|
||||||
ngx_queue_remove(&sid->queue);
|
|
||||||
|
|
||||||
ngx_memzero(sid, sizeof(ngx_quic_server_id_t));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
sid = ngx_pcalloc(c->pool, sizeof(ngx_quic_server_id_t));
|
|
||||||
if (sid == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame)
|
ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
typedef struct ngx_quic_connection_s ngx_quic_connection_t;
|
typedef struct ngx_quic_connection_s ngx_quic_connection_t;
|
||||||
|
|
||||||
#include <ngx_event_quic_migration.h>
|
#include <ngx_event_quic_migration.h>
|
||||||
|
#include <ngx_event_quic_connid.h>
|
||||||
|
|
||||||
|
|
||||||
#define NGX_QUIC_MAX_SHORT_HEADER 25 /* 1 flags + 20 dcid + 4 pn */
|
#define NGX_QUIC_MAX_SHORT_HEADER 25 /* 1 flags + 20 dcid + 4 pn */
|
||||||
@ -44,10 +45,10 @@ typedef struct ngx_quic_connection_s ngx_quic_connection_t;
|
|||||||
|
|
||||||
#define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */
|
#define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */
|
||||||
|
|
||||||
#define NGX_QUIC_MAX_SERVER_IDS 8
|
|
||||||
|
|
||||||
#define NGX_QUIC_BUFFER_SIZE 4096
|
#define NGX_QUIC_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
#define NGX_QUIC_UNSET_PN (uint64_t) -1
|
||||||
|
|
||||||
#define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1)
|
#define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1)
|
||||||
|
|
||||||
/* 0-RTT and 1-RTT data exist in the same packet number space,
|
/* 0-RTT and 1-RTT data exist in the same packet number space,
|
||||||
@ -223,6 +224,9 @@ void ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame);
|
|||||||
void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc);
|
void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc);
|
||||||
ngx_msec_t ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx);
|
ngx_msec_t ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx);
|
||||||
|
|
||||||
|
ngx_int_t ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid,
|
||||||
|
u_char *secret, u_char *token);
|
||||||
|
|
||||||
/********************************* DEBUG *************************************/
|
/********************************* DEBUG *************************************/
|
||||||
|
|
||||||
/* #define NGX_QUIC_DEBUG_PACKETS */ /* dump packet contents */
|
/* #define NGX_QUIC_DEBUG_PACKETS */ /* dump packet contents */
|
||||||
|
532
src/event/quic/ngx_event_quic_connid.c
Normal file
532
src/event/quic/ngx_event_quic_connid.c
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nginx, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_core.h>
|
||||||
|
#include <ngx_event.h>
|
||||||
|
#include <ngx_event_quic_connection.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define NGX_QUIC_MAX_SERVER_IDS 8
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id);
|
||||||
|
#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_retire_connection_id(ngx_connection_t *c,
|
||||||
|
enum ssl_encryption_level_t level, uint64_t seqnum);
|
||||||
|
static ngx_quic_server_id_t *ngx_quic_insert_server_id(ngx_connection_t *c,
|
||||||
|
ngx_quic_connection_t *qc, ngx_str_t *id);
|
||||||
|
static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c,
|
||||||
|
ngx_quic_connection_t *qc);
|
||||||
|
static ngx_quic_server_id_t *ngx_quic_alloc_server_id(ngx_connection_t *c,
|
||||||
|
ngx_quic_connection_t *qc);
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_quic_setup_connection_ids(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
||||||
|
ngx_quic_header_t *pkt)
|
||||||
|
{
|
||||||
|
ngx_quic_server_id_t *sid, *osid;
|
||||||
|
ngx_quic_client_id_t *cid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qc->nclient_ids = 0
|
||||||
|
* qc->nserver_ids = 0
|
||||||
|
* qc->max_retired_seqnum = 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
ngx_queue_init(&qc->client_ids);
|
||||||
|
ngx_queue_init(&qc->server_ids);
|
||||||
|
ngx_queue_init(&qc->free_client_ids);
|
||||||
|
ngx_queue_init(&qc->free_server_ids);
|
||||||
|
|
||||||
|
qc->odcid.len = pkt->odcid.len;
|
||||||
|
qc->odcid.data = ngx_pstrdup(c->pool, &pkt->odcid);
|
||||||
|
if (qc->odcid.data == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
qc->tp.original_dcid = qc->odcid;
|
||||||
|
|
||||||
|
qc->scid.len = pkt->scid.len;
|
||||||
|
qc->scid.data = ngx_pstrdup(c->pool, &pkt->scid);
|
||||||
|
if (qc->scid.data == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
qc->dcid.len = NGX_QUIC_SERVER_CID_LEN;
|
||||||
|
qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len);
|
||||||
|
if (qc->dcid.data == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_quic_create_server_id(c, qc->dcid.data) != NGX_OK) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
qc->tp.initial_scid = qc->dcid;
|
||||||
|
|
||||||
|
cid = ngx_quic_alloc_client_id(c, qc);
|
||||||
|
if (cid == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
cid->seqnum = 0;
|
||||||
|
cid->len = pkt->scid.len;
|
||||||
|
ngx_memcpy(cid->id, pkt->scid.data, pkt->scid.len);
|
||||||
|
|
||||||
|
ngx_queue_insert_tail(&qc->client_ids, &cid->queue);
|
||||||
|
qc->nclient_ids++;
|
||||||
|
qc->client_seqnum = 0;
|
||||||
|
|
||||||
|
qc->server_seqnum = NGX_QUIC_UNSET_PN;
|
||||||
|
|
||||||
|
osid = ngx_quic_insert_server_id(c, qc, &qc->odcid);
|
||||||
|
if (osid == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
qc->server_seqnum = 0;
|
||||||
|
|
||||||
|
sid = ngx_quic_insert_server_id(c, qc, &qc->dcid);
|
||||||
|
if (sid == NULL) {
|
||||||
|
ngx_rbtree_delete(&c->listening->rbtree, &osid->udp.node);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->udp = &sid->udp;
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_quic_create_server_id(ngx_connection_t *c, u_char *id)
|
||||||
|
{
|
||||||
|
if (RAND_bytes(id, NGX_QUIC_SERVER_CID_LEN) != 1) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (NGX_QUIC_BPF)
|
||||||
|
if (ngx_quic_bpf_attach_id(c, id) != NGX_OK) {
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||||
|
"quic bpf failed to generate socket key");
|
||||||
|
/* ignore error, things still may work */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||||
|
"quic create server id %*xs",
|
||||||
|
(size_t) NGX_QUIC_SERVER_CID_LEN, id);
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_QUIC_BPF)
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
uint64_t cookie;
|
||||||
|
socklen_t optlen;
|
||||||
|
|
||||||
|
fd = c->listening->fd;
|
||||||
|
|
||||||
|
optlen = sizeof(cookie);
|
||||||
|
|
||||||
|
if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &optlen) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno,
|
||||||
|
"quic getsockopt(SO_COOKIE) failed");
|
||||||
|
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_quic_dcid_encode_key(id, cookie);
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
|
||||||
|
ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f)
|
||||||
|
{
|
||||||
|
ngx_queue_t *q;
|
||||||
|
ngx_quic_client_id_t *cid, *item;
|
||||||
|
ngx_quic_connection_t *qc;
|
||||||
|
|
||||||
|
qc = ngx_quic_get_connection(c);
|
||||||
|
|
||||||
|
if (f->seqnum < qc->max_retired_seqnum) {
|
||||||
|
/*
|
||||||
|
* An endpoint that receives a NEW_CONNECTION_ID frame with
|
||||||
|
* a sequence number smaller than the Retire Prior To field
|
||||||
|
* of a previously received NEW_CONNECTION_ID frame MUST send
|
||||||
|
* a corresponding RETIRE_CONNECTION_ID frame that retires
|
||||||
|
* the newly received connection ID, unless it has already
|
||||||
|
* done so for that sequence number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ngx_quic_retire_connection_id(c, pkt->level, f->seqnum) != NGX_OK) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto retire;
|
||||||
|
}
|
||||||
|
|
||||||
|
cid = NULL;
|
||||||
|
|
||||||
|
for (q = ngx_queue_head(&qc->client_ids);
|
||||||
|
q != ngx_queue_sentinel(&qc->client_ids);
|
||||||
|
q = ngx_queue_next(q))
|
||||||
|
{
|
||||||
|
item = ngx_queue_data(q, ngx_quic_client_id_t, queue);
|
||||||
|
|
||||||
|
if (item->seqnum == f->seqnum) {
|
||||||
|
cid = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cid) {
|
||||||
|
/*
|
||||||
|
* Transmission errors, timeouts and retransmissions might cause the
|
||||||
|
* same NEW_CONNECTION_ID frame to be received multiple times
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cid->len != f->len
|
||||||
|
|| ngx_strncmp(cid->id, f->cid, f->len) != 0
|
||||||
|
|| ngx_strncmp(cid->sr_token, f->srt, NGX_QUIC_SR_TOKEN_LEN) != 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ..a sequence number is used for different connection IDs,
|
||||||
|
* the endpoint MAY treat that receipt as a connection error
|
||||||
|
* of type PROTOCOL_VIOLATION.
|
||||||
|
*/
|
||||||
|
qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION;
|
||||||
|
qc->error_reason = "seqnum refers to different connection id/token";
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
cid = ngx_quic_alloc_client_id(c, qc);
|
||||||
|
if (cid == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
cid->seqnum = f->seqnum;
|
||||||
|
cid->len = f->len;
|
||||||
|
ngx_memcpy(cid->id, f->cid, f->len);
|
||||||
|
|
||||||
|
ngx_memcpy(cid->sr_token, f->srt, NGX_QUIC_SR_TOKEN_LEN);
|
||||||
|
|
||||||
|
ngx_queue_insert_tail(&qc->client_ids, &cid->queue);
|
||||||
|
qc->nclient_ids++;
|
||||||
|
|
||||||
|
/* always use latest available connection id */
|
||||||
|
if (f->seqnum > qc->client_seqnum) {
|
||||||
|
qc->scid.len = cid->len;
|
||||||
|
qc->scid.data = cid->id;
|
||||||
|
qc->client_seqnum = f->seqnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retire:
|
||||||
|
|
||||||
|
if (qc->max_retired_seqnum && f->retire <= qc->max_retired_seqnum) {
|
||||||
|
/*
|
||||||
|
* Once a sender indicates a Retire Prior To value, smaller values sent
|
||||||
|
* in subsequent NEW_CONNECTION_ID frames have no effect. A receiver
|
||||||
|
* MUST ignore any Retire Prior To fields that do not increase the
|
||||||
|
* largest received Retire Prior To value.
|
||||||
|
*/
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
qc->max_retired_seqnum = f->retire;
|
||||||
|
|
||||||
|
q = ngx_queue_head(&qc->client_ids);
|
||||||
|
|
||||||
|
while (q != ngx_queue_sentinel(&qc->client_ids)) {
|
||||||
|
|
||||||
|
cid = ngx_queue_data(q, ngx_quic_client_id_t, queue);
|
||||||
|
q = ngx_queue_next(q);
|
||||||
|
|
||||||
|
if (cid->seqnum >= f->retire) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this connection id must be retired */
|
||||||
|
|
||||||
|
if (ngx_quic_retire_connection_id(c, pkt->level, cid->seqnum)
|
||||||
|
!= NGX_OK)
|
||||||
|
{
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_queue_remove(&cid->queue);
|
||||||
|
ngx_queue_insert_head(&qc->free_client_ids, &cid->queue);
|
||||||
|
qc->nclient_ids--;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
if (qc->nclient_ids > qc->tp.active_connection_id_limit) {
|
||||||
|
/*
|
||||||
|
* After processing a NEW_CONNECTION_ID frame and
|
||||||
|
* adding and retiring active connection IDs, if the number of active
|
||||||
|
* connection IDs exceeds the value advertised in its
|
||||||
|
* active_connection_id_limit transport parameter, an endpoint MUST
|
||||||
|
* close the connection with an error of type CONNECTION_ID_LIMIT_ERROR.
|
||||||
|
*/
|
||||||
|
qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR;
|
||||||
|
qc->error_reason = "too many connection ids received";
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_quic_retire_connection_id(ngx_connection_t *c,
|
||||||
|
enum ssl_encryption_level_t level, uint64_t seqnum)
|
||||||
|
{
|
||||||
|
ngx_quic_frame_t *frame;
|
||||||
|
ngx_quic_connection_t *qc;
|
||||||
|
|
||||||
|
qc = ngx_quic_get_connection(c);
|
||||||
|
|
||||||
|
frame = ngx_quic_alloc_frame(c);
|
||||||
|
if (frame == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->level = level;
|
||||||
|
frame->type = NGX_QUIC_FT_RETIRE_CONNECTION_ID;
|
||||||
|
frame->u.retire_cid.sequence_number = seqnum;
|
||||||
|
|
||||||
|
ngx_quic_queue_frame(qc, frame);
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
|
||||||
|
ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f)
|
||||||
|
{
|
||||||
|
ngx_queue_t *q;
|
||||||
|
ngx_quic_server_id_t *sid;
|
||||||
|
ngx_quic_connection_t *qc;
|
||||||
|
|
||||||
|
qc = ngx_quic_get_connection(c);
|
||||||
|
|
||||||
|
for (q = ngx_queue_head(&qc->server_ids);
|
||||||
|
q != ngx_queue_sentinel(&qc->server_ids);
|
||||||
|
q = ngx_queue_next(q))
|
||||||
|
{
|
||||||
|
sid = ngx_queue_data(q, ngx_quic_server_id_t, queue);
|
||||||
|
|
||||||
|
if (sid->seqnum == f->sequence_number) {
|
||||||
|
ngx_queue_remove(q);
|
||||||
|
ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue);
|
||||||
|
ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node);
|
||||||
|
qc->nserver_ids--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ngx_quic_issue_server_ids(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_quic_issue_server_ids(ngx_connection_t *c)
|
||||||
|
{
|
||||||
|
ngx_str_t dcid;
|
||||||
|
ngx_uint_t n;
|
||||||
|
ngx_quic_frame_t *frame;
|
||||||
|
ngx_quic_server_id_t *sid;
|
||||||
|
ngx_quic_connection_t *qc;
|
||||||
|
u_char id[NGX_QUIC_SERVER_CID_LEN];
|
||||||
|
|
||||||
|
qc = ngx_quic_get_connection(c);
|
||||||
|
|
||||||
|
n = ngx_min(NGX_QUIC_MAX_SERVER_IDS, qc->ctp.active_connection_id_limit);
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||||
|
"quic issue server ids has:%ui max:%ui", qc->nserver_ids, n);
|
||||||
|
|
||||||
|
while (qc->nserver_ids < n) {
|
||||||
|
if (ngx_quic_create_server_id(c, id) != NGX_OK) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcid.len = NGX_QUIC_SERVER_CID_LEN;
|
||||||
|
dcid.data = id;
|
||||||
|
|
||||||
|
sid = ngx_quic_insert_server_id(c, qc, &dcid);
|
||||||
|
if (sid == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = ngx_quic_alloc_frame(c);
|
||||||
|
if (frame == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->level = ssl_encryption_application;
|
||||||
|
frame->type = NGX_QUIC_FT_NEW_CONNECTION_ID;
|
||||||
|
frame->u.ncid.seqnum = sid->seqnum;
|
||||||
|
frame->u.ncid.retire = 0;
|
||||||
|
frame->u.ncid.len = NGX_QUIC_SERVER_CID_LEN;
|
||||||
|
ngx_memcpy(frame->u.ncid.cid, id, NGX_QUIC_SERVER_CID_LEN);
|
||||||
|
|
||||||
|
if (ngx_quic_new_sr_token(c, &dcid, qc->conf->sr_token_key,
|
||||||
|
frame->u.ncid.srt)
|
||||||
|
!= NGX_OK)
|
||||||
|
{
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_quic_queue_frame(qc, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ngx_quic_clear_temp_server_ids(ngx_connection_t *c)
|
||||||
|
{
|
||||||
|
ngx_queue_t *q, *next;
|
||||||
|
ngx_quic_server_id_t *sid;
|
||||||
|
ngx_quic_connection_t *qc;
|
||||||
|
|
||||||
|
qc = ngx_quic_get_connection(c);
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||||
|
"quic clear temp server ids");
|
||||||
|
|
||||||
|
for (q = ngx_queue_head(&qc->server_ids);
|
||||||
|
q != ngx_queue_sentinel(&qc->server_ids);
|
||||||
|
q = next)
|
||||||
|
{
|
||||||
|
next = ngx_queue_next(q);
|
||||||
|
sid = ngx_queue_data(q, ngx_quic_server_id_t, queue);
|
||||||
|
|
||||||
|
if (sid->seqnum != NGX_QUIC_UNSET_PN) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_queue_remove(q);
|
||||||
|
ngx_queue_insert_tail(&qc->free_server_ids, &sid->queue);
|
||||||
|
ngx_rbtree_delete(&c->listening->rbtree, &sid->udp.node);
|
||||||
|
qc->nserver_ids--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_quic_server_id_t *
|
||||||
|
ngx_quic_insert_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
||||||
|
ngx_str_t *id)
|
||||||
|
{
|
||||||
|
ngx_str_t dcid;
|
||||||
|
ngx_quic_server_id_t *sid;
|
||||||
|
|
||||||
|
sid = ngx_quic_alloc_server_id(c, qc);
|
||||||
|
if (sid == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sid->quic = qc;
|
||||||
|
|
||||||
|
sid->seqnum = qc->server_seqnum;
|
||||||
|
|
||||||
|
if (qc->server_seqnum != NGX_QUIC_UNSET_PN) {
|
||||||
|
qc->server_seqnum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sid->len = id->len;
|
||||||
|
ngx_memcpy(sid->id, id->data, id->len);
|
||||||
|
|
||||||
|
ngx_queue_insert_tail(&qc->server_ids, &sid->queue);
|
||||||
|
qc->nserver_ids++;
|
||||||
|
|
||||||
|
dcid.data = sid->id;
|
||||||
|
dcid.len = sid->len;
|
||||||
|
|
||||||
|
ngx_insert_udp_connection(c, &sid->udp, &dcid);
|
||||||
|
|
||||||
|
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||||
|
"quic insert server id seqnum:%uL id len:%uz %xV",
|
||||||
|
sid->seqnum, id->len, id);
|
||||||
|
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_quic_client_id_t *
|
||||||
|
ngx_quic_alloc_client_id(ngx_connection_t *c, ngx_quic_connection_t *qc)
|
||||||
|
{
|
||||||
|
ngx_queue_t *q;
|
||||||
|
ngx_quic_client_id_t *cid;
|
||||||
|
|
||||||
|
if (!ngx_queue_empty(&qc->free_client_ids)) {
|
||||||
|
|
||||||
|
q = ngx_queue_head(&qc->free_client_ids);
|
||||||
|
cid = ngx_queue_data(q, ngx_quic_client_id_t, queue);
|
||||||
|
|
||||||
|
ngx_queue_remove(&cid->queue);
|
||||||
|
|
||||||
|
ngx_memzero(cid, sizeof(ngx_quic_client_id_t));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
cid = ngx_pcalloc(c->pool, sizeof(ngx_quic_client_id_t));
|
||||||
|
if (cid == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_quic_server_id_t *
|
||||||
|
ngx_quic_alloc_server_id(ngx_connection_t *c, ngx_quic_connection_t *qc)
|
||||||
|
{
|
||||||
|
ngx_queue_t *q;
|
||||||
|
ngx_quic_server_id_t *sid;
|
||||||
|
|
||||||
|
if (!ngx_queue_empty(&qc->free_server_ids)) {
|
||||||
|
|
||||||
|
q = ngx_queue_head(&qc->free_server_ids);
|
||||||
|
sid = ngx_queue_data(q, ngx_quic_server_id_t, queue);
|
||||||
|
|
||||||
|
ngx_queue_remove(&sid->queue);
|
||||||
|
|
||||||
|
ngx_memzero(sid, sizeof(ngx_quic_server_id_t));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
sid = ngx_pcalloc(c->pool, sizeof(ngx_quic_server_id_t));
|
||||||
|
if (sid == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sid;
|
||||||
|
}
|
25
src/event/quic/ngx_event_quic_connid.h
Normal file
25
src/event/quic/ngx_event_quic_connid.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Nginx, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _NGX_EVENT_QUIC_CONNID_H_INCLUDED_
|
||||||
|
#define _NGX_EVENT_QUIC_CONNID_H_INCLUDED_
|
||||||
|
|
||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_core.h>
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t ngx_quic_setup_connection_ids(ngx_connection_t *c,
|
||||||
|
ngx_quic_connection_t *qc, ngx_quic_header_t *pkt);
|
||||||
|
void ngx_quic_clear_temp_server_ids(ngx_connection_t *c);
|
||||||
|
ngx_int_t ngx_quic_issue_server_ids(ngx_connection_t *c);
|
||||||
|
|
||||||
|
ngx_int_t ngx_quic_handle_retire_connection_id_frame(ngx_connection_t *c,
|
||||||
|
ngx_quic_header_t *pkt, ngx_quic_retire_cid_frame_t *f);
|
||||||
|
ngx_int_t ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c,
|
||||||
|
ngx_quic_header_t *pkt, ngx_quic_new_conn_id_frame_t *f);
|
||||||
|
|
||||||
|
#endif /* _NGX_EVENT_QUIC_CONNID_H_INCLUDED_ */
|
Loading…
Reference in New Issue
Block a user