summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSergey Kandaurov <pluknet@nginx.com>2026-02-25 21:09:21 +0400
committerSergey Kandaurov <s.kandaurov@f5.com>2026-02-26 18:05:07 +0400
commite6ffe8384ebf1972faac9b031b9ff6182e79cfd6 (patch)
tree9027106b8f2b8d73bc173bfe6ab771eede38a663
parent2f039e6f7233c7fd9ab88888642410352572c089 (diff)
downloadnginx-e6ffe8384ebf1972faac9b031b9ff6182e79cfd6.tar.gz
nginx-e6ffe8384ebf1972faac9b031b9ff6182e79cfd6.tar.bz2
QUIC: Stateless Reset rate limiting.
It uses a bloom filter to limit sending Stateless Reset packets no more than once per second in average for the given address. This allows to address resource asymmetry from precomputed packets, as well as to limit potential Stateless Reset exchange.
-rw-r--r--src/event/quic/ngx_event_quic_output.c65
1 files changed, 61 insertions, 4 deletions
diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c
index 72119a8ea..f98c834a1 100644
--- a/src/event/quic/ngx_event_quic_output.c
+++ b/src/event/quic/ngx_event_quic_output.c
@@ -64,6 +64,7 @@ static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
struct sockaddr *sockaddr, socklen_t socklen);
static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt,
ngx_quic_send_ctx_t *ctx);
+static ngx_int_t ngx_quic_stateless_reset_filter(ngx_connection_t *c);
ngx_int_t
@@ -823,10 +824,11 @@ ngx_int_t
ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
ngx_quic_header_t *pkt)
{
- u_char *token;
- size_t len, max;
- uint16_t rndbytes;
- u_char buf[NGX_QUIC_MAX_SR_PACKET];
+ u_char *token;
+ size_t len, max;
+ uint16_t rndbytes;
+ ngx_int_t rc;
+ u_char buf[NGX_QUIC_MAX_SR_PACKET];
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic handle stateless reset output");
@@ -835,6 +837,11 @@ ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
return NGX_DECLINED;
}
+ rc = ngx_quic_stateless_reset_filter(c);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
if (pkt->len <= NGX_QUIC_MIN_SR_PACKET) {
len = pkt->len - 1;
@@ -870,6 +877,56 @@ ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
}
+static ngx_int_t
+ngx_quic_stateless_reset_filter(ngx_connection_t *c)
+{
+ time_t now;
+ u_char salt;
+ ngx_uint_t i, n, m, hit;
+ u_char hash[20];
+
+ static time_t t;
+ static u_char rndbyte;
+ static uint8_t bitmap[65536];
+
+ now = ngx_time();
+
+ if (t != now) {
+ t = now;
+
+ if (RAND_bytes(&rndbyte, 1) != 1) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(bitmap, sizeof(bitmap));
+ }
+
+ hit = 0;
+
+ for (i = 0; i < 3; i++) {
+ salt = rndbyte + i;
+
+ ngx_quic_address_hash(c->sockaddr, c->socklen, 0, &salt, 1, hash);
+
+ n = hash[0] | hash[1] << 8;
+ m = 1 << hash[2] % 8;
+
+ if (!(bitmap[n] & m)) {
+ bitmap[n] |= m;
+
+ } else {
+ hit++;
+ }
+ }
+
+ if (hit == 3) {
+ return NGX_DECLINED;
+ }
+
+ return NGX_OK;
+}
+
+
ngx_int_t
ngx_quic_send_cc(ngx_connection_t *c)
{