Commit f985e9fb authored by Ladislav Lhotka's avatar Ladislav Lhotka

Merge branch 'master' of gitlab.labs.nic.cz:labs/resolvers-yang

parents 4673f262 8d4c72c2
Pipeline #41737 passed with stages
in 1 minute and 10 seconds
......@@ -63,7 +63,7 @@ Generator module
.. autoclass:: Generator
:members:
:members: generate_kresd, generate_unbound
Import ``Generator`` class which contains ``generate_unbound`` and ``generate_kresd`` functions to generate Unbound and Knot Resolver configuration strings from valid python dictionary loaded from Json. Returns string.
......@@ -101,6 +101,7 @@ Call generator functions to generate `unbound.conf` and `kresd.conf`.
msg-cache-size: 104857600
cache-max-ttl: 172800
cache-min-ttl: 0
val-override-date: "20181028131530"
dns64-prefix: 64:ff9b::/96
<BLANKLINE>
stub-zone:
......@@ -160,17 +161,18 @@ Call generator functions to generate `unbound.conf` and `kresd.conf`.
>>> with open("unbound.conf", "w") as unb_file:
... unb_file.write(unbound_conf)
687
724
Converter module
----------------
.. automodule:: converter
:members: Converter
.. autoclass:: Converter
:members:
:members: from_unbound
Import ``Converter`` class which contains ``from_unbound`` function for converting Unbound configuration string to python dictionary, which can be validate against `resolvers-yang` data model and save as Json file.
......@@ -191,9 +193,9 @@ Input parameter of ``from_unbound`` function is a list of string lines loaded fr
>>> converter = Converter()
>>> json_data = converter.from_unbound(unbconf_data)
>>> json_data
{'cznic-resolver-common:dns-resolver': {'server': {'user-name': 'jetconf'}, 'network': {'listen-interfaces': [{'name': 'interface0', 'ip-address': '127.0.0.1', 'port': 53}, {'name': 'interface1', 'ip-address': '::1', 'port': 53}, {'name': 'interface2', 'ip-address': '198.51.100.1', 'port': 8853}], 'source-address': {'ipv6': '2001:db8:0:2::1'}, 'udp-payload-size': 4096, 'recursion-transport': {'l2-protocols': 'ipv4 ipv6'}}, 'resolver': {'stub-zones': [{'domain': 'stub.example.com', 'nameserver': '192.0.2.1', 'port': 53}, {'domain': 'stub.example.net', 'nameserver': '198.51.100.1', 'port': 53}], 'options': {'glue-checking': 'strict', 'qname-minimisation': True, 'reorder-rrset': True, 'query-loopback': True}, 'hints': {'root-zone-file': '/etc/resolver/root.hints'}}, 'logging': {'verbosity': 2}, 'dnssec': {'trust-anchors': {'key-files': [{'domain': 'domain0', 'file': '/var/tmp/root.keys'}]}, 'negative-trust-anchors': ['bad.example.com', 'worse.example.com']}, 'cache': {'max-size': 104857600, 'max-ttl': 172800, 'min-ttl': 0}, 'dns64': {'prefix': '64:ff9b::/96'}}}
{'cznic-resolver-common:dns-resolver': {'server': {'user-name': 'jetconf'}, 'network': {'listen-interfaces': [{'name': 'interface0', 'ip-address': '127.0.0.1', 'port': 53}, {'name': 'interface1', 'ip-address': '::1', 'port': 53}, {'name': 'interface2', 'ip-address': '198.51.100.1', 'port': 8853}], 'source-address': {'ipv6': '2001:db8:0:2::1'}, 'udp-payload-size': 4096, 'recursion-transport': {'l2-protocols': 'ipv4 ipv6'}}, 'resolver': {'stub-zones': [{'domain': 'stub.example.com', 'nameserver': '192.0.2.1', 'port': 53}, {'domain': 'stub.example.net', 'nameserver': '198.51.100.1', 'port': 53}], 'options': {'glue-checking': True, 'qname-minimisation': True, 'reorder-rrset': True, 'query-loopback': True}, 'hints': {'root-zone-file': '/etc/resolver/root.hints'}}, 'logging': {'verbosity': 2}, 'dnssec': {'trust-anchors': {'key-files': [{'domain': 'domain0', 'file': '/var/tmp/root.keys'}]}, 'negative-trust-anchors': ['bad.example.com', 'worse.example.com']}, 'cache': {'max-size': 104857600, 'max-ttl': 172800, 'min-ttl': 0}, 'debugging': {'cznic-resolver-unbound:val-override-date': '2018-10-28T13:15:30Z'}, 'dns64': {'prefix': '64:ff9b::/96'}}}
``json_data`` variable is python dictionary, which can be easily validate against data model by ``Yangson`` library and save to Json-encoded file.
``json_data`` variable is python dictionary, which can be easily validate against data model by ``Yangson`` library and saved to Json-encoded file.
.. doctest::
......@@ -210,5 +212,4 @@ Input parameter of ``from_unbound`` function is a list of string lines loaded fr
os.remove("unbound-data.json")
os.remove("unbound.conf")
os.remove("kresd.conf")
os.chdir("../..")
......@@ -72,7 +72,7 @@
"root-zone-file": "/etc/resolver/root.hints"
},
"options": {
"glue-checking": "strict",
"glue-checking": true,
"qname-minimisation": true,
"reorder-rrset": true,
"query-loopback": true
......@@ -108,6 +108,9 @@
}
]
},
"debugging":{
"cznic-resolver-unbound:val-override-date": "2018-10-28T13:15:30Z"
},
"dns64": {
"prefix": "64:ff9b::/96"
}
......
......@@ -22,6 +22,7 @@ class Converter:
self.logging = {}
self.dnssec = {'trust-anchors': {}, 'negative-trust-anchors': []}
self.cache = {}
self.debugging = {}
self.dns64 = {}
self.stub = {}
......@@ -39,7 +40,7 @@ class Converter:
ipv4_addr = compile('^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$')
# TODO: not working very well, for example 20001:503:ba3e::2:30 and 20001:503:ba3e::::2:30 are allowe
# TODO: not working very well, for example 20001:503:ba3e::2:30 and 20001:503:ba3e::::2:30 are allowed
ipv6_addr = compile('^(((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
......@@ -173,9 +174,9 @@ class Converter:
def _harden_glue(self, key: str, value: str) -> None:
if value == 'yes':
self.resolver['options']['glue-checking'] = "strict"
self.resolver['options']['glue-checking'] = True
elif value == 'no':
self.resolver['options']['glue-checking'] = "normal"
self.resolver['options']['glue-checking'] = False
else:
raise UnboundConfValueError("Value: '{0}' of '{1}' option is not Valid: "
"Must be 'yes' or 'no'".format(value, key))
......@@ -239,6 +240,14 @@ class Converter:
def _cache_maxttl(self, key: str, value: str) -> None:
self.cache['max-ttl'] = int(value)
def _date_override(self, key: str, value: str) -> None:
utc_datetime = value[:4] + '-' + value[4:6] + '-' \
+ value[6:8] + 'T' + value[8:10] \
+ ':' + value[10:12] + ':' + value[12:] + 'Z'
self.debugging['cznic-resolver-unbound:val-override-date'] = utc_datetime
def _dns64_prefix(self, key: str, value: str) -> None:
if Converter.ipv6_prefix.match(value):
self.dns64['prefix'] = str(value)
......@@ -307,7 +316,7 @@ class Converter:
def _noop(self, key: str, value: str) -> None:
if not value.strip() == "":
raise UnboundConfValueError("Unknown Unbound Configuration Option.")
raise UnboundConfValueError("Unknown Unbound Configuration Option. {} {}" .format(key, value))
def _recursion_transport(self):
l2_protocols = 'ipv4 ipv6'
......@@ -381,6 +390,8 @@ class Converter:
data['dnssec'] = self.dnssec
if self.cache:
data['cache'] = self.cache
if self.debugging:
data['debugging'] = self.debugging
if self.dns64:
data['dns64'] = self.dns64
......@@ -409,6 +420,7 @@ class Converter:
"msg-cache-size": "_cache_size",
"cache-max-ttl": "_cache_maxttl",
"cache-min-ttl": "_cache_minttl",
"val-override-date": "_date_override",
"dns64-prefix": "_dns64_prefix",
}
......
......@@ -2,7 +2,7 @@
Module for generating Unbound and Knot Resolver configuration files from valid loaded Json.
"""
from re import compile
from re import compile, sub
from socket import gethostbyname
ip_address = compile('^((\d{1,3}\.){3}\d{1,3})|(([\dA-Fa-f]{1,4})|(:)|(:[\dA-Fa-f]{1,4})){2,7}[\dA-Fa-f]$')
......@@ -170,30 +170,35 @@ class Generator:
if 'root-zone-file' in resolver_conf['hints']:
rzf_path = resolver_conf['hints']['root-zone-file']
# rzf_path = sub('resolver', 'knot-resolver', str(rzf_path))
self.kresd_conf += str("hints.root_file('{0}')\n".format(rzf_path))
# options
if 'options' in resolver_conf:
# glue-checking
if 'glue-checking' in resolver_conf['options']:
self.kresd_conf += str("mode('{}')\n".format(resolver_conf['options']['glue-checking']))
if bool(resolver_conf['options']['glue-checking']) == True:
self.kresd_conf += str("mode('strict')\n")
else:
self.kresd_conf += str("mode('normal')\n")
# qname-minimisation
if 'qname-minimisation' in resolver_conf['options']:
if resolver_conf['options']['qname-minimisation']:
if bool(resolver_conf['options']['qname-minimisation']) == True:
self.kresd_conf += "option('NO_MINIMIZE', false)\n"
else:
self.kresd_conf += "option('NO_MINIMIZE', true)\n"
# reorder-rrset
if 'reorder-rrset' in resolver_conf['options']:
if resolver_conf['options']['reorder-rrset']:
if bool(resolver_conf['options']['reorder-rrset']) == True:
self.kresd_conf += str("reorder_RR(true)\n")
else:
self.kresd_conf += str("reorder_RR(false)\n")
# query-loopback
if 'query-loopback' in resolver_conf['options']:
if resolver_conf['options']['query-loopback']:
if bool(resolver_conf['options']['query-loopback']) == True:
self.kresd_conf += "option('ALLOW_LOCAL', true)\n"
else:
self.kresd_conf += "option('ALLOW_LOCAL', false)\n"
......@@ -220,7 +225,7 @@ class Generator:
# read-only
if 'read-only' in kf:
self.kresd_conf += str("trust_anchors.add_file('{0}',{1})\n".format(kf['file'],
kf['read-only']))
kf['read-only']))
else:
self.kresd_conf += str("trust_anchors.add_file('{0}')\n".format(kf['file']))
......@@ -277,9 +282,10 @@ class Generator:
temp += ", \n"
temp += "\t['" + str(origin) + "'] = {\n" \
"\t\turl = '" + str(url) + "', \n" \
"\t\tca_file = '" + str(ca) + "', \n" \
"\t\tinterval = " + str(interval) + "\n\t}"
"\t\turl = '" + str(url) + "', \n" \
"\t\tca_file = '" + str(ca) + "', \n" \
"\t\tinterval = " + str(
interval) + "\n\t}"
self.kresd_conf += "prefill.config({\n" + temp + "\n})\n"
......@@ -308,7 +314,7 @@ class Generator:
def _resolver_hostsfile_kresd(self, hostsfile_conf: dict):
self.kresd_conf += "hints.add_hosts({0})\n".format(hostsfile_conf)
########### UNBOUND ###########
########### UNBOUND COMMON ###########
def _network_unbound(self, network_conf: dict) -> None:
# listen-interfaces
......@@ -423,34 +429,35 @@ class Generator:
# root-zone-file
if 'root-zone-file' in resolver_conf['hints']:
rzf_path = resolver_conf['hints']['root-zone-file']
# rzf_path = sub('resolver', 'unbound', str(rzf_path))
self.server_unbound_conf += ("\troot-hints: \"{}\"\n".format(rzf_path))
# options
if 'options' in resolver_conf:
# glue-checking
if 'glue-checking' in resolver_conf['options']:
if str(resolver_conf['options']['glue-checking']) == "strict":
if bool(resolver_conf['options']['glue-checking']) == True:
self.server_unbound_conf += str("\tharden-glue: yes\n")
else:
self.server_unbound_conf += str("\tharden-glue: no\n")
# qname-minimisation
if 'qname-minimisation' in resolver_conf['options']:
if resolver_conf['options']['qname-minimisation']:
if bool(resolver_conf['options']['qname-minimisation']) == True:
self.server_unbound_conf += str("\tqname-minimisation: yes\n")
else:
self.server_unbound_conf += str("\tqname-minimisation: no\n")
# reorder-rrset
if 'reorder-rrset' in resolver_conf['options']:
if resolver_conf['options']['reorder-rrset']:
if bool(resolver_conf['options']['reorder-rrset']) == True:
self.server_unbound_conf += str("\trrset-roundrobin: yes\n")
else:
self.server_unbound_conf += str("\trrset-roundrobin: no\n")
# query-loopback
if 'query-loopback' in resolver_conf['options']:
if resolver_conf['options']['query-loopback']:
if bool(resolver_conf['options']['query-loopback']) == True:
self.server_unbound_conf += str("\tdo-not-query-localhost: no\n")
else:
self.server_unbound_conf += str("\tdo-not-query-localhost: yes\n")
......@@ -497,6 +504,15 @@ class Generator:
if 'prefix' in dns64_conf:
self.server_unbound_conf += str("\tdns64-prefix: {}\n".format(dns64_conf['prefix']))
########### UNBOUND ONLY ###########
def _debugging_unbound(self, debugging_conf: dict) -> None:
if 'cznic-resolver-unbound:val-override-date' in debugging_conf:
rrsig_date = str(debugging_conf['cznic-resolver-unbound:val-override-date'])
rrsig_date = sub("-|:|Z|T", "", rrsig_date)
self.server_unbound_conf += str("\tval-override-date: \"{}\"\n".format(rrsig_date))
def generate_unbound(self, data: dict):
"""
:param data: data loaded from Json and Validated with Data Model
......@@ -506,23 +522,37 @@ class Generator:
"""
self.__reset_unbound_conf()
data = data["cznic-resolver-common:dns-resolver"]
if 'network' in data:
self._network_unbound(data['network'])
if 'server' in data:
self._server_unbound(data['server'])
if 'resolver' in data:
self._resolver_unbound(data['resolver'])
if 'logging' in data:
self._logging_unbound(data['logging'])
if 'dnssec' in data:
self._dnssec_unbound(data['dnssec'])
if 'cache' in data:
self._cache_unbound(data['cache'])
if 'dns64' in data:
self._dns64_unbound(data['dns64'])
resolver_conf = {}
resolve_record = {}
if 'cznic-resolver-common:dns-resolver' in data:
resolver_conf = data["cznic-resolver-common:dns-resolver"]
if 'cznic-resolver-common:resolve' in data:
resolve_record = data["cznic-resolver-common:dns-resolver"]
if 'network' in resolver_conf:
self._network_unbound(resolver_conf['network'])
if 'server' in resolver_conf:
self._server_unbound(resolver_conf['server'])
if 'resolver' in resolver_conf:
self._resolver_unbound(resolver_conf['resolver'])
if 'logging' in resolver_conf:
self._logging_unbound(resolver_conf['logging'])
if 'dnssec' in resolver_conf:
self._dnssec_unbound(resolver_conf['dnssec'])
if 'cache' in resolver_conf:
self._cache_unbound(resolver_conf['cache'])
if 'debugging' in resolver_conf:
self._debugging_unbound(resolver_conf['debugging'])
if 'dns64' in resolver_conf:
self._dns64_unbound(resolver_conf['dns64'])
# if 'cznic-resolver-common:class' in resolve_record:
# self._dns64_unbound(resolver_conf['cznic-resolver-common:class'])
# if 'cznic-resolver-common:name' in resolve_record:
# self._dns64_unbound(resolver_conf['cznic-resolver-common:name'])
# if 'cznic-resolver-common:type' in resolve_record:
# self._dns64_unbound(resolver_conf['cznic-resolver-common:type'])
unbound_conf = self.server_unbound_conf + self.stub_unbound_conf
......@@ -556,5 +586,3 @@ class Generator:
self._dns64_kresd(data['dns64'])
return self.kresd_conf
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment