Intro

This is part two of another post I wrote: Should I enable ICMP?

The goals of this firewall ruleset are as follows:

  • Enforce sane limits over the number of automated ICMP responses that can be elicited by sources on the internet; mitigating ICMP amplification while still allowing some symbolance of networking mechanisms that rely on ICMP to function.
  • Establish the basis for a “zero trust” model by ensuring the use of end-to-end encrypted protocols for necessary egress traffic (primarily NTPSEC and DoTLS.) This is necessary in an environment where protocols like NDP-RA are in use because of the possibility that other users on a network can advertise routes themselves which can potentially be used to hijack another user’s traffic. Unauthorized route advertisements can certainly be mitigated with multicast filtering/snooping however it is not necessarily consistent from one network to the next.
  • Providing an abstract ruleset such that it can be the basis for application virtually anywhere while minimizing the amount of overhead that can be potentially introduced by abstraction as much as possible (YMMV)

The simplest way to go about this is to start at the filter state / configuration format section.

Preparation

This demo uses Debian on Parallels, updated from bullseye to bookworm:

1sed -i 's/http:\/\//https:\/\//g' /etc/apt/sources.list
2sed -i 's/bullseye/bookworm/g' apt/sources.list
3apt update && apt -y dist-upgrade
4apt -y install nftables chrony systemd-resolved && reboot

Chrony (NTPSEC)

Unencrypted NTP (UDP 123) destinations will only be permitted in the NFTables ruleset if they are local networks, if you need internet time setup chrony Disable systemd-timesyncd if it is enabled:

1sudo systemctl stop systemd-timesyncd.service
2sudo systemctl disable systemd-timesyncd.service

replace /etc/chrony.conf with:

 1confdir       /etc/chrony/conf.d
 2server        time.cloudflare.com nts iburst
 3sourcedir     /run/chrony-dhcp
 4sourcedir     /etc/chrony/sources.d
 5keyfile       /etc/chrony/chrony.keys
 6driftfile     /var/lib/chrony/chrony.drift
 7ntsdumpdir    /var/lib/chrony
 8logdir        /var/log/chrony
 9maxupdateskew 100.0
10rtcsync
11makestep      1 3
12leapsectz     right/UTC

Enable the Chrony service:

1systemctl enable chrony
2systemctl start chrony 

(a list of other NTS-enabled NTP servers is available.)

DNSoTLS

Unencrypted DNS (UDP 53) destinations will only be permitted in the NFTables ruleset if they are local networks, if you need internet DNS setup systemd-resolved with DoTLS then replace the contents of /etc/systemd/resolved.conf with:

1[Resolve]
2DNS=1.1.1.1,1.0.0.1,2606:4700:4700::1111,2606:4700:4700::1001
3DNSSEC=yes
4DNSOverTLS=yes

start systemd-resolved:

1systemctl enable systemd-resolved
2systemctl start systemd-resolved

Creating the default table

1nft flush ruleset
2nft add table inet filter

Chains

 1nft add chain inet filter input '{ type filter hook input priority filter; policy accept; }'
 2nft add chain inet filter forward '{ type filter hook forward priority filter; policy accept; }'
 3nft add chain inet filter output '{ type filter hook output priority filter; policy accept; }'
 4nft add chain inet filter prerouting '{ type nat hook prerouting priority 100; policy accept; }'
 5nft add chain inet filter postrouting '{ type nat hook postrouting priority 100; policy accept; }'
 6nft add chain inet filter masq
 7nft add chain inet filter ether_in
 8nft add chain inet filter ether_out
 9nft add chain inet filter ether_forward
10nft add chain inet filter icmp_in
11nft add chain inet filter icmp_out
12nft add chain inet filter icmp_forward
13nft add chain inet filter icmp_echo_reply_rate_limit
14nft add chain inet filter reject_with_icmp_port_unreachable_metered
15nft add chain inet filter reject_with_icmp_port_unreachable
16nft add chain inet filter reject_with_icmp_host_unreachable_metered
17nft add chain inet filter reject_with_icmp_host_unreachable
18nft add chain inet filter reject_with_icmp_no_route_metered
19nft add chain inet filter reject_with_icmp_no_route
20nft add chain inet filter reject_with_icmp_admin_prohibited_metered
21nft add chain inet filter reject_with_icmp_admin_prohibited
22nft add chain inet filter tcp_in
23nft add chain inet filter tcp_out
24nft add chain inet filter tcp_forward
25nft add chain inet filter udp_in
26nft add chain inet filter udp_out
27nft add chain inet filter udp_forward
28nft add chain inet filter bogon
29nft add rule inet filter bogon log prefix "bogon" group 1
30nft add rule inet filter bogon counter drop
31nft add chain inet filter wont_forward
32nft add rule inet filter wont_forward log prefix "wont_forward" group 1
33nft add rule inet filter wont_forward counter drop

Meter sets

1nft add set inet filter icmp_egress_meter4 '{ type ipv4_addr; size 8; flags timeout, dynamic; }'
2nft add set inet filter icmp_egress_meter6 '{ type ipv6_addr; size 8; flags timeout, dynamic; }'

Verdict maps and sets

IPv4 bogons

 1nft add map inet filter drop_bogons4 '{ type ipv4_addr : verdict; flags interval; }'
 2nft add element inet filter drop_bogons4 '{ 224.0.0.0/4     : continue   }'
 3nft add element inet filter drop_bogons4 '{ 192.168.0.0/16  : continue   }'
 4nft add element inet filter drop_bogons4 '{ 10.0.0.0/8      : continue   }'
 5nft add element inet filter drop_bogons4 '{ 172.16.0.0/12   : continue   }' 
 6nft add element inet filter drop_bogons4 '{ 169.254.0.0/16  : continue   }'
 7nft add element inet filter drop_bogons4 '{ 100.64.0.0/10   : jump bogon }' 
 8nft add element inet filter drop_bogons4 '{ 0.0.0.0/8       : jump bogon }'
 9nft add element inet filter drop_bogons4 '{ 127.0.0.0/8     : jump bogon }'
10nft add element inet filter drop_bogons4 '{ 192.0.0.0/24    : jump bogon }'
11nft add element inet filter drop_bogons4 '{ 192.0.2.0/24    : jump bogon }'
12nft add element inet filter drop_bogons4 '{ 198.18.0.0/15   : jump bogon }'
13nft add element inet filter drop_bogons4 '{ 198.51.100.0/24 : jump bogon }' 
14nft add element inet filter drop_bogons4 '{ 203.0.113.0/24  : jump bogon }'
15nft add element inet filter drop_bogons4 '{ 240.0.0.0/4     : jump bogon }'

Local networks

1nft add set inet filter local_networks '{ type ipv4_addr; flags interval; }'
2nft add element inet filter local_networks '{ 169.254.0.0/16, 10.0.0.0/8, 172.17.0.0/12, 192.168.0.0/16 }'
TODO
  • Class E / limited broadcast (240.0.0.0/4)

IPv6 bogons

 1nft add map inet filter drop_bogons6 '{ type ipv6_addr : verdict; flags interval; }'
 2nft add element inet filter drop_bogons6 '{ fe80::/10             : continue   }'
 3nft add element inet filter drop_bogons6 '{ fc00::/7              : continue   }'
 4nft add element inet filter drop_bogons6 '{ ff00::/8              : continue   }'
 5nft add element inet filter drop_bogons6 '{ ::ffff:0:0/96         : jump bogon }'
 6nft add element inet filter drop_bogons6 '{ ::/96                 : jump bogon }'
 7nft add element inet filter drop_bogons6 '{ 100::/64              : jump bogon }'
 8nft add element inet filter drop_bogons6 '{ 2001:10::/28          : jump bogon }'
 9nft add element inet filter drop_bogons6 '{ 2001:db8::/32         : jump bogon }'
10nft add element inet filter drop_bogons6 '{ fec0::/10             : jump bogon }'
11nft add element inet filter drop_bogons6 '{ 2002::/24             : jump bogon }'
12nft add element inet filter drop_bogons6 '{ 2002:a00::/24         : jump bogon }'
13nft add element inet filter drop_bogons6 '{ 2002:7f00::/24        : jump bogon }'
14nft add element inet filter drop_bogons6 '{ 2002:a9fe::/32        : jump bogon }'
15nft add element inet filter drop_bogons6 '{ 2002:ac10::/28        : jump bogon }'
16nft add element inet filter drop_bogons6 '{ 2002:c000::/40        : jump bogon }'
17nft add element inet filter drop_bogons6 '{ 2002:c000:200::/40    : jump bogon }'
18nft add element inet filter drop_bogons6 '{ 2002:c0a8::/32        : jump bogon }'
19nft add element inet filter drop_bogons6 '{ 2002:c612::/31        : jump bogon }'
20nft add element inet filter drop_bogons6 '{ 2002:c633:6400::/40   : jump bogon }'
21nft add element inet filter drop_bogons6 '{ 2002:cb00:7100::/40   : jump bogon }'
22nft add element inet filter drop_bogons6 '{ 2002:e000::/20        : jump bogon }'
23nft add element inet filter drop_bogons6 '{ 2002:f000::/20        : jump bogon }'
24nft add element inet filter drop_bogons6 '{ 2001::/40             : jump bogon }'
25nft add element inet filter drop_bogons6 '{ 2001:0:a00::/40       : jump bogon }'
26nft add element inet filter drop_bogons6 '{ 2001:0:7f00::/40      : jump bogon }'
27nft add element inet filter drop_bogons6 '{ 2001:0:a9fe::/48      : jump bogon }'
28nft add element inet filter drop_bogons6 '{ 2001:0:ac10::/44      : jump bogon }'
29nft add element inet filter drop_bogons6 '{ 2001:0:c000::/56      : jump bogon }'
30nft add element inet filter drop_bogons6 '{ 2001:0:c000:200::/56  : jump bogon }'
31nft add element inet filter drop_bogons6 '{ 2001:0:c0a8::/48      : jump bogon }'
32nft add element inet filter drop_bogons6 '{ 2001:0:c612::/47      : jump bogon }'
33nft add element inet filter drop_bogons6 '{ 2001:0:c633:6400::/56 : jump bogon }'
34nft add element inet filter drop_bogons6 '{ 2001:0:cb00:7100::/56 : jump bogon }'
35nft add element inet filter drop_bogons6 '{ 2001:0:e000::/36      : jump bogon }'
36nft add element inet filter drop_bogons6 '{ 2001:0:f000::/36      : jump bogon }'
TODO

IPv4 reject or drop

1nft add map inet filter reject_or_drop_port4 '{ typeof ip saddr . ip daddr : verdict; flags interval; }'
2nft add element inet filter reject_or_drop_port4 '{ 10.0.0.0/8     . 10.0.0.0/8     : jump reject_with_icmp_port_unreachable         }'
3nft add element inet filter reject_or_drop_port4 '{ 172.16.0.0/12  . 172.16.0.0/12  : jump reject_with_icmp_port_unreachable         }'
4nft add element inet filter reject_or_drop_port4 '{ 192.168.0.0/16 . 192.168.0.0/16 : jump reject_with_icmp_port_unreachable         }'
5nft add element inet filter reject_or_drop_port4 '{ 169.254.0.0/16 . 169.254.0.0/16 : jump reject_with_icmp_port_unreachable         }'
6nft add element inet filter reject_or_drop_port4 '{ 0.0.0.0/0      . 0.0.0.0/0      : jump reject_with_icmp_port_unreachable_metered }'

IPv6 reject or drop

1nft add map inet filter reject_or_drop_port6 '{ typeof ip6 saddr . ip6 daddr : verdict; flags interval; }'
2nft add element inet filter reject_or_drop_port6 '{ fe80::/10 . fe80::/10 : jump reject_with_icmp_port_unreachable         }'
3nft add element inet filter reject_or_drop_port6 '{ fc00::/7  . fc00::/7  : jump reject_with_icmp_port_unreachable         }'
4nft add element inet filter reject_or_drop_port6 '{ ::/0      . ::/0      : jump reject_with_icmp_port_unreachable_metered }'

IPv4 ingress ICMP types

1nft add map inet filter icmp_types_in4 '{ typeof ip saddr . ip daddr . icmp type : verdict; flags interval; }'
2nft add element inet filter icmp_types_in4 '{ 0.0.0.0/0 . 0.0.0.0/0 . echo-request            : accept }'
3nft add element inet filter icmp_types_in4 '{ 0.0.0.0/0 . 0.0.0.0/0 . echo-reply              : accept }'
4nft add element inet filter icmp_types_in4 '{ 0.0.0.0/0 . 0.0.0.0/0 . destination-unreachable : accept }'

IPv6 ingress ICMP types

 1nft add map inet filter icmp_types_in6 '{ typeof ip6 saddr . ip6 daddr . icmpv6 type : verdict; flags interval; }'
 2nft add element inet filter icmp_types_in6 '{ fe80::/10 . fe80::/10 . echo-request        : accept }'
 3nft add element inet filter icmp_types_in6 '{ fe80::/10 . ff00::/8  . echo-request        : accept }'
 4nft add element inet filter icmp_types_in6 '{ fc00::/7  . fc00::/7  . echo-request        : accept }'
 5nft add element inet filter icmp_types_in6 '{ fe80::/10 . fe80::/10 . echo-reply          : accept }'
 6nft add element inet filter icmp_types_in6 '{ fe80::/10 . ff00::/8  . echo-reply          : accept }'
 7nft add element inet filter icmp_types_in6 '{ fc00::/7  . fc00::/7  . echo-reply          : accept }'
 8nft add element inet filter icmp_types_in6 '{ fe80::/10 . fe80::/10 . nd-neighbor-solicit : accept }'
 9nft add element inet filter icmp_types_in6 '{ fc00::/7  . ff00::/8  . nd-neighbor-solicit : accept }'
10nft add element inet filter icmp_types_in6 '{ fc00::/7  . fc00::/7  . nd-neighbor-solicit : accept }'
11nft add element inet filter icmp_types_in6 '{ fc00::/7  . fc00::/7  . nd-neighbor-advert  : accept }'
12nft add element inet filter icmp_types_in6 '{ fe80::/10 . fe80::/10 . nd-neighbor-advert  : accept }'
13nft add element inet filter icmp_types_in6 '{ fe80::/10 . ff00::/8  . nd-router-advert    : accept }'
14nft add element inet filter icmp_types_in6 '{ fe80::/10 . fe80::/10 . nd-router-advert    : accept }'
TODO
  • NDP for GUA

IPv4 ingress TCP ports

1nft add map inet filter tcp_ports_in4 '{ typeof ip saddr . ip daddr . tcp dport : verdict; flags interval; }'
2nft add element inet filter tcp_ports_in4 '{ 0.0.0.0/0 . 0.0.0.0/0 . 22 : accept }'

IPv6 ingress TCP ports

1nft add map inet filter tcp_ports_in6 '{ typeof ip6 saddr . ip6 daddr . tcp dport : verdict; flags interval; }'
2nft add element inet filter tcp_ports_in6 '{ ::/0 . ::/0 . 22 : accept }'

IPv4 ingress UDP ports

 1nft add map inet filter udp_ports_in4 '{ typeof ip saddr . ip daddr . udp dport : verdict; flags interval; }'
 2nft add element inet filter udp_ports_in4 '{ 169.254.0.0/16 . 169.254.0.0/16 . 68   : accept }'
 3nft add element inet filter udp_ports_in4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 68   : accept }'
 4nft add element inet filter udp_ports_in4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 68   : accept }'
 5nft add element inet filter udp_ports_in4 '{ 192.168.0.0/12 . 192.168.0.0/16 . 68   : accept }'
 6nft add element inet filter udp_ports_in4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 137  : accept }'
 7nft add element inet filter udp_ports_in4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 137  : accept }'
 8nft add element inet filter udp_ports_in4 '{ 192.168.0.0/12 . 192.168.0.0/16 . 137  : accept }'
 9nft add element inet filter udp_ports_in4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 5353 : accept }'
10nft add element inet filter udp_ports_in4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 5353 : accept }'
11nft add element inet filter udp_ports_in4 '{ 192.168.0.0/12 . 192.168.0.0/16 . 5353 : accept }'
12nft add element inet filter udp_ports_in4 '{ 10.0.0.0/8     . 224.0.0.0/4    . 5353 : accept }'
13nft add element inet filter udp_ports_in4 '{ 172.16.0.0/12  . 224.0.0.0/4    . 5353 : accept }'
14nft add element inet filter udp_ports_in4 '{ 192.168.0.0/12 . 224.0.0.0/4    . 5353 : accept }'

IPv6 ingress UDP ports

1nft add map inet filter udp_ports_in6 '{ typeof ip6 saddr . ip6 daddr . udp dport : verdict; flags interval; }'
2nft add element inet filter udp_ports_in6 '{ fe80::/10 . ff00::/8 . 546   : accept }'
3nft add element inet filter udp_ports_in6 '{ fe80::/10 . ff00::/8 . 5353  : accept }'
4nft add element inet filter udp_ports_in6 '{ fc00::/7  . ff00::/8 . 5353  : accept }'

IPv4 default forward networks

 1nft add map inet filter default_forward4 '{ typeof ip saddr . ip daddr . ct state : verdict; flags interval; }'
 2nft add element inet filter default_forward4 '{ 169.254.0.0/16 . 0.0.0.0/0      . new         : jump wont_forward }'
 3nft add element inet filter default_forward4 '{ 0.0.0.0/0      . 169.254.0.0/16 . new         : jump wont_forward }'
 4nft add element inet filter default_forward4 '{ 10.0.0.0/8     . 172.16.0.0/12  . new         : jump reject_with_icmp_no_route }'
 5nft add element inet filter default_forward4 '{ 10.0.0.0/8     . 192.168.0.0/16 . new         : jump reject_with_icmp_no_route }'
 6nft add element inet filter default_forward4 '{ 172.16.0.0/12  . 10.0.0.0/8     . new         : jump reject_with_icmp_no_route }'
 7nft add element inet filter default_forward4 '{ 172.16.0.0/12  . 192.168.0.0/16 . new         : jump reject_with_icmp_no_route }'
 8nft add element inet filter default_forward4 '{ 192.168.0.0/16 . 10.0.0.0/8     . new         : jump reject_with_icmp_no_route }'
 9nft add element inet filter default_forward4 '{ 192.168.0.0/16 . 172.16.0.0/12  . new         : jump reject_with_icmp_no_route }'
10nft add element inet filter default_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . new         : continue }'
11nft add element inet filter default_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . established : accept }'
12nft add element inet filter default_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . new         : continue }'
13nft add element inet filter default_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . established : accept }'
14nft add element inet filter default_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . new         : continue }'
15nft add element inet filter default_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . established : accept }'
16nft add element inet filter default_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . new         : continue }'
17nft add element inet filter default_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . new         : continue }'
18nft add element inet filter default_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . new         : continue }'
19nft add element inet filter default_forward4 '{ 0.0.0.0/0      . 10.0.0.0/8     . established : accept }'
20nft add element inet filter default_forward4 '{ 0.0.0.0/0      . 172.16.0.0/12  . established : accept }'
21nft add element inet filter default_forward4 '{ 0.0.0.0/0      . 192.168.0.0/16 . established : accept }'

IPv6 default forward networks

1nft add map inet filter default_forward6 '{ typeof ip6 saddr . ip6 daddr . ct state : verdict; flags interval; }'
2nft add element inet filter default_forward6 '{ fe80::/10 . ::/0      . new : jump wont_forward }'
3nft add element inet filter default_forward6 '{ ::/0      . fe80::/10 . new : jump wont_forward }'
4nft add element inet filter default_forward6 '{ fc00::/7  . fc00::/7  . new : continue }'
5nft add element inet filter default_forward6 '{ fc00::/7  . fc00::/7  . established : accept }'

IPv4 egress ICMP types

 1nft add map inet filter icmp_types_out4 '{ typeof ip saddr . ip daddr . icmp type : verdict; flags interval; }'
 2nft add element inet filter icmp_types_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . echo-request            : accept }'
 3nft add element inet filter icmp_types_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . echo-request            : accept }'
 4nft add element inet filter icmp_types_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . echo-request            : accept }'
 5nft add element inet filter icmp_types_out4 '{ 10.0.0.0/8     . 10.0.0.0/8     . echo-reply              : accept }'
 6nft add element inet filter icmp_types_out4 '{ 172.16.0.0/12  . 172.16.0.0/12  . echo-reply              : accept }'
 7nft add element inet filter icmp_types_out4 '{ 192.168.0.0/16 . 192.168.0.0/16 . echo-reply              : accept }'
 8nft add element inet filter icmp_types_out4 '{ 10.0.0.0/8     . 10.0.0.0/8     . destination-unreachable : accept }'
 9nft add element inet filter icmp_types_out4 '{ 172.16.0.0/12  . 172.16.0.0/12  . destination-unreachable : accept }'
10nft add element inet filter icmp_types_out4 '{ 192.168.0.0/16 . 192.168.0.0/16 . destination-unreachable : accept }'
11nft add element inet filter icmp_types_out4 '{ 0.0.0.0/0      . 0.0.0.0/0      . echo-reply              : jump icmp_echo_reply_rate_limit }'

IPv6 egress ICMP types

 1nft add map inet filter icmp_types_out6 '{ typeof ip6 saddr . ip6 daddr . icmpv6 type : verdict; flags interval; }'
 2nft add element inet filter icmp_types_out6 '{ fe80::/10 . ff00::/8  . echo-request        : accept }'
 3nft add element inet filter icmp_types_out6 '{ fc00::/7  . fc00::/7  . echo-reply          : accept }'
 4nft add element inet filter icmp_types_out6 '{ 2000::/3  . ::/0      . echo-reply          : jump icmp_echo_reply_rate_limit }'
 5nft add element inet filter icmp_types_out6 '{ fc00::/7  . fc00::/7  . nd-neighbor-advert  : accept }'
 6nft add element inet filter icmp_types_out6 '{ fe80::/10 . fe80::/10 . nd-neighbor-advert  : accept }'
 7nft add element inet filter icmp_types_out6 '{ fc00::/7  . ff00::/8  . nd-neighbor-solicit : accept }'
 8nft add element inet filter icmp_types_out6 '{ fe80::/10 . fc00::/7  . nd-neighbor-solicit : accept }'
 9nft add element inet filter icmp_types_out6 '{ fe80::/10 . fe80::/10 . nd-neighbor-solicit : accept }'
10nft add element inet filter icmp_types_out6 '{ fe80::/10 . ff00::/8  . nd-router-solicit   : accept }'
GUA prefixes

The same rules apply, but it’s less than ideal to use an over-reaching prefix like 2000::/3 because 2000::/3 should be metered. That is, anything except local GUA prefixes should be metered.

IPv4 egress TCP ports

Ports 21, 23, 25, 53, and 80 can be omitted if the point is to ensure that no egress traffic will ever be destined for unencrypted protocols. With this particular ruleset they are limited to the following destinations:

  • 169.254.0.0/16
  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

This is covered later in the hardening section.

 1nft add map inet filter tcp_ports_out4 '{ typeof ip saddr . ip daddr . tcp dport : verdict; flags interval; }'
 2nft add element inet filter tcp_ports_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 22   : accept }'
 3nft add element inet filter tcp_ports_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 22   : accept }' 
 4nft add element inet filter tcp_ports_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 22   : accept }'
 5nft add element inet filter tcp_ports_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 443  : accept }'
 6nft add element inet filter tcp_ports_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 443  : accept }' 
 7nft add element inet filter tcp_ports_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 443  : accept }'
 8nft add element inet filter tcp_ports_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 853  : accept }'
 9nft add element inet filter tcp_ports_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 853  : accept }' 
10nft add element inet filter tcp_ports_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 853  : accept }'
11nft add element inet filter tcp_ports_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 4460 : accept }'
12nft add element inet filter tcp_ports_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 4460 : accept }' 
13nft add element inet filter tcp_ports_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 4460 : accept }'
14nft add element inet filter tcp_ports_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 5349 : accept }'
15nft add element inet filter tcp_ports_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 5349 : accept }' 
16nft add element inet filter tcp_ports_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 5349 : accept }'

IPv6 egress TCP ports

Ports 21, 23, 25, 53, and 80 can be omitted if the point is to ensure that no egress traffic will ever be destined for unencrypted protocols. With this particular ruleset they are limited to the following destinations:

  • fc00::/7 (ULA)

This is covered later in the hardening section.

1nft add map inet filter tcp_ports_out6 '{ typeof ip6 saddr . ip6 daddr . tcp dport : verdict; flags interval; }'
2nft add element inet filter tcp_ports_out6 '{ fc00::/7 . fc00::/7 . 443  : accept }'
3nft add element inet filter tcp_ports_out6 '{ fc00::/7 . fc00::/7 . 853  : accept }'
4nft add element inet filter tcp_ports_out6 '{ fc00::/7 . fc00::/7 . 4460 : accept }'
5nft add element inet filter tcp_ports_out6 '{ fc00::/7 . fc00::/7 . 5349 : accept }'
6nft add element inet filter tcp_ports_out6 '{ 2000::/3 . 2000::/3 . 443  : accept }'
7nft add element inet filter tcp_ports_out6 '{ 2000::/3 . 2000::/3 . 853  : accept }'
8nft add element inet filter tcp_ports_out6 '{ 2000::/3 . 2000::/3 . 4460 : accept }'
9nft add element inet filter tcp_ports_out6 '{ 2000::/3 . 2000::/3 . 5349 : accept }'

IPv4 egress UDP ports

Ports 53, 67, 137 can be omitted if the point is to ensure that no egress traffic will ever be destined for unencrypted protocols. With this particular ruleset they are limited to the following destinations:

  • 169.254.0.0/16
  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

Port 5353 is used for mDNS. It can be safely omitted, but it is useful for enumeration of hostnames on local networks (zeroconf). Currently mDNS doesn’t use any encryption as of 1-26-2023, and I would say it should be omitted in environments that use NDP-RA. For more information on mDNS, refer to: https://datatracker.ietf.org/doc/html/draft-rafiee-dnssd-mdns-threatmodel-01

This is covered later in the hardening section.

 1nft add map inet filter udp_ports_out4 '{ typeof ip saddr . ip daddr . udp dport : verdict; flags interval; }'
 2nft add element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 67   : accept }'
 3nft add element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 67   : accept }'
 4nft add element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 67   : accept }'
 5nft add element inet filter udp_ports_out4 '{ 169.254.0.0/16 . 169.254.0.0/16 . 67   : accept }'
 6nft add element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 53   : accept }'
 7nft add element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 53   : accept }'
 8nft add element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 53   : accept }'
 9nft add element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 137  : accept }'
10nft add element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 137  : accept }'
11nft add element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 137  : accept }'
12nft add element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 224.0.0.0/4    . 5353 : accept }'
13nft add element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 224.0.0.0/4    . 5353 : accept }'
14nft add element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 224.0.0.0/4    . 5353 : accept }'
15nft add element inet filter udp_ports_out4 '{ 169.254.0.0/16 . 224.0.0.0/4    . 5353 : accept }'
16nft add element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 443  : accept }'
17nft add element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 443  : accept }'
18nft add element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 443  : accept }'
19nft add element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 1194 : accept }'
20nft add element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 1194 : accept }'
21nft add element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 1194 : accept }'

IPv6 egress UDP ports

1nft add map inet filter udp_ports_out6 '{ typeof ip6 saddr . ip6 daddr . udp dport : verdict; flags interval; }'
2nft add element inet filter udp_ports_out6 '{ fe80::/10 . ff00::/8 . 547  : accept }'
3nft add element inet filter udp_ports_out6 '{ 2000::/3  . ::/0     . 443  : accept }'
4nft add element inet filter udp_ports_out6 '{ fc00::/7  . ff00::/8 . 5353 : accept }'

IPv4 forward ICMP types

 1nft add map inet filter icmp_types_forward4 '{ typeof ip saddr . ip daddr . icmp type : verdict; flags interval; }'
 2nft add element inet filter icmp_types_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . echo-request            : accept }'
 3nft add element inet filter icmp_types_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . echo-request            : accept }'
 4nft add element inet filter icmp_types_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . echo-request            : accept }'
 5nft add element inet filter icmp_types_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . echo-reply              : accept }'
 6nft add element inet filter icmp_types_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . echo-reply              : accept }'
 7nft add element inet filter icmp_types_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . echo-reply              : accept }'
 8nft add element inet filter icmp_types_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . destination-unreachable : accept }'
 9nft add element inet filter icmp_types_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . destination-unreachable : accept }'
10nft add element inet filter icmp_types_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . destination-unreachable : accept }'
11nft add element inet filter icmp_types_forward4 '{ 0.0.0.0/0      . 0.0.0.0/0      . echo-reply              : jump icmp_echo_reply_rate_limit }'

IPv6 forward ICMP types

1nft add map inet filter icmp_types_forward6 '{ typeof ip6 saddr . ip6 daddr . icmpv6 type : verdict; flags interval; }'
2nft add element inet filter icmp_types_forward6 '{ fe80::/10 . ff00::/8  . echo-request        : accept }'
3nft add element inet filter icmp_types_forward6 '{ fc00::/7  . fc00::/7  . echo-reply          : accept }'
4nft add element inet filter icmp_types_forward6 '{ 2000::/3  . ::/0      . echo-reply          : jump icmp_echo_reply_rate_limit }'

IPv4 forward TCP ports

 1nft add map inet filter tcp_ports_forward4 '{ typeof ip saddr . ip daddr . tcp dport : verdict; flags interval; }'
 2nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 21   : accept }'
 3nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 21   : accept }'
 4nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 21   : accept }'
 5nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 23   : accept }'
 6nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 23   : accept }'
 7nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 23   : accept }'
 8nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 25   : accept }'
 9nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 25   : accept }'
10nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 25   : accept }'
11nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 53   : accept }'
12nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 53   : accept }'
13nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 53   : accept }'
14nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 80   : accept }'
15nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 80   : accept }'
16nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 80   : accept }'
17nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 22   : accept }'
18nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 22   : accept }' 
19nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 22   : accept }'
20nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 443  : accept }'
21nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 443  : accept }' 
22nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 443  : accept }'
23nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 853  : accept }'
24nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 853  : accept }' 
25nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 853  : accept }'
26nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 4460 : accept }'
27nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 4460 : accept }' 
28nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 4460 : accept }'
29nft add element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 5349 : accept }'
30nft add element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 5349 : accept }' 
31nft add element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 5349 : accept }'

IPv6 forward TCP ports

 1nft add map inet filter tcp_ports_forward6 '{ typeof ip6 saddr . ip6 daddr . tcp dport : verdict; flags interval; }'
 2nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 21   : accept }'
 3nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 23   : accept }'
 4nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 25   : accept }'
 5nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 53   : accept }'
 6nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 80   : accept }'
 7nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 443  : accept }'
 8nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 853  : accept }'
 9nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 4460 : accept }'
10nft add element inet filter tcp_ports_forward6 '{ fc00::/7 . fc00::/7 . 5349 : accept }'
11nft add element inet filter tcp_ports_forward6 '{ 2000::/3 . 2000::/3 . 443  : accept }'
12nft add element inet filter tcp_ports_forward6 '{ 2000::/3 . 2000::/3 . 853  : accept }'
13nft add element inet filter tcp_ports_forward6 '{ 2000::/3 . 2000::/3 . 4460 : accept }'
14nft add element inet filter tcp_ports_forward6 '{ 2000::/3 . 2000::/3 . 5349 : accept }'

IPv4 forward UDP ports

1nft add map inet filter udp_ports_forward4 '{ typeof ip saddr . ip daddr . udp dport : verdict; flags interval; }'
2nft add element inet filter udp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 53   : accept }'
3nft add element inet filter udp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 53   : accept }'
4nft add element inet filter udp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 53   : accept }'
5nft add element inet filter udp_ports_forward4 '{ 10.0.0.0/8     . 0.0.0.0/0      . 443  : accept }'
6nft add element inet filter udp_ports_forward4 '{ 172.16.0.0/12  . 0.0.0.0/0      . 443  : accept }'
7nft add element inet filter udp_ports_forward4 '{ 192.168.0.0/16 . 0.0.0.0/0      . 443  : accept }'

IPv6 forward UDP ports

1nft add map inet filter udp_ports_forward6 '{ typeof ip6 saddr . ip6 daddr . udp dport : verdict; flags interval; }'
2nft add element inet filter udp_ports_forward6 '{ 2000::/3  . ::/0     . 443  : accept }'

NAT Forwarding ports for IPv4

1nft add map inet filter tcp_ports_nat_forward4 '{ type inet_service : ipv4_addr; }'
2nft add map inet filter udp_ports_nat_forward4 '{ type inet_service : ipv4_addr; }'

Masquerading

1nft add map inet filter masquerade_networks4 '{ typeof oif . ip saddr : verdict; flags interval; }'

Rules

Metered ICMP port unreachable

1nft add rule inet filter reject_with_icmp_port_unreachable_metered add @icmp_egress_meter4 '{ ip daddr timeout 4s limit rate 3/second }' counter reject with icmpx type port-unreachable
2nft add rule inet filter reject_with_icmp_port_unreachable_metered add @icmp_egress_meter6 '{ ip6 daddr timeout 4s limit rate 3/second }' counter reject with icmpx type port-unreachable

Un-metered ICMP port unreachable

1nft add rule inet filter reject_with_icmp_port_unreachable counter reject with icmpx type port-unreachable

Metered ICMP host unreachable

1nft add rule inet filter reject_with_icmp_host_unreachable_metered add @icmp_egress_meter4 '{ ip daddr timeout 4s limit rate 3/second }' counter reject with icmpx type host-unreachable
2nft add rule inet filter reject_with_icmp_host_unreachable_metered add @icmp_egress_meter6 '{ ip6 daddr timeout 4s limit rate 3/second }' counter reject with icmpx type host-unreachable

Un-Metered ICMP host unreachable

1nft add rule inet filter reject_with_icmp_host_unreachable counter reject with icmpx type host-unreachable

Metered ICMP no route

1nft add rule inet filter reject_with_icmp_no_route_metered add @icmp_egress_meter4 '{ ip daddr timeout 4s limit rate 3/second }' counter reject with icmpx type no-route
2nft add rule inet filter reject_with_icmp_no_route_metered add @icmp_egress_meter6 '{ ip6 daddr timeout 4s limit rate 3/second }' counter reject with icmpx type no-route

Un-Metered ICMP no route

1nft add rule inet filter reject_with_icmp_no_route counter reject with icmpx type no-route

Metered ICMP admin prohibited

1nft add rule inet filter reject_with_icmp_admin_prohibited add @icmp_egress_meter4 '{ ip daddr timeout 4s limit rate 3/second }' counter reject with icmpx type admin-prohibited
2nft add rule inet filter reject_with_icmp_admin_prohibited_metered add @icmp_egress_meter6 '{ ip6 daddr timeout 4s limit rate 3/second }' counter reject with icmpx type admin-prohibited

Un-Metered ICMP admin-prohibited

1nft add rule inet filter reject_with_icmp_admin_prohibited counter reject with icmpx type admin-prohibited

icmp_in

1nft add rule inet filter icmp_in ip saddr . ip daddr . icmp type vmap @icmp_types_in4
2nft add rule inet filter icmp_in ip6 saddr . ip6 daddr . icmpv6 type vmap @icmp_types_in6

tcp_in

1nft add rule inet filter tcp_in ct state established accept
2nft add rule inet filter tcp_in ip saddr . ip daddr . tcp dport vmap @tcp_ports_in4
3nft add rule inet filter tcp_in ip6 saddr . ip6 daddr . tcp dport vmap @tcp_ports_in6

udp_in

1nft add rule inet filter udp_in ct state established accept
2nft add rule inet filter udp_in ip saddr . ip daddr . udp dport vmap @udp_ports_in4
3nft add rule inet filter udp_in ip6 saddr . ip6 daddr . udp dport vmap @udp_ports_in6

ether_in

1nft add rule inet filter ether_in ip protocol vmap '{ tcp : jump tcp_in, udp : jump udp_in , icmp : jump icmp_in }'
2nft add rule inet filter ether_in ip6 nexthdr vmap '{ tcp : jump tcp_in, udp : jump udp_in , icmpv6 : jump icmp_in, ipv6-icmp: jump icmp_in }'

input

1nft add rule inet filter input meta iiftype vmap '{ loopback: accept }'
2nft add rule inet filter input ip saddr vmap @drop_bogons4
3nft add rule inet filter input ip6 saddr vmap @drop_bogons6
4nft add rule inet filter input meta iiftype vmap '{ ether: jump ether_in }'

icmp_forward

1nft add rule inet filter icmp_forward ip saddr . ip daddr . icmp type vmap @icmp_types_forward4
2nft add rule inet filter icmp_forward ip6 saddr . ip6 daddr . icmpv6 type vmap @icmp_types_forward6

tcp_forward

1nft add rule inet filter tcp_forward ct state established accept
2nft add rule inet filter tcp_forward ip saddr . ip daddr . tcp dport vmap @tcp_ports_forward4
3nft add rule inet filter tcp_forward ip6 saddr . ip6 daddr . tcp dport vmap @tcp_ports_forward6

udp_forward

1nft add rule inet filter udp_forward ct state established accept
2nft add rule inet filter udp_forward ip saddr . ip daddr . udp dport vmap @udp_ports_forward4
3nft add rule inet filter udp_forward ip6 saddr . ip6 daddr . udp dport vmap @udp_ports_forward6

ether_forward

1nft add rule inet filter ether_forward ip saddr . ip daddr . ct state vmap @default_forward4
2nft add rule inet filter ether_forward ip6 saddr . ip6 daddr . ct state vmap @default_forward6
3nft add rule inet filter ether_forward ip protocol vmap '{ tcp : jump tcp_forward, udp : jump udp_forward , icmp : jump icmp_forward }' 

forward

1nft add rule inet filter forward ip saddr vmap @drop_bogons4
2nft add rule inet filter forward ip6 saddr vmap @drop_bogons6
3nft add rule inet filter forward meta oiftype vmap '{ ether: jump ether_forward }'

ICMP echo-reply rate limit

1nft add rule inet filter icmp_echo_reply_rate_limit add @icmp_egress_meter4 '{ ip saddr timeout 4s limit rate 3/second }' accept
2nft add rule inet filter icmp_echo_reply_rate_limit add @icmp_egress_meter6 '{ ip6 saddr timeout 4s limit rate 3/second }' accept

icmp_out

1nft add rule inet filter icmp_out ip saddr . ip daddr . icmp type vmap @icmp_types_out4
2nft add rule inet filter icmp_out ip6 saddr . ip6 daddr . icmpv6 type vmap @icmp_types_out6

tcp_out

1nft add rule inet filter tcp_out ct state established accept
2nft add rule inet filter tcp_out ip saddr . ip daddr . tcp dport vmap @tcp_ports_out4
3nft add rule inet filter tcp_out ip6 saddr . ip6 daddr . tcp dport vmap @tcp_ports_out6

udp_out

1nft add rule inet filter udp_out ct state established accept
2nft add rule inet filter udp_out ip saddr . ip daddr . udp dport vmap @udp_ports_out4
3nft add rule inet filter udp_out ip6 saddr . ip6 daddr . udp dport vmap @udp_ports_out6

ether_out

1nft add rule inet filter ether_out ip protocol vmap '{ tcp : jump tcp_out, udp : jump udp_out, icmp : jump icmp_out }'
2nft add rule inet filter ether_out ip6 nexthdr vmap '{ tcp : jump tcp_out, udp : jump udp_out, icmpv6 : jump icmp_out, ipv6-icmp: jump icmp_out }'

masq

1nft add rule inet filter masq ip daddr vmap @drop_bogons4
2nft add rule inet filter masq ip daddr @local_networks return
3nft add rule inet filter masq masquerade

output

1nft add rule inet filter output meta oiftype vmap '{ loopback: accept }'
2nft add rule inet filter output ip daddr vmap @drop_bogons4
3nft add rule inet filter output ip6 daddr vmap @drop_bogons6
4nft add rule inet filter output meta oiftype vmap '{ ether: jump ether_out }'

prerouting

1nft add rule inet filter prerouting ip protocol tcp dnat to tcp dport map @tcp_ports_nat_forward4
2nft add rule inet filter prerouting ip protocol udp dnat to udp dport map @udp_ports_nat_forward4

postrouting

1nft add rule inet filter postrouting oif . ip saddr vmap @masquerade_networks4

Default chain policies

1nft add chain inet filter input '{ policy drop; }'
2nft add chain inet filter forward '{ policy drop; }'
3nft add chain inet filter output '{ policy drop; }'

Logging

1nft add rule inet filter input log prefix "input" group 1
2nft add rule inet filter input counter
3
4nft add rule inet filter forward log prefix "forward" group 1
5nft add rule inet filter forward counter
6
7nft add rule inet filter output log prefix "output" group 1
8nft add rule inet filter output counter

Viewing logged packets

Dropped packets are logged in pcap format: tcpdump -vvv -n -e -ttt -i nflog:1 -XX

 1 00:00:00.000207 version 0, resource ID 1, family IPv4 (2), length 128: (tos 0x10, ttl 64, id 39694, offset 0, flags [DF], proto UDP (17), length 76)
 2    10.211.55.11.50429 > 108.59.2.24.123: [bad udp cksum 0xb07a -> 0x5c51!] NTPv4, Client, length 48
 3	Leap indicator:  (0), Stratum 0 (unspecified), poll 0 (1s), precision 0
 4	Root Delay: 0.000000, Root dispersion: 0.000000, Reference-ID: (unspec)
 5	  Reference Timestamp:  0.000000000
 6	  Originator Timestamp: 0.000000000
 7	  Receive Timestamp:    0.000000000
 8	  Transmit Timestamp:   3883429715.031809542 (2023-01-23T02:28:35Z)
 9	    Originator - Receive Timestamp:  0.000000000
10	    Originator - Transmit Timestamp: 3883429715.031809542 (2023-01-23T02:28:35Z)
11	0x0000:  0200 0001 0800 0100 0800 0300 0b00 0a00  ................
12	0x0010:  6f75 7470 7574 0000 0800 0500 0000 0002  output..........
13	0x0020:  0800 0b00 0000 0069 0800 0e00 0000 006f  .......i.......o
14	0x0030:  5000 0900 4510 004c 9b0e 4000 4011 ef51  P...E..L..@.@..Q
15	0x0040:  0ad3 370b 6c3b 0218 c4fd 007b 0038 b07a  ..7.l;.....{.8.z
16	0x0050:  2300 0000 0000 0000 0000 0000 0000 0000  #...............
17	0x0060:  0000 0000 0000 0000 0000 0000 0000 0000  ................
18	0x0070:  0000 0000 0000 0000 e778 6f53 0824 ab92  .........xoS.$..

Per-chain logging

Metered ICMP port unreachable
1nft add rule inet filter reject_with_icmp_port_unreachable_metered log prefix "reject_with_icmp_port_unreachable_metered" group 1
2nft add rule inet filter reject_with_icmp_port_unreachable_metered counter drop
Metered ICMP host unreachable
1nft add rule inet filter reject_with_icmp_host_unreachable_metered log prefix "reject_with_icmp_host_unreachable_metered" group 1
2nft add rule inet filter reject_with_icmp_host_unreachable_metered counter drop
Metered ICMP no route
1nft add rule inet filter reject_with_icmp_no_route_metered log prefix "reject_with_icmp_no_route_metered" group 1
2nft add rule inet filter reject_with_icmp_no_route_metered counter drop
Metered ICMP admin prohibited
1nft add rule inet filter reject_with_icmp_admin_prohibited_metered log prefix "reject_with_icmp_admin_prohibited_metered" group 1
2nft add rule inet filter reject_with_icmp_admin_prohibited_metered counter drop
Ingress ICMP
1nft add rule inet filter icmp_in log prefix "icmp_in" group 1
2nft add rule inet filter icmp_in counter drop
Ingress TCP
1nft add rule inet filter tcp_in log prefix "tcp_in" group 1
2nft add rule inet filter tcp_in counter drop
Ingress UDP
1nft add rule inet filter udp_in log prefix "udp_in" group 1
2nft add rule inet filter udp_in counter drop
Ingress Ether
1nft add rule inet filter ether_in log prefix "ether_in" group 1
2nft add rule inet filter ether_in counter drop
Forward ICMP
1nft add rule inet filter icmp_forward log prefix "icmp_forward" group 1
2nft add rule inet filter icmp_forward counter drop
Forward TCP
1nft add rule inet filter tcp_forward log prefix "tcp_forward" group 1
2nft add rule inet filter tcp_forward counter drop
Forward UDP
1nft add rule inet filter udp_forward log prefix "udp_forward" group 1
2nft add rule inet filter udp_forward counter drop
Forward Ether
1nft add rule inet filter ether_forward log prefix "ether_forward" group 1
2nft add rule inet filter ether_forward counter drop
Egress ICMP echo replies
1nft add rule inet filter icmp_echo_reply_rate_limit log prefix "icmp_echo_reply_rate_limit" group 1
2nft add rule inet filter icmp_echo_reply_rate_limit counter drop
Egress ICMP
1nft add rule inet filter icmp_out log prefix "icmp_out" group 1
2nft add rule inet filter icmp_out counter drop
Egress TCP
1nft add rule inet filter tcp_out log prefix "tcp_out" group 1
2nft add rule inet filter tcp_out counter drop
Egress UDP
1nft add rule inet filter udp_out log prefix "udp_out" group 1
2nft add rule inet filter udp_out counter drop
Egress Ether
1nft add rule inet filter ether_out log prefix "ether_out" group 1
2nft add rule inet filter ether_out counter drop

Filter state persistence

Configuration format

If you are starting from here you can copy / paste this section to /etc/nftables.conf. Otherwise the current filter state can be made to persist with:

  • nft -a -s list ruleset | tee /etc/nftables.conf
  1table inet filter { # handle 60
  2	set icmp_egress_meter4 { # handle 34
  3		type ipv4_addr
  4		size 8
  5		flags dynamic,timeout
  6	}
  7
  8	set icmp_egress_meter6 { # handle 35
  9		type ipv6_addr
 10		size 8
 11		flags dynamic,timeout
 12	}
 13
 14	map drop_bogons4 { # handle 36
 15		type ipv4_addr : verdict
 16		flags interval
 17		elements = { 0.0.0.0/8 : jump bogon, 10.0.0.0/8 : continue,
 18			     100.64.0.0/10 : jump bogon, 127.0.0.0/8 : jump bogon,
 19			     169.254.0.0/16 : continue, 172.16.0.0/12 : continue,
 20			     192.0.0.0/24 : jump bogon, 192.0.2.0/24 : jump bogon,
 21			     192.168.0.0/16 : continue, 198.18.0.0/15 : jump bogon,
 22			     198.51.100.0/24 : jump bogon, 203.0.113.0/24 : jump bogon,
 23			     224.0.0.0/4 : continue, 240.0.0.0/4 : jump bogon }
 24	}
 25
 26	set local_networks { # handle 37
 27		type ipv4_addr
 28		flags interval
 29		elements = { 10.0.0.0/8, 169.254.0.0/16,
 30			     172.16.0.0/12, 192.168.0.0/16 }
 31	}
 32
 33	map drop_bogons6 { # handle 38
 34		type ipv6_addr : verdict
 35		flags interval
 36		elements = { ::/96 : jump bogon,
 37			     ::ffff:0.0.0.0/96 : jump bogon,
 38			     100::/64 : jump bogon,
 39			     2001::/40 : jump bogon,
 40			     2001:0:a00::/40 : jump bogon,
 41			     2001:0:7f00::/40 : jump bogon,
 42			     2001:0:a9fe::/48 : jump bogon,
 43			     2001:0:ac10::/44 : jump bogon,
 44			     2001:0:c000::/56 : jump bogon,
 45			     2001:0:c000:200::/56 : jump bogon,
 46			     2001:0:c0a8::/48 : jump bogon,
 47			     2001:0:c612::/47 : jump bogon,
 48			     2001:0:c633:6400::/56 : jump bogon,
 49			     2001:0:cb00:7100::/56 : jump bogon,
 50			     2001:0:e000::/36 : jump bogon,
 51			     2001:0:f000::/36 : jump bogon,
 52			     2001:10::/28 : jump bogon,
 53			     2001:db8::/32 : jump bogon,
 54			     2002::/24 : jump bogon,
 55			     2002:a00::/24 : jump bogon,
 56			     2002:7f00::/24 : jump bogon,
 57			     2002:a9fe::/32 : jump bogon,
 58			     2002:ac10::/28 : jump bogon,
 59			     2002:c000::/40 : jump bogon,
 60			     2002:c000:200::/40 : jump bogon,
 61			     2002:c0a8::/32 : jump bogon,
 62			     2002:c612::/31 : jump bogon,
 63			     2002:c633:6400::/40 : jump bogon,
 64			     2002:cb00:7100::/40 : jump bogon,
 65			     2002:e000::/20 : jump bogon,
 66			     2002:f000::/20 : jump bogon,
 67			     fc00::/7 : continue,
 68			     fe80::/10 : continue,
 69			     fec0::/10 : jump bogon,
 70			     ff00::/8 : continue }
 71	}
 72
 73	map reject_or_drop_port4 { # handle 39
 74		typeof ip saddr . ip daddr : verdict
 75		flags interval
 76		elements = { 10.0.0.0/8 . 10.0.0.0/8 : jump reject_with_icmp_port_unreachable,
 77			     172.16.0.0/12 . 172.16.0.0/12 : jump reject_with_icmp_port_unreachable,
 78			     192.168.0.0/16 . 192.168.0.0/16 : jump reject_with_icmp_port_unreachable,
 79			     169.254.0.0/16 . 169.254.0.0/16 : jump reject_with_icmp_port_unreachable,
 80			     0.0.0.0/0 . 0.0.0.0/0 : jump reject_with_icmp_port_unreachable_metered }
 81	}
 82
 83	map reject_or_drop_port6 { # handle 40
 84		typeof ip6 saddr . ip6 daddr : verdict
 85		flags interval
 86		elements = { fe80::/10 . fe80::/10 : jump reject_with_icmp_port_unreachable,
 87			     fc00::/7 . fc00::/7 : jump reject_with_icmp_port_unreachable,
 88			     ::/0 . ::/0 : jump reject_with_icmp_port_unreachable_metered }
 89	}
 90
 91	map icmp_types_in4 { # handle 41
 92		typeof ip saddr . ip daddr . icmp type : verdict
 93		flags interval
 94		elements = { 0.0.0.0/0 . 0.0.0.0/0 . echo-request : accept,
 95			     0.0.0.0/0 . 0.0.0.0/0 . echo-reply : accept,
 96			     0.0.0.0/0 . 0.0.0.0/0 . destination-unreachable : accept }
 97	}
 98
 99	map icmp_types_in6 { # handle 42
100		typeof ip6 saddr . ip6 daddr . icmpv6 type : verdict
101		flags interval
102		elements = { fe80::/10 . fe80::/10 . echo-request : accept,
103			     fe80::/10 . ff00::/8 . echo-request : accept,
104			     fc00::/7 . fc00::/7 . echo-request : accept,
105			     fe80::/10 . fe80::/10 . echo-reply : accept,
106			     fe80::/10 . ff00::/8 . echo-reply : accept,
107			     fc00::/7 . fc00::/7 . echo-reply : accept,
108			     fe80::/10 . fe80::/10 . nd-neighbor-solicit : accept,
109			     fc00::/7 . ff00::/8 . nd-neighbor-solicit : accept,
110			     fc00::/7 . fc00::/7 . nd-neighbor-solicit : accept,
111			     fc00::/7 . fc00::/7 . nd-neighbor-advert : accept,
112			     fe80::/10 . fe80::/10 . nd-neighbor-advert : accept,
113			     fe80::/10 . ff00::/8 . nd-router-advert : accept,
114			     fe80::/10 . fe80::/10 . nd-router-advert : accept }
115	}
116
117	map tcp_ports_in4 { # handle 43
118		typeof ip saddr . ip daddr . tcp dport : verdict
119		flags interval
120		elements = { 0.0.0.0/0 . 0.0.0.0/0 . 22 : accept }
121	}
122
123	map tcp_ports_in6 { # handle 44
124		typeof ip6 saddr . ip6 daddr . tcp dport : verdict
125		flags interval
126		elements = { ::/0 . ::/0 . 22 : accept }
127	}
128
129	map udp_ports_in4 { # handle 45
130		typeof ip saddr . ip daddr . udp dport : verdict
131		flags interval
132		elements = { 169.254.0.0/16 . 169.254.0.0/16 . 68 : accept,
133			     10.0.0.0/8 . 10.0.0.0/8 . 68 : accept,
134			     172.16.0.0/12 . 172.16.0.0/12 . 68 : accept,
135			     192.160.0.0/12 . 192.168.0.0/16 . 68 : accept,
136			     10.0.0.0/8 . 10.0.0.0/8 . 137 : accept,
137			     172.16.0.0/12 . 172.16.0.0/12 . 137 : accept,
138			     192.160.0.0/12 . 192.168.0.0/16 . 137 : accept,
139			     10.0.0.0/8 . 10.0.0.0/8 . 5353 : accept,
140			     172.16.0.0/12 . 172.16.0.0/12 . 5353 : accept,
141			     192.160.0.0/12 . 192.168.0.0/16 . 5353 : accept,
142			     10.0.0.0/8 . 224.0.0.0/4 . 5353 : accept,
143			     172.16.0.0/12 . 224.0.0.0/4 . 5353 : accept,
144			     192.160.0.0/12 . 224.0.0.0/4 . 5353 : accept }
145	}
146
147	map udp_ports_in6 { # handle 46
148		typeof ip6 saddr . ip6 daddr . udp dport : verdict
149		flags interval
150		elements = { fe80::/10 . ff00::/8 . 546 : accept,
151			     fe80::/10 . ff00::/8 . 5353 : accept,
152			     fc00::/7 . ff00::/8 . 5353 : accept }
153	}
154
155	map default_forward4 { # handle 47
156		typeof ip saddr . ip daddr . ct state : verdict
157		flags interval
158		elements = { 169.254.0.0/16 . 0.0.0.0/0 . new : jump wont_forward,
159			     0.0.0.0/0 . 169.254.0.0/16 . new : jump wont_forward,
160			     10.0.0.0/8 . 172.16.0.0/12 . new : jump reject_with_icmp_no_route,
161			     10.0.0.0/8 . 192.168.0.0/16 . new : jump reject_with_icmp_no_route,
162			     172.16.0.0/12 . 10.0.0.0/8 . new : jump reject_with_icmp_no_route,
163			     172.16.0.0/12 . 192.168.0.0/16 . new : jump reject_with_icmp_no_route,
164			     192.168.0.0/16 . 10.0.0.0/8 . new : jump reject_with_icmp_no_route,
165			     192.168.0.0/16 . 172.16.0.0/12 . new : jump reject_with_icmp_no_route,
166			     10.0.0.0/8 . 10.0.0.0/8 . new : continue,
167			     10.0.0.0/8 . 10.0.0.0/8 . established : accept,
168			     172.16.0.0/12 . 172.16.0.0/12 . new : continue,
169			     172.16.0.0/12 . 172.16.0.0/12 . established : accept,
170			     192.168.0.0/16 . 192.168.0.0/16 . new : continue,
171			     192.168.0.0/16 . 192.168.0.0/16 . established : accept,
172			     10.0.0.0/8 . 0.0.0.0/0 . new : continue,
173			     172.16.0.0/12 . 0.0.0.0/0 . new : continue,
174			     192.168.0.0/16 . 0.0.0.0/0 . new : continue,
175			     0.0.0.0/0 . 10.0.0.0/8 . established : accept,
176			     0.0.0.0/0 . 172.16.0.0/12 . established : accept,
177			     0.0.0.0/0 . 192.168.0.0/16 . established : accept }
178	}
179
180	map default_forward6 { # handle 48
181		typeof ip6 saddr . ip6 daddr . ct state : verdict
182		flags interval
183		elements = { fe80::/10 . ::/0 . new : jump wont_forward,
184			     ::/0 . fe80::/10 . new : jump wont_forward,
185			     fc00::/7 . fc00::/7 . new : continue,
186			     fc00::/7 . fc00::/7 . established : accept }
187	}
188
189	map icmp_types_out4 { # handle 49
190		typeof ip saddr . ip daddr . icmp type : verdict
191		flags interval
192		elements = { 10.0.0.0/8 . 0.0.0.0/0 . echo-request : accept,
193			     172.16.0.0/12 . 0.0.0.0/0 . echo-request : accept,
194			     192.168.0.0/16 . 0.0.0.0/0 . echo-request : accept,
195			     10.0.0.0/8 . 10.0.0.0/8 . echo-reply : accept,
196			     172.16.0.0/12 . 172.16.0.0/12 . echo-reply : accept,
197			     192.168.0.0/16 . 192.168.0.0/16 . echo-reply : accept,
198			     10.0.0.0/8 . 10.0.0.0/8 . destination-unreachable : accept,
199			     172.16.0.0/12 . 172.16.0.0/12 . destination-unreachable : accept,
200			     192.168.0.0/16 . 192.168.0.0/16 . destination-unreachable : accept,
201			     0.0.0.0/0 . 0.0.0.0/0 . echo-reply : jump icmp_echo_reply_rate_limit }
202	}
203
204	map icmp_types_out6 { # handle 50
205		typeof ip6 saddr . ip6 daddr . icmpv6 type : verdict
206		flags interval
207		elements = { fe80::/10 . ff00::/8 . echo-request : accept,
208			     fc00::/7 . fc00::/7 . echo-reply : accept,
209			     2000::/3 . ::/0 . echo-reply : jump icmp_echo_reply_rate_limit,
210			     fc00::/7 . fc00::/7 . nd-neighbor-advert : accept,
211			     fe80::/10 . fe80::/10 . nd-neighbor-advert : accept,
212			     fc00::/7 . ff00::/8 . nd-neighbor-solicit : accept,
213			     fe80::/10 . fc00::/7 . nd-neighbor-solicit : accept,
214			     fe80::/10 . fe80::/10 . nd-neighbor-solicit : accept,
215			     fe80::/10 . ff00::/8 . nd-router-solicit : accept }
216	}
217
218	map tcp_ports_out4 { # handle 51
219		typeof ip saddr . ip daddr . tcp dport : verdict
220		flags interval
221		elements = { 10.0.0.0/8 . 0.0.0.0/0 . 22 : accept,
222			     172.16.0.0/12 . 0.0.0.0/0 . 22 : accept,
223			     192.168.0.0/16 . 0.0.0.0/0 . 22 : accept,
224			     10.0.0.0/8 . 0.0.0.0/0 . 443 : accept,
225			     172.16.0.0/12 . 0.0.0.0/0 . 443 : accept,
226			     192.168.0.0/16 . 0.0.0.0/0 . 443 : accept,
227			     10.0.0.0/8 . 0.0.0.0/0 . 853 : accept,
228			     172.16.0.0/12 . 0.0.0.0/0 . 853 : accept,
229			     192.168.0.0/16 . 0.0.0.0/0 . 853 : accept,
230			     10.0.0.0/8 . 0.0.0.0/0 . 4460 : accept,
231			     172.16.0.0/12 . 0.0.0.0/0 . 4460 : accept,
232			     192.168.0.0/16 . 0.0.0.0/0 . 4460 : accept,
233			     10.0.0.0/8 . 0.0.0.0/0 . 5349 : accept,
234			     172.16.0.0/12 . 0.0.0.0/0 . 5349 : accept,
235			     192.168.0.0/16 . 0.0.0.0/0 . 5349 : accept }
236	}
237
238	map tcp_ports_out6 { # handle 52
239		typeof ip6 saddr . ip6 daddr . tcp dport : verdict
240		flags interval
241		elements = { fc00::/7 . fc00::/7 . 443 : accept,
242			     fc00::/7 . fc00::/7 . 853 : accept,
243			     fc00::/7 . fc00::/7 . 4460 : accept,
244			     fc00::/7 . fc00::/7 . 5349 : accept,
245			     2000::/3 . 2000::/3 . 443 : accept,
246			     2000::/3 . 2000::/3 . 853 : accept,
247			     2000::/3 . 2000::/3 . 4460 : accept,
248			     2000::/3 . 2000::/3 . 5349 : accept }
249	}
250
251	map udp_ports_out4 { # handle 53
252		typeof ip saddr . ip daddr . udp dport : verdict
253		flags interval
254		elements = { 10.0.0.0/8 . 10.0.0.0/8 . 67 : accept,
255			     172.16.0.0/12 . 172.16.0.0/12 . 67 : accept,
256			     192.168.0.0/16 . 192.168.0.0/16 . 67 : accept,
257			     169.254.0.0/16 . 169.254.0.0/16 . 67 : accept,
258			     10.0.0.0/8 . 10.0.0.0/8 . 53 : accept,
259			     172.16.0.0/12 . 172.16.0.0/12 . 53 : accept,
260			     192.168.0.0/16 . 192.168.0.0/16 . 53 : accept,
261			     10.0.0.0/8 . 10.0.0.0/8 . 137 : accept,
262			     172.16.0.0/12 . 172.16.0.0/12 . 137 : accept,
263			     192.168.0.0/16 . 192.168.0.0/16 . 137 : accept,
264			     10.0.0.0/8 . 224.0.0.0/4 . 5353 : accept,
265			     172.16.0.0/12 . 224.0.0.0/4 . 5353 : accept,
266			     192.168.0.0/16 . 224.0.0.0/4 . 5353 : accept,
267			     169.254.0.0/16 . 224.0.0.0/4 . 5353 : accept,
268			     10.0.0.0/8 . 0.0.0.0/0 . 443 : accept,
269			     172.16.0.0/12 . 0.0.0.0/0 . 443 : accept,
270			     192.168.0.0/16 . 0.0.0.0/0 . 443 : accept,
271			     10.0.0.0/8 . 0.0.0.0/0 . 1194 : accept,
272			     172.16.0.0/12 . 0.0.0.0/0 . 1194 : accept,
273			     192.168.0.0/16 . 0.0.0.0/0 . 1194 : accept }
274	}
275
276	map udp_ports_out6 { # handle 54
277		typeof ip6 saddr . ip6 daddr . udp dport : verdict
278		flags interval
279		elements = { fe80::/10 . ff00::/8 . 547 : accept,
280			     2000::/3 . ::/0 . 443 : accept,
281			     fc00::/7 . ff00::/8 . 5353 : accept }
282	}
283
284	map icmp_types_forward4 { # handle 55
285		typeof ip saddr . ip daddr . icmp type : verdict
286		flags interval
287		elements = { 10.0.0.0/8 . 0.0.0.0/0 . echo-request : accept,
288			     172.16.0.0/12 . 0.0.0.0/0 . echo-request : accept,
289			     192.168.0.0/16 . 0.0.0.0/0 . echo-request : accept,
290			     10.0.0.0/8 . 10.0.0.0/8 . echo-reply : accept,
291			     172.16.0.0/12 . 172.16.0.0/12 . echo-reply : accept,
292			     192.168.0.0/16 . 192.168.0.0/16 . echo-reply : accept,
293			     10.0.0.0/8 . 10.0.0.0/8 . destination-unreachable : accept,
294			     172.16.0.0/12 . 172.16.0.0/12 . destination-unreachable : accept,
295			     192.168.0.0/16 . 192.168.0.0/16 . destination-unreachable : accept,
296			     0.0.0.0/0 . 0.0.0.0/0 . echo-reply : jump icmp_echo_reply_rate_limit }
297	}
298
299	map icmp_types_forward6 { # handle 56
300		typeof ip6 saddr . ip6 daddr . icmpv6 type : verdict
301		flags interval
302		elements = { fe80::/10 . ff00::/8 . echo-request : accept,
303			     fc00::/7 . fc00::/7 . echo-reply : accept,
304			     2000::/3 . ::/0 . echo-reply : jump icmp_echo_reply_rate_limit }
305	}
306
307	map tcp_ports_forward4 { # handle 57
308		typeof ip saddr . ip daddr . tcp dport : verdict
309		flags interval
310		elements = { 10.0.0.0/8 . 10.0.0.0/8 . 21 : accept,
311			     172.16.0.0/12 . 172.16.0.0/12 . 21 : accept,
312			     192.168.0.0/16 . 192.168.0.0/16 . 21 : accept,
313			     10.0.0.0/8 . 10.0.0.0/8 . 23 : accept,
314			     172.16.0.0/12 . 172.16.0.0/12 . 23 : accept,
315			     192.168.0.0/16 . 192.168.0.0/16 . 23 : accept,
316			     10.0.0.0/8 . 10.0.0.0/8 . 25 : accept,
317			     172.16.0.0/12 . 172.16.0.0/12 . 25 : accept,
318			     192.168.0.0/16 . 192.168.0.0/16 . 25 : accept,
319			     10.0.0.0/8 . 10.0.0.0/8 . 53 : accept,
320			     172.16.0.0/12 . 172.16.0.0/12 . 53 : accept,
321			     192.168.0.0/16 . 192.168.0.0/16 . 53 : accept,
322			     10.0.0.0/8 . 10.0.0.0/8 . 80 : accept,
323			     172.16.0.0/12 . 172.16.0.0/12 . 80 : accept,
324			     192.168.0.0/16 . 192.168.0.0/16 . 80 : accept,
325			     10.0.0.0/8 . 0.0.0.0/0 . 22 : accept,
326			     172.16.0.0/12 . 0.0.0.0/0 . 22 : accept,
327			     192.168.0.0/16 . 0.0.0.0/0 . 22 : accept,
328			     10.0.0.0/8 . 0.0.0.0/0 . 443 : accept,
329			     172.16.0.0/12 . 0.0.0.0/0 . 443 : accept,
330			     192.168.0.0/16 . 0.0.0.0/0 . 443 : accept,
331			     10.0.0.0/8 . 0.0.0.0/0 . 853 : accept,
332			     172.16.0.0/12 . 0.0.0.0/0 . 853 : accept,
333			     192.168.0.0/16 . 0.0.0.0/0 . 853 : accept,
334			     10.0.0.0/8 . 0.0.0.0/0 . 4460 : accept,
335			     172.16.0.0/12 . 0.0.0.0/0 . 4460 : accept,
336			     192.168.0.0/16 . 0.0.0.0/0 . 4460 : accept,
337			     10.0.0.0/8 . 0.0.0.0/0 . 5349 : accept,
338			     172.16.0.0/12 . 0.0.0.0/0 . 5349 : accept,
339			     192.168.0.0/16 . 0.0.0.0/0 . 5349 : accept }
340	}
341
342	map tcp_ports_forward6 { # handle 58
343		typeof ip6 saddr . ip6 daddr . tcp dport : verdict
344		flags interval
345		elements = { fc00::/7 . fc00::/7 . 21 : accept,
346			     fc00::/7 . fc00::/7 . 23 : accept,
347			     fc00::/7 . fc00::/7 . 25 : accept,
348			     fc00::/7 . fc00::/7 . 53 : accept,
349			     fc00::/7 . fc00::/7 . 80 : accept,
350			     fc00::/7 . fc00::/7 . 443 : accept,
351			     fc00::/7 . fc00::/7 . 853 : accept,
352			     fc00::/7 . fc00::/7 . 4460 : accept,
353			     fc00::/7 . fc00::/7 . 5349 : accept,
354			     2000::/3 . 2000::/3 . 443 : accept,
355			     2000::/3 . 2000::/3 . 853 : accept,
356			     2000::/3 . 2000::/3 . 4460 : accept,
357			     2000::/3 . 2000::/3 . 5349 : accept }
358	}
359
360	map udp_ports_forward4 { # handle 59
361		typeof ip saddr . ip daddr . udp dport : verdict
362		flags interval
363		elements = { 10.0.0.0/8 . 10.0.0.0/8 . 53 : accept,
364			     172.16.0.0/12 . 172.16.0.0/12 . 53 : accept,
365			     192.168.0.0/16 . 192.168.0.0/16 . 53 : accept,
366			     10.0.0.0/8 . 0.0.0.0/0 . 443 : accept,
367			     172.16.0.0/12 . 0.0.0.0/0 . 443 : accept,
368			     192.168.0.0/16 . 0.0.0.0/0 . 443 : accept }
369	}
370
371	map udp_ports_forward6 { # handle 60
372		typeof ip6 saddr . ip6 daddr . udp dport : verdict
373		flags interval
374		elements = { 2000::/3 . ::/0 . 443 : accept }
375	}
376
377	map tcp_ports_nat_forward4 { # handle 61
378		type inet_service : ipv4_addr
379	}
380
381	map udp_ports_nat_forward4 { # handle 62
382		type inet_service : ipv4_addr
383	}
384
385	map masquerade_networks4 { # handle 63
386		typeof oif . ip saddr : verdict
387		flags interval
388	}
389
390	chain input { # handle 1
391		type filter hook input priority filter; policy drop;
392		meta iiftype vmap { loopback : accept } # handle 89
393		ip saddr vmap @drop_bogons4 # handle 90
394		ip6 saddr vmap @drop_bogons6 # handle 91
395		meta iiftype vmap { ether : jump ether_in } # handle 93
396		log prefix "input" group 1 # handle 136
397		counter # handle 137
398	}
399
400	chain forward { # handle 2
401		type filter hook forward priority filter; policy drop;
402		ip saddr vmap @drop_bogons4 # handle 106
403		ip6 saddr vmap @drop_bogons6 # handle 107
404		meta oiftype vmap { ether : jump ether_forward } # handle 109
405		log prefix "forward" group 1 # handle 138
406		counter # handle 139
407	}
408
409	chain output { # handle 3
410		type filter hook output priority filter; policy drop;
411		meta oiftype vmap { loopback : accept } # handle 128
412		ip daddr vmap @drop_bogons4 # handle 129
413		ip6 daddr vmap @drop_bogons6 # handle 130
414		meta oiftype vmap { ether : jump ether_out } # handle 132
415		log prefix "output" group 1 # handle 140
416		counter # handle 141
417	}
418
419	chain prerouting { # handle 4
420		type nat hook prerouting priority 100; policy accept;
421		ip protocol tcp dnat ip to tcp dport map @tcp_ports_nat_forward4 # handle 133
422		ip protocol udp dnat ip to udp dport map @udp_ports_nat_forward4 # handle 134
423	}
424
425	chain postrouting { # handle 5
426		type nat hook postrouting priority srcnat; policy accept;
427		oif . ip saddr vmap @masquerade_networks4 # handle 135
428	}
429
430	chain masq { # handle 6
431		ip daddr vmap @drop_bogons4 # handle 124
432		ip daddr @local_networks return # handle 125
433		masquerade # handle 126
434	}
435
436	chain ether_in { # handle 7
437		ip protocol vmap { icmp : jump icmp_in, tcp : jump tcp_in, udp : jump udp_in } # handle 85
438		ip6 nexthdr vmap { tcp : jump tcp_in, udp : jump udp_in, ipv6-icmp : jump icmp_in } # handle 87
439		log prefix "ether_in" group 1 # handle 156
440		counter drop # handle 157
441	}
442
443	chain ether_out { # handle 8
444		ip protocol vmap { icmp : jump icmp_out, tcp : jump tcp_out, udp : jump udp_out } # handle 121
445		ip6 nexthdr vmap { tcp : jump tcp_out, udp : jump udp_out, ipv6-icmp : jump icmp_out } # handle 123
446		log prefix "ether_out" group 1 # handle 174
447		counter drop # handle 175
448	}
449
450	chain ether_forward { # handle 9
451		ip saddr . ip daddr . ct state vmap @default_forward4 # handle 102
452		ip6 saddr . ip6 daddr . ct state vmap @default_forward6 # handle 103
453		ip protocol vmap { icmp : jump icmp_forward, tcp : jump tcp_forward, udp : jump udp_forward } # handle 105
454		log prefix "ether_forward" group 1 # handle 164
455		counter drop # handle 165
456	}
457
458	chain icmp_in { # handle 10
459		ip saddr . ip daddr . icmp type vmap @icmp_types_in4 # handle 76
460		ip6 saddr . ip6 daddr . icmpv6 type vmap @icmp_types_in6 # handle 77
461		log prefix "icmp_in" group 1 # handle 150
462		counter drop # handle 151
463	}
464
465	chain icmp_out { # handle 11
466		ip saddr . ip daddr . icmp type vmap @icmp_types_out4 # handle 112
467		ip6 saddr . ip6 daddr . icmpv6 type vmap @icmp_types_out6 # handle 113
468		log prefix "icmp_out" group 1 # handle 168
469		counter drop # handle 169
470	}
471
472	chain icmp_forward { # handle 12
473		ip saddr . ip daddr . icmp type vmap @icmp_types_forward4 # handle 94
474		ip6 saddr . ip6 daddr . icmpv6 type vmap @icmp_types_forward6 # handle 95
475		log prefix "icmp_forward" group 1 # handle 158
476		counter drop # handle 159
477	}
478
479	chain icmp_echo_reply_rate_limit { # handle 13
480		add @icmp_egress_meter4 { ip saddr timeout 4s limit rate 3/second } accept # handle 110
481		add @icmp_egress_meter6 { ip6 saddr timeout 4s limit rate 3/second } accept # handle 111
482		log prefix "icmp_echo_reply_rate_limit" group 1 # handle 166
483		counter drop # handle 167
484	}
485
486	chain reject_with_icmp_port_unreachable_metered { # handle 14
487		add @icmp_egress_meter4 { ip daddr timeout 4s limit rate 3/second } counter reject # handle 64
488		add @icmp_egress_meter6 { ip6 daddr timeout 4s limit rate 3/second } counter reject # handle 65
489		log prefix "reject_with_icmp_port_unreachable_metered" group 1 # handle 142
490		counter drop # handle 143
491	}
492
493	chain reject_with_icmp_port_unreachable { # handle 15
494		counter reject # handle 66
495	}
496
497	chain reject_with_icmp_host_unreachable_metered { # handle 16
498		add @icmp_egress_meter4 { ip daddr timeout 4s limit rate 3/second } counter reject with icmpx host-unreachable # handle 67
499		add @icmp_egress_meter6 { ip6 daddr timeout 4s limit rate 3/second } counter reject with icmpx host-unreachable # handle 68
500		log prefix "reject_with_icmp_host_unreachable_metered" group 1 # handle 144
501		counter drop # handle 145
502	}
503
504	chain reject_with_icmp_host_unreachable { # handle 17
505		counter reject with icmpx host-unreachable # handle 69
506	}
507
508	chain reject_with_icmp_no_route_metered { # handle 18
509		add @icmp_egress_meter4 { ip daddr timeout 4s limit rate 3/second } counter reject with icmpx no-route # handle 70
510		add @icmp_egress_meter6 { ip6 daddr timeout 4s limit rate 3/second } counter reject with icmpx no-route # handle 71
511		log prefix "reject_with_icmp_no_route_metered" group 1 # handle 146
512		counter drop # handle 147
513	}
514
515	chain reject_with_icmp_no_route { # handle 19
516		counter reject with icmpx no-route # handle 72
517	}
518
519	chain reject_with_icmp_admin_prohibited_metered { # handle 20
520		add @icmp_egress_meter6 { ip6 daddr timeout 4s limit rate 3/second } counter reject with icmpx admin-prohibited # handle 74
521		log prefix "reject_with_icmp_admin_prohibited_metered" group 1 # handle 148
522		counter drop # handle 149
523	}
524
525	chain reject_with_icmp_admin_prohibited { # handle 21
526		add @icmp_egress_meter4 { ip daddr timeout 4s limit rate 3/second } counter reject with icmpx admin-prohibited # handle 73
527		counter reject with icmpx admin-prohibited # handle 75
528	}
529
530	chain tcp_in { # handle 22
531		ct state established accept # handle 78
532		ip saddr . ip daddr . tcp dport vmap @tcp_ports_in4 # handle 79
533		ip6 saddr . ip6 daddr . tcp dport vmap @tcp_ports_in6 # handle 80
534		log prefix "tcp_in" group 1 # handle 152
535		counter drop # handle 153
536	}
537
538	chain tcp_out { # handle 23
539		ct state established accept # handle 114
540		ip saddr . ip daddr . tcp dport vmap @tcp_ports_out4 # handle 115
541		ip6 saddr . ip6 daddr . tcp dport vmap @tcp_ports_out6 # handle 116
542		log prefix "tcp_out" group 1 # handle 170
543		counter drop # handle 171
544	}
545
546	chain tcp_forward { # handle 24
547		ct state established accept # handle 96
548		ip saddr . ip daddr . tcp dport vmap @tcp_ports_forward4 # handle 97
549		ip6 saddr . ip6 daddr . tcp dport vmap @tcp_ports_forward6 # handle 98
550		log prefix "tcp_forward" group 1 # handle 160
551		counter drop # handle 161
552	}
553
554	chain udp_in { # handle 25
555		ct state established accept # handle 81
556		ip saddr . ip daddr . udp dport vmap @udp_ports_in4 # handle 82
557		ip6 saddr . ip6 daddr . udp dport vmap @udp_ports_in6 # handle 83
558		log prefix "udp_in" group 1 # handle 154
559		counter drop # handle 155
560	}
561
562	chain udp_out { # handle 26
563		ct state established accept # handle 117
564		ip saddr . ip daddr . udp dport vmap @udp_ports_out4 # handle 118
565		ip6 saddr . ip6 daddr . udp dport vmap @udp_ports_out6 # handle 119
566		log prefix "udp_out" group 1 # handle 172
567		counter drop # handle 173
568	}
569
570	chain udp_forward { # handle 27
571		ct state established accept # handle 99
572		ip saddr . ip daddr . udp dport vmap @udp_ports_forward4 # handle 100
573		ip6 saddr . ip6 daddr . udp dport vmap @udp_ports_forward6 # handle 101
574		log prefix "udp_forward" group 1 # handle 162
575		counter drop # handle 163
576	}
577
578	chain bogon { # handle 28
579		log prefix "bogon" group 1 # handle 29
580		counter drop # handle 30
581	}
582
583	chain wont_forward { # handle 31
584		log prefix "wont_forward" group 1 # handle 32
585		counter drop # handle 33
586	}
587}

Flushing the ruleset

Something that helps me is adding flush ruleset to the beginning of the new /etc/nftables.conf file so that the existing state is flushed before loading the file.

Hardening

 1nft delete element inet filter udp_ports_in4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 137  : accept }'
 2nft delete element inet filter udp_ports_in4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 137  : accept }'
 3nft delete element inet filter udp_ports_in4 '{ 192.168.0.0/12 . 192.168.0.0/16 . 137  : accept }'
 4nft delete element inet filter udp_ports_in4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 5353 : accept }'
 5nft delete element inet filter udp_ports_in4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 5353 : accept }'
 6nft delete element inet filter udp_ports_in4 '{ 192.168.0.0/12 . 192.168.0.0/16 . 5353 : accept }'
 7nft delete element inet filter udp_ports_in4 '{ 10.0.0.0/8     . 224.0.0.0/4    . 5353 : accept }'
 8nft delete element inet filter udp_ports_in4 '{ 172.16.0.0/12  . 224.0.0.0/4    . 5353 : accept }'
 9nft delete element inet filter udp_ports_in4 '{ 192.168.0.0/12 . 224.0.0.0/4    . 5353 : accept }'
10nft delete element inet filter udp_ports_in6 '{ fe80::/10 . ff00::/8 . 5353  : accept }'
11nft delete element inet filter udp_ports_in6 '{ fc00::/7  . ff00::/8 . 5353  : accept }'
12nft delete element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 21   : accept }'
13nft delete element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 21   : accept }'
14nft delete element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 21   : accept }'
15nft delete element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 23   : accept }'
16nft delete element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 23   : accept }'
17nft delete element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 23   : accept }'
18nft delete element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 25   : accept }'
19nft delete element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 25   : accept }'
20nft delete element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 25   : accept }'
21nft delete element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 53   : accept }'
22nft delete element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 53   : accept }'
23nft delete element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 53   : accept }'
24nft delete element inet filter tcp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 80   : accept }'
25nft delete element inet filter tcp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 80   : accept }'
26nft delete element inet filter tcp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 80   : accept }'
27nft delete element inet filter tcp_ports_forward6 '{ fc00::/7  . fc00::/7 . 21 : accept }'
28nft delete element inet filter tcp_ports_forward6 '{ fc00::/7  . fc00::/7 . 23 : accept }'
29nft delete element inet filter tcp_ports_forward6 '{ fc00::/7  . fc00::/7 . 25 : accept }'
30nft delete element inet filter tcp_ports_forward6 '{ fc00::/7  . fc00::/7 . 53 : accept }'
31nft delete element inet filter tcp_ports_forward6 '{ fc00::/7  . fc00::/7 . 80 : accept }'
32nft delete element inet filter udp_ports_forward4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 53   : accept }'
33nft delete element inet filter udp_ports_forward4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 53   : accept }'
34nft delete element inet filter udp_ports_forward4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 53   : accept }'
35nft delete element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 10.0.0.0/8     . 137  : accept }'
36nft delete element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 172.16.0.0/12  . 137  : accept }'
37nft delete element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 192.168.0.0/16 . 137  : accept }'
38nft delete element inet filter udp_ports_out4 '{ 10.0.0.0/8     . 224.0.0.0/4    . 5353 : accept }'
39nft delete element inet filter udp_ports_out4 '{ 172.16.0.0/12  . 224.0.0.0/4    . 5353 : accept }'
40nft delete element inet filter udp_ports_out4 '{ 192.168.0.0/16 . 224.0.0.0/4    . 5353 : accept }'
41nft delete element inet filter udp_ports_out4 '{ 169.254.0.0/16 . 224.0.0.0/4    . 5353 : accept }'
42nft delete element inet filter udp_ports_out6 '{ fc00::/7  . ff00::/8 . 5353 : accept }'

Testing

Testing can be performed from another client using scapy:

1from scapy.all import *; from ipaddress import IPv4Network as N4; [send(IP(src=str(x), dst='10.211.55.11')/ICMP(id=1, seq=1), loop=0) for x, y in zip(N4('65.146.55.0/24').hosts(), range(254))]

On the firewall:

 1tcpdump -vvv -n -e -ttt -i nflog:1 -XX
 2...
 3 00:00:00.000036 version 0, resource ID 1, family IPv4 (2), length 84: (tos 0x0, ttl 64, id 41167, offset 0, flags [none], proto ICMP (1), length 28)
 4    10.211.55.11 > 65.146.55.254: ICMP echo reply, id 1, seq 1, length 8
 5	0x0000:  0200 0001 0800 0100 0800 0300 1f00 0a00  ................
 6	0x0010:  6963 6d70 5f65 6368 6f5f 7265 706c 795f  icmp_echo_reply_
 7	0x0020:  7261 7465 5f6c 696d 6974 0000 0800 0500  rate_limit......
 8	0x0030:  0000 0002 2000 0900 4500 001c a0cf 0000  ........E.......
 9	0x0040:  4001 1ea4 0ad3 370b 4192 37fe 0000 fffd  @.....7.A.7.....
10	0x0050:  0001 0001                                ....

Custom Docker support

Preparation

1apt -y install docker.io 
2systemctl stop docker
3rm -rf /var/lib/docker/*
4rm /etc/docker/key.json
5echo DOCKER_OPTS="-H unix:///var/run/docker.sock --iptables=false --ip-masq=false --userns-remap=default --bip=100.64.80.1/20 --default-address-pool='base=100.64.96.0/20,size=28'" > /etc/default/docker

Custom prefix

This example will use the 100.64.0.0/17 prefix for docker. Earlier that prefix was marked to be discarded as a bogon, that can be changed easily:

 1nft delete element inet filter drop_bogons4 '{ 100.64.0.0/10 : jump bogon }'
 2nft add element inet filter drop_bogons4 '{ 100.64.0.0/17 : continue      }'
 3nft add element inet filter drop_bogons4 '{ 100.64.128.0/17 : jump bogon  }'
 4nft add element inet filter drop_bogons4 '{ 100.65.0.0/16 : jump bogon    }'
 5nft add element inet filter drop_bogons4 '{ 100.66.0.0/15 : jump bogon    }'
 6nft add element inet filter drop_bogons4 '{ 100.68.0.0/15 : jump bogon    }'
 7nft add element inet filter drop_bogons4 '{ 100.70.0.0/15 : jump bogon    }'
 8nft add element inet filter drop_bogons4 '{ 100.72.0.0/15 : jump bogon    }'
 9nft add element inet filter drop_bogons4 '{ 100.74.0.0/15 : jump bogon    }'
10nft add element inet filter drop_bogons4 '{ 100.76.0.0/15 : jump bogon    }'
11nft add element inet filter drop_bogons4 '{ 100.78.0.0/15 : jump bogon    }'
12nft add element inet filter drop_bogons4 '{ 100.80.0.0/15 : jump bogon    }'
13nft add element inet filter drop_bogons4 '{ 100.82.0.0/15 : jump bogon    }'
14nft add element inet filter drop_bogons4 '{ 100.84.0.0/15 : jump bogon    }'
15nft add element inet filter drop_bogons4 '{ 100.86.0.0/15 : jump bogon    }'
16nft add element inet filter drop_bogons4 '{ 100.88.0.0/15 : jump bogon    }'
17nft add element inet filter drop_bogons4 '{ 100.90.0.0/15 : jump bogon    }'
18nft add element inet filter drop_bogons4 '{ 100.92.0.0/15 : jump bogon    }'
19nft add element inet filter drop_bogons4 '{ 100.94.0.0/15 : jump bogon    }'
20nft add element inet filter drop_bogons4 '{ 100.96.0.0/11 : jump bogon    }'
21nft add element inet filter local_networks '{ 100.64.0.0/17 }'

Verify this with the nft list map inet filter drop_bogons4 command:

 1table inet filter {
 2	map drop_bogons4 {
 3		type ipv4_addr : verdict
 4		flags interval
 5		elements = { 0.0.0.0/8 : jump bogon, 10.0.0.0/8 : continue,
 6			     100.64.0.0/17 : continue, 100.64.128.0/17 : jump bogon,
 7			     100.65.0.0/16 : jump bogon, 100.66.0.0/15 : jump bogon,
 8			     100.68.0.0/15 : jump bogon, 100.70.0.0/15 : jump bogon,
 9			     100.72.0.0/15 : jump bogon, 100.74.0.0/15 : jump bogon,
10			     100.76.0.0/15 : jump bogon, 100.78.0.0/15 : jump bogon,
11			     100.80.0.0/15 : jump bogon, 100.82.0.0/15 : jump bogon,
12			     100.84.0.0/15 : jump bogon, 100.86.0.0/15 : jump bogon,
13			     100.88.0.0/15 : jump bogon, 100.90.0.0/15 : jump bogon,
14			     100.92.0.0/15 : jump bogon, 100.94.0.0/15 : jump bogon,
15			     100.96.0.0/11 : jump bogon, 127.0.0.0/8 : jump bogon,
16			     169.254.0.0/16 : continue, 172.16.0.0/12 : continue,
17			     192.0.0.0/24 : jump bogon, 192.0.2.0/24 : jump bogon,
18			     192.168.0.0/16 : continue, 198.18.0.0/15 : jump bogon,
19			     198.51.100.0/24 : jump bogon, 203.0.113.0/24 : jump bogon,
20			     224.0.0.0/4 : continue, 240.0.0.0/4 : jump bogon }
21	}
22}

Forward verdict map

 1nft add element inet filter default_forward4 '{ 100.64.0.0/20  . 0.0.0.0/0      . new         : jump reject_with_icmp_no_route }'
 2nft add element inet filter default_forward4 '{ 100.64.16.0/20 . 100.64.32.0/20 . new         : continue                       }'
 3nft add element inet filter default_forward4 '{ 100.64.32.0/20 . 100.64.16.0/20 . established : accept                         }'
 4nft add element inet filter default_forward4 '{ 100.64.48.0/20 . 100.64.0.0/17  . new         : continue                       }'
 5nft add element inet filter default_forward4 '{ 100.64.80.0/20 . 100.64.0.0/17  . new         : continue                       }'
 6nft add element inet filter default_forward4 '{ 100.64.48.0/20 . 0.0.0.0/0      . new         : continue                       }'
 7nft add element inet filter default_forward4 '{ 100.64.80.0/20 . 0.0.0.0/0      . new         : continue                       }'
 8nft add element inet filter default_forward4 '{ 100.64.48.0/20 . 0.0.0.0/0      . established : accept                         }'
 9nft add element inet filter default_forward4 '{ 100.64.80.0/20 . 0.0.0.0/0      . established : accept                         }'
10nft add element inet filter default_forward4 '{ 0.0.0.0/0      . 100.64.48.0/20 . established : accept                         }'
11nft add element inet filter default_forward4 '{ 0.0.0.0/0      . 100.64.80.0/20 . established : accept                         }'
12nft add element inet filter default_forward4 '{ 100.64.64.0/20 . 100.64.64.0/20 . new         : continue                       }'
13nft add element inet filter default_forward4 '{ 100.64.96.0/20 . 100.64.96.0/20 . new         : continue                       }'
14nft add element inet filter default_forward4 '{ 100.64.64.0/20 . 100.64.64.0/20 . established : accept                         }'
15nft add element inet filter default_forward4 '{ 100.64.96.0/20 . 100.64.96.0/20 . established : accept                         }'

NAT

1nft add element inet filter masquerade_networks4 '{ enp0s5 . 100.64.80.0/20 : jump masq }'
2nft add element inet filter masquerade_networks4 '{ enp0s5 . 100.64.48.0/20 : jump masq }'

Allow ICMP out to containers

1nft add element inet filter icmp_types_out4 '{ 100.64.0.0/17 . 100.64.0.0/17 . destination-unreachable : accept }'

Allow forwarded ICMP by src/dst/type

1nft add element inet filter icmp_types_forward4 '{ 100.64.80.0/20 . 100.64.0.0/17 . echo-request : jump reject_with_icmp_admin_prohibited }'
2nft add element inet filter icmp_types_forward4 '{ 100.64.80.0/20 . 0.0.0.0/0     . echo-request : accept }'
3nft add element inet filter icmp_types_forward4 '{ 100.64.48.0/20 . 100.64.0.0/17 . echo-request : jump reject_with_icmp_admin_prohibited }'
4nft add element inet filter icmp_types_forward4 '{ 100.64.48.0/20 . 0.0.0.0/0     . echo-request : accept }'

Allow forwarded TCP by src/dst/dport

1nft add element inet filter tcp_ports_forward4 '{ 100.64.80.0/20 . 100.64.0.0/17 . 80  : jump reject_with_icmp_admin_prohibited }'
2nft add element inet filter tcp_ports_forward4 '{ 100.64.80.0/20 . 0.0.0.0/0     . 80  : accept }'
3nft add element inet filter tcp_ports_forward4 '{ 100.64.80.0/20 . 100.64.0.0/17 . 443 : jump reject_with_icmp_admin_prohibited }'
4nft add element inet filter tcp_ports_forward4 '{ 100.64.80.0/20 . 0.0.0.0/0     . 443 : accept }'
5nft add element inet filter tcp_ports_forward4 '{ 100.64.48.0/20 . 100.64.0.0/17 . 443 : jump reject_with_icmp_admin_prohibited }'
6nft add element inet filter tcp_ports_forward4 '{ 100.64.48.0/20 . 0.0.0.0/0     . 443 : accept }'

Allow forwarded UDP by src/dst/dport

1nft add element inet filter udp_ports_forward4 '{ 100.64.80.0/20 . 100.64.0.0/17 . 53 : jump reject_with_icmp_admin_prohibited }'
2nft add element inet filter udp_ports_forward4 '{ 100.64.80.0/20 . 0.0.0.0/0     . 53 : accept }'

TODO

This networking scheme is nice for Docker, but it sucks having to specify every address in docker-compose. I have an IPAM driver for Docker that will allow tags to specified for networks as options to the IPAM driver in compose, but it is a work in progress.

IPAM Driver

Network Driver

  • EVPN/VXLAN transports
  • NFTables Flowtables; interface names must be known to the firewall state for offloading