ROON linux firewall settings for nftables

I put some efforts in a working nftables configuration to migrate from iptables. Was more of a hassle than expected.
If anyone interested her my initial config (to be nailed down further):
Incorporated @Christophe_Saelens excellent suggestions from post 2 of this thread.

Install webmin

sudo apt-get update -y
sudo apt-get install webmin -y
 

# start it:

sudo service webmin start
sudo service webmin status
sudo service webmin restart

Test it (with your root credentials)

http://run-core.local:10000

Security

Now install nftables:

sudo apt-get install nftables -y

start it

sudo systemctl enable nftables.service
sudo systemctl start nftables
sudo systemctl status nftables

This is not my final hardened version, however the first one that works. Coming from IPTABLES it was more hassle than expected

# let´s start fresh
sudo nft flush ruleset

# and now the fun begins

sudo nft add table inet filter
sudo nft add chain inet filter input { type filter hook input priority 0 \;policy drop\; }
sudo nft add chain inet filter output { type filter hook output priority 0 \; }
# as our system should not route anything, we do not need a forward chain


sudo nft add rule inet filter input ct state established,related accept

# ROON needs the loopback to work, check the loopback Interface Name
sudo nft add rule inet filter input iifname lo counter accept


# We need Broadcasting and Multicasting
sudo nft add rule inet filter input pkttype multicast counter accept
sudo nft add rule inet filter input pkttype broadcast counter accept

# SSH secure shell is alway needed
sudo nft add rule inet filter input tcp dport {ssh} accept
# WEBMIN access
sudo nft add rule inet filter input tcp dport 10000 accept
sudo nft add rule inet filter input ip saddr 192.168.1.1/24 udp dport 9003 counter accept
sudo nft add rule inet filter input ip saddr 192.168.1.1/24  tcp dport 9300-9339  counter accept
# logging
sudo nft add rule inet filter input log prefix "droping "


Let´s see if it worked:

sudo nft -s list ruleset

should look like:

table inet filter {
        chain input {
                type filter hook input priority filter; policy drop;
                ct state established,related accept
                iifname "lo" counter accept
                meta pkttype multicast counter accept
                meta pkttype broadcast counter accept
                tcp dport { 22 } accept
                tcp dport 10000 accept
                ip saddr 192.168.1.0/24 udp dport 9003 counter accept
                ip saddr 192.168.1.0/24 tcp dport 9300-9339 counter accept
                log prefix "droping"
        }

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

And store it

sudo nft -s list ruleset | sudo tee /etc/nftables.rules

start it when booting:

sudo vim /etc/nftables.conf

should look like:

#!/usr/sbin/nft -f

flush ruleset
include "/etc/nftables.rules"

and finaly test it by restarting

sudo systemctl restart nftables
sudo nft -s list ruleset
3 Likes

Nice write-up, this will help a lot of people using Linux!

I think you can simplify your rules quite a bit.

Set policy to drop, so that any traffic that s isn’t explicitly allowed gets dropped.

You can leave out the rule for accepting 127.0.0.1, since you already accept interface lo0. lo0 should have the 127.0.0.1 and ::1 ip addresses. You can check the loopback interface name and ip using ip addr Sometimes this is just lo and not lo0

IYou should be able to leave these out too, since you allow them with meta pkttype multicast counter accept
If you check, the counter for multicast should stay at zero the way you have configured it.

For tcp 9100-9400: 9330-9339 should be sufficient.

Don’t think forwarding is used by Roon, you can change the policy to drop.

I think you should be able to get everything working using only these (just add your own rules for ssh and webmin)

        chain input {
                type filter hook input priority filter; policy drop;
                iifname "lo0" accept
                ct state invalid drop
                ct state established,related accept
                meta pkttype multicast counter accept
                meta pkttype broadcast counter accept
                ip saddr 192.168.1.0/24 udp dport 9003 counter accept
                ip saddr 192.168.1.0/24 tcp dport 9330-9339 counter accept
        }

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

        chain output {
                type filter hook output priority filter; policy accept;
        }
1 Like

Christophe,

thanks for you valuable input which I incoporated! You were correct that the loopback interface name was wrong (the reason for the SADDR rule, and I completely dropped the not used forward chain.

Everything works fine (Roon native and USB, only DEVIALET AIR and Airplay is not working yet). So I will tweak further.

Christophe,

thanks for you valuable input which I incoporated! You were correct that the loopback interface name was wrong (the reason for the SADDR rule, and I completely dropped the not used forward chain.

One Question , the only reason I used a policy accept and dropped verything at the End was the Log rule. How do you log dropped packet (for troubleshhooting) in a “policy drop” chain?

Everything works fine (Roon native and USB, only DEVIALET AIR and Airplay is not working yet). So I will tweak further.

You should still be able to put the log rule last if you want to do some debugging. You can comment it out using a # if you don’t need it.

log flags all

I thnk (but unsure since i don’t use Airplay) you’ll have to allow the udp ports 32768-65535

ip protocol udp ip saddr 192.168.1./24 udp dport 32768-65535 counter accept

Don’t know what ports or protocols are used by Devialet Air, you’re on your own with that one :wink:
Maybe it uses the same ports as Airplay, but you’ll have to look at your logs for that.

PS: If your devices have fixed IP’s, and you feel bold you can close down your firewall even more with some sets. These go just above your input chain. If you add a device, just add it to the set and the rules are updated. It’s also nicer to look at than a list of ip’s.

	set Roon {
		type ipv4_addr
		flags interval
		elements = { 192.168.1.100, 192.168.1.101, 192.168.1.102  }
	}

	set Airplay {
		type ipv4_addr
		flags interval
		elements = { 192.168.1.100, 192.168.1.101 }
	}

For the rules, you can then use

ip saddr @Roon udp dport 9003 counter accept
ip saddr @Roon tcp dport 9330-9339 counter accept
ip saddr @Airplay udp dport 32768-65535 counter accept

EDIT:
This post on Reddit from a few years back mentions udp 6002 and 49152-65535, but strangely enough as source ports.
If I were you, I’d start with these, and if it doesn’t work, you can swich to source ports.

ip saddr @Airplay udp dport { 6002, 49152-65535 } counter accept

This is my working configuration. Now supports:

ROON native
Apple Airplay
Devailet AIR

table inet filter {
        chain input {
                type filter hook input priority filter; policy drop;
                # let´s be statefull:
                ct state established,related accept
                # check the neame of you loopback before !
                iifname "lo" counter accept
                # ROON needs to receive Multicasts and Broadcasts !
                meta pkttype multicast counter accept
                meta pkttype broadcast counter accept
                # SSH is always a good idea
                tcp dport { 22 } accept
                # Webmin
                tcp dport 10000 accept
                # Needed for Roon
                ip saddr 192.168.1.0/24 udp dport 9003 counter accept
                ip saddr 192.168.1.0/24 tcp dport 9300-9339 counter accept
                # Apple Airplay
                ip saddr 192.168.1.0/24 udp dport 32768-65535 counter accept
                # Devialet Air
                ip saddr 129.168.1.0/24 udp dport 6002 counter accept
                # comment out logging for production use
                log prefix "droping  " flags all
        }

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



1 Like

Looking good, glad you got it working!