After compiling the 4.19.66-gentoo
kernel, udev
renamed the network interfaces of my home linux Router / Firewall and my iptables
setup stopped working due ip-conntrack kernel deprecations. I decided to move over to nftables
, the new packet classification framework that replaces the existing {ip,ip6,arp,eb} tables infrastructure.
Even though nftables
has been in the Linux kernel since 2014, the documentation is extremely sparse. As such this gist :)
Subjectively, using nftables
setting up connections to my machine seems to be more responsive compared to using iptables
. Connections seem to be made more quickly and ssh
-ing into my machine seems more responsive. There always used to be a bit of a lag when I was using iptables
, not anymore.
In order to be able to use nftables
, new kernel modules need to be configured.
I marked pretty much everything named nf_tables
as a <M>
module, more than the list taken from the Gentoo HowTo below:
[*] Networking support --->
Networking options --->
[*] Network packet filtering framework (Netfilter) --->
[*] Advanced netfilter configuratio
Core Netfilter Configuration --->
<M> Netfilter nf_tables support
<M> Netfilter nf_tables conntrack module
<M> Netfilter nf_tables counter module
<M> Netfilter nf_tables log module
<M> Netfilter nf_tables limit module
<M> Netfilter nf_tables masquerade support
<M> Netfilter nf_tables nat module
IP: Netfilter Configuration --->
<M> IPv4 nf_tables support
<M> IPv4 nf_tables route chain support
<M> IPv4 packet rejection
<M> IPv4 NAT
<M> IPv4 nf_tables nat chain support
<M> IPv4 masquerade support
<M> IPv4 masquerading support for nf_tables
Please note: nftables masquerade will not work if iptables masquerade is in the kernel, so be sure to unload or disable it.
In order for other packages to use nftables
(like miniupnpd
), add the nftables
USE flag to /etc/portage/make.conf
:
# nftables support (see https://packages.gentoo.org/useflags/nftables)
USE="$USE nftables"
The base rules below will set up a Gentoo Linux box with 2 network interfaces (wan
and lan
) as a home firewall / router.
The goal is to:
- set up the base firewall
- set up NAT / Masquerade so that the LAN has access to the internet
- use MiniUPnPd to allow services on the LAN to manage their own port forwarding via
UPnP
andNAT-PMP
(like Plex Media Server or Transmission)
While some documentation mentions storing rules in /etc/nftables
, the directory is absent on my installation. I found managing the rules manually, and persisting them (through nftables save
) to work reliably. Of course you could also use something like firewalld instead.
I have stored a file describing my base firewall rules in the home dir of the root
user:
#
# Netfilter's NFTable firewall
#
# To invoke and persist the rules between reboots:
#
# nft -f nftables-init.rules; /etc/init.d/nftables save
#
# Other example commands:
#
# $ nft list tables
# $ nft list tables ip
# $ nft list table ip filter
# $ nft list table ip nat
# $ nft list ruleset
# $ nft monitor
# $ nft list ruleset
#
# See: https://gist.github.com/4np/f6eb7fe6be1de07f35271eba593b4dc5
# See: https://wiki.gentoo.org/wiki/Nftables
# See: https://wiki.gentoo.org/wiki/Nftables/Examples
# See: https://github.com/yoramvandevelde/nftables-example/blob/master/nftables-init.rules
# See: https://home.regit.org/2014/01/why-you-will-love-nftables/
# Clear all
flush ruleset
# Network interfaces
define wan = eno0
define lan = enp2s0
# Base firewall
table inet filter {
# allow LAN to firewall, disallow WAN to firewall
chain input {
type filter hook input priority 0
# ICMP flood protection
ip protocol icmp icmp type echo-request limit rate over 1/second burst 1 packets counter drop comment "prevent IPv4 ping floods"
ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 1/second burst 1 packets counter drop comment "prevent IPv6 ping floods"
# Connection state based
ct state invalid counter drop comment "early drop of invalid packets"
ct state { established, related } counter accept comment "accept all connections related to connections made by us"
# accept any localhost traffic
iif lo accept comment "accept loopback"
iif != lo ip daddr 127.0.0.1/8 counter drop comment "drop connections to loopback not coming from loopback"
# accept IPv4 ICMP
ip protocol icmp counter accept comment "accept all ICMP types"
# accept IPv6 neighbour discovery (otherwise connectivity breaks)
ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, echo-request, nd-router-advert, nd-neighbor-advert } accept
# Services
tcp dport { ssh } ct state new limit rate 2/minute accept comment "accept SSH and avoid brute force"
tcp dport { http, https } ct state new counter accept comment "accept HTTP"
# Networks
iifname $lan accept comment "accept all connection from LAN"
iifname $wan drop comment "drop all connections from WAN"
}
# allow all packets sent by the firewall machine itself
chain output {
type filter hook output priority 0
ct state related, established accept
accept
}
# allow packets from LAN to WAN, and WAN to LAN if LAN initiated the connection
chain forward {
type filter hook forward priority 0
accept
}
}
# NAT: The first packet in each flow will hit this table; none others will.
table ip nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
}
# for all packets to WAN, after routing, replace source address with primary IP of WAN interface
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname $wan masquerade
}
}
nft -f /root/nftables-init.rules; /etc/init.d/nftables save
This will flush nftables (due to flush ruleset
inside the rules above) and configure all the specified chains and their respective rules. /etc/init.d/nftables save
will persist the rules between reboots.
MiniUPnPd supports nftables.
Add the nftables
USE flag to /etc/portage/make.conf
:
# nftables support (see https://packages.gentoo.org/useflags/nftables)
USE="$USE nftables"
install MiniUPnPd
:
emerge miniupnpd
and add it to the default runlevel and launch on boot:
rc-update add miniupnpd default
This is my diff from the stock miniupnpd.conf
configuration:
2c2
< #ext_ifname=eth1
---
> ext_ifname=eno0
41c41
< #listening_ip=eth0
---
> listening_ip=enp2s0
57c57
< #enable_natpmp=yes
---
> enable_natpmp=yes
104,105c104,105
< #secure_mode=yes
< secure_mode=no
---
> secure_mode=yes
> #secure_mode=no
170,173c170,173
< allow 1024-65535 192.168.0.0/24 1024-65535
< allow 1024-65535 192.168.1.0/24 1024-65535
< allow 1024-65535 192.168.0.0/23 22
< allow 12345 192.168.7.113/32 54321
---
> #allow 1024-65535 192.168.0.0/24 1024-65535
> allow 1024-65535 192.168.2.0/24 1024-65535
> #allow 1024-65535 192.168.0.0/23 22
> #allow 12345 192.168.7.113/32 54321
Note: don't forget to update the uuid
with a random uuid as well, which I left out of this diff.
While MiniUPnPd will take care of most of the on-demand hole-punching via UPnP and NAT-PMP, you still might need to manually configure port forwarding.
Below is an example on how to configure forwarding of remote port 32423
to Plex Media Server on LAN at 192.168.1.10:32400
:
# Plex
define plex_wan_port = 32423
define plex_lan_port = 32400
define plex_server = 192.168.2.10
table inet filter {
...
chain input {
...
tcp dport { $plex_wan_port } ct state new counter accept comment "accept Plex Media Server"
}
...
chain forward {
...
iifname $wan meta oif $lan ip daddr $plex_server tcp dport $plex_lan_port ct state new accept
}
}
table ip nat {
...
chain prerouting {
...
iifname $wan tcp dport $plex_wan_port dnat $plex_server:$plex_lan_port comment "Port forwarding to Plex"
}
}
I see bots trying to get into ssh
every couple of minutes or so, so it is best to use something like fail2ban (or SSHGuard) to protect yourself against those.
emerge fail2ban
and add it to the default runlevel and launch on boot:
rc-update add fail2ban default
Follow the configuration guidelines from the Gentoo Wiki.