diff src/http/v3/ngx_http_v3_request.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 a09bcc304eef
children 925572184d4a
line wrap: on
line diff
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -218,6 +218,7 @@ ngx_http_v3_process_request(ngx_event_t 
     ngx_int_t                     rc;
     ngx_connection_t             *c;
     ngx_http_request_t           *r;
+    ngx_http_v3_session_t        *h3c;
     ngx_http_core_srv_conf_t     *cscf;
     ngx_http_v3_parse_headers_t  *st;
 
@@ -233,6 +234,8 @@ ngx_http_v3_process_request(ngx_event_t 
         return;
     }
 
+    h3c = ngx_http_v3_get_session(c);
+
     st = &r->v3_parse->headers;
 
     b = r->header_in;
@@ -298,6 +301,12 @@ ngx_http_v3_process_request(ngx_event_t 
         }
 
         r->request_length += b->pos - p;
+        h3c->total_bytes += b->pos - p;
+
+        if (ngx_http_v3_check_flood(c) != NGX_OK) {
+            ngx_http_close_request(r, NGX_HTTP_CLOSE);
+            break;
+        }
 
         if (rc == NGX_BUSY) {
             if (rev->error) {
@@ -318,6 +327,10 @@ ngx_http_v3_process_request(ngx_event_t 
 
         /* rc == NGX_OK || rc == NGX_DONE */
 
+        h3c->payload_bytes += ngx_http_v3_encode_field_l(NULL,
+                                                   &st->field_rep.field.name,
+                                                   &st->field_rep.field.value);
+
         if (ngx_http_v3_process_header(r, &st->field_rep.field.name,
                                        &st->field_rep.field.value)
             != NGX_OK)
@@ -1080,6 +1093,7 @@ ngx_http_v3_request_body_filter(ngx_http
     ngx_buf_t                 *b;
     ngx_uint_t                 last;
     ngx_chain_t               *cl, *out, *tl, **ll;
+    ngx_http_v3_session_t     *h3c;
     ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
@@ -1088,6 +1102,8 @@ ngx_http_v3_request_body_filter(ngx_http
     rb = r->request_body;
     st = &r->v3_parse->body;
 
+    h3c = ngx_http_v3_get_session(r->connection);
+
     if (rb->rest == -1) {
 
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1135,6 +1151,11 @@ ngx_http_v3_request_body_filter(ngx_http
                 rc = ngx_http_v3_parse_data(r->connection, st, cl->buf);
 
                 r->request_length += cl->buf->pos - p;
+                h3c->total_bytes += cl->buf->pos - p;
+
+                if (ngx_http_v3_check_flood(r->connection) != NGX_OK) {
+                    return NGX_HTTP_CLOSE;
+                }
 
                 if (rc == NGX_AGAIN) {
                     continue;
@@ -1178,6 +1199,8 @@ ngx_http_v3_request_body_filter(ngx_http
             {
                 rb->received += st->length;
                 r->request_length += st->length;
+                h3c->total_bytes += st->length;
+                h3c->payload_bytes += st->length;
 
                 if (st->length < 8) {
 
@@ -1222,12 +1245,16 @@ ngx_http_v3_request_body_filter(ngx_http
                 cl->buf->pos += (size_t) st->length;
                 rb->received += st->length;
                 r->request_length += st->length;
+                h3c->total_bytes += st->length;
+                h3c->payload_bytes += st->length;
                 st->length = 0;
 
             } else {
                 st->length -= size;
                 rb->received += size;
                 r->request_length += size;
+                h3c->total_bytes += size;
+                h3c->payload_bytes += size;
                 cl->buf->pos = cl->buf->last;
             }