From e4fbbca023ae51e7c131a10eec7e8ca3a35fa2fd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ale=C5=A1?= Date: Wed, 15 Dec 2021 19:11:14 +0100 Subject: [PATCH] datamodel: policy: added Lua template - new jinja2 macros --- .../datamodel/policy_schema.py | 3 +- .../datamodel/templates/config.lua.j2 | 3 + .../templates/macros/common_macros.lua.j2 | 15 +- .../templates/macros/policy_macros.lua.j2 | 151 ++++++++++++++++-- .../datamodel/templates/policy.lua.j2 | 64 ++++++++ 5 files changed, 218 insertions(+), 18 deletions(-) create mode 100644 manager/knot_resolver_manager/datamodel/templates/policy.lua.j2 diff --git a/manager/knot_resolver_manager/datamodel/policy_schema.py b/manager/knot_resolver_manager/datamodel/policy_schema.py index 87f74e2b6..a159e450b 100644 --- a/manager/knot_resolver_manager/datamodel/policy_schema.py +++ b/manager/knot_resolver_manager/datamodel/policy_schema.py @@ -1,13 +1,12 @@ from typing import List, Optional from knot_resolver_manager.datamodel.network_schema import AddressRenumberingSchema -from knot_resolver_manager.datamodel.types import ActionEnum, DomainName, IPAddressPort, QTypeEnum, TimeUnit +from knot_resolver_manager.datamodel.types import ActionEnum, IPAddressPort, QTypeEnum, TimeUnit from knot_resolver_manager.datamodel.view_schema import FlagsEnum from knot_resolver_manager.utils import SchemaNode class FilterSchema(SchemaNode): - domain: Optional[List[DomainName]] = None suffix: Optional[List[str]] = None pattern: Optional[List[str]] = None qtype: Optional[List[QTypeEnum]] = None diff --git a/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 index 29af22378..a8ef7d7b1 100644 --- a/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 +++ b/manager/knot_resolver_manager/datamodel/templates/config.lua.j2 @@ -18,6 +18,9 @@ -- VIEWS section {% include "views.lua.j2" %} +-- POLICY section +{% include "policy.lua.j2" %} + -- RPZ section {% include "rpz.lua.j2" %} diff --git a/manager/knot_resolver_manager/datamodel/templates/macros/common_macros.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/macros/common_macros.lua.j2 index 31f9f176d..af8a5d76f 100644 --- a/manager/knot_resolver_manager/datamodel/templates/macros/common_macros.lua.j2 +++ b/manager/knot_resolver_manager/datamodel/templates/macros/common_macros.lua.j2 @@ -24,6 +24,19 @@ kres.str2ip('{{ item|string }}'), {%- endif -%} {%- 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 -%} +} +{%- endif -%} +{%- endmacro %} + {# Return server address or table of server addresses #} {% macro servers_table(servers) -%} {%- if servers is string -%} @@ -77,4 +90,4 @@ pin_sha256= }, {%- endif -%} {%- endif -%} -{%- endmacro %} \ No newline at end of file +{%- endmacro %} diff --git a/manager/knot_resolver_manager/datamodel/templates/macros/policy_macros.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/macros/policy_macros.lua.j2 index c52c831da..9e11ea51c 100644 --- a/manager/knot_resolver_manager/datamodel/templates/macros/policy_macros.lua.j2 +++ b/manager/knot_resolver_manager/datamodel/templates/macros/policy_macros.lua.j2 @@ -1,13 +1,17 @@ -{% from 'macros/common_macros.lua.j2' import string_table, str2ip_table, servers_table, tls_servers_table %} +{% from 'macros/common_macros.lua.j2' import string_table, str2ip_table, qtype_table, servers_table, tls_servers_table %} + + +{# Add policy #} {% macro policy_add(rule, postrule=false) -%} {%- if postrule -%} policy.add({{ rule }}, true) -{% else %} +{%- else -%} policy.add({{ rule }}) -{% endif %} +{%- endif -%} {%- endmacro %} + {# Flags #} {% macro policy_flags(flags) -%} @@ -18,6 +22,7 @@ policy.FLAGS({ }) {%- endmacro %} + {# Filters #} {% macro policy_all(action) -%} @@ -28,6 +33,10 @@ policy.all({{ action }}) policy.suffix({{ action }}, {{ suffix_table }}) {%- endmacro %} +{% macro policy_suffix_common(action, suffix_table, common_suffix) -%} +policy.suffix_common({{ action }}, {{ suffix_table }}, {{ common_suffix }}) +{%- endmacro %} + {% macro policy_pattern(action, pattern) -%} policy.pattern({{ action }}, {{ pattern }}) {%- endmacro %} @@ -36,6 +45,54 @@ policy.pattern({{ action }}, {{ pattern }}) policy.rpz({{ action|string }}, '{{ path|string }}', {{ 'true' if watch else 'false' }}) {%- endmacro %} + +{# Custom filters #} + +{% macro declare_policy_qtype_custom_filter() -%} +function policy_qtype(action, qtype) + + local function has_value (tab, val) + for index, value in ipairs(tab) do + if value == val then + return true + end + end + + return false + end + + return function (state, query) + if query.stype == qtype then + return action + elseif has_value(qtype, query.stype) then + return action + else + return nil + end + end +end +{%- endmacro %} + +{% macro policy_qtype_custom_filter(action, qtype) -%} +policy_qtype({{ action }}, {{ qtype }}) +{%- endmacro %} + + +{# Auto Filter #} + +{% macro policy_auto_filter(action, filter=none) -%} +{%- if filter.suffix -%} +{{ policy_suffix(action, policy_todname(filter.suffix)) }} +{%- elif filter.pattern -%} +{{ policy_pattern(action, filter.pattern) }} +{%- elif filter.qtype -%} +{{ policy_qtype_custom_filter(action, qtype_table(filter.qtype)) }} +{%- else -%} +{{ policy_all(action) }} +{%- endif %} +{%- endmacro %} + + {# Non-chain actions #} {% macro policy_pass() -%} @@ -58,6 +115,16 @@ policy.DROP policy.REFUSE {%- endmacro %} +{% macro policy_tc() -%} +policy.TC +{%- endmacro %} + +{% macro policy_reroute(reroute) -%} +policy.REROUTE({ +{# TODO: completion of this action #} +}) +{%- endmacro %} + {% macro policy_answer(answer) -%} policy.ANSWER({ [kres.type.{{ answer.query_type }}] = { rdata= {%- if answer.query_type == 'A' -%} @@ -74,20 +141,38 @@ ttl={{ answer.ttl.seconds()|int }}, } }, nodata={{ 'true' if answer.nodata else 'false' }} ) {%- endmacro %} -{% macro policy_action(policy) -%} -{%- if policy.action == 'pass' -%} -{{ policy_pass()|string }} -{%- elif policy.action == 'deny' -%} -{%- if policy.message -%} -{{ policy_deny_msg(policy.message)|string }} -{%- else -%} -{{ policy_deny()|string }} -{%- endif -%} -{# TODO: do same for other actions #} + +{# Chain actions #} + +{% macro policy_mirror(mirror) -%} +policy.MIRROR( +{% if mirror is string %} +'{{ mirror }}' +{% else %} +{ +{%- for addr in mirror -%} +'{{ addr }}', +{%- endfor -%} +} {%- endif -%} +) {%- endmacro %} -{# Chain actions #} +{% macro policy_debug_always() -%} +policy.DEBUG_ALWAYS +{%- endmacro %} + +{% macro policy_debug_cache_miss() -%} +policy.DEBUG_CACHE_MISS +{%- endmacro %} + +{% macro policy_qtrace() -%} +policy.QTRACE +{%- endmacro %} + +{% macro policy_reqtrace() -%} +policy.REQTRACE +{%- endmacro %} {% macro policy_stub(servers) -%} policy.STUB({{ servers_table(servers) }}) @@ -101,7 +186,43 @@ policy.FORWARD({{ servers_table(servers) }}) policy.TLS_FORWARD({{ tls_servers_table(servers) }}) {%- endmacro %} -{# other #} + +{# Auto Action #} + +{% macro policy_auto_action(rule) -%} +{%- if rule.action == 'pass' -%} +{{ policy_pass()|string }} +{%- elif rule.action == 'deny' -%} +{%- if rule.message -%} +{{ policy_deny_msg(rule.message)|string }} +{%- else -%} +{{ policy_deny()|string }} +{%- endif -%} +{%- elif rule.action == 'drop' -%} +{{ policy_drop() }} +{%- elif rule.action == 'refuse' -%} +{{ policy_refuse() }} +{%- elif rule.action == 'tc' -%} +{{ policy_tc() }} +{%- elif rule.action == 'reroute' -%} +{{ policy_reroute(rule.reroute) }} +{%- elif rule.action == 'answer' -%} +{{ policy_answer(rule.answer) }} +{%- elif rule.action == 'mirror' -%} +{{ policy_mirror(rule.mirror) }} +{%- elif rule.action == 'debug-always' -%} +{{ policy_debug_always() }} +{%- elif rule.action == 'debug-cache-miss' -%} +{{ policy_sebug_cache_miss() }} +{%- elif rule.action == 'qtrace' -%} +{{ policy_qtrace() }} +{%- elif rule.action == 'reqtrace' -%} +{{ policy_reqtrace() }} +{%- endif -%} +{%- endmacro %} + + +{# Other #} {% macro policy_todname(names) -%} policy.todnames({ diff --git a/manager/knot_resolver_manager/datamodel/templates/policy.lua.j2 b/manager/knot_resolver_manager/datamodel/templates/policy.lua.j2 new file mode 100644 index 000000000..688e0fe0c --- /dev/null +++ b/manager/knot_resolver_manager/datamodel/templates/policy.lua.j2 @@ -0,0 +1,64 @@ +{% from 'macros/policy_macros.lua.j2' import declare_policy_qtype_custom_filter, policy_flags, policy_add, policy_auto_filter, policy_auto_action %} +{% from 'macros/view_macros.lua.j2' import view_tsig, view_addr %} + +{% if cfg.policy -%} + +-- query type based custom policy filter +{{ declare_policy_qtype_custom_filter() }} + +{% for id, rule in cfg.policy.items() %} +-- policy rule: {{ id }} +{% if rule.views -%} +{# views set for rule #} +{% for view_id in rule.views -%} +{%- set view = cfg.views[view_id] -%} + +{# merge options from view and forward-zone #} +{%- set options = none -%} +{% if rule.options and view.options -%} +{% set options = rule.options|list + view.options|list %} +{% elif rule.options %} +{% set options = rule.options|list %} +{% elif view.options %} +{% set options = view.options|list %} +{%- endif %} + +{# view tsig #} +{% if view.tsig -%} +{% for tsig in view.tsig -%} + +{% if options -%} +{{ view_tsig(tsig|string, policy_auto_filter(policy_flags(options|list), rule.filter)) }} +{%- endif %} + +{{ view_tsig(tsig|string, policy_auto_filter(policy_auto_action(rule), rule.filter)) }} + +{% endfor %} +{% endif -%} + +{# view addr #} +{% if view.subnets -%} +{% for addr in view.subnets -%} + +{% if options -%} +{{ view_addr(addr|string, policy_auto_filter(policy_flags(options|list), rule.filter)) }} +{%- endif %} + +{{ view_addr(addr|string, policy_auto_filter(policy_auto_action(rule), rule.filter)) }} + +{% endfor %} +{% endif %} + +{%- endfor -%} +{%- else -%} +{# no views set for policy rule #} + +{% if rule.options -%} +{{ policy_add(policy_auto_filter(policy_flags(rule.options|list), rule.filter)) }} +{%- endif %} + +{{ policy_add(policy_auto_filter(policy_auto_action(rule), rule.filter)) }} + +{% endif %} +{% endfor %} +{% endif %} \ No newline at end of file -- 2.47.3