Library Usage¶
For better understanding, look at the Examples and Yangson library
Yangson¶
Yangson is a Python3 library for working with JSON-encoded [RFC7951] configuration and state data modelled using the YANG [RFC7895] data modelling language. Here Yangson is used to work with data model and validate loaded Json data against it.
Import necessary python modules.
>>> from json import load
>>> from yangson.datamodel import DataModel
Initialize the YANG data model. It can be done easily by reading YANG library data [RFC7895] from a file:
>>> model = DataModel.from_file('../yang-modules/yanglib.json', ["../yang-modules"])
Load data from Json-encoded file [RFC7951]
>>> with open('example-data.json') as infile:
... ri = load(infile)
>>> json_data = model.from_raw(ri)
Validate data against the data model:
>>> json_data.validate()
>>> json_data = json_data.add_defaults()
Now the data are valid and you can work with it.
Resolvers-YANG¶
YANG modules¶
yang-modules/
├── cznic-deckard.yang
├── cznic-deckard.yinx
├── cznic-dns-parameters.yang
├── cznic-dns-parameters.yinx
├── cznic-dns-rdata.yang
├── cznic-dns-rdata.yinx
├── cznic-resolver-common.yang
├── cznic-resolver-common.yinx
├── cznic-resolver-knot.yang
├── cznic-resolver-knot.yinx
├── cznic-resolver-unbound.yang
├── cznic-resolver-unbound.yinx
├── iana-dns-class-rr-type.yang
├── ietf-inet-types@2013-07-15.yang
├── ietf-netconf-acm@2012-02-22.yang
├── ietf-yang-library@2016-06-21.yang
├── ietf-yang-types@2013-07-15.yang
├── Makefile
├── model.tree
├── yanglib-deckard.json
└── yanglib.json
Library¶
resolvers_yang/
├── __init__.py
├── kresd/
│ ├── __init__.py
│ └── kresd_conf_gen.py
├── unbound/
| ├── __init__.py
| ├── unbound_conf_gen.py
| └── unbound_conf_loader.py
├── errors.py
├── parser.py
└── regex.py
Knot-Resolver modules¶
kresd_conf_gen.py¶
Import kresd.kresd_conf_gen
module which contains generate
function to generate Knot-Resolver configuration strings from valid python dictionary loaded from Json. Returns string.
>>> from resolvers_yang.kresd import kresd_conf_gen
Call kresd_conf_gen.generate()
functions to create kresd_conf string.
>>> kresd_conf = kresd_conf_gen.generate(json_data)
>>> print(kresd_conf)
net = {'127.0.0.1@53', '::1@53', '198.51.100.1@8853'}
net.outgoing_v6('2001:db8:0:2::1')
net.ipv6 = true
net.ipv4 = true
net.bufsize(4096)
user('jetconf','wheel')
modules.load('hints')
hints.set("localhost 127.0.0.1")
hints.set("localhost ::1")
hints.set("loopback 127.0.0.1")
hints.add_hosts('/etc/hosts')
hints.root({['a.root-servers.net'] = {'198.41.0.4', '2001:503:ba3e::2:30'}})
hints.root_file('/etc/resolver/root.hints')
mode('strict')
option('NO_MINIMIZE', false)
reorder_RR(true)
option('ALLOW_LOCAL', true)
verbose(true)
trust_anchors.add('. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5')
trust_anchors.add('. IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D')
trust_anchors.add('. IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0=')
trust_anchors.negative = {'bad.example.com', 'worse.example.com'}
cache.open(104857600)
cache.max_ttl(172800)
cache.min_ttl(0)
modules.load('prefill')
prefill.config({['.'] = {url = 'https://www.internic.net/domain/root.zone', ca_file = '/etc/pki/tls/certs/ca-bundle.crt', interval = 86400}})
modules = {dns64 = '64:ff9b::'}
Unbound modules¶
unbound_conf_gen.py¶
Import unbound.unbound_conf_gen
module which contains generate
function to generate Unbound configuration strings from valid python dictionary loaded from Json. Returns string.
>>> from resolvers_yang.unbound import unbound_conf_gen
Call unbound_conf_gen.generate()
functions to create unbound_conf string.
>>> unbound_conf = unbound_conf_gen.generate(json_data)
>>> print(unbound_conf)
server:
interface: 127.0.0.1@53
interface: ::1@53
interface: 198.51.100.1@8853
outgoing-interface: 2001:db8:0:2::1
do-ip6: yes
do-ip4: yes
edns-buffer-size: 4096
username: "jetconf"
verbosity: 2
trust-anchor: ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5"
trust-anchor: ". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D"
trust-anchor: ". IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0="
domain-insecure: "bad.example.com"
domain-insecure: "worse.example.com"
msg-cache-size: 104857600
cache-max-ttl: 172800
cache-min-ttl: 0
val-override-date: "20181028131530"
dns64-prefix: 64:ff9b::/96
root-hints: "/etc/resolver/root.hints"
harden-glue: yes
qname-minimisation: yes
rrset-roundrobin: yes
do-not-query-localhost: no
stub-zone:
name: "stub.example.com"
stub-addr: "192.0.2.1@53"
stub-zone:
name: "stub.example.net"
stub-addr: "198.51.100.1@53"
unbound_conf
and kresd_conf
are raw strings , which can be save as text files.
>>> with open("unbound.conf", "w") as unb_file:
... unb_file.write(unbound_conf)
1264
unbound_conf_loader.py¶
Import unbound.unbound_conf_loader
class which contains load
function for loading Unbound configuration string to python dictionary, which can be validate against resolvers-yang data model and save as Json file.
>>> from resolvers_yang.unbound import unbound_conf_loader
Input parameter of load
function is string loaded from unbound.conf
file. Returns python dictionary.
>>> with open("unbound.conf", "r") as unb_file:
... unbconf_data = unb_file.read()
Call load
function to load configuration string to dictionary.
>>> json_data = unbound_conf_loader.load(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': True, 'qname-minimisation': True, 'reorder-rrset': True, 'query-loopback': True}, 'hints': {'root-zone-file': '/etc/resolver/root.hints'}}, 'logging': {'verbosity': 2}, 'dnssec': {'trust-anchors': [{'domain': '.', 'auto-update': True, 'trust-anchor': [{'id': 0, 'ds': {'algorithm': 'RSASHA256', 'digest': '49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5', 'digest-type': 'SHA-256', 'key-tag': 19036}}, {'id': 1, 'ds': {'algorithm': 'RSASHA256', 'digest': 'E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D', 'digest-type': 'SHA-256', 'key-tag': 20326}}, {'id': 2, 'dnskey': {'algorithm': 'RSASHA256', 'flags': 'ZONE SEP', 'protocol': 3, 'public-key': 'AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0='}}]}], '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 saved to Json-encoded file.
>>> model_data = model.from_raw(json_data)
>>> model_data.validate()
>>> from json import dump
>>> with open("unbound-data.json", 'w') as json_file:
... dump(json_data, json_file, indent=2, sort_keys=False)