From: Aleš Mrázek Date: Mon, 20 Feb 2023 18:55:47 +0000 (+0100) Subject: manager: datamodel: local-data schema added X-Git-Tag: v6.0.1~11^2^2~27 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d868d0e9d1545383dae9bf6f990f5ecec365e47b;p=thirdparty%2Fknot-resolver.git manager: datamodel: local-data schema added --- diff --git a/manager/knot_resolver_manager/datamodel/config_schema.py b/manager/knot_resolver_manager/datamodel/config_schema.py index 1fc612e88..fed9b2c48 100644 --- a/manager/knot_resolver_manager/datamodel/config_schema.py +++ b/manager/knot_resolver_manager/datamodel/config_schema.py @@ -12,6 +12,7 @@ from knot_resolver_manager.datamodel.cache_schema import CacheSchema from knot_resolver_manager.datamodel.dns64_schema import Dns64Schema from knot_resolver_manager.datamodel.dnssec_schema import DnssecSchema from knot_resolver_manager.datamodel.forward_schema import ForwardSchema +from knot_resolver_manager.datamodel.local_data_schema import LocalDataSchema from knot_resolver_manager.datamodel.logging_schema import LoggingSchema from knot_resolver_manager.datamodel.lua_schema import LuaSchema from knot_resolver_manager.datamodel.management_schema import ManagementSchema @@ -21,7 +22,6 @@ from knot_resolver_manager.datamodel.options_schema import OptionsSchema from knot_resolver_manager.datamodel.policy_schema import PolicySchema from knot_resolver_manager.datamodel.rpz_schema import RPZSchema from knot_resolver_manager.datamodel.slice_schema import SliceSchema -from knot_resolver_manager.datamodel.static_hints_schema import StaticHintsSchema from knot_resolver_manager.datamodel.stub_zone_schema import StubZoneSchema from knot_resolver_manager.datamodel.types import IntPositive from knot_resolver_manager.datamodel.types.files import UncheckedPath @@ -96,8 +96,8 @@ class KresConfig(ConfigSchema): webmgmt: Configuration of legacy web management endpoint. options: Fine-tuning global parameters of DNS resolver operation. network: Network connections and protocols configuration. - static_hints: Static hints for forward records (A/AAAA) and reverse records (PTR) views: List of views and its configuration. + local_data: Local data for forward records (A/AAAA) and reverse records (PTR). slices: Split the entire DNS namespace into distinct slices. policy: List of policy rules and its configuration. rpz: List of Response Policy Zones and its configuration. @@ -121,8 +121,8 @@ class KresConfig(ConfigSchema): webmgmt: Optional[WebmgmtSchema] = None options: OptionsSchema = OptionsSchema() network: NetworkSchema = NetworkSchema() - static_hints: StaticHintsSchema = StaticHintsSchema() views: Optional[List[ViewSchema]] = None + local_data: LocalDataSchema = LocalDataSchema() slices: Optional[List[SliceSchema]] = None policy: Optional[List[PolicySchema]] = None rpz: Optional[List[RPZSchema]] = None @@ -146,8 +146,8 @@ class KresConfig(ConfigSchema): webmgmt: Optional[WebmgmtSchema] options: OptionsSchema network: NetworkSchema - static_hints: StaticHintsSchema views: Optional[List[ViewSchema]] + local_data: LocalDataSchema slices: Optional[List[SliceSchema]] policy: Optional[List[PolicySchema]] rpz: Optional[List[RPZSchema]] diff --git a/manager/knot_resolver_manager/datamodel/local_data_schema.py b/manager/knot_resolver_manager/datamodel/local_data_schema.py new file mode 100644 index 000000000..e10f6c3bd --- /dev/null +++ b/manager/knot_resolver_manager/datamodel/local_data_schema.py @@ -0,0 +1,59 @@ +from typing import Dict, List, Optional, Union + +from typing_extensions import Literal + +from knot_resolver_manager.datamodel.types import DomainName, IDPattern, IPAddress, TimeUnit, UncheckedPath +from knot_resolver_manager.utils.modeling import BaseSchema + + +class SubtreeSchema(BaseSchema): + """ + Local data and configuration of subtree. + + --- + type: Type of the subtree. + tags: Tags to link with other policy rules. + addresses: Subtree addresses. + roots: Subtree roots. + roots_file: Subtree roots from given file. + roots_url: Subtree roots form given URL. + refresh: Refresh time to update data from 'roots-file' or 'roots-url'. + """ + + type: Literal["empty", "nxdomain", "redirect"] + tags: Optional[List[IDPattern]] = None + addresses: Optional[Union[List[IPAddress], IPAddress]] = None + roots: Optional[Union[List[DomainName], DomainName]] = None + roots_file: Optional[UncheckedPath] = None + roots_url: Optional[str] = None + refresh: Optional[TimeUnit] = None + + def _validate(self) -> None: + options_sum = sum([bool(self.roots), bool(self.roots_file), bool(self.roots_url)]) + if options_sum > 1: + raise ValueError("only one of, 'roots', 'roots-file' or 'roots-url' can be configured") + elif options_sum < 1: + raise ValueError("one of, 'roots', 'roots-file' or 'roots-url' must be configured") + if self.refresh and not (self.roots_file or self.roots_url): + raise ValueError("'refresh' can be only configured with 'roots-file' or 'roots-url'") + + +class LocalDataSchema(BaseSchema): + """ + Local data for forward records (A/AAAA) and reverse records (PTR). + + --- + ttl: Default TTL value used for added local data/records. + nodata: Use NODATA synthesis. NODATA will be synthesised for matching name, but mismatching type(e.g. AAAA query when only A exists). + addresses: Direct addition of hostname and IP addresses pairs. + addresses_files: Direct addition of hostname and IP addresses pairs from files in '/etc/hosts' like format. + records: Direct addition of records in DNS zone file format. + subtrees: Direct addition of subtrees. + """ + + ttl: Optional[TimeUnit] = None + nodata: bool = True + addresses: Optional[Dict[DomainName, Union[List[IPAddress], IPAddress]]] = None + addresses_files: Optional[Union[List[UncheckedPath], UncheckedPath]] = None + records: Optional[str] = None + subtrees: Optional[List[SubtreeSchema]] = None diff --git a/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 index 52bef3893..9dc7ef214 100644 --- a/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 +++ b/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 @@ -21,12 +21,12 @@ nsid.name('{{ cfg.nsid }}_' .. worker.id) -- NETWORK section ---------------------------------- {% include "network.lua.j2" %} --- STATIC-HINTS section ----------------------------- -{% include "static_hints.lua.j2" %} - -- VIEWS section ------------------------------------ {% include "views.lua.j2" %} +-- LOCAL-DATA section ----------------------------- +{% include "local_data.lua.j2" %} + -- SLICES section ----------------------------------- {% include "slices.lua.j2" %} diff --git a/manager/knot_resolver_manager/datamodel/templates/local_data.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/local_data.lua.j2 new file mode 100644 index 000000000..e69de29bb diff --git a/manager/tests/unit/datamodel/test_local_data.py b/manager/tests/unit/datamodel/test_local_data.py new file mode 100644 index 000000000..198bccd2c --- /dev/null +++ b/manager/tests/unit/datamodel/test_local_data.py @@ -0,0 +1,33 @@ +from typing import Any + +import pytest +from pytest import raises + +from knot_resolver_manager.datamodel.local_data_schema import LocalDataSchema, SubtreeSchema +from knot_resolver_manager.utils.modeling.exceptions import DataValidationError + + +@pytest.mark.parametrize( + "val", + [ + {"type": "empty", "roots": ["sub2.example.org"]}, + {"type": "empty", "roots-url": "https://example.org/blocklist.txt", "refresh": "1d"}, + {"type": "nxdomain", "roots-file": "/path/to/file.txt"}, + {"type": "redirect", "roots": ["sub4.example.org"], "addresses": ["127.0.0.1", "::1"]}, + ], +) +def test_subtree_valid(val: Any): + SubtreeSchema(val) + + +@pytest.mark.parametrize( + "val", + [ + {"type": "empty"}, + {"type": "empty", "roots": ["sub2.example.org"], "roots-url": "https://example.org/blocklist.txt"}, + {"type": "redirect", "roots": ["sub4.example.org"], "refresh": "1d"}, + ], +) +def test_subtree_invalid(val: Any): + with raises(DataValidationError): + SubtreeSchema(val)