]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
datamodel: add /local-data/rpz/*/{log,dry-run}
authorVladimír Čunát <vladimir.cunat@nic.cz>
Wed, 28 May 2025 12:35:46 +0000 (14:35 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 29 May 2025 08:33:04 +0000 (10:33 +0200)
doc/_static/config.schema.json
doc/user/config-local-data.rst
python/knot_resolver/datamodel/local_data_schema.py
python/knot_resolver/datamodel/templates/local_data.lua.j2
python/knot_resolver/datamodel/templates/macros/local_data_macros.lua.j2

index ce32b94f468f6cad7396b73a0ffd6f2e733d9726..a9ceb1f6a563679100041ca72cdfe24fb5556a7b 100644 (file)
                                 },
                                 "description": "Tags to link with other policy rules.",
                                 "default": null
+                            },
+                            "log": {
+                                "type": [
+                                    "array",
+                                    "null"
+                                ],
+                                "items": {
+                                    "type": "string",
+                                    "enum": [
+                                        "ip",
+                                        "name"
+                                    ]
+                                },
+                                "description": "Enables logging information whenever this RPZ matches.",
+                                "default": null
                             }
                         }
                     },
index ee89547da332118294c106f7483e29243afd7cff..27f9dd2021ea5275057933cc36390b051052cdb1 100644 (file)
@@ -100,14 +100,32 @@ It provides various input formats described in following subsections.
 
          Optional, restrict when this RPZ applies.  See :ref:`config-policy-new-tags`.
 
+      .. option:: log: <list, subset of [ name, ip ]>
+
+         Optional, indicate that each application of a rule should log the domain name
+         triggering it and/or the requestor's IP.
+         Logging is then done at the *notice* level.
+
+         .. code-block::
+
+            [rules ] => local data applied, user: ::1, name: foo.bar.93.100.in-addr.arpa.
+
+      .. option:: dry-run: <boolean, false by default>
+
+         Do not apply these rules.  You want to combine this with ``log``.
+
    .. code-block:: yaml
 
       local-data:
         rpz:
           - file: /tmp/adult.rpz
             tags: [ adult ]
-            # security blocklist applied for everyone
+          # security blocklist applied for everyone
           - file: /tmp/security.rpz
+          # log these but do not block them
+          - file: /tmp/suspicious.rpz
+            dry-run: true
+            log: [ name, ip ]
 
    So far, RPZ support is limited to the most common features:
 
index 478a0e2310ef6d6fd02519310666a9e64a501352..1373e09e3f05552f3800006c0cb6802fb2c91d45 100644 (file)
@@ -36,6 +36,7 @@ class RuleSchema(ConfigSchema):
     tags: Optional[List[IDPattern]] = None
     ttl: Optional[TimeUnit] = None
     nodata: Optional[bool] = None
+    # TODO: probably also implement the rule options from RPZSchema (.log + .dry_run)
 
     def _validate(self) -> None:
         options_sum = sum([bool(self.address), bool(self.subtree), bool(self.file), bool(self.records)])
@@ -63,17 +64,22 @@ class RPZSchema(ConfigSchema):
         file: Path to the RPZ zone file.
         watchdog: Enables files watchdog for configured RPZ file. Requires the optional 'watchdog' dependency.
         tags: Tags to link with other policy rules.
+        log: Enables logging information whenever this RPZ matches.
         """
 
         file: ReadableFile
         watchdog: Union[Literal["auto"], bool] = "auto"
         tags: Optional[List[IDPattern]] = None
+        log: Optional[List[Literal["ip", "name"]]] = None
+        dry_run: bool = False
 
     _LAYER = Raw
 
     file: ReadableFile
     watchdog: bool
     tags: Optional[List[IDPattern]]
+    log: Optional[List[Literal["ip", "name"]]]
+    dry_run: bool
 
     def _watchdog(self, obj: Raw) -> Any:
         if obj.watchdog == "auto":
index 8882471fd9df94af05a337260716e81d4c59ae8c..78e167382fa45348a04ba1fb3ffd06007858fc81 100644 (file)
@@ -25,7 +25,7 @@ modules = { 'hints > iterate' }
 
 {# records #}
 {% if cfg.local_data.records -%}
-{{ local_data_records(cfg.local_data.records, false, cfg.local_data.nodata, cfg.local_data.ttl) }}
+{{ local_data_records(cfg.local_data.records, false, cfg.local_data.nodata, cfg.local_data.ttl, none) }}
 {%- endif %}
 
 {# rules #}
@@ -36,6 +36,6 @@ modules = { 'hints > iterate' }
 {# rpz #}
 {% if cfg.local_data.rpz -%}
 {% for rpz in cfg.local_data.rpz %}
-{{ local_data_records(rpz.file, true, cfg.local_data.nodata, cfg.local_data.ttl, rpz.tags) }}
+{{ local_data_records(rpz.file, true, cfg.local_data.nodata, cfg.local_data.ttl, rpz) }}
 {% endfor %}
 {%- endif %}
index 5bfb45afd5ba7b3921a1ef61b1246bd6ca4d8980..518795dbcb4bb451e364384a05f4ca3b4238bf89 100644 (file)
@@ -55,13 +55,12 @@ assert(C.kr_rule_local_hosts('{{ file }}', {{ boolean(nodata) }},
 {%- endmacro %}
 
 
-{% macro local_data_records(input_str, is_rpz, nodata, ttl, tags=none, id='rrs') -%}
+{% macro local_data_records(input_str, is_rpz, nodata, ttl, extra, id='rrs') -%}
 {{ id }} = ffi.new('struct kr_rule_zonefile_config')
 {{ id }}.ttl = {{ local_data_ttl(ttl) }}
-{{ id }}.tags = {{ policy_get_tagset(tags) }}
+{{ id }}.tags = {{ policy_get_tagset(extra.tags) }}
 {{ id }}.nodata = {{ boolean(nodata) }}
 {{ id }}.is_rpz = {{ boolean(is_rpz) }}
-{{ id }}.opts = C.KR_RULE_OPTS_DEFAULT
 {% if is_rpz -%}
 {{ id }}.filename = '{{ input_str }}'
 {% else %}
@@ -69,6 +68,24 @@ assert(C.kr_rule_local_hosts('{{ file }}', {{ boolean(nodata) }},
 {{ input_str.multiline() }}
 ]]
 {% endif %}
+{# .opts are complicated #}
+{{ id }}.opts = C.KR_RULE_OPTS_DEFAULT
+{% if extra is not none -%}
+{% if extra.dry_run is not none and extra.dry_run -%}
+{{ id }}.opts.score = 4
+{% else %}
+{{ id }}.opts.score = 9
+{% endif %}
+{% if extra.log is not none -%}
+{{ id }}.opts.log_level = 3  -- notice
+{% endif %}
+{% if extra.log is not none and 'ip' in extra.log -%}
+{{ id }}.opts.log_ip = true
+{% endif %}
+{% if extra.log is not none and 'name' in extra.log -%}
+{{ id }}.opts.log_name = true
+{% endif %}
+{% endif %}
 assert(C.kr_rule_zonefile({{ id }})==0)
 {%- endmacro %}
 
@@ -98,7 +115,7 @@ assert(C.kr_rule_local_subtree(todname('{{ name }}'),
 {{ kr_rule_local_hosts(file, nodata if item.nodata is none else item.nodata, item.ttl or ttl, item.tags) }}
 {% endfor %}
 {% elif item.records %}
-{{ local_data_records(item.records, false, nodata if item.nodata is none else item.nodata, item.ttl or ttl, item.tags) }}
+{{ local_data_records(item.records, false, nodata if item.nodata is none else item.nodata, item.ttl or ttl, item) }}
 {% endif %}
 {% endfor %}
 {%- endmacro %}