-{% 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) -%}
})
{%- endmacro %}
+
{# Filters #}
{% macro 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 %}
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() -%}
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' -%}
} }, 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) }})
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({
--- /dev/null
+{% 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