Mercurial > hg > nginx-quic
annotate src/event/quic/ngx_event_quic_socket.c @ 8797:1e2f4e9c8195 quic
QUIC: reworked migration handling.
The quic connection now holds active, backup and probe paths instead
of sockets. The number of migration paths is now limited and cannot
be inflated by a bad client or an attacker.
The client id is now associated with path rather than socket. This allows
to simplify processing of output and connection ids handling.
New migration abandons any previously started migrations. This allows to
free consumed client ids and request new for use in future migrations and
make progress in case when connection id limit is hit during migration.
A path now can be revalidated without losing its state.
The patch also fixes various issues with NAT rebinding case handling:
- paths are now validated (previously, there was no validation
and paths were left in limited state)
- attempt to reuse id on different path is now again verified
(this was broken in 40445fc7c403)
- former path is now validated in case of apparent migration
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 19 Jan 2022 22:39:24 +0300 |
parents | 32daba3aabb2 |
children | fab36e4abf83 |
rev | line source |
---|---|
8423 | 1 |
2 /* | |
3 * Copyright (C) Nginx, Inc. | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_event_quic_connection.h> | |
11 | |
12 | |
13 ngx_int_t | |
14 ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc, | |
15 ngx_quic_header_t *pkt) | |
16 { | |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
17 ngx_quic_socket_t *qsock, *tmp; |
8423 | 18 ngx_quic_client_id_t *cid; |
19 | |
20 /* | |
8797
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
21 * qc->path = NULL |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
22 * |
8423 | 23 * qc->nclient_ids = 0 |
24 * qc->nsockets = 0 | |
25 * qc->max_retired_seqnum = 0 | |
26 * qc->client_seqnum = 0 | |
27 */ | |
28 | |
29 ngx_queue_init(&qc->sockets); | |
30 ngx_queue_init(&qc->free_sockets); | |
31 | |
32 ngx_queue_init(&qc->paths); | |
33 ngx_queue_init(&qc->free_paths); | |
34 | |
35 ngx_queue_init(&qc->client_ids); | |
36 ngx_queue_init(&qc->free_client_ids); | |
37 | |
38 qc->tp.original_dcid.len = pkt->odcid.len; | |
39 qc->tp.original_dcid.data = ngx_pstrdup(c->pool, &pkt->odcid); | |
40 if (qc->tp.original_dcid.data == NULL) { | |
41 return NGX_ERROR; | |
42 } | |
43 | |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
44 /* socket to use for further processing (id auto-generated) */ |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
45 qsock = ngx_quic_create_socket(c, qc); |
8423 | 46 if (qsock == NULL) { |
47 return NGX_ERROR; | |
48 } | |
49 | |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
50 /* socket is listening at new server id */ |
8423 | 51 if (ngx_quic_listen(c, qc, qsock) != NGX_OK) { |
52 return NGX_ERROR; | |
53 } | |
54 | |
8797
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
55 qsock->used = 1; |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
56 |
8423 | 57 qc->tp.initial_scid.len = qsock->sid.len; |
58 qc->tp.initial_scid.data = ngx_pnalloc(c->pool, qsock->sid.len); | |
59 if (qc->tp.initial_scid.data == NULL) { | |
60 goto failed; | |
61 } | |
62 ngx_memcpy(qc->tp.initial_scid.data, qsock->sid.id, qsock->sid.len); | |
63 | |
64 /* for all packets except first, this is set at udp layer */ | |
65 c->udp = &qsock->udp; | |
66 | |
67 /* ngx_quic_get_connection(c) macro is now usable */ | |
68 | |
69 /* we have a client identified by scid */ | |
70 cid = ngx_quic_create_client_id(c, &pkt->scid, 0, NULL); | |
71 if (cid == NULL) { | |
72 goto failed; | |
73 } | |
74 | |
8797
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
75 /* path of the first packet is our initial active path */ |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
76 qc->path = ngx_quic_new_path(c, c->sockaddr, c->socklen, cid); |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
77 if (qc->path == NULL) { |
8423 | 78 goto failed; |
79 } | |
80 | |
8797
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
81 qc->path->tag = NGX_QUIC_PATH_ACTIVE; |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
82 |
8423 | 83 if (pkt->validated) { |
8797
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
84 qc->path->validated = 1; |
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
85 qc->path->limited = 0; |
8423 | 86 } |
87 | |
8797
1e2f4e9c8195
QUIC: reworked migration handling.
Vladimir Homutov <vl@nginx.com>
parents:
8768
diff
changeset
|
88 ngx_quic_path_dbg(c, "set active", qc->path); |
8423 | 89 |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
90 tmp = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t)); |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
91 if (tmp == NULL) { |
8423 | 92 goto failed; |
93 } | |
94 | |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
95 tmp->sid.seqnum = NGX_QUIC_UNSET_PN; /* temporary socket */ |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
96 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
97 ngx_memcpy(tmp->sid.id, pkt->odcid.data, pkt->odcid.len); |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
98 tmp->sid.len = pkt->odcid.len; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
99 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
100 if (ngx_quic_listen(c, qc, tmp) != NGX_OK) { |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
101 goto failed; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
102 } |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
103 |
8423 | 104 return NGX_OK; |
105 | |
106 failed: | |
107 | |
108 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); | |
109 c->udp = NULL; | |
110 | |
111 return NGX_ERROR; | |
112 } | |
113 | |
114 | |
115 ngx_quic_socket_t * | |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
116 ngx_quic_create_socket(ngx_connection_t *c, ngx_quic_connection_t *qc) |
8423 | 117 { |
118 ngx_queue_t *q; | |
119 ngx_quic_socket_t *sock; | |
120 | |
121 if (!ngx_queue_empty(&qc->free_sockets)) { | |
122 | |
123 q = ngx_queue_head(&qc->free_sockets); | |
124 sock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
125 | |
126 ngx_queue_remove(&sock->queue); | |
127 | |
128 ngx_memzero(sock, sizeof(ngx_quic_socket_t)); | |
129 | |
130 } else { | |
131 | |
132 sock = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t)); | |
133 if (sock == NULL) { | |
134 return NULL; | |
135 } | |
136 } | |
137 | |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
138 sock->sid.len = NGX_QUIC_SERVER_CID_LEN; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
139 if (ngx_quic_create_server_id(c, sock->sid.id) != NGX_OK) { |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
140 return NULL; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
141 } |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
142 |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
143 sock->sid.seqnum = qc->server_seqnum++; |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
144 |
8423 | 145 return sock; |
146 } | |
147 | |
148 | |
149 void | |
150 ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock) | |
151 { | |
152 ngx_quic_connection_t *qc; | |
153 | |
154 qc = ngx_quic_get_connection(c); | |
155 | |
156 ngx_queue_remove(&qsock->queue); | |
157 ngx_queue_insert_head(&qc->free_sockets, &qsock->queue); | |
158 | |
159 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); | |
160 qc->nsockets--; | |
161 | |
162 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
163 "quic socket #%L closed nsock:%ui", | |
164 (int64_t) qsock->sid.seqnum, qc->nsockets); | |
165 } | |
166 | |
167 | |
168 ngx_int_t | |
169 ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc, | |
170 ngx_quic_socket_t *qsock) | |
171 { | |
172 ngx_str_t id; | |
173 ngx_quic_server_id_t *sid; | |
174 | |
175 sid = &qsock->sid; | |
176 | |
177 id.data = sid->id; | |
178 id.len = sid->len; | |
179 | |
180 ngx_insert_udp_connection(c, &qsock->udp, &id); | |
181 | |
182 ngx_queue_insert_tail(&qc->sockets, &qsock->queue); | |
183 | |
184 qc->nsockets++; | |
185 qsock->quic = qc; | |
186 | |
187 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
8768
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
188 "quic socket #%L listening at sid:%xV nsock:%ui", |
32daba3aabb2
QUIC: got rid of ngx_quic_create_temp_socket().
Vladimir Homutov <vl@nginx.com>
parents:
8729
diff
changeset
|
189 (int64_t) sid->seqnum, &id, qc->nsockets); |
8423 | 190 |
191 return NGX_OK; | |
192 } | |
193 | |
194 | |
195 void | |
196 ngx_quic_close_sockets(ngx_connection_t *c) | |
197 { | |
198 ngx_queue_t *q; | |
199 ngx_quic_socket_t *qsock; | |
200 ngx_quic_connection_t *qc; | |
201 | |
202 qc = ngx_quic_get_connection(c); | |
203 | |
204 while (!ngx_queue_empty(&qc->sockets)) { | |
205 q = ngx_queue_head(&qc->sockets); | |
206 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
207 | |
208 ngx_quic_close_socket(c, qsock); | |
209 } | |
210 } | |
211 | |
212 | |
213 ngx_quic_socket_t * | |
214 ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum) | |
215 { | |
216 ngx_queue_t *q; | |
217 ngx_quic_socket_t *qsock; | |
218 ngx_quic_connection_t *qc; | |
219 | |
220 qc = ngx_quic_get_connection(c); | |
221 | |
222 for (q = ngx_queue_head(&qc->sockets); | |
223 q != ngx_queue_sentinel(&qc->sockets); | |
224 q = ngx_queue_next(q)) | |
225 { | |
226 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue); | |
227 | |
228 if (qsock->sid.seqnum == seqnum) { | |
229 return qsock; | |
230 } | |
231 } | |
232 | |
233 return NULL; | |
234 } |