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
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
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.
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
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]]
--- /dev/null
+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
-- 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" %}
--- /dev/null
+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)