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 /*