[PATCH 4 of 5] QUIC: traffic-based flood detection

Vladimir Homutov vl at nginx.com
Tue Oct 12 12:39:38 UTC 2021


On Thu, Oct 07, 2021 at 02:36:17PM +0300, Roman Arutyunyan wrote:
> # HG changeset patch
> # User Roman Arutyunyan <arut at nginx.com>
> # Date 1633602816 -10800
> #      Thu Oct 07 13:33:36 2021 +0300
> # Branch quic
> # Node ID e20f00b8ac9005621993ea19375b1646c9182e7b
> # Parent  31561ac584b74d29af9a442afca47821a98217b2
> 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
> @@ -662,13 +662,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) {
> @@ -701,7 +705,8 @@ ngx_quic_input(ngx_connection_t *c, ngx_
>
>          if (rc == NGX_DONE) {
>              /* stop further processing */
> -            return NGX_DECLINED;
> +            good = 0;
> +            break;
>          }

this chunk looks unnecessary: we will test 'good' after the loop and
return NGX_DECLINED anyway in this case (good = 0).

>
>          if (rc == NGX_OK) {
> @@ -733,7 +738,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)
> +        {

note: the comparison is intentionally similar to one used HTTP/2 for the
same purposes

> +            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;

As a whole, it seems to be working good enough.


More information about the nginx-devel mailing list