Welcome! Log In Create A New Profile

Advanced

[nginx] HTTP/2: traffic-based flood detection.

Maxim Dounin
September 18, 2019 02:44PM
details: https://hg.nginx.org/nginx/rev/80359395b345
branches:
changeset: 7569:80359395b345
user: Maxim Dounin <mdounin@mdounin.ru>
date: Wed Sep 18 20:28:12 2019 +0300
description:
HTTP/2: traffic-based flood detection.

With this patch, all traffic over an HTTP/2 connection is counted in
the h2c->total_bytes field, and payload traffic is counted in
the h2c->payload_bytes field. As long as total traffic is many times
larger than payload traffic, we consider this to be a flood.

diffstat:

src/http/v2/ngx_http_v2.c | 21 +++++++++++++++++++--
src/http/v2/ngx_http_v2.h | 3 +++
src/http/v2/ngx_http_v2_filter_module.c | 13 ++++++++++++-
3 files changed, 34 insertions(+), 3 deletions(-)

diffs (130 lines):

diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -419,6 +419,14 @@ ngx_http_v2_read_handler(ngx_event_t *re

} while (p != end);

+ h2c->total_bytes += n;
+
+ if (h2c->total_bytes / 8 > h2c->payload_bytes + 1048576) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "http2 flood detected");
+ ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
+ return;
+ }
+
} while (rev->ready);

if (ngx_handle_read_event(rev, 0) != NGX_OK) {
@@ -963,6 +971,8 @@ ngx_http_v2_state_read_data(ngx_http_v2_
stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
}

+ h2c->payload_bytes += size;
+
if (r->request_body) {
rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed);

@@ -2909,9 +2919,9 @@ ngx_http_v2_get_frame(ngx_http_v2_connec
"requested control frame is too large: %uz", length);
return NULL;
}
+#endif

frame->length = length;
-#endif

buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type);

@@ -2938,6 +2948,8 @@ ngx_http_v2_frame_handler(ngx_http_v2_co
frame->next = h2c->free_frames;
h2c->free_frames = frame;

+ h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
+
return NGX_OK;
}

@@ -3723,7 +3735,8 @@ ngx_http_v2_construct_cookie_header(ngx_
static void
ngx_http_v2_run_request(ngx_http_request_t *r)
{
- ngx_connection_t *fc;
+ ngx_connection_t *fc;
+ ngx_http_v2_connection_t *h2c;

fc = r->connection;

@@ -3755,6 +3768,10 @@ ngx_http_v2_run_request(ngx_http_request
r->headers_in.chunked = 1;
}

+ h2c = r->stream->connection;
+
+ h2c->payload_bytes += r->request_length;
+
ngx_http_process_request(r);

failed:
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -119,6 +119,9 @@ struct ngx_http_v2_connection_s {
ngx_connection_t *connection;
ngx_http_connection_t *http_connection;

+ off_t total_bytes;
+ off_t payload_bytes;
+
ngx_uint_t processing;
ngx_uint_t frames;
ngx_uint_t idle;
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -1877,6 +1877,8 @@ ngx_http_v2_headers_frame_handler(ngx_ht
stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE
+ frame->length;

+ h2c->payload_bytes += frame->length;
+
ngx_http_v2_handle_frame(stream, frame);

ngx_http_v2_handle_stream(h2c, stream);
@@ -1931,6 +1933,8 @@ ngx_http_v2_push_frame_handler(ngx_http_
stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE
+ frame->length;

+ h2c->payload_bytes += frame->length;
+
ngx_http_v2_handle_frame(stream, frame);

ngx_http_v2_handle_stream(h2c, stream);
@@ -2024,6 +2028,8 @@ done:

stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE;

+ h2c->payload_bytes += frame->length;
+
ngx_http_v2_handle_frame(stream, frame);

ngx_http_v2_handle_stream(h2c, stream);
@@ -2036,12 +2042,17 @@ static ngx_inline void
ngx_http_v2_handle_frame(ngx_http_v2_stream_t *stream,
ngx_http_v2_out_frame_t *frame)
{
- ngx_http_request_t *r;
+ ngx_http_request_t *r;
+ ngx_http_v2_connection_t *h2c;

r = stream->request;

r->connection->sent += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;

+ h2c = stream->connection;
+
+ h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
+
if (frame->fin) {
stream->out_closed = 1;
}
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[nginx] HTTP/2: traffic-based flood detection.

Maxim Dounin 430 September 18, 2019 02:44PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 161
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready