+{% from 'macros/common_macros.lua.j2' import modules_load, cache_prefill_config, cache_predict_config %}
+{% from 'macros/cache_macros.lua.j2' import prefill_config, predict_config %}
+
+--------------------------------------------------------------------------------
+-- CACHE configuration
+--------------------------------------------------------------------------------
+
cache.open({{ cfg.cache.size_max.bytes() }}, 'lmdb://{{ cfg.cache.storage }}')
cache.min_ttl({{ cfg.cache.ttl_min.seconds() }})
cache.max_ttl({{ cfg.cache.ttl_max.seconds() }})
{% if cfg.cache.prefill %}
-- cache.prefill
-modules.load('prefill')
-prefill.config({
-{% for item in cfg.cache.prefill %}
- ['{{ item.origin.punycode() }}'] = {
- url = '{{ item.url }}',
- interval = {{ item.refresh_interval.seconds() }}
- {{ "ca_file = '"+item.ca_file+"'," if item.ca_file }}
- }
-{% endfor %}
-})
+{{ modules_load('prefill') }}
+{{ prefill_config(cfg.cache.prefill) }}
{% endif %}
{% if cfg.cache.prediction %}
-- cache.prediction
-modules.load('predict')
-predict.config({
- window = {{ cfg.cache.prediction.window.minutes() }},
- period = {{ cfg.cache.prediction.period }},
-})
-{% endif %}
+{{ modules_load('predict') }}
+{{ predict_config(cfg.cache.prediction) }}
+{% endif %}
\ No newline at end of file
+{% from 'macros/common_macros.lua.j2' import quotes, modules_load %}
+
{% if not cfg.lua.script_only %}
-- FFI library
local C = ffi.C
-- hostname
-hostname('{{ cfg.hostname }}')
+hostname({{ quotes(cfg.hostname) }})
{% if cfg.nsid %}
-- nsid
-modules.load('nsid')
-nsid.name('{{ cfg.nsid }}' .. worker.id)
+{{ modules_load('nsid') }}
+nsid.name({{ quotes(cfg.nsid) }} .. worker.id)
{% endif %}
--- LOGGING section ----------------------------------
{% include "logging.lua.j2" %}
--- MONITORING section -------------------------------
{% include "monitoring.lua.j2" %}
--- WEBMGMT section ----------------------------------
{% include "webmgmt.lua.j2" %}
--- OPTIONS section ----------------------------------
{% include "options.lua.j2" %}
--- NETWORK section ----------------------------------
{% include "network.lua.j2" %}
--- VIEWS section ------------------------------------
{% include "views.lua.j2" %}
--- DNSSEC section -----------------------------------
{% include "dnssec.lua.j2" %}
--- LOCAL-DATA section -------------------------------
{% include "local_data.lua.j2" %}
--- FORWARD section ----------------------------------
{% include "forward.lua.j2" %}
--- CACHE section ------------------------------------
{% include "cache.lua.j2" %}
--- DNS64 section ------------------------------------
{% include "dns64.lua.j2" %}
{% endif %}
--- LUA section --------------------------------------
--- Custom Lua code cannot be validated
+{% if cfg.lua.script_file or cfg.lua.script%}
+--------------------------------------------------------------------------------
+-- LUA custom script
+--------------------------------------------------------------------------------
+-- Additional lua code that cannot be validated.
{% if cfg.lua.script_file %}
-{% import cfg.lua.script_file as script_file %}
-{{ script_file }}
-{% endif %}
-
-{% if cfg.lua.script %}
+{% import cfg.lua.script_file as file_script %}
+{{ file_script }}
+{% elif cfg.lua.script %}
{{ cfg.lua.script }}
{% endif %}
+{% endif %}
\ No newline at end of file
-{% from 'macros/common_macros.lua.j2' import string_table %}
+{% from 'macros/common_macros.lua.j2' import modules_load %}
+{% from 'macros/dns64_macros.lua.j2' import dns64_config %}
{% if cfg.dns64 %}
--- load dns64 module
-modules.load('dns64')
+--------------------------------------------------------------------------------
+-- DNS64 configuration
+--------------------------------------------------------------------------------
--- dns64.prefix
-dns64.config({
- prefix = '{{ cfg.dns64.prefix.to_std().network_address|string }}',
-{% if cfg.dns64.rev_ttl %}
- rev_ttl = {{ cfg.dns64.rev_ttl.seconds() }},
+{{ modules_load('dns64') }}
+{{ dns64_config(cfg.dns64) }}
{% endif %}
-{% if cfg.dns64.exclude_subnets %}
- exclude_subnets = {{ string_table(cfg.dns64.exclude_subnets) }},
-{% endif %}
-})
-{% endif %}
\ No newline at end of file
-{% from 'macros/common_macros.lua.j2' import boolean %}
+{% from 'macros/common_macros.lua.j2' import boolean, module_loader %}
+{% from 'macros/dnssec_macros.lua.j2' import trust_anchors, negative_trust_anchors, trust_anchors_files %}
-{% if not cfg.dnssec %}
--- disable dnssec
-trust_anchors.remove('.')
-{% endif %}
+--------------------------------------------------------------------------------
+-- DNSSEC configuration
+--------------------------------------------------------------------------------
--- options.trust-anchor-sentinel
-{% if cfg.dnssec.trust_anchor_sentinel %}
-modules.load('ta_sentinel')
+{% if cfg.dnssec is false %}
+-- DNSSEC is disabled
+trust_anchors.remove('.')
{% else %}
-modules.unload('ta_sentinel')
-{% endif %}
+-- dnssec.trust-anchor-sentinel
+{{ module_loader(cfg.dnssec.trust_anchor_sentinel, 'ta_sentinel') }}
--- options.trust-anchor-signal-query
-{% if cfg.dnssec.trust_anchor_signal_query %}
-modules.load('ta_signal_query')
-{% else %}
-modules.unload('ta_signal_query')
-{% endif %}
+-- dnssec.trust-anchor-signal-query
+{{ module_loader(cfg.dnssec.trust_anchor_signal_query, 'ta_signal_query') }}
--- options.time-skew-detection
-{% if cfg.dnssec.time_skew_detection %}
-modules.load('detect_time_skew')
-{% else %}
-modules.unload('detect_time_skew')
-{% endif %}
+-- dnssec.time-skew-detection
+{{ module_loader(cfg.dnssec.time_skew_detection, 'detect_time_skew') }}
-- dnssec.keep-removed
trust_anchors.keep_removed = {{ cfg.dnssec.keep_removed }}
{% if cfg.dnssec.trust_anchors %}
-- dnssec.trust-anchors
-{% for ta in cfg.dnssec.trust_anchors %}
-trust_anchors.add('{{ ta }}')
-{% endfor %}
+{{ trust_anchors(cfg.dnssec.trust_anchors) }}
{% endif %}
{% if cfg.dnssec.negative_trust_anchors %}
-- dnssec.negative-trust-anchors
-trust_anchors.set_insecure({
-{% for nta in cfg.dnssec.negative_trust_anchors %}
- '{{ nta }}',
-{% endfor %}
-})
+{{ negative_trust_anchors(cfg.dnssec.negative_trust_anchors) }}
{% endif %}
{% if cfg.dnssec.trust_anchors_files %}
-- dnssec.trust-anchors-files
-{% for taf in cfg.dnssec.trust_anchors_files %}
-trust_anchors.add_file('{{ taf.file }}', readonly = {{ boolean(taf.read_only) }})
-{% endfor %}
+{{ trust_anchors_files(cfg.dnssec.trust_anchors_files) }}
+{% endif %}
{% endif %}
\ No newline at end of file
-{% from 'macros/forward_macros.lua.j2' import policy_rule_forward_add %}
+{% from 'macros/forward_macros.lua.j2' import forward %}
{% if cfg.forward %}
+--------------------------------------------------------------------------------
+-- FORWARD configuration
+--------------------------------------------------------------------------------
+
{% for fwd in cfg.forward %}
-{% for subtree in fwd.subtree %}
-{{ policy_rule_forward_add(subtree,fwd.options,fwd.servers) }}
-{% endfor %}
+{{ forward(fwd) }}
{% endfor %}
{% endif %}
{% from 'macros/local_data_macros.lua.j2' import local_data_rules, local_data_records, local_data_root_fallback_addresses, local_data_root_fallback_addresses_files, local_data_addresses, local_data_addresses_files %}
-{% from 'macros/common_macros.lua.j2' import boolean %}
+{% from 'macros/common_macros.lua.j2' import boolean, modules_load %}
-modules = { 'hints > iterate' }
+--------------------------------------------------------------------------------
+-- LOCAL-DATA configuration
+--------------------------------------------------------------------------------
+
+-- load 'hints' module
+{{ modules_load('hints > iterate') }}
-{# root-fallback-addresses #}
{% if cfg.local_data.root_fallback_addresses -%}
+-- local-data.root-fallback-addresses
{{ local_data_root_fallback_addresses(cfg.local_data.root_fallback_addresses) }}
{%- endif %}
-{# root-fallback-addresses-files #}
-{% if cfg.local_data.root_fallback_addresses_files -%}
+{% if cfg.local_data.root_fallback_addresses_files %}
+-- local-data.root-fallback-addresses-files
{{ local_data_root_fallback_addresses_files(cfg.local_data.root_fallback_addresses_files) }}
{%- endif %}
-{# addresses #}
-{% if cfg.local_data.addresses -%}
+{% if cfg.local_data.addresses %}
+-- local-data.addresses
{{ local_data_addresses(cfg.local_data.addresses, cfg.local_data.nodata, cfg.local_data.ttl) }}
-{%- endif %}
+{% endif %}
-{# addresses-files #}
-{% if cfg.local_data.addresses_files -%}
+{% if cfg.local_data.addresses_files %}
+-- local-data.addresses-files
{{ local_data_addresses_files(cfg.local_data.addresses_files, cfg.local_data.nodata, cfg.local_data.ttl) }}
-{%- endif %}
+{% endif %}
-{# records #}
-{% if cfg.local_data.records -%}
+{% if cfg.local_data.records %}
+-- local-data.records
{{ local_data_records(cfg.local_data.records, false, cfg.local_data.nodata, cfg.local_data.ttl) }}
-{%- endif %}
+{% endif %}
-{# rules #}
-{% if cfg.local_data.rules -%}
+{% if cfg.local_data.rules %}
+-- local-data.rules
{{ local_data_rules(cfg.local_data.rules, cfg.local_data.nodata, cfg.local_data.ttl) }}
-{%- endif %}
+{% endif %}
-{# rpz #}
-{% if cfg.local_data.rpz -%}
+{% if cfg.local_data.rpz %}
+-- local-data.rpz
{% for rpz in cfg.local_data.rpz %}
{{ local_data_records(rpz.file, true, cfg.local_data.nodata, cfg.local_data.ttl, rpz.tags) }}
{% endfor %}
-{%- endif %}
+{% endif %}
-{% from 'macros/common_macros.lua.j2' import boolean %}
+{% from 'macros/common_macros.lua.j2' import boolean, modules_load, module_loader %}
+{% from 'macros/logging_macros.lua.j2' import logging_groups, logging_dnstap %}
+
+--------------------------------------------------------------------------------
+-- LOGGING configuration
+--------------------------------------------------------------------------------
-- logging.level
log_level('{{ cfg.logging.level }}')
-{% if cfg.logging.target -%}
-- logging.target
log_target('{{ cfg.logging.target }}')
-{%- endif %}
{% if cfg.logging.groups %}
-- logging.groups
-log_groups({
-{% for g in cfg.logging.groups %}
-{% if g != "manager" and g != "supervisord" %}
- '{{ g }}',
-{% endif %}
-{% endfor %}
-})
+{{ logging_groups(cfg.logging.groups) }}
{% endif %}
-{% if cfg.logging.dnssec_bogus %}
-modules.load('bogus_log')
-{% endif %}
+-- logging.dnssec-bogus
+{{ module_loader(cfg.logging.dnssec_bogus, 'bogus_log') }}
{% if cfg.logging.dnstap -%}
-- logging.dnstap
-modules.load('dnstap')
-dnstap.config({
- socket_path = '{{ cfg.logging.dnstap.unix_socket }}',
- client = {
- log_queries = {{ boolean(cfg.logging.dnstap.log_queries) }},
- log_responses = {{ boolean(cfg.logging.dnstap.log_responses) }},
- log_tcp_rtt = {{ boolean(cfg.logging.dnstap.log_tcp_rtt) }}
- }
-})
+{{ modules_load('dnstap') }}
+{{ logging_dnstap(cfg.logging.dnstap) }}
{%- endif %}
-- logging.debugging.assertion-abort
--- /dev/null
+{% from 'macros/common_macros.lua.j2' import quotes %}
+
+{% macro prefill_config(config) -%}
+prefill.config({
+{% for item in config %}
+ [{{ quotes(item.origin.punycode()) }}] = {
+ url = {{ quotes(item.url) }},
+ interval = {{ item.refresh_interval.seconds() }},
+{% if item.ca_file %}
+ ca_file = {{ quotes(item.ca_file) }},
+{% endif %}
+ }
+{% endfor %}
+})
+{%- endmacro %}
+
+
+{% macro predict_config(config) -%}
+predict.config({
+ window = {{ config.window.minutes() }},
+ period = {{ config.period }},
+})
+{%- endmacro %}
{% macro quotes(string) -%}
-'{{ string }}'
+'{{ string|string }}'
{%- endmacro %}
-{% macro boolean(val, negation=false) -%}
-{%- if negation -%}
-{{ 'false' if val else 'true' }}
-{%- else-%}
-{{ 'true' if val else 'false' }}
+
+{% macro boolean(bool, negation=false) -%}
+{%- if bool in [true, 1] -%}
+{{ 'false' if negation else 'true' }}
+{%- elif bool in [false, 0]-%}
+{{ 'true' if negation else 'false' }}
+{%- else -%}
+{# raise some ERROR #}
{%- endif -%}
{%- endmacro %}
-{# Return string or table of strings #}
-{% macro string_table(table) -%}
-{%- if table is string -%}
-'{{ table|string }}'
-{%- elif table -%}
-{
-{%- for item in table -%}
-'{{ item|string }}',
-{%- endfor -%}
-}
-{%- endif -%}
+
+{# MODULES #}
+
+{% macro modules_load(module_name) -%}
+modules.load({{ quotes(module_name) }})
{%- endmacro %}
-{# Return str2ip or table of str2ip #}
-{% macro str2ip_table(table) -%}
-{%- if table is string -%}
-kres.str2ip('{{ table|string }}')
-{%- else-%}
-{
-{%- for item in table -%}
-kres.str2ip('{{ item|string }}'),
-{%- endfor -%}
-}
-{%- endif -%}
+
+{% macro modules_unload(module_name) -%}
+modules.unload({{ quotes(module_name) }})
{%- endmacro %}
-{# Return qtype or table of qtype #}
-{% macro qtype_table(table) -%}
-{%- if table is string -%}
-kres.type.{{ table|string }}
-{%- else-%}
-{
-{%- for item in table -%}
-kres.type.{{ item|string }},
-{%- endfor -%}
-}
+
+{% macro module_loader(bool, module_name) -%}
+{%- if bool is true -%}
+{{ modules_load(module_name) }}
+{%- elif bool is false -%}
+{{ modules_load(module_name) }}
+{{ modules_unload(module_name) }}
+{%- else -%}
+{# raise some ERROR #}
{%- endif -%}
{%- endmacro %}
-{# Return server address or table of server addresses #}
-{% macro servers_table(servers) -%}
-{%- if servers is string -%}
-'{{ servers|string }}'
-{%- else-%}
+
+{# TABLES #}
+
+{% macro table_or_string(val) -%}
+{%- if val is string -%}
+{{ quotes(val) }}
+{%- elif val is iterable -%}
{
-{%- for item in servers -%}
-{%- if item.address is defined -%}
-'{{ item.address|string }}',
-{%- else -%}
-'{{ item|string }}',
-{%- endif -%}
+{%- for item in val -%}
+{{ quotes(item) }},
{%- endfor -%}
}
+{%- else -%}
+{# raise some ERROR #}
{%- endif -%}
{%- endmacro %}
-{# Return server address or table of server addresses #}
-{% macro tls_servers_table(servers) -%}
+
+{% macro table_or_str2ip(val) -%}
+{%- if val is string -%}
+kres.str2ip({{ quotes(val) }})
+{%- elif val is iterable -%}
{
-{%- for item in servers -%}
-{%- if item.address is defined-%}
-{'{{ item.address|string }}',{{ tls_server_auth(item) }}},
-{%- else -%}
-'{{ item|string }}',
-{%- endif -%}
+{%- for item in val -%}
+kres.str2ip({{ quotes(item) }}),
{%- endfor -%}
}
+{%- else -%}
+{# raise some ERROR #}
+{%- endif -%}
{%- endmacro %}
-{% macro tls_server_auth(server) -%}
-{%- if server.hostname -%}
-hostname='{{ server.hostname|string }}',
-{%- endif -%}
-{%- if server.ca_file -%}
-ca_file='{{ server.ca_file|string }}',
-{%- endif -%}
-{%- if server.pin_sha256 -%}
-pin_sha256=
-{%- if server.pin_sha256 is string -%}
-'{{ server.pin_sha256|string }}',
-{%- else -%}
+
+{% macro table_or_qtype(val) -%}
+{%- if val is string -%}
+kres.type.{{ val|string }}
+{%- elif val is iterable -%}
{
-{%- for pin in server.pin_sha256 -%}
-'{{ pin|string }}',
+{%- for item in val -%}
+kres.type.{{ item|string }},
{%- endfor -%}
}
+{%- else -%}
+{# raise some ERROR #}
{%- endif -%}
-{%- endif -%}
-{%- endmacro %}
+{%- endmacro %}
\ No newline at end of file
--- /dev/null
+{% from 'macros/common_macros.lua.j2' import quotes, table_or_string %}
+
+{%- macro dns64_config(config) -%}
+dns64.config({
+ prefix = {{ quotes(config.prefix.to_std().network_address|string) }},
+{% if config.rev_ttl %}
+ rev_ttl = {{ config.rev_ttl.seconds() }},
+{% endif %}
+{% if config.exclude_subnets %}
+ exclude_subnets = {{ table_or_string(config.exclude_subnets) }},
+{% endif %}
+})
+{%- endmacro -%}
\ No newline at end of file
--- /dev/null
+{% from 'macros/common_macros.lua.j2' import quotes, boolean %}
+
+
+{% macro trust_anchors(tas) -%}
+{% for ta in tas %}
+trust_anchors.add({{ quotes(ta) }})
+{% endfor %}
+{%- endmacro %}
+
+
+{% macro negative_trust_anchors(ntas) -%}
+trust_anchors.set_insecure({
+{% for nta in ntas %}
+ {{ quotes(nta) }},
+{% endfor %}
+})
+{%- endmacro %}
+
+
+{% macro trust_anchors_files(tafs) -%}
+{% for taf in tafs %}
+trust_anchors.add_file({{ quotes(taf.file) }}, readonly = {{ boolean(taf.read_only) }})
+{% endfor %}
+{%- endmacro %}
\ No newline at end of file
-{% from 'macros/common_macros.lua.j2' import boolean, string_table %}
+{% from 'macros/common_macros.lua.j2' import quotes, boolean, table_or_string %}
+
{% macro forward_options(options) -%}
-{dnssec={{ boolean(options.dnssec) }},auth={{ boolean(options.authoritative) }}}
+{
+ dnssec = {{ boolean(options.dnssec) }},
+ auth = {{ boolean(options.authoritative) }}
+}
{%- endmacro %}
+
+{% macro forward_server_config(address, transport, hostname, pin_sha256, ca_file) -%}
+{
+ {{ quotes(address) }},
+ tls = {{ 'true' if transport == 'tls' else 'false' }},
+{% if hostname %}
+ hostname = {{ quotes(hostname) }},
+{% endif %}
+{% if pin_sha256 %}
+ pin_sha256 = {{ table_or_string(pin_sha256) }},
+{% endif %}
+{% if ca_file %}
+ ca_file = {{ quotes(ca_file) }},
+{% endif %}
+}
+{%- endmacro %}
+
+
{% macro forward_server(server) -%}
{% if server.address is defined %}
-{%- for addr in server.address -%}
-{'{{ addr }}',
-{%- if server.transport == 'tls' -%}
-tls=true,
-{%- else -%}
-tls=false,
-{%- endif -%}
-{%- if server.hostname -%}
-hostname='{{ server.hostname }}',
-{%- endif -%}
-{%- if server.pin_sha256 -%}
-pin_sha256={{ string_table(server.pin_sha256) }},
-{%- endif -%}
-{%- if server.ca_file -%}
-ca_file='{{ server.ca_file }}',
-{%- endif -%}
-},
-{%- endfor -%}
+{% for address in server.address %}
+{{ forward_server_config(address, server.transport, server.hostname, server.pin_sha256, server.ca_file) }},
+{% endfor %}
{% else %}
-{'{{ server }}'},
-{%- endif -%}
+{ {{ quotes(server) }} },
+{%- endif %}
{%- endmacro %}
-{% macro forward_servers(servers) -%}
+
+{% macro forward_servers(servers) %}
{
-{%- for server in servers -%}
-{{ forward_server(server) }}
-{%- endfor -%}
+{% for server in servers %}
+ {{ forward_server(server)|indent }}
+{% endfor %}
}
{%- endmacro %}
-{% macro policy_rule_forward_add(subtree,options,servers) -%}
-policy.rule_forward_add('{{ subtree }}',{{ forward_options(options) }},{{ forward_servers(servers) }})
+
+{% macro policy_rule_forward_add(subtree, options, servers) -%}
+policy.rule_forward_add(
+ {{ quotes(subtree) }},
+ {{ options|indent }},
+ {{ servers|indent }}
+)
{%- endmacro %}
+
+
+{% macro forward(fwd) -%}
+{% for subtree in fwd.subtree %}
+{{ policy_rule_forward_add(subtree, forward_options(fwd.options), forward_servers(fwd.servers)) }}
+{% endfor %}
+{%- endmacro %}
\ No newline at end of file
-{% from 'macros/common_macros.lua.j2' import string_table, boolean %}
+{% from 'macros/common_macros.lua.j2' import quotes, table_or_string, boolean %}
{% from 'macros/policy_macros.lua.j2' import policy_get_tagset, policy_todname %}
{% macro local_data_root_fallback_addresses(pairs) -%}
hints.root({
{% for name, addresses in pairs.items() %}
- ['{{ name }}']={{ string_table(addresses) }},
+ [{{ quotes(name) }}] = {{ table_or_string(addresses) }},
{% endfor %}
})
{%- endmacro %}
{% macro local_data_root_fallback_addresses_files(files) -%}
{% for file in files %}
-hints.root_file('{{ file }}')
+hints.root_file({{ quotes(file) }})
{% endfor %}
{%- endmacro %}
-{%- macro local_data_ttl(ttl) -%}
+
+{% macro local_data_ttl(ttl) -%}
{%- if ttl -%}
{{ ttl.seconds() }}
{%- else -%}
{{ 'C.KR_RULE_TTL_DEFAULT' }}
{%- endif -%}
-{%- endmacro -%}
+{%- endmacro %}
{% macro kr_rule_local_address(name, address, nodata, ttl, tags=none) -%}
-assert(C.kr_rule_local_address('{{ name }}', '{{ address }}',
+assert(C.kr_rule_local_address({{ quotes(name) }}, {{ quotes(address) }},
{{ boolean(nodata) }}, {{ local_data_ttl(ttl)}}, {{ policy_get_tagset(tags) }}) == 0)
{%- endmacro -%}
{% macro kr_rule_local_hosts(file, nodata, ttl, tags=none) -%}
-assert(C.kr_rule_local_hosts('{{ file }}', {{ boolean(nodata) }},
+assert(C.kr_rule_local_hosts({{ quotes(file) }}, {{ boolean(nodata) }},
{{ local_data_ttl(ttl)}}, {{ policy_get_tagset(tags) }}) == 0)
{%- endmacro %}
{{ local_data_records(item.records, false, nodata if item.nodata is none else item.nodata, item.ttl or ttl, tags) }}
{% endif %}
{% endfor %}
-{%- endmacro %}
+{%- endmacro %}
\ No newline at end of file
--- /dev/null
+{% from 'macros/common_macros.lua.j2' import boolean %}
+
+{% macro logging_groups(groups) -%}
+log_groups({
+{% for group in groups %}
+{% if group not in [ "manager", "supervisord" ] %}
+ '{{ group }}',
+{% endif %}
+{% endfor %}
+})
+{%- endmacro %}
+
+{% macro logging_dnstap(config) -%}
+dnstap.config({
+ socket_path = '{{ config.unix_socket }}',
+ client = {
+ log_queries = {{ boolean(config.log_queries) }},
+ log_responses = {{ boolean(config.log_responses) }},
+ log_tcp_rtt = {{ boolean(config.log_tcp_rtt) }}
+ }
+})
+{%- endmacro %}
\ No newline at end of file
--- /dev/null
+{% from 'macros/common_macros.lua.j2' import modules_load %}
+
+
+{% macro monitoring_control_socket() -%}
+--- control socket location
+local ffi = require('ffi')
+local id = os.getenv('SYSTEMD_INSTANCE')
+if not id then
+ log_error(ffi.C.LOG_GRP_SYSTEM, 'environment variable $SYSTEMD_INSTANCE not set, which should not have been possible due to running under manager')
+else
+ -- Bind to control socket in CWD (= rundir in config)
+ -- FIXME replace with relative path after fixing https://gitlab.nic.cz/knot/knot-resolver/-/issues/720
+ local path = '{{ cwd }}/control/'..id
+ log_warn(ffi.C.LOG_GRP_SYSTEM, 'path = ' .. path)
+ local ok, err = pcall(net.listen, path, nil, { kind = 'control' })
+ if not ok then
+ log_warn(ffi.C.LOG_GRP_NETWORK, 'bind to '..path..' failed '..err)
+ end
+end
+{%- endmacro %}
+
+
+{% macro monitoring_collect_lazy_statistics() -%}
+--- function used for statistics collection
+function collect_lazy_statistics()
+ if stats == nil then
+ modules.load('stats')
+ end
+ return tojson(stats.list())
+end
+{%- endmacro %}
+
+
+{% macro monitoring_collect_statistics() -%}
+--- function used for statistics collection
+function collect_statistics()
+ return tojson(stats.list())
+end
+{%- endmacro %}
\ No newline at end of file
-{% macro http_config(http_cfg, kind, tls=true) -%}
-http.config({tls={{ 'true' if tls else 'false'}},
-{%- if http_cfg.cert_file -%}
- cert='{{ http_cfg.cert_file }}',
-{%- endif -%}
-{%- if http_cfg.key_file -%}
- key='{{ http_cfg.key_file }}',
-{%- endif -%}
-},'{{ kind }}')
+{% from 'macros/common_macros.lua.j2' import boolean, quotes %}
+
+
+{% macro http_config(service_name=none, tls=false, cert_file=none, key_file=none) -%}
+http.config({
+ tls = {{ boolean(tls) }},
+{% if cert_file %}
+ cert = '{{ cert_file }}',
+{% endif %}
+{% if key_file %}
+ key = '{{ key_file }}',
+{% endif %}
+},
+{% if service_name %}
+'{{ service_name }}'
+{% endif %}
+)
{%- endmacro %}
{%- endmacro %}
-{% macro net_listen_unix_socket(path, kind, freebind) -%}
-net.listen('{{ path }}',nil,{kind={{ listen_kind(kind) }},freebind={{ 'true' if freebind else 'false'}}})
-{%- endmacro %}
+{% macro network_listen(listen) -%}
+{%- if listen.unix_socket -%}
+{% for path in listen.unix_socket %}
+{{ net_listen(quotes(path), 'nil', listen.kind, listen.freebind) }}
+{% endfor %}
+{%- elif listen.interface -%}
+{% for interface in listen.interface %}
+{%- set vars = {
+ 'interface': none,
+ 'port': listen.port
+ }
+-%}
-{% macro net_listen_interface(interface, kind, freebind, port) -%}
-net.listen(
{%- if interface.addr -%}
-'{{ interface.addr }}',
+{%- if vars.update({'interface': quotes(interface.addr)}) -%}{%- endif -%}
{%- elif interface.if_name -%}
-net.{{ interface.if_name }},
+{%- if vars.update({'interface': 'net.'+interface.if_name|string}) -%}{%- endif -%}
{%- endif -%}
+
{%- if interface.port -%}
-{{ interface.port }},
+{%- if vars.update({'port': interface.port}) -%}{%- endif -%}
+{%- endif -%}
+
+{{ net_listen(vars.interface, vars.port, listen.kind, listen.freebind) }}
+{% endfor %}
+{%- endif -%}
+{%- endmacro %}
+
+
+{% macro net_listen(interface, port='nil', kind='dns', freebind=false, nic_queue=none) -%}
+net.listen({{ interface }}, {{ port }}, {
+ kind = {{ listen_kind(kind) }},
+ freebind = {{ boolean(freebind) }},
+{% if nic_queue %}
+ nic_queue = {{ nic_queue }},
+{% endif %}
+})
+{%- endmacro %}
+
+
+{% macro net_tls(cert_file=none, key_file=none) -%}
+net.tls(
+{% if cert_file %}
+ cert_file = '{{ cert_file }}',
+{% endif %}
+{% if key_file %}
+ key_file = '{{ key_file }}',
+{% endif %}
+)
+{%- endmacro %}
+
+
+{% macro net_tls_padding(padding) -%}
+net.tls_padding(
+{%- if padding is true -%}
+true
+{%- elif padding is false -%}
+false
{%- else -%}
-{{ port }},
+{{ padding }}
{%- endif -%}
-{kind={{ listen_kind(kind) }},freebind={{ 'true' if freebind else 'false'}}})
+)
{%- endmacro %}
-{% macro network_listen(listen) -%}
-{%- if listen.unix_socket -%}
-{% for path in listen.unix_socket %}
-{{ net_listen_unix_socket(path, listen.kind, listen.freebind) }}
+{% macro proxy_allowed(proxy_protocol) -%}
+{% if proxy_protocol %}
+net.proxy_allowed({
+{% for item in proxy_protocol.allow %}
+ '{{ item }}',
{% endfor %}
-{%- elif listen.interface -%}
-{% for interface in listen.interface %}
-{{ net_listen_interface(interface, listen.kind, listen.freebind, listen.port) }}
+})
+{% else %}
+net.proxy_allowed({})
+{% endif %}
+{%- endmacro %}
+
+{% macro renumber_config(config) -%}
+renumber.config = {
+{% for item in config %}
+ {'{{ item.source }}', '{{ item.destination }}'},
{% endfor %}
+}
+{%- endmacro %}
+
+
+{% macro table_or_server(val) -%}
+{%- if val is string -%}
+{{ quotes(val) }}
+{%- elif val is iterable -%}
+{
+{%- for item in val -%}
+{%- if item.address is defined -%}
+{{ quotes(item.address) }},
+{%- elif item is string -%}
+{{ quotes(item) }},
+{%- else -%}
+{# raise some ERROR #}
+{%- endif -%}
+{%- endfor -%}
+}
+{%- else -%}
+{# raise some ERROR #}
+{%- endif -%}
+{%- endmacro %}
+
+
+{# Return server address or table of server addresses #}
+{% macro tls_servers_table(servers) -%}
+{
+{%- for item in servers -%}
+{%- if item.address is defined-%}
+{'{{ item.address|string }}',{{ tls_server_auth(item) }}},
+{%- else -%}
+'{{ item|string }}',
{%- endif -%}
-{%- endmacro %}
\ No newline at end of file
+{%- endfor -%}
+}
+{%- endmacro %}
+
+
+{% macro tls_server_auth(server) -%}
+{%- if server.hostname -%}
+hostname='{{ server.hostname|string }}',
+{%- endif -%}
+{%- if server.ca_file -%}
+ca_file='{{ server.ca_file|string }}',
+{%- endif -%}
+{%- if server.pin_sha256 -%}
+pin_sha256=
+{%- if server.pin_sha256 is string -%}
+'{{ server.pin_sha256|string }}',
+{%- else -%}
+{
+{%- for pin in server.pin_sha256 -%}
+'{{ pin|string }}',
+{%- endfor -%}
+}
+{%- endif -%}
+{%- endif -%}
+{%- endmacro %}
--- /dev/null
+{% from 'macros/common_macros.lua.j2' import boolean %}
+
+{% macro option(option_name, value, negation=false) -%}
+option('{{ option_name }}', {{ boolean(value, negation) }})
+{%- endmacro %}
\ No newline at end of file
-{% from 'macros/common_macros.lua.j2' import string_table, str2ip_table, qtype_table, servers_table, tls_servers_table %}
+{% from 'macros/common_macros.lua.j2' import table_or_string, table_or_str2ip, table_or_qtype %}
+{% from 'macros/common_macros.lua.j2' import table_or_server, tls_servers_table %}
{# Add policy #}
{% macro policy_flags(flags) -%}
policy.FLAGS({
-{{- flags -}}
+ {{ flags|indent }}
})
{%- endmacro %}
{# Tags assign #}
{% macro policy_tags_assign(tags) -%}
-policy.TAGS_ASSIGN({{ string_table(tags) }})
+policy.TAGS_ASSIGN({{ table_or_string(tags) }})
{%- endmacro %}
{% macro policy_get_tagset(tags) -%}
{%- if tags is defined-%}
-policy.get_tagset({{ string_table(tags) }})
+policy.get_tagset({{ table_or_string(tags) }})
{%- else -%}
0
{%- endif -%}
{%- elif filter.pattern -%}
{{ policy_pattern(action, filter.pattern) }}
{%- elif filter.qtype -%}
-{{ policy_qtype_custom_filter(action, qtype_table(filter.qtype)) }}
+{{ policy_qtype_custom_filter(action, table_or_qtype(filter.qtype)) }}
{%- else -%}
{{ policy_all(action) }}
{%- endif %}
{% macro policy_answer(answer) -%}
policy.ANSWER({[kres.type.{{ answer.rtype }}]={rdata=
{%- if answer.rtype in ['A','AAAA'] -%}
-{{ str2ip_table(answer.rdata) }},
+{{ table_or_str2ip(answer.rdata) }},
{%- elif answer.rtype == '' -%}
{# TODO: Do the same for other record types that require a special rdata type in Lua.
By default, the raw string from config is used. #}
{%- else -%}
-{{ string_table(answer.rdata) }},
+{{ table_or_string(answer.rdata) }},
{%- endif -%}
ttl={{ answer.ttl.seconds()|int }}}},{{ 'true' if answer.nodata else 'false' }})
{%- endmacro %}
{%- endmacro %}
{% macro policy_stub(servers) -%}
-policy.STUB({{ servers_table(servers) }})
+policy.STUB({{ table_or_server(servers) }})
{%- endmacro %}
{% macro policy_forward(servers) -%}
-policy.FORWARD({{ servers_table(servers) }})
+policy.FORWARD({{ table_or_server(servers) }})
{%- endmacro %}
{% macro policy_tls_forward(servers) -%}
-{%- macro get_proto_set(protocols) -%}
+{% from 'macros/common_macros.lua.j2' import quotes %}
+{% from 'macros/policy_macros.lua.j2' import policy_flags, policy_tags_assign %}
+
+
+{% macro view_protocols(protocols) -%}
0
-{%- for p in protocols or [] -%}
+{%- for p in protocols or [] %}
+ 2^C.KR_PROTO_{{ p.upper() }}
-{%- endfor -%}
-{%- endmacro -%}
+{%- endfor %}
+{%- endmacro %}
+
-{% macro view_flags(options) -%}
-{% if not options.minimize -%}
+{% macro view_options_flags(options) -%}
+{% if not options.minimize %}
"NO_MINIMIZE",
-{%- endif %}
-{% if not options.dns64 -%}
+{% endif %}
+{% if not options.dns64 %}
"DNS64_DISABLE",
-{%- endif %}
+{% endif %}
{%- endmacro %}
+
{% macro view_answer(answer) -%}
{%- if answer == 'allow' -%}
policy.TAGS_ASSIGN({})
'policy.NO_ANSWER'
{%- endif -%}
{%- endmacro %}
+
+
+{% macro view_insert_action(subnet, dst_subnet, protocols, options, tags, answer) -%}
+{%- set flags = view_options_flags(options) -%}
+assert(C.kr_view_insert_action(
+ {{ quotes(subnet) }}, {{ quotes(dst_subnet or '') }},
+ {{ view_protocols(protocols) }},
+{% if flags %}
+ policy.COMBINE({
+ {{ quotes(policy_flags(flags))|indent }},
+{% if tags %}
+ {{ policy_tags_assign(tags)|indent }}
+{% elif answer %}
+ {{ view_answer(answer)|indent }}
+{% endif %}
+ })
+{% elif tags %}
+ {{ policy_tags_assign(tags)|indent }}
+{% elif answer %}
+ {{ view_answer(answer)|indent }}
+{% endif %}
+) == 0)
+{%- endmacro %}
\ No newline at end of file
--- /dev/null
+{% from 'macros/common_macros.lua.j2' import quotes %}
+{% from 'macros/network_macros.lua.j2' import net_listen, http_config %}
+
+
+{% macro webmgmt_config(config) -%}
+{{ http_config('webmgmt', config.tls, config.cert_file, config.key_file, ) }}
+{%- endmacro %}
+
+
+{% macro webmgmt_listen(webmgmt, kind='webmgmt') -%}
+{% if webmgmt.unix_socket %}
+{{ net_listen(quotes(webmgmt.unix_socket), kind=kind) }}
+{% elif webmgmt.interface %}
+{% if webmgmt.interface.addr %}
+{{ net_listen(quotes(webmgmt.interface.addr), webmgmt.interface.port, kind) }}
+{% elif webmgmt.interface.if_name %}
+{{ net_listen('net.'+webmgmt.interface.if_name|string, webmgmt.interface.port, kind) }}
+{% endif %}
+{% endif %}
+{%- endmacro %}
\ No newline at end of file
---- control socket location
-local ffi = require('ffi')
-local id = os.getenv('SYSTEMD_INSTANCE')
-if not id then
- log_error(ffi.C.LOG_GRP_SYSTEM, 'environment variable $SYSTEMD_INSTANCE not set, which should not have been possible due to running under manager')
-else
- -- Bind to control socket in CWD (= rundir in config)
- -- FIXME replace with relative path after fixing https://gitlab.nic.cz/knot/knot-resolver/-/issues/720
- local path = '{{ cwd }}/control/'..id
- log_warn(ffi.C.LOG_GRP_SYSTEM, 'path = ' .. path)
- local ok, err = pcall(net.listen, path, nil, { kind = 'control' })
- if not ok then
- log_warn(ffi.C.LOG_GRP_NETWORK, 'bind to '..path..' failed '..err)
- end
-end
+{% from 'macros/common_macros.lua.j2' import modules_load %}
+{% from 'macros/monitoring_macros.lua.j2' import monitoring_control_socket, monitoring_collect_lazy_statistics, monitoring_collect_statistics %}
+
+--------------------------------------------------------------------------------
+-- MONITORING configuration
+--------------------------------------------------------------------------------
+
+{{ monitoring_control_socket() }}
{% if cfg.monitoring.enabled == "always" %}
-modules.load('stats')
+{{ modules_load('stats') }}
{% endif %}
---- function used for statistics collection
-function collect_lazy_statistics()
- if stats == nil then
- modules.load('stats')
- end
-
- return tojson(stats.list())
-end
+{{ monitoring_collect_lazy_statistics }}
---- function used for statistics collection
-function collect_statistics()
- return tojson(stats.list())
-end
+{{ monitoring_collect_statistics }}
-{% from 'macros/common_macros.lua.j2' import boolean %}
-{% from 'macros/network_macros.lua.j2' import network_listen, http_config %}
+{% from 'macros/common_macros.lua.j2' import boolean, module_loader, modules_load %}
+{% from 'macros/network_macros.lua.j2' import network_listen, http_config, net_tls, net_tls_padding, proxy_allowed, renumber_config %}
+
+--------------------------------------------------------------------------------
+-- NETWORK configuration
+--------------------------------------------------------------------------------
-- network.do-ipv4/6
net.ipv4 = {{ boolean(cfg.network.do_ipv4) }}
net.tcp_pipeline({{ cfg.network.tcp_pipeline }})
-- network.edns-keep-alive
-{% if cfg.network.edns_tcp_keepalive %}
-modules.load('edns_keepalive')
-{% else %}
-modules.unload('edns_keepalive')
-{% endif %}
+{{ module_loader(cfg.network.edns_tcp_keepalive, 'edns_keepalive') }}
-- network.edns-buffer-size
net.bufsize(
{{ cfg.network.edns_buffer_size.downstream.bytes() }}
)
-{% if cfg.network.tls.cert_file and cfg.network.tls.key_file %}
+{% if cfg.network.tls.cert_file or cfg.network.tls.key_file %}
-- network.tls
-net.tls('{{ cfg.network.tls.cert_file }}', '{{ cfg.network.tls.key_file }}')
+{{ net_tls(cfg.network.tls.cert_file, cfg.network.tls.key_file) }}
{% endif %}
{% if cfg.network.tls.sticket_secret %}
net.tls_sticket_secret_file('{{ cfg.network.tls.sticket_secret_file }}')
{% endif %}
-{% if cfg.network.tls.auto_discovery %}
-- network.tls.auto-discovery
-modules.load('experimental_dot_auth')
-{% else %}
--- modules.unload('experimental_dot_auth')
-{% endif %}
+{{ module_loader(cfg.network.tls.auto_discovery, 'experimental_dot_auth') }}
-- network.tls.padding
-net.tls_padding(
-{%- if cfg.network.tls.padding == true -%}
-true
-{%- elif cfg.network.tls.padding == false -%}
-false
-{%- else -%}
-{{ cfg.network.tls.padding }}
-{%- endif -%}
-)
+{{ net_tls_padding(cfg.network.tls.padding ) }}
{% if cfg.network.address_renumbering %}
-- network.address-renumbering
-modules.load('renumber')
-renumber.config = {
-{% for item in cfg.network.address_renumbering %}
- {'{{ item.source }}', '{{ item.destination }}'},
-{% endfor %}
-}
+{{ modules_load('renumber') }}
+{{ renumber_config(cfg.network.address_renumbering) }}
{% endif %}
-{%- set vars = {'doh_legacy': False} -%}
+-- network.proxy-protocol
+{{ proxy_allowed(cfg.network.proxy_protocol) }}
+
+{%- set vars = {'doh_legacy': false} -%}
{% for listen in cfg.network.listen if listen.kind == "doh-legacy" -%}
-{%- if vars.update({'doh_legacy': True}) -%}{%- endif -%}
+{%- if vars.update({'doh_legacy': true}) -%}{%- endif -%}
{%- endfor %}
{% if vars.doh_legacy %}
-- doh_legacy http config
-modules.load('http')
-{{ http_config(cfg.network.tls,"doh_legacy") }}
-{% endif %}
-
-{% if cfg.network.proxy_protocol %}
--- network.proxy-protocol
-net.proxy_allowed({
-{% for item in cfg.network.proxy_protocol.allow %}
-'{{ item }}',
-{% endfor %}
-})
-{% else %}
-net.proxy_allowed({})
+{{ modules_load('http') }}
+{{ http_config("doh_legacy", true, cfg.network.tls.cert_file, cfg.network.tls.key_file) }}
{% endif %}
-- network.listen
-{% for listen in cfg.network.listen %}
+{% for listen in cfg.network.listen -%}
{{ network_listen(listen) }}
-{% endfor %}
\ No newline at end of file
+{%- endfor %}
-{% from 'macros/common_macros.lua.j2' import boolean %}
+{% from 'macros/common_macros.lua.j2' import boolean, module_loader, modules_load %}
+{% from 'macros/options_macros.lua.j2' import option %}
+
+--------------------------------------------------------------------------------
+-- OPTIONS configuration
+--------------------------------------------------------------------------------
-- options.glue-checking
mode('{{ cfg.options.glue_checking }}')
{% if cfg.options.rebinding_protection %}
-- options.rebinding-protection
-modules.load('rebinding < iterate')
+{{ modules_load('rebinding < iterate') }}
{% endif %}
{% if cfg.options.violators_workarounds %}
-- options.violators-workarounds
-modules.load('workarounds < iterate')
+{{ modules_load('workarounds < iterate') }}
{% endif %}
{% if cfg.options.serve_stale %}
-- options.serve-stale
-modules.load('serve_stale < cache')
+{{ modules_load('serve_stale < cache') }}
{% endif %}
-- options.query-priming
-{% if cfg.options.priming %}
-modules.load('priming')
-{% else %}
-modules.unload('priming')
-{% endif %}
+{{ module_loader(cfg.options.priming, 'priming') }}
-- options.time-jump-detection
-{% if cfg.options.time_jump_detection %}
-modules.load('detect_time_jump')
-{% else %}
-modules.unload('detect_time_jump')
-{% endif %}
+{{ module_loader(cfg.options.time_jump_detection, 'detect_time_jump') }}
-- options.refuse-no-rd
-{% if cfg.options.refuse_no_rd %}
-modules.load('refuse_nord')
-{% else %}
-modules.unload('refuse_nord')
-{% endif %}
+{{ module_loader(cfg.options.refuse_no_rd, 'refuse_nord') }}
-- options.qname-minimisation
-option('NO_MINIMIZE', {{ boolean(cfg.options.minimize,true) }})
+{{ option('NO_MINIMIZE', cfg.options.minimize, true) }}
-- options.query-loopback
-option('ALLOW_LOCAL', {{ boolean(cfg.options.query_loopback) }})
+{{ option('ALLOW_LOCAL', cfg.options.query_loopback) }}
-- options.reorder-rrset
-option('REORDER_RR', {{ boolean(cfg.options.reorder_rrset) }})
+{{ option('REORDER_RR', cfg.options.reorder_rrset) }}
-- options.query-case-randomization
-option('NO_0X20', {{ boolean(cfg.options.query_case_randomization,true) }})
\ No newline at end of file
+{{ option('NO_0X20', cfg.options.query_case_randomization) }}
\ No newline at end of file
{% from 'macros/common_macros.lua.j2' import quotes %}
-{% from 'macros/view_macros.lua.j2' import get_proto_set, view_flags, view_answer %}
-{% from 'macros/policy_macros.lua.j2' import policy_flags, policy_tags_assign %}
+{% from 'macros/view_macros.lua.j2' import view_insert_action %}
{% if cfg.views %}
+--------------------------------------------------------------------------------
+-- VIEWS configuration
+--------------------------------------------------------------------------------
+
{% for view in cfg.views %}
{% for subnet in view.subnets %}
-
-assert(C.kr_view_insert_action('{{ subnet }}', '{{ view.dst_subnet or '' }}',
- {{ get_proto_set(view.protocols) }}, policy.COMBINE({
-{%- set flags = view_flags(view.options) -%}
-{% if flags %}
- {{ quotes(policy_flags(flags)) }},
-{%- endif %}
-
-{% if view.tags %}
- {{ policy_tags_assign(view.tags) }},
-{% elif view.answer %}
- {{ view_answer(view.answer) }},
-{%- endif %}
- })) == 0)
-
-{% endfor %}
-{% endfor %}
+{{ view_insert_action(
+ subnet, view.dst_subnet, view.protocols,
+ view.options, view.tags, view.answer
+) }}
+{% endfor %}{% endfor %}
{% endif %}
-{% from 'macros/common_macros.lua.j2' import boolean %}
+{% from 'macros/common_macros.lua.j2' import modules_load %}
+{% from 'macros/webmgmt_macros.lua.j2' import webmgmt_config, webmgmt_listen %}
{% if cfg.webmgmt -%}
--- webmgmt
-modules.load('http')
-http.config({tls = {{ boolean(cfg.webmgmt.tls) }},
-{%- if cfg.webmgmt.cert_file -%}
- cert = '{{ cfg.webmgmt.cert_file }}',
-{%- endif -%}
-{%- if cfg.webmgmt.cert_file -%}
- key = '{{ cfg.webmgmt.key_file }}',
-{%- endif -%}
-}, 'webmgmt')
-net.listen(
-{%- if cfg.webmgmt.unix_socket -%}
- '{{ cfg.webmgmt.unix_socket }}',nil,
-{%- elif cfg.webmgmt.interface -%}
- {%- if cfg.webmgmt.interface.addr -%}
- '{{ cfg.webmgmt.interface.addr }}',{{ cfg.webmgmt.interface.port }},
- {%- elif cfg.webmgmt.interface.if_name -%}
- net.{{ cfg.webmgmt.interface.if_name }},{{ cfg.webmgmt.interface.port }},
- {%- endif -%}
-{%- endif -%}
-{ kind = 'webmgmt' })
+--------------------------------------------------------------------------------
+-- WEBMGMT configuration
+--------------------------------------------------------------------------------
+
+{{ modules_load('http') }}
+{{ webmgmt_config(cfg.webmgmt) }}
+{{ webmgmt_listen(cfg.webmgmt) }}
{%- endif %}
\ No newline at end of file