Podman is no longer supporting iptables so I am trying to learn how to set up nftables in its place. It’s been a struggle to get it to work properly. I can not ping my own server after starting the nftables rules. I am using Alpine Linux v2.24.1 and nftables v1.1.6 (Commodore Bullmoose #7).

nftables has a config file with basic rules which include receiving pings:
/etc/nftables.nft

#!/usr/sbin/nft -f
# vim: set ts=4 sw=4:
# You can find examples in /usr/share/nftables/.

# Clear all prior state
flush ruleset

# Basic IPv4/IPv6 stateful firewall for server/workstation.
table inet filter {
	chain input {
		type filter hook input priority 0; policy drop;

		iifname lo accept \
		comment "Accept any localhost traffic"

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

		ct state invalid drop \
		comment "Drop invalid connections"

		tcp dport 113 reject with icmpx type port-unreachable \
		comment "Reject AUTH to make it fail fast"

		# 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 ICMP"

		# 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"

		icmpv6 type {
			nd-router-solicit,  # type 133
			nd-router-advert,  # type 134
			nd-neighbor-solicit,  # type 135
			nd-neighbor-advert,  # type 136
		} ip6 hoplimit 255 accept \
		comment "Allow IPv6 SLAAC"

		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"

		ip6 saddr fe80::/10 udp sport 547 udp dport 546 accept \
		comment "Accept DHCPv6 replies from IPv6 link-local addresses"
	}

	chain forward {
		type filter hook forward priority 0; policy drop;
	}

	chain output {
		type filter hook output priority 0; policy accept;
	}
}

# The state of stateful objects saved on the nftables service stop.
include "/var/lib/nftables/*.nft"

# Rules
include "/etc/nftables.d/*.nft"

I also have a small config file:
/etc/nftables.d/firewall.nft

#!/usr/sbin/nft -f

define WIREGUARD_PORT = 51820
define WIREGUARD_ADDRESS = 10.0.0.0/24
define SSH_PORT = 5025
define SSH_ADDRESSES = { $WIREGUARD_ADDRESS . $SSH_PORT, 192.168.40.204 . $SSH_PORT }
define PUBLIC_PORTS = { 5050 }

table inet filter {
	chain input {
		udp dport $WIREGUARD_PORT accept \
		comment "Accept WireGuard connections"

		ip saddr . tcp dport $SSH_ADDRESSES accept \
		comment "Accept SSH connections from known devices or WireGuard"

		tcp dport $PUBLIC_PORTS accept \
		comment "Accept public connections"
	}
}

After loading the new rules, I get the following output while listing the ruleset:

21:23 server-pi:~ $ doas nft list ruleset
table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		iifname "lo" accept comment "Accept any localhost traffic"
		ct state { established, related } accept comment "Accept traffic originated from us"
		ct state invalid drop comment "Drop invalid connections"
		tcp dport 113 reject comment "Reject AUTH to make it fail fast"
		ip protocol icmp icmp type { echo-reply, destination-unreachable, echo-request, time-exceeded, parameter-problem } accept comment "Accept ICMP"
		icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply } accept comment "Accept basic IPv6 functionality"
		icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept comment "Allow IPv6 SLAAC"
		icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, mld2-listener-report } ip6 saddr fe80::/10 accept comment "Allow IPv6 multicast listener discovery on link-local"
		ip6 saddr fe80::/10 udp sport 547 udp dport 546 accept comment "Accept DHCPv6 replies from IPv6 link-local addresses"
		udp dport 51820 accept comment "Accept WireGuard connections"
		ip saddr . tcp dport { 10.0.0.0/24 . 5025, 192.168.40.204 . 5025 } accept comment "Accept SSH connections from known devices or WireGuard"
		tcp dport 5050 accept comment "Accept public connections"
	}

	chain forward {
		type filter hook forward priority filter; policy drop;
	}

	chain output {
		type filter hook output priority filter; policy accept;
	}
}
21:23 server-pi:~ $ doas netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:8000          0.0.0.0:*               LISTEN      3515/rootlessport   
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN      3584/rootlessport   
tcp        0      0 0.0.0.0:5025            0.0.0.0:*               LISTEN      3743/sshd: /usr/sbi 
tcp6       0      0 :::5025                 :::*                    LISTEN      3743/sshd: /usr/sbi 
tcp6       0      0 :::5050                 :::*                    LISTEN      3515/rootlessport   
udp        0      0 0.0.0.0:51820           0.0.0.0:*                           -                   
udp6       0      0 :::51820                :::*                                -                   
21:23 server-pi:~ $ 

I can connect perfectly fine with SSH, WireGuard and my reverse proxy on port 5050 but if I ping the server I don’t get any response at all. Pings worked as normal when I was using iptables so I am not sure what I am doing wrong with nftables. I’ve tried to keep the rules as simple as possible to figure out what is happening but I have not been able to make any progress. Any help would be appreciated.

  • farcaller@fstab.sh
    link
    fedilink
    English
    arrow-up
    2
    ·
    4 hours ago

    nftables offers a very decent debugging interface. First, you add a rule to trace the packet (a new chain with high priority works best). Usually I’d suggest to add those rules by hand instead of relying on declarative configs:

    nft add table ip ping_trace
    nft 'add chain ip ping_trace prerouting { type filter hook prerouting priority -301; policy accept; }'
    

    Then you add the actual tracing rule there with the shape to match the incoming traffic:

    nft 'add rule ip ping_trace prerouting icmp type { echo-request, echo-reply } meta nftrace set 1'
    

    now you can run nft monitor trace and see the decisions made for the matching packets. Remember to delete the ping_trace table afterwards to clean up.