#!/usr/sbin/nft -f
# {{ ansible_managed }}

flush ruleset

table inet filter {

# Named sets
set trusted4 {
    type ipv4_addr
    flags interval
    elements = {
{% for ip in trusted_ranges %}
{%     if ip.v == 'ipv4' %}
        {{ ip.cidr }}, # {{ ip.comment | default('') }}
{%     endif %}
{% endfor %}
    }
}

set trusted6 {
    type ipv6_addr
    flags interval
    elements = {
{% for ip in trusted_ranges %}
{%     if ip.v == 'ipv6' %}
        {{ ip.cidr }}, # {{ ip.comment | default('') }}
{%     endif %}
{% endfor %}
    }
}


# Firewall chains
    chain input {
        type filter hook input priority 0;
        policy {{ nft_policy_input }};

        # Established connections
        ct state established,related accept
        ct state invalid counter drop comment "drop invalid packets"

        # Limit icmp echo/reply
        ip protocol icmp icmp type echo-request limit rate over 10/second burst 50 packets log prefix "high icmp-echo rate: " drop
        # icmp6 from trusted ranges
        ip6 nexthdr icmpv6 icmpv6 type echo-request accept
        # icmpv6 from the rest of the world
        ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 10/second burst 50 packets log prefix "high icmp6-echo rate: " drop

        # Loopback traffic
        iifname lo accept

        # icmp
        ip protocol icmp icmp type {
            destination-unreachable,
            echo-reply,
            echo-request,
            source-quench,
            time-exceeded
        } accept

        # icmp6
        ip6 nexthdr icmpv6 icmpv6 type {
            destination-unreachable,
            echo-reply,
            echo-request,
            nd-neighbor-solicit,
            nd-router-advert,
            nd-neighbor-advert,
            packet-too-big,
            parameter-problem,
            time-exceeded
        } accept

        # Open ssh only for trusted machines
        ip saddr @trusted4 tcp dport { {{ trusted_ports | join(', ') }} } accept
        ip6 saddr @trusted6 tcp dport { {{ trusted_ports | join(', ') }} } accept

        # Rules based on group-vars
{% for custom in nft_group_rules %}
{%     if custom.comment is defined %}
        # {{ custom.comment | default('') }}
{%     endif %}
        {{ custom.version | default('ip') }} saddr { {{ custom.from | join(', ') }} } {{ custom.proto | default('tcp') }} dport { {{ custom.port }} } {{ custom.policy | default('accept') }}

{% endfor %}

{% for rule in group_nft_input %}
        # Group input rules
        {{ rule }}
{% endfor %}
{% for rule in host_nft_input %}
        # Host input rules
        {{ rule }}
{% endfor %}
    }
    chain forward {
        type filter hook forward priority 0;
        policy {{ nft_policy_forward }};

        ct state established,related accept

{% for rule in group_nft_forward %}
        # Group forward rules
        {{ rule }}
{% endfor %}
{% for rule in host_nft_forward %}
        # Host forward rules
        {{ rule }}
{% endfor %}

        counter comment "count dropped incoming packets"
    }
    chain output {
        type filter hook output priority 0;
        policy {{ nft_policy_output }};

        # Established connections
        ct state established,related accept
        ct state invalid counter drop comment "drop invalid packets"

        # icmp
        ip protocol icmp icmp type {
            destination-unreachable,
            echo-reply,
            echo-request,
            source-quench,
            time-exceeded
        } accept

        # icmp6
        ip6 nexthdr icmpv6 icmpv6 type {
            destination-unreachable,
            echo-reply,
            echo-request,
            nd-neighbor-solicit,
            nd-router-advert,
            nd-neighbor-advert,
            packet-too-big,
            parameter-problem,
            time-exceeded
        } accept

{% for rule in group_nft_output %}
        # Group output rules
        {{ rule }}
{% endfor %}
{% for rule in host_nft_output %}
        # Host output rules
        {{ rule }}
{% endfor %}
        counter comment "count dropped outgoing packets"
    }
}

table ip nat {
    chain prerouting {
        type nat hook prerouting priority 100
        policy {{ nft_policy_prerouting }};
{% for rule in group_nft_prerouting %}
        # Group prerouting rules
        {{ rule }}
{% endfor %}
{% for rule in host_nft_prerouting %}
        # Host prerouting rules
        {{ rule }}
{% endfor %}
    }
    chain postrouting {
        type nat hook postrouting priority 100
        policy {{ nft_policy_postrouting }};

{% for rule in group_nft_postrouting %}
        # Group postrouting rules
        {{ rule }}
{% endfor %}
{% for rule in host_nft_postrouting %}
        # Host postrouting rules
        {{ rule }}
{% endfor %}
    }
}