]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
datamodel: stabilize rate-limiting schema
authorAleš Mrázek <ales.mrazek@nic.cz>
Tue, 15 Apr 2025 14:16:50 +0000 (16:16 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Tue, 5 Aug 2025 09:18:27 +0000 (11:18 +0200)
NEWS
doc/_static/config.schema.json
doc/user/config-rate-limiting.rst
python/knot_resolver/datamodel/config_schema.py
python/knot_resolver/datamodel/rate_limiting_schema.py
python/knot_resolver/datamodel/templates/rate_limiting.lua.j2

diff --git a/NEWS b/NEWS
index a9e0464a09bceced5ac089ff50a7da62e279f317..9788bb0a5dbae4915f510b5267763d9ff384d741 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,7 @@ Incompatible changes
   - /dnssec/trust-anchor-signal-query -> /dnssec/signal-query
   - /logging/dnssec-bogus -> /dnssec/log-bogus
   - /network/tls/files-watchdog -> /network/tls/watchdog
+  - /rate-limiting -> /rate-limiting/enabled
 
 
 Knot Resolver 6.0.15 (2025-07-17)
index 26bed23ba6a1b3341cb6151bf3d842a465a4cf70..9bed9abda2232c655c950ae80c5c91e3a1bf3f29 100644 (file)
         },
         "rate-limiting": {
             "description": "Configuration of rate limiting.",
-            "type": [
-                "object",
-                "null"
-            ],
+            "type": "object",
             "properties": {
-                "capacity": {
-                    "type": "integer",
-                    "minimum": 1,
-                    "description": "Expected maximal number of blocked networks/hosts at the same time.",
-                    "default": 524288
+                "enabled": {
+                    "type": "boolean",
+                    "description": "Enable/disable rate limiting",
+                    "default": false
                 },
                 "rate-limit": {
-                    "type": "integer",
+                    "type": [
+                        "integer",
+                        "null"
+                    ],
                     "minimum": 1,
-                    "description": "Maximal number of allowed queries per second from a single host."
+                    "description": "Maximal number of allowed queries per second from a single host.",
+                    "default": null
                 },
                 "instant-limit": {
                     "type": "integer",
                     "description": "Maximal number of allowed queries at a single point in time from a single host.",
                     "default": 50
                 },
+                "capacity": {
+                    "type": "integer",
+                    "minimum": 1,
+                    "description": "Expected maximal number of blocked networks/hosts at the same time.",
+                    "default": 524288
+                },
                 "slip": {
                     "type": "integer",
                     "minimum": 0,
                     "default": false
                 }
             },
-            "default": null
+            "default": {
+                "enabled": false,
+                "rate_limit": null,
+                "instant_limit": 50,
+                "capacity": 524288,
+                "slip": 2,
+                "log_period": "0s",
+                "dry_run": false
+            }
         },
         "prioritization": {
             "description": "Configuration of request prioritization (defer).",
index 41984e40a020ac2da3a3b4477e97b43a8a55bb9d..a0798d2d7d7afa33515243cc10c55d943752edfe 100644 (file)
@@ -21,6 +21,15 @@ that's common in other DNS servers.
 
 The limits can be adjusted for different packet origins using :option:`price-factor <price-factor: <float>` in :ref:`views <config-views>`.
 
+.. option:: rate-limiting/enabled: true|false
+
+  :default: false
+
+  Enable rate limiting.
+  
+  To start using rate limiting, you need to set at least the :option: `rate-limit <rate-limiting/rate-limit: <int>>` which has no default value.
+
+
 .. option:: rate-limiting/rate-limit: <int>
 
     Maximal allowed number of UDP queries per second from a single IPv6 or IPv4 address.
index 13aaae17bfe0b6469e6ae760d1f1809cb7fcd754..0f322bc7e39b6e0caebb4ceec76ebe40325db8ce 100644 (file)
@@ -125,7 +125,7 @@ class KresConfig(ConfigSchema):
         dns64: Dns64Schema = Dns64Schema()
         logging: LoggingSchema = LoggingSchema()
         monitoring: MonitoringSchema = MonitoringSchema()
-        rate_limiting: Optional[RateLimitingSchema] = None
+        rate_limiting: RateLimitingSchema = RateLimitingSchema()
         prioritization: PrioritizationSchema = PrioritizationSchema()
         lua: LuaSchema = LuaSchema()
 
@@ -146,7 +146,7 @@ class KresConfig(ConfigSchema):
     dns64: Dns64Schema
     logging: LoggingSchema
     monitoring: MonitoringSchema
-    rate_limiting: Optional[RateLimitingSchema]
+    rate_limiting: RateLimitingSchema
     prioritization: PrioritizationSchema
     lua: LuaSchema
 
index 01771713c6c167a6a42c320e08223fb24c9e262c..3a8116dabcce0dc0668fcd2a9d3a67e90c19cb20 100644 (file)
@@ -1,3 +1,5 @@
+from typing import Optional
+
 from knot_resolver.datamodel.types import (
     Int0_32,
     IntPositive,
@@ -11,24 +13,29 @@ class RateLimitingSchema(ConfigSchema):
     Configuration of rate limiting.
 
     ---
-    capacity: Expected maximal number of blocked networks/hosts at the same time.
+    enabled: Enable/disable rate limiting
     rate_limit: Maximal number of allowed queries per second from a single host.
     instant_limit: Maximal number of allowed queries at a single point in time from a single host.
+    capacity: Expected maximal number of blocked networks/hosts at the same time.
     slip: Number of restricted responses out of which one is sent as truncated, the others are dropped.
     log_period: Minimal time between two log messages, or '0s' to disable.
     dry_run: Perform only classification and logging but no restrictions.
     """
 
-    capacity: IntPositive = IntPositive(524288)
-    rate_limit: IntPositive
+    enabled: bool = False
+    rate_limit: Optional[IntPositive] = None
     instant_limit: IntPositive = IntPositive(50)
+    capacity: IntPositive = IntPositive(524288)
     slip: Int0_32 = Int0_32(2)
     log_period: TimeUnit = TimeUnit("0s")
     dry_run: bool = False
 
     def _validate(self) -> None:
+        if self.enabled and not self.rate_limit:
+            raise ValueError("'rate-limit' has to be configured to enable rate limiting")
+
         max_instant_limit = int(2**32 // 768 - 1)
         if not int(self.instant_limit) <= max_instant_limit:
             raise ValueError(f"'instant-limit' has to be in range 1..{max_instant_limit}")
-        if not int(self.rate_limit) <= 1000 * int(self.instant_limit):
+        if self.rate_limit and not int(self.rate_limit) <= 1000 * int(self.instant_limit):
             raise ValueError("'rate-limit' has to be in range 1..(1000 * instant-limit)")
index 1f2a546d082f0dd90ab8fead7606d5d5562f14b6..0b6bd81424202604f28603cdb076c6aa39b44fe4 100644 (file)
@@ -1,12 +1,15 @@
 {% from 'macros/common_macros.lua.j2' import boolean %}
 
-{% if cfg.rate_limiting.rate_limit is defined and cfg.rate_limiting.rate_limit -%}
-assert(C.ratelimiting_init(
-       '{{ cfg.rundir }}/ratelimiting',
-       {{ cfg.rate_limiting.capacity }},
-       {{ cfg.rate_limiting.instant_limit }},
-       {{ cfg.rate_limiting.rate_limit }},
-       {{ cfg.rate_limiting.slip }},
-       {{ cfg.rate_limiting.log_period.millis() }},
-       {{ boolean(cfg.rate_limiting.dry_run) }}) == 0)
-{%- endif %}
+{% if cfg.rate_limiting.enabled %}
+assert(
+    C.ratelimiting_init(
+        '{{ cfg.rundir }}/ratelimiting',
+        {{ cfg.rate_limiting.capacity }},
+        {{ cfg.rate_limiting.instant_limit }},
+        {{ cfg.rate_limiting.rate_limit }},
+        {{ cfg.rate_limiting.slip }},
+        {{ cfg.rate_limiting.log_period.millis() }},
+        {{ boolean(cfg.rate_limiting.dry_run) }}
+    ) == 0
+)
+{% endif %}