Mercurial > hg > nginx-quic
comparison src/http/v3/ngx_http_v3_streams.c @ 8643:72b304f6207c quic
HTTP/3: traffic-based flood detection.
With this patch, all traffic over HTTP/3 bidi and uni streams is counted in
the h3c->total_bytes field, and payload traffic is counted in the
h3c->payload_bytes field. As long as total traffic is many times larger than
payload traffic, we consider this to be a flood.
Request header traffic is counted as if all fields are literal. Response
header traffic is counted as is.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Thu, 07 Oct 2021 13:22:42 +0300 |
parents | 531075860fe2 |
children | 925572184d4a |
comparison
equal
deleted
inserted
replaced
8642:a09bcc304eef | 8643:72b304f6207c |
---|---|
169 u_char buf[128]; | 169 u_char buf[128]; |
170 ssize_t n; | 170 ssize_t n; |
171 ngx_buf_t b; | 171 ngx_buf_t b; |
172 ngx_int_t rc; | 172 ngx_int_t rc; |
173 ngx_connection_t *c; | 173 ngx_connection_t *c; |
174 ngx_http_v3_session_t *h3c; | |
174 ngx_http_v3_uni_stream_t *us; | 175 ngx_http_v3_uni_stream_t *us; |
175 | 176 |
176 c = rev->data; | 177 c = rev->data; |
177 us = c->data; | 178 us = c->data; |
178 | 179 |
205 } | 206 } |
206 | 207 |
207 b.pos = buf; | 208 b.pos = buf; |
208 b.last = buf + n; | 209 b.last = buf + n; |
209 | 210 |
211 h3c = ngx_http_v3_get_session(c); | |
212 h3c->total_bytes += n; | |
213 | |
214 if (ngx_http_v3_check_flood(c) != NGX_OK) { | |
215 ngx_http_v3_close_uni_stream(c); | |
216 return; | |
217 } | |
218 | |
210 rc = ngx_http_v3_parse_uni(c, &us->parse, &b); | 219 rc = ngx_http_v3_parse_uni(c, &us->parse, &b); |
211 | 220 |
212 if (rc == NGX_DONE) { | 221 if (rc == NGX_DONE) { |
213 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | 222 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
214 "http3 read done"); | 223 "http3 read done"); |
280 p = buf; | 289 p = buf; |
281 p = (u_char *) ngx_http_v3_encode_varlen_int(p, NGX_HTTP_V3_STREAM_PUSH); | 290 p = (u_char *) ngx_http_v3_encode_varlen_int(p, NGX_HTTP_V3_STREAM_PUSH); |
282 p = (u_char *) ngx_http_v3_encode_varlen_int(p, push_id); | 291 p = (u_char *) ngx_http_v3_encode_varlen_int(p, push_id); |
283 n = p - buf; | 292 n = p - buf; |
284 | 293 |
294 h3c = ngx_http_v3_get_session(c); | |
295 h3c->total_bytes += n; | |
296 | |
285 if (sc->send(sc, buf, n) != (ssize_t) n) { | 297 if (sc->send(sc, buf, n) != (ssize_t) n) { |
286 goto failed; | 298 goto failed; |
287 } | 299 } |
288 | 300 |
289 cln = ngx_pool_cleanup_add(sc->pool, sizeof(ngx_http_v3_push_t)); | 301 cln = ngx_pool_cleanup_add(sc->pool, sizeof(ngx_http_v3_push_t)); |
290 if (cln == NULL) { | 302 if (cln == NULL) { |
291 goto failed; | 303 goto failed; |
292 } | 304 } |
293 | 305 |
294 h3c = ngx_http_v3_get_session(c); | |
295 h3c->npushing++; | 306 h3c->npushing++; |
296 | 307 |
297 cln->handler = ngx_http_v3_push_cleanup; | 308 cln->handler = ngx_http_v3_push_cleanup; |
298 | 309 |
299 push = cln->data; | 310 push = cln->data; |
381 h3c->known_streams[index] = sc; | 392 h3c->known_streams[index] = sc; |
382 } | 393 } |
383 | 394 |
384 n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf; | 395 n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf; |
385 | 396 |
397 h3c = ngx_http_v3_get_session(c); | |
398 h3c->total_bytes += n; | |
399 | |
386 if (sc->send(sc, buf, n) != (ssize_t) n) { | 400 if (sc->send(sc, buf, n) != (ssize_t) n) { |
387 goto failed; | 401 goto failed; |
388 } | 402 } |
389 | 403 |
390 return sc; | 404 return sc; |
401 ngx_http_v3_send_settings(ngx_connection_t *c) | 415 ngx_http_v3_send_settings(ngx_connection_t *c) |
402 { | 416 { |
403 u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6]; | 417 u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6]; |
404 size_t n; | 418 size_t n; |
405 ngx_connection_t *cc; | 419 ngx_connection_t *cc; |
420 ngx_http_v3_session_t *h3c; | |
406 ngx_http_v3_srv_conf_t *h3scf; | 421 ngx_http_v3_srv_conf_t *h3scf; |
407 | 422 |
408 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings"); | 423 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings"); |
409 | 424 |
410 cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL); | 425 cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL); |
429 p = (u_char *) ngx_http_v3_encode_varlen_int(p, | 444 p = (u_char *) ngx_http_v3_encode_varlen_int(p, |
430 NGX_HTTP_V3_PARAM_BLOCKED_STREAMS); | 445 NGX_HTTP_V3_PARAM_BLOCKED_STREAMS); |
431 p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_blocked_streams); | 446 p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_blocked_streams); |
432 n = p - buf; | 447 n = p - buf; |
433 | 448 |
449 h3c = ngx_http_v3_get_session(c); | |
450 h3c->total_bytes += n; | |
451 | |
434 if (cc->send(cc, buf, n) != (ssize_t) n) { | 452 if (cc->send(cc, buf, n) != (ssize_t) n) { |
435 goto failed; | 453 goto failed; |
436 } | 454 } |
437 | 455 |
438 return NGX_OK; | 456 return NGX_OK; |
446 | 464 |
447 | 465 |
448 ngx_int_t | 466 ngx_int_t |
449 ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id) | 467 ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id) |
450 { | 468 { |
451 u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 3]; | 469 u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 3]; |
452 size_t n; | 470 size_t n; |
453 ngx_connection_t *cc; | 471 ngx_connection_t *cc; |
472 ngx_http_v3_session_t *h3c; | |
454 | 473 |
455 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send goaway %uL", id); | 474 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send goaway %uL", id); |
456 | 475 |
457 cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL); | 476 cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL); |
458 if (cc == NULL) { | 477 if (cc == NULL) { |
463 p = (u_char *) ngx_http_v3_encode_varlen_int(buf, NGX_HTTP_V3_FRAME_GOAWAY); | 482 p = (u_char *) ngx_http_v3_encode_varlen_int(buf, NGX_HTTP_V3_FRAME_GOAWAY); |
464 p = (u_char *) ngx_http_v3_encode_varlen_int(p, n); | 483 p = (u_char *) ngx_http_v3_encode_varlen_int(p, n); |
465 p = (u_char *) ngx_http_v3_encode_varlen_int(p, id); | 484 p = (u_char *) ngx_http_v3_encode_varlen_int(p, id); |
466 n = p - buf; | 485 n = p - buf; |
467 | 486 |
487 h3c = ngx_http_v3_get_session(c); | |
488 h3c->total_bytes += n; | |
489 | |
468 if (cc->send(cc, buf, n) != (ssize_t) n) { | 490 if (cc->send(cc, buf, n) != (ssize_t) n) { |
469 goto failed; | 491 goto failed; |
470 } | 492 } |
471 | 493 |
472 return NGX_OK; | 494 return NGX_OK; |
480 | 502 |
481 | 503 |
482 ngx_int_t | 504 ngx_int_t |
483 ngx_http_v3_send_ack_section(ngx_connection_t *c, ngx_uint_t stream_id) | 505 ngx_http_v3_send_ack_section(ngx_connection_t *c, ngx_uint_t stream_id) |
484 { | 506 { |
485 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | 507 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; |
486 size_t n; | 508 size_t n; |
487 ngx_connection_t *dc; | 509 ngx_connection_t *dc; |
510 ngx_http_v3_session_t *h3c; | |
488 | 511 |
489 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 512 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
490 "http3 client ack section %ui", stream_id); | 513 "http3 client ack section %ui", stream_id); |
491 | 514 |
492 dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); | 515 dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); |
495 } | 518 } |
496 | 519 |
497 buf[0] = 0x80; | 520 buf[0] = 0x80; |
498 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf; | 521 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf; |
499 | 522 |
523 h3c = ngx_http_v3_get_session(c); | |
524 h3c->total_bytes += n; | |
525 | |
500 if (dc->send(dc, buf, n) != (ssize_t) n) { | 526 if (dc->send(dc, buf, n) != (ssize_t) n) { |
501 ngx_http_v3_close_uni_stream(dc); | 527 ngx_http_v3_close_uni_stream(dc); |
502 return NGX_ERROR; | 528 return NGX_ERROR; |
503 } | 529 } |
504 | 530 |
507 | 533 |
508 | 534 |
509 ngx_int_t | 535 ngx_int_t |
510 ngx_http_v3_send_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id) | 536 ngx_http_v3_send_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id) |
511 { | 537 { |
512 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | 538 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; |
513 size_t n; | 539 size_t n; |
514 ngx_connection_t *dc; | 540 ngx_connection_t *dc; |
541 ngx_http_v3_session_t *h3c; | |
515 | 542 |
516 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 543 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
517 "http3 client cancel stream %ui", stream_id); | 544 "http3 client cancel stream %ui", stream_id); |
518 | 545 |
519 dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); | 546 dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); |
522 } | 549 } |
523 | 550 |
524 buf[0] = 0x40; | 551 buf[0] = 0x40; |
525 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf; | 552 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf; |
526 | 553 |
554 h3c = ngx_http_v3_get_session(c); | |
555 h3c->total_bytes += n; | |
556 | |
527 if (dc->send(dc, buf, n) != (ssize_t) n) { | 557 if (dc->send(dc, buf, n) != (ssize_t) n) { |
528 ngx_http_v3_close_uni_stream(dc); | 558 ngx_http_v3_close_uni_stream(dc); |
529 return NGX_ERROR; | 559 return NGX_ERROR; |
530 } | 560 } |
531 | 561 |
534 | 564 |
535 | 565 |
536 ngx_int_t | 566 ngx_int_t |
537 ngx_http_v3_send_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc) | 567 ngx_http_v3_send_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc) |
538 { | 568 { |
539 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; | 569 u_char buf[NGX_HTTP_V3_PREFIX_INT_LEN]; |
540 size_t n; | 570 size_t n; |
541 ngx_connection_t *dc; | 571 ngx_connection_t *dc; |
572 ngx_http_v3_session_t *h3c; | |
542 | 573 |
543 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 574 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
544 "http3 client increment insert count %ui", inc); | 575 "http3 client increment insert count %ui", inc); |
545 | 576 |
546 dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); | 577 dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER); |
548 return NGX_ERROR; | 579 return NGX_ERROR; |
549 } | 580 } |
550 | 581 |
551 buf[0] = 0; | 582 buf[0] = 0; |
552 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf; | 583 n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf; |
584 | |
585 h3c = ngx_http_v3_get_session(c); | |
586 h3c->total_bytes += n; | |
553 | 587 |
554 if (dc->send(dc, buf, n) != (ssize_t) n) { | 588 if (dc->send(dc, buf, n) != (ssize_t) n) { |
555 ngx_http_v3_close_uni_stream(dc); | 589 ngx_http_v3_close_uni_stream(dc); |
556 return NGX_ERROR; | 590 return NGX_ERROR; |
557 } | 591 } |