# HG changeset patch # User Roman Arutyunyan # Date 1634125306 -10800 # Node ID 6204120cf37f229fde0c18ecb36dd93eb4ce86c4 # Parent 72b304f6207cb6483974d02543dda6b9959a79a4 QUIC: traffic-based flood detection. With this patch, all traffic over a QUIC connection is compared to traffic over QUIC streams. As long as total traffic is many times larger than stream traffic, we consider this to be a flood. diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c --- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -665,13 +665,17 @@ ngx_quic_close_timer_handler(ngx_event_t static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b, ngx_quic_conf_t *conf) { - u_char *p; - ngx_int_t rc; - ngx_uint_t good; - ngx_quic_header_t pkt; + size_t size; + u_char *p; + ngx_int_t rc; + ngx_uint_t good; + ngx_quic_header_t pkt; + ngx_quic_connection_t *qc; good = 0; + size = b->last - b->pos; + p = b->pos; while (p < b->last) { @@ -736,7 +740,27 @@ ngx_quic_input(ngx_connection_t *c, ngx_ p = b->pos; } - return good ? NGX_OK : NGX_DECLINED; + if (!good) { + return NGX_DECLINED; + } + + qc = ngx_quic_get_connection(c); + + if (qc) { + qc->received += size; + + if ((uint64_t) (c->sent + qc->received) / 8 > + (qc->streams.sent + qc->streams.recv_last) + 1048576) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic flood detected"); + + qc->error = NGX_QUIC_ERR_NO_ERROR; + qc->error_reason = "QUIC flood detected"; + return NGX_ERROR; + } + } + + return NGX_OK; } diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h --- a/src/event/quic/ngx_event_quic_connection.h +++ b/src/event/quic/ngx_event_quic_connection.h @@ -236,6 +236,8 @@ struct ngx_quic_connection_s { ngx_quic_streams_t streams; ngx_quic_congestion_t congestion; + off_t received; + ngx_uint_t error; enum ssl_encryption_level_t error_level; ngx_uint_t error_ftype;