Debian 11: nftables

nftables replaces the popular {ip,ip6,arp,eb}tables. This software provides a new in-kernel packet classification framework that is based on a network-specific Virtual Machine (VM) and a new nft userspace command line tool. nftables reuses the existing Netfilter subsystems such as the existing hook infrastructure, the connection tracking system, NAT, userspace queueing and logging subsystem.

<work in progress>

Basic Firewall

  • ens192: Internal Interface
  • ens224: External Interface
  • includes docker entrires, remove these if you don’t want/need them

 

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {

        # By default, drop all traffic unless it meets a filter
        # criteria specified by the rules that follow below.
        type filter hook input priority 0; policy drop;

        # accept any localhost traffic
        iif lo accept
        iifname != lo ip daddr 127.0.0.1/8 counter log prefix "[nftables] drop connections to loopback not coming from loopback: " drop
        iifname != lo ip6 daddr ::1/128 counter log prefix "[nftables] drop connections to loopback not coming from loopback: " drop

        # accept trafic originated from us
        ct state {established, related} accept comment "Accept traffic originated from us"

        # early drop of invalid connections
        ct state invalid counter drop comment "Drop invalid connections"

        # mitigate ping floods
        ip protocol icmp icmp type {echo-reply, echo-request} limit rate over 7/second burst 4 packets drop
        ip6 nexthdr icmpv6 icmpv6 type {echo-reply, echo-request} limit rate over 7/second burst 4 packets drop

        # Allow following ICMPv4
        ip protocol icmp icmp type {
            echo-reply,  # type 0
            destination-unreachable,  # type 3
            echo-request,  # type 8
            time-exceeded,  # type 11
            parameter-problem,  # type 12
        } accept \
        comment "Accept basic IPv4 functionality"

        # Allow following ICMPv6
        ip6 nexthdr icmpv6 icmpv6 type {
            destination-unreachable,  # type 1
            packet-too-big,  # type 2
            time-exceeded,  # type 3
            parameter-problem,  # type 4
            echo-request,  # type 128
            echo-reply,  # type 129
        } accept \
        comment "Accept basic IPv6 functionality"

        # allow auto configuration support
        ip6 nexthdr icmpv6 icmpv6 type {
            nd-neighbor-solicit, # type 135
            nd-neighbor-advert, # type 136
            nd-router-advert, # type 134
            nd-router-solicit # type 133
        } ip6 hoplimit 255 accept; \
        comment "Allow IPv6 sollicit"

        # allow link-local discovery
        # see https://ao2.it/it/blog/2018/04/27/nftables-experiments-icmpv6-hop-hop-options-header
        hbh nexthdr ipv6-icmp icmpv6 type {
            mld-listener-query,  # type 130
            mld-listener-report,  # type 131
            mld-listener-reduction,  # type 132
            mld2-listener-report,  # type 143
        } ip6 saddr fe80::/10 accept \
        comment "Allow IPv6 multicast listener discovery on link-local"

        # allow multicast router discovery messages on link-local addresses (hop limit 1)
        ip6 nexthdr icmpv6 icmpv6 type {
            nd-router-advert,
            nd-router-solicit
        } ip6 hoplimit 1 ip6 saddr fe80::/10 accept;

        # accept ssh on internal interfaces, mitigate brute force login attempts
        iffname ens192 tcp dport ssh ct state new limit rate 7/minute counter log prefix "[nftables] accept ssh: " accept

        # log denied
        counter log prefix "[nftables] Inbound Denied: "

    }
    chain forward {

        # Drop everything (assumes this device is not a router)
        type filter hook forward priority 0; policy drop;

        # Uncomment to enable logging of denied forwards
        counter log prefix "[nftables] Forward Denied: "

    }
    chain output {

        # Allow all outbound traffic
        type filter hook output priority 0; policy accept;

    }
    chain DOCKER {
    }

    chain DOCKER-ISOLATION-STAGE-1 {
	iifname "docker0" oifname != "docker0" counter jump DOCKER-ISOLATION-STAGE-2
	counter return
    }

    chain DOCKER-ISOLATION-STAGE-2 {
	oifname "docker0" counter drop
	counter return
    }

    chain DOCKER-USER {
	counter return
     }
}

table ip nat {
    chain PREROUTING {
	type nat hook prerouting priority -100; policy accept;
	fib daddr type local counter jump DOCKER
    }

    chain INPUT {
	type nat hook input priority 100; policy accept;
    }

    chain POSTROUTING {
	type nat hook postrouting priority 100; policy accept;
	oifname != "docker0" ip saddr 172.17.0.0/16 counter masquerade
    }

    chain OUTPUT {
	type nat hook output priority -100; policy accept;
	ip daddr != 127.0.0.0/8 fib daddr type local counter jump DOCKER
    }

    chain DOCKER {
	iifname "docker0" counter return
    }
}