comparison src/http/v3/ngx_http_v3_streams.c @ 8881: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
8880:a09bcc304eef 8881: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 }