from jinja2 import Environment, Template
from knot_resolver_manager.datamodel.dns64_config import Dns64, Dns64Strict
+from knot_resolver_manager.datamodel.dnssec_config import Dnssec, DnssecStrict
from knot_resolver_manager.datamodel.lua_config import Lua, LuaStrict
from knot_resolver_manager.datamodel.network_config import Network, NetworkStrict
from knot_resolver_manager.datamodel.options_config import Options, OptionsStrict
server: Server = Server()
options: Options = Options()
network: Network = Network()
+ dnssec: Union[bool, Dnssec] = True
dns64: Union[bool, Dns64] = False
lua: Lua = Lua()
server: ServerStrict
options: OptionsStrict
network: NetworkStrict
+ dnssec: Union[bool, DnssecStrict]
dns64: Union[bool, Dns64Strict]
lua: LuaStrict
+ def _dnssec(self, obj: KresConfig) -> Union[bool, Dnssec]:
+ if obj.dnssec is True:
+ return Dnssec()
+ return obj.dnssec
+
def _dns64(self, obj: KresConfig) -> Union[bool, Dns64]:
if obj.dns64 is True:
return Dns64()
--- /dev/null
+from typing import List, Optional
+
+from knot_resolver_manager.datamodel.types import TimeUnit
+from knot_resolver_manager.utils import DataParser, DataValidator
+
+
+class TrustAnchorFile(DataParser):
+ file: str
+ read_only: bool = False
+
+
+class Dnssec(DataParser):
+ trust_anchor_sentinel: bool = True
+ trust_anchor_signal_query: bool = True
+ time_skew_detection: bool = True
+ keep_removed: int = 0
+ refresh_time: Optional[TimeUnit] = None
+ hold_down_time: TimeUnit = TimeUnit("30d")
+
+ trust_anchors: Optional[List[str]] = None
+ negative_trust_anchors: Optional[List[str]] = None
+ trust_anchors_files: Optional[List[TrustAnchorFile]] = None
+
+
+class TrustAnchorFileStrict(DataValidator):
+ file: str
+ read_only: bool
+
+ def _validate(self) -> None:
+ pass
+
+
+class DnssecStrict(DataValidator):
+ trust_anchor_sentinel: bool
+ trust_anchor_signal_query: bool
+ time_skew_detection: bool
+ keep_removed: int
+ refresh_time: Optional[int]
+ hold_down_time: int
+
+ trust_anchors: Optional[List[str]]
+ negative_trust_anchors: Optional[List[str]]
+ trust_anchors_files: Optional[List[TrustAnchorFileStrict]]
+
+ def _validate(self) -> None:
+ pass
{{ "modules.unload('detect_time_jump')" if not cfg.options.time_jump_detection }}
{{ "modules.unload('refuse_nord')" if not cfg.options.refuse_no_rd }}
+-- DNSSEC section
+{% if not cfg.dnssec %}
+trust_anchors.remove('.')
+{% endif %}
+
+{{ "modules.unload('ta_sentinel')" if not cfg.dnssec.trust_anchor_sentinel }}
+{{ "modules.unload('ta_signal_query')" if not cfg.dnssec.trust_anchor_signal_query }}
+{{ "modules.unload('detect_time_skew')" if not cfg.dnssec.time_skew_detection }}
+
+trust_anchors.keep_removed = {{ cfg.dnssec.keep_removed }}
+{{ "trust_anchors.refresh_time = "+cfg.dnssec.refresh_time|string if cfg.dnssec.refresh_time }}
+
+-- dnssec.trust-anchors
+{% if cfg.dnssec.trust_anchors %}
+{% for ta in cfg.dnssec.trust_anchors %}
+trust_anchors.add('{{ ta }}')
+{% endfor %}
+{% endif %}
+
+-- dnssec.negative-trust-anchors
+{% if cfg.dnssec.negative_trust_anchors %}
+trust_anchors.set_insecure({
+{% for nta in cfg.dnssec.negative_trust_anchors %}
+ '{{ nta }}',
+{% endfor %}
+})
+{% endif %}
+
+-- dnssec.trust-anchors-files
+{% if cfg.dnssec.trust_anchors_files %}
+{% for taf in cfg.dnssec.trust_anchors_files %}
+trust_anchors.add_file('{{ taf.file }}', readonly = {{ 'true' if taf.read_only else 'false' }})
+{% endfor %}
+{% endif %}
+
{% endif %}
-- LUA section
{% if cfg.lua.script_file %}
assert strict.dns64
assert strict.dns64.prefix == "64:ff9b::"
+
+
+def test_dnssec_true_default():
+ config = KresConfig({"dnssec": True})
+ strict = KresConfigStrict(config)
+
+ assert strict.dnssec.trust_anchor_sentinel == True
+ assert strict.dnssec.trust_anchor_signal_query == True
+ assert strict.dnssec.time_skew_detection == True
+ assert strict.dnssec.keep_removed == 0
+ assert strict.dnssec.refresh_time == None
+ assert strict.dnssec.hold_down_time == 30 * 24 * 60 ** 2
+
+ assert strict.dnssec.trust_anchors == None
+ assert strict.dnssec.negative_trust_anchors == None
+ assert strict.dnssec.trust_anchors_files == None
--- /dev/null
+from knot_resolver_manager.datamodel.dnssec_config import Dnssec, DnssecStrict
+from knot_resolver_manager.datamodel.types import TimeUnit
+
+yaml = """
+trust-anchor-sentinel: false
+trust-anchor-signal-query: false
+time-skew-detection: false
+keep-removed: 3
+refresh-time: 10s
+hold-down-time: 45d
+trust-anchors:
+ - ". 3600 IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5"
+negative-trust-anchors:
+ - bad.boy
+ - example.com
+trust-anchors-files:
+ - file: root.key
+ read-only: true
+"""
+
+config = Dnssec.from_yaml(yaml)
+strict = DnssecStrict(config)
+
+
+def test_parsing():
+ assert config.trust_anchor_sentinel == False
+ assert config.trust_anchor_signal_query == False
+ assert config.time_skew_detection == False
+ assert config.keep_removed == 3
+ assert config.refresh_time == TimeUnit("10s")
+ assert config.hold_down_time == TimeUnit("45d")
+
+ assert config.trust_anchors == [". 3600 IN DS 19036 8 2 49AAC11..."]
+ assert config.negative_trust_anchors == ["bad.boy", "example.com"]
+ assert config.trust_anchors_files[0].file == "root.key"
+ assert config.trust_anchors_files[0].read_only == True
+
+
+def test_validating():
+ assert strict.trust_anchor_sentinel == False
+ assert strict.trust_anchor_signal_query == False
+ assert strict.time_skew_detection == False
+ assert strict.keep_removed == 3
+ assert strict.refresh_time == 10
+ assert strict.hold_down_time == 45 * 24 * 60 ** 2
+
+ assert strict.trust_anchors == [". 3600 IN DS 19036 8 2 49AAC11..."]
+ assert strict.negative_trust_anchors == ["bad.boy", "example.com"]
+ assert strict.trust_anchors_files[0].file == "root.key"
+ assert strict.trust_anchors_files[0].read_only == True