From: Vladimír Čunát Date: Wed, 28 May 2025 12:35:46 +0000 (+0200) Subject: datamodel: add /local-data/rpz/*/{log,dry-run} X-Git-Tag: v6.0.13~2^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4227fdb06a3c8a1197acce1088009f9c19b8513c;p=thirdparty%2Fknot-resolver.git datamodel: add /local-data/rpz/*/{log,dry-run} --- diff --git a/doc/_static/config.schema.json b/doc/_static/config.schema.json index ce32b94f4..a9ceb1f6a 100644 --- a/doc/_static/config.schema.json +++ b/doc/_static/config.schema.json @@ -954,6 +954,21 @@ }, "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 } } }, diff --git a/doc/user/config-local-data.rst b/doc/user/config-local-data.rst index ee89547da..27f9dd202 100644 --- a/doc/user/config-local-data.rst +++ b/doc/user/config-local-data.rst @@ -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: + + 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: + + 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: diff --git a/python/knot_resolver/datamodel/local_data_schema.py b/python/knot_resolver/datamodel/local_data_schema.py index 478a0e231..1373e09e3 100644 --- a/python/knot_resolver/datamodel/local_data_schema.py +++ b/python/knot_resolver/datamodel/local_data_schema.py @@ -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": diff --git a/python/knot_resolver/datamodel/templates/local_data.lua.j2 b/python/knot_resolver/datamodel/templates/local_data.lua.j2 index 8882471fd..78e167382 100644 --- a/python/knot_resolver/datamodel/templates/local_data.lua.j2 +++ b/python/knot_resolver/datamodel/templates/local_data.lua.j2 @@ -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 %} diff --git a/python/knot_resolver/datamodel/templates/macros/local_data_macros.lua.j2 b/python/knot_resolver/datamodel/templates/macros/local_data_macros.lua.j2 index 5bfb45afd..518795dbc 100644 --- a/python/knot_resolver/datamodel/templates/macros/local_data_macros.lua.j2 +++ b/python/knot_resolver/datamodel/templates/macros/local_data_macros.lua.j2 @@ -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 %}