Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_migration.c @ 8939:ddd5e5c0f87d quic
QUIC: improved path validation.
Previously, path was considered valid during arbitrary selected 10m timeout
since validation. This is quite not what RFC 9000 says; the relevant
part is:
An endpoint MAY skip validation of a peer address if that
address has been seen recently.
The patch considers a path to be 'recently seen' if packets were received
during idle timeout. If a packet is received from the path that was seen
not so recently, such path is considered new, and anti-amplification
restrictions apply.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Mon, 13 Dec 2021 17:27:29 +0300 |
parents | 02a9ad88e2df |
children | fb41e37ddeb0 |
comparison
equal
deleted
inserted
replaced
8938:23880e4ad3e2 | 8939:ddd5e5c0f87d |
---|---|
156 | 156 |
157 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 157 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
158 "quic path #%uL successfully validated", path->seqnum); | 158 "quic path #%uL successfully validated", path->seqnum); |
159 | 159 |
160 path->state = NGX_QUIC_PATH_VALIDATED; | 160 path->state = NGX_QUIC_PATH_VALIDATED; |
161 path->validated_at = ngx_time(); | |
162 | 161 |
163 return NGX_OK; | 162 return NGX_OK; |
164 } | 163 } |
165 | 164 |
166 | 165 |
215 if (path == NULL) { | 214 if (path == NULL) { |
216 return NULL; | 215 return NULL; |
217 } | 216 } |
218 | 217 |
219 path->seqnum = qc->path_seqnum++; | 218 path->seqnum = qc->path_seqnum++; |
219 path->last_seen = ngx_current_msec; | |
220 | 220 |
221 path->socklen = socklen; | 221 path->socklen = socklen; |
222 ngx_memcpy(path->sockaddr, sockaddr, socklen); | 222 ngx_memcpy(path->sockaddr, sockaddr, socklen); |
223 | 223 |
224 path->addr_text.data = path->text; | 224 path->addr_text.data = path->text; |
270 ngx_quic_path_t *path; | 270 ngx_quic_path_t *path; |
271 ngx_quic_socket_t *qsock; | 271 ngx_quic_socket_t *qsock; |
272 ngx_quic_client_id_t *cid; | 272 ngx_quic_client_id_t *cid; |
273 ngx_quic_connection_t *qc; | 273 ngx_quic_connection_t *qc; |
274 | 274 |
275 qc = ngx_quic_get_connection(c); | |
275 qsock = ngx_quic_get_socket(c); | 276 qsock = ngx_quic_get_socket(c); |
276 | 277 |
277 if (c->udp->dgram == NULL) { | 278 if (c->udp->dgram == NULL) { |
278 /* 1st ever packet in connection, path already exists */ | 279 /* 1st ever packet in connection, path already exists */ |
279 path = qsock->path; | 280 path = qsock->path; |
311 | 312 |
312 /* try to reuse connection ID used on the same path */ | 313 /* try to reuse connection ID used on the same path */ |
313 cid = ngx_quic_used_client_id(c, path); | 314 cid = ngx_quic_used_client_id(c, path); |
314 if (cid == NULL) { | 315 if (cid == NULL) { |
315 | 316 |
316 qc = ngx_quic_get_connection(c); | |
317 qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR; | 317 qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR; |
318 qc->error_reason = "no available client ids for new path"; | 318 qc->error_reason = "no available client ids for new path"; |
319 | 319 |
320 ngx_log_error(NGX_LOG_ERR, c->log, 0, | 320 ngx_log_error(NGX_LOG_ERR, c->log, 0, |
321 "no available client ids for new path"); | 321 "no available client ids for new path"); |
325 } | 325 } |
326 | 326 |
327 ngx_quic_connect(c, qsock, path, cid); | 327 ngx_quic_connect(c, qsock, path, cid); |
328 | 328 |
329 update: | 329 update: |
330 | |
331 if (path->state != NGX_QUIC_PATH_NEW) { | |
332 /* force limits/revalidation for paths that were not seen recently */ | |
333 if (ngx_current_msec - path->last_seen > qc->tp.max_idle_timeout) { | |
334 path->state = NGX_QUIC_PATH_NEW; | |
335 path->sent = 0; | |
336 path->received = 0; | |
337 } | |
338 } | |
339 | |
340 path->last_seen = ngx_current_msec; | |
330 | 341 |
331 len = pkt->raw->last - pkt->raw->start; | 342 len = pkt->raw->last - pkt->raw->start; |
332 | 343 |
333 /* TODO: this may be too late in some cases; | 344 /* TODO: this may be too late in some cases; |
334 * for example, if error happens during decrypt(), we cannot | 345 * for example, if error happens during decrypt(), we cannot |
394 qc->socket->path->seqnum, | 405 qc->socket->path->seqnum, |
395 ngx_quic_path_state_str(qc->socket->path), | 406 ngx_quic_path_state_str(qc->socket->path), |
396 qsock->sid.seqnum, qsock->cid->seqnum, next->seqnum, | 407 qsock->sid.seqnum, qsock->cid->seqnum, next->seqnum, |
397 ngx_quic_path_state_str(next)); | 408 ngx_quic_path_state_str(next)); |
398 | 409 |
399 switch (next->state) { | 410 if (next->state == NGX_QUIC_PATH_NEW) { |
400 case NGX_QUIC_PATH_NEW: | |
401 if (ngx_quic_validate_path(c, qsock) != NGX_OK) { | 411 if (ngx_quic_validate_path(c, qsock) != NGX_OK) { |
402 return NGX_ERROR; | 412 return NGX_ERROR; |
403 } | 413 } |
404 break; | |
405 | |
406 /* migration to previously known path */ | |
407 | |
408 case NGX_QUIC_PATH_VALIDATING: | |
409 /* alredy validating, nothing to do */ | |
410 break; | |
411 | |
412 case NGX_QUIC_PATH_VALIDATED: | |
413 /* if path is old enough, revalidate */ | |
414 if (ngx_time() - next->validated_at > NGX_QUIC_PATH_VALID_TIME) { | |
415 | |
416 next->state = NGX_QUIC_PATH_NEW; | |
417 | |
418 if (ngx_quic_validate_path(c, qsock) != NGX_OK) { | |
419 return NGX_ERROR; | |
420 } | |
421 } | |
422 | |
423 break; | |
424 } | 414 } |
425 | 415 |
426 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | 416 ctx = ngx_quic_get_send_ctx(qc, pkt->level); |
427 | 417 |
428 /* | 418 /* |