#!/usr/sbin/nft -f

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

{% if cleanup_commands is vyos_defined %}
{%     for command in cleanup_commands %}
{{ command }}
{%     endfor %}
{% endif %}

table ip filter {
{% if first_install is vyos_defined %}
    chain VYOS_FW_FORWARD {
        type filter hook forward priority 0; policy accept;
        jump VYOS_POST_FW
    }
    chain VYOS_FW_LOCAL {
        type filter hook input priority 0; policy accept;
        jump VYOS_POST_FW
    }
    chain VYOS_FW_OUTPUT {
        type filter hook output priority 0; policy accept;
        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
    }
{% endif %}
{% 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 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 %}
}

table ip6 filter {
{% if first_install is vyos_defined %}
    chain VYOS_FW6_FORWARD {
        type filter hook forward priority 0; policy accept;
        jump VYOS_POST_FW6
    }
    chain VYOS_FW6_LOCAL {
        type filter hook input priority 0; policy accept;
        jump VYOS_POST_FW6
    }
    chain VYOS_FW6_OUTPUT {
        type filter hook output priority 0; policy accept;
        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
    }
{% endif %}
{% 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) }}
    }
{%     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 state_policy is vyos_defined %}
    chain VYOS_STATE_POLICY6 {
{%     if state_policy.established is vyos_defined %}
        {{ state_policy.established | nft_state_policy('established', ipv6=True) }}
{%     endif %}
{%     if state_policy.invalid is vyos_defined %}
        {{ state_policy.invalid | nft_state_policy('invalid', ipv6=True) }}
{%     endif %}
{%     if state_policy.related is vyos_defined %}
        {{ state_policy.related | nft_state_policy('related', ipv6=True) }}
{%     endif %}
        return
    }
{% endif %}
}

{% if first_install is vyos_defined %}
table ip nat {
    chain PREROUTING {
        type nat hook prerouting priority -100; policy accept;
        counter jump VYOS_PRE_DNAT_HOOK
    }

    chain POSTROUTING {
        type nat hook postrouting priority 100; policy accept;
        counter jump VYOS_PRE_SNAT_HOOK
    }

    chain VYOS_PRE_DNAT_HOOK {
        return
    }

    chain VYOS_PRE_SNAT_HOOK {
        return
    }
}

table ip6 nat {
    chain PREROUTING {
        type nat hook prerouting priority -100; policy accept;
        counter jump VYOS_DNPT_HOOK
    }

    chain POSTROUTING {
        type nat hook postrouting priority 100; policy accept;
        counter jump VYOS_SNPT_HOOK
    }

    chain VYOS_DNPT_HOOK {
        return
    }

    chain VYOS_SNPT_HOOK {
        return
    }
}

table inet mangle {
    chain FORWARD {
        type filter hook forward priority -150; policy accept;
    }
}

table raw {
    chain VYOS_TCP_MSS {
        type filter hook forward priority -300; policy accept;
    }

    chain PREROUTING {
        type filter hook prerouting priority -200; policy accept;
        counter jump VYOS_CT_IGNORE
        counter jump VYOS_CT_TIMEOUT
        counter jump VYOS_CT_PREROUTING_HOOK
        counter jump FW_CONNTRACK
        notrack
    }

    chain OUTPUT {
        type filter hook output priority -200; policy accept;
        counter jump VYOS_CT_IGNORE
        counter jump VYOS_CT_TIMEOUT
        counter jump VYOS_CT_OUTPUT_HOOK
        counter jump FW_CONNTRACK
        notrack
    }

    ct helper rpc_tcp {
        type "rpc" protocol tcp;
    }

    ct helper rpc_udp {
        type "rpc" protocol udp;
    }

    ct helper tns_tcp {
        type "tns" protocol tcp;
    }

    chain VYOS_CT_HELPER {
        ct helper set "rpc_tcp" tcp dport {111} return
        ct helper set "rpc_udp" udp dport {111} return
        ct helper set "tns_tcp" tcp dport {1521,1525,1536} return
        return
    }

    chain VYOS_CT_IGNORE {
        return
    }

    chain VYOS_CT_TIMEOUT {
        return
    }

    chain VYOS_CT_PREROUTING_HOOK {
        return
    }

    chain VYOS_CT_OUTPUT_HOOK {
        return
    }

    chain FW_CONNTRACK {
        accept
    }
}

table ip6 raw {
    chain VYOS_TCP_MSS {
        type filter hook forward priority -300; policy accept;
    }

    chain PREROUTING {
        type filter hook prerouting priority -300; policy accept;
        counter jump VYOS_CT_PREROUTING_HOOK
        counter jump FW_CONNTRACK
        notrack
    }

    chain OUTPUT {
        type filter hook output priority -300; policy accept;
        counter jump VYOS_CT_OUTPUT_HOOK
        counter jump FW_CONNTRACK
        notrack
    }

    chain VYOS_CT_PREROUTING_HOOK {
        return
    }

    chain VYOS_CT_OUTPUT_HOOK {
        return
    }

    chain FW_CONNTRACK {
        accept
    }
}
{% endif %}