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
}
}