From 10d3e51b9a94505d1ada47ffb8a45890d86d7515 Mon Sep 17 00:00:00 2001 From: Hakase Date: Fri, 20 Sep 2019 03:48:06 +0900 Subject: [PATCH] Latest update - 7569 --- src/http/v2/ngx_http_v2.c | 43 +++++++++++-------------- src/http/v2/ngx_http_v2.h | 3 ++ src/http/v2/ngx_http_v2_filter_module.c | 13 +++++++- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 9b6f44c..adcbf6d 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -421,6 +421,14 @@ ngx_http_v2_read_handler(ngx_event_t *rev) } 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) { @@ -965,6 +973,8 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, 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); @@ -2919,9 +2929,9 @@ ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length, "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); @@ -2948,6 +2958,8 @@ ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, frame->next = h2c->free_frames; h2c->free_frames = frame; + h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length; + return NGX_OK; } @@ -3733,7 +3745,8 @@ ngx_http_v2_construct_cookie_header(ngx_http_request_t *r) 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; @@ -3765,6 +3778,10 @@ ngx_http_v2_run_request(ngx_http_request_t *r) r->headers_in.chunked = 1; } + h2c = r->stream->connection; + + h2c->payload_bytes += r->request_length; + ngx_http_process_request(r); failed: @@ -4294,33 +4311,11 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) } } else if (!stream->in_closed) { -#if 0 if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR) != NGX_OK) { h2c->connection->error = 1; } -#else - /* - * At the time of writing at least the latest versions of Chrome - * do not properly handle RST_STREAM with NO_ERROR status. - * - * See: https://bugs.chromium.org/p/chromium/issues/detail?id=603182 - * - * As a workaround, the stream window is maximized before closing - * the stream. This allows a client to send up to 2 GB of data - * before getting blocked on flow control. - */ - - if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW - && ngx_http_v2_send_window_update(h2c, node->id, - NGX_HTTP_V2_MAX_WINDOW - - stream->recv_window) - != NGX_OK) - { - h2c->connection->error = 1; - } -#endif } } diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 7d36173..e2d05d9 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -167,6 +167,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 index 968254e..8ddf408 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1853,6 +1853,8 @@ ngx_http_v2_headers_frame_handler(ngx_http_v2_connection_t *h2c, 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); @@ -1907,6 +1909,8 @@ ngx_http_v2_push_frame_handler(ngx_http_v2_connection_t *h2c, 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); @@ -2000,6 +2004,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); @@ -2012,12 +2018,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; }