#!/usr/sbin/nft -f

{% import 'firewall/nftables-defines.j2' as group_tmpl %}
{% import 'firewall/nftables-zone.j2' as zone_tmpl %}

{% if first_install is not vyos_defined %}
delete table ip vyos_filter
{% endif %}
table ip vyos_filter {
    chain VYOS_FW_FORWARD {
        type filter hook forward priority 0; policy accept;
{% if state_policy is vyos_defined %}
        jump VYOS_STATE_POLICY
{% endif %}
{% if interface is vyos_defined %}
{%     for ifname, ifconf in interface.items() %}
{%         if ifconf.in is vyos_defined and ifconf.in.name is vyos_defined %}
        iifname {{ ifname }} counter jump NAME_{{ ifconf.in.name }}
{%         endif %}
{%         if ifconf.out is vyos_defined and ifconf.out.name is vyos_defined %}
        oifname {{ ifname }} counter jump NAME_{{ ifconf.out.name }}
{%         endif %}
{%     endfor %}
{% endif %}
        jump VYOS_POST_FW
    }
    chain VYOS_FW_LOCAL {
        type filter hook input priority 0; policy accept;
{% if state_policy is vyos_defined %}
        jump VYOS_STATE_POLICY
{% endif %}
{% if interface is vyos_defined %}
{%     for ifname, ifconf in interface.items() %}
{%         if ifconf.local is vyos_defined and ifconf.local.name is vyos_defined %}
        iifname {{ ifname }} counter jump NAME_{{ ifconf.local.name }}
{%         endif %}
{%     endfor %}
{% endif %}
        jump VYOS_POST_FW
    }
    chain VYOS_FW_OUTPUT {
        type filter hook output priority 0; policy accept;
{% if state_policy is vyos_defined %}
        jump VYOS_STATE_POLICY
{% endif %}
        jump VYOS_POST_FW
    }
    chain VYOS_POST_FW {
        return
    }
    chain VYOS_FRAG_MARK {
        type filter hook prerouting priority -450; policy accept;
        ip frag-off & 0x3fff != 0 meta mark set 0xffff1 return
    }
{% if name is vyos_defined %}
{%     set ns = namespace(sets=[]) %}
{%     for name_text, conf in name.items() %}
    chain NAME_{{ name_text }} {
{%         if conf.rule is vyos_defined %}
{%             for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
        {{ rule_conf | nft_rule(name_text, rule_id) }}
{%                 if rule_conf.recent is vyos_defined %}
{%                     set ns.sets = ns.sets + [name_text + '_' + rule_id] %}
{%                 endif %}
{%             endfor %}
{%         endif %}
        {{ conf | nft_default_rule(name_text) }}
    }
{%     endfor %}
{%     if group is vyos_defined and group.domain_group is vyos_defined %}
{%         for name, name_config in group.domain_group.items() %}
    set D_{{ name }} {
        type ipv4_addr
        flags interval
    }
{%         endfor %}
{%     endif %}
{%     for set_name in ns.sets %}
    set RECENT_{{ set_name }} {
        type ipv4_addr
        size 65535
        flags dynamic
    }
{%     endfor %}
{%     if geoip_updated.name is vyos_defined %}
{%         for setname in geoip_updated.name %}
    set {{ setname }} {
        type ipv4_addr
        flags interval
    }
{%         endfor %}
{%     endif %}
{% endif %}

{{ group_tmpl.groups(group, False) }}

{% if zone is vyos_defined %}
{{ zone_tmpl.zone_chains(zone, state_policy is vyos_defined, False) }}
{% endif %}

{% if state_policy is vyos_defined %}
    chain VYOS_STATE_POLICY {
{%     if state_policy.established is vyos_defined %}
        {{ state_policy.established | nft_state_policy('established') }}
{%     endif %}
{%     if state_policy.invalid is vyos_defined %}
        {{ state_policy.invalid | nft_state_policy('invalid') }}
{%     endif %}
{%     if state_policy.related is vyos_defined %}
        {{ state_policy.related | nft_state_policy('related') }}
{%     endif %}
        return
    }
{% endif %}
}

{% if first_install is not vyos_defined %}
delete table ip6 vyos_filter
{% endif %}
table ip6 vyos_filter {
    chain VYOS_FW6_FORWARD {
        type filter hook forward priority 0; policy accept;
{% if state_policy is vyos_defined %}
        jump VYOS_STATE_POLICY6
{% endif %}
{% if interface is vyos_defined %}
{%     for ifname, ifconf in interface.items() %}
{%         if ifconf.in is vyos_defined and ifconf.in.ipv6_name is vyos_defined %}
        iifname {{ ifname }} counter jump NAME6_{{ ifconf.in.ipv6_name }}
{%         endif %}
{%         if ifconf.out is vyos_defined and ifconf.out.ipv6_name is vyos_defined %}
        oifname {{ ifname }} counter jump NAME6_{{ ifconf.out.ipv6_name }}
{%         endif %}
{%     endfor %}
{% endif %}
        jump VYOS_POST_FW6
    }
    chain VYOS_FW6_LOCAL {
        type filter hook input priority 0; policy accept;
{% if state_policy is vyos_defined %}
        jump VYOS_STATE_POLICY6
{% endif %}
{% if interface is vyos_defined %}
{%     for ifname, ifconf in interface.items() %}
{%         if ifconf.local is vyos_defined and ifconf.local.ipv6_name is vyos_defined %}
        iifname {{ ifname }} counter jump NAME6_{{ ifconf.local.ipv6_name }}
{%         endif %}
{%     endfor %}
{% endif %}
        jump VYOS_POST_FW6
    }
    chain VYOS_FW6_OUTPUT {
        type filter hook output priority 0; policy accept;
{% if state_policy is vyos_defined %}
        jump VYOS_STATE_POLICY6
{% endif %}
        jump VYOS_POST_FW6
    }
    chain VYOS_POST_FW6 {
        return
    }
    chain VYOS_FRAG6_MARK {
        type filter hook prerouting priority -450; policy accept;
        exthdr frag exists meta mark set 0xffff1 return
    }
{% if ipv6_name is vyos_defined %}
{%     set ns = namespace(sets=[]) %}
{%     for name_text, conf in ipv6_name.items() %}
    chain NAME6_{{ name_text }} {
{%         if conf.rule is vyos_defined %}
{%             for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
        {{ rule_conf | nft_rule(name_text, rule_id, 'ip6') }}
{%                 if rule_conf.recent is vyos_defined %}
{%                     set ns.sets = ns.sets + [name_text + '_' + rule_id] %}
{%                 endif %}
{%             endfor %}
{%         endif %}
        {{ conf | nft_default_rule(name_text, ipv6=True) }}
    }
{%     endfor %}
{%     for set_name in ns.sets %}
    set RECENT6_{{ set_name }} {
        type ipv6_addr
        size 65535
        flags dynamic
    }
{%     endfor %}
{%     if geoip_updated.ipv6_name is vyos_defined %}
{%         for setname in geoip_updated.ipv6_name %}
    set {{ setname }} {
        type ipv6_addr
        flags interval
    }
{%         endfor %}
{%     endif %}
{% endif %}

{{ group_tmpl.groups(group, True) }}

{% if zone is vyos_defined %}
{{ zone_tmpl.zone_chains(zone, state_policy is vyos_defined, True) }}
{% endif %}

{% if state_policy is vyos_defined %}
    chain VYOS_STATE_POLICY6 {
{%     if state_policy.established is vyos_defined %}
        {{ state_policy.established | nft_state_policy('established') }}
{%     endif %}
{%     if state_policy.invalid is vyos_defined %}
        {{ state_policy.invalid | nft_state_policy('invalid') }}
{%     endif %}
{%     if state_policy.related is vyos_defined %}
        {{ state_policy.related | nft_state_policy('related') }}
{%     endif %}
        return
    }
{% endif %}
}