blastdoor

0.1.0

blastdoor is the firewall tool of UraniumOS. The firewall is one nftables ruleset in /etc/nftables.conf, which /etc/rc loads at boot. blastdoor opens and closes ports by writing one-line files to /etc/nftables.d, which the ruleset includes, and loading the ruleset again. It is part of the uranium-tools package and needs root.

The ruleset

This is /etc/nftables.conf as installed:

flush ruleset
table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        iif lo accept
        ct state established,related accept
        ct state invalid drop
        meta l4proto { icmp, icmpv6 } accept
        udp sport 67 udp dport 68 accept
        tcp dport 22 ct state new limit rate 10/minute accept
        include "/etc/nftables.d/*.nft"
    }
    chain forward { type filter hook forward priority 0; policy drop; }
    chain output { type filter hook output priority 0; policy accept; }
}
flush ruleset
Removes every table of every family before the new one is added, in the same transaction. Rules another tool put in nftables are removed by a load too.
table inet filter
One table for IPv4 and IPv6.
policy drop on input and forward
A packet that no rule accepts is dropped. The forward chain accepts nothing, so the machine does not route for others.
iif lo accept
Everything on the loopback interface. Services listening on 127.0.0.1 or ::1 are not filtered, including sandboxes and containers that share the network.
ct state established,related accept, ct state invalid drop
Replies to connections the machine opened, and related traffic, are accepted. Packets that connection tracking calls invalid are dropped.
meta l4proto { icmp, icmpv6 } accept
All ICMP and ICMPv6 is accepted, with no rate limit. The machine answers ping, and IPv6 neighbour and router messages get through.
udp sport 67 udp dport 68 accept
DHCP replies for the dhcp service.
tcp dport 22 ct state new limit rate 10/minute accept
New ssh connections, at ten a minute counted over all sources together. nft adds a burst of 5 packets when it loads the rule. The limit is not kept per source, so one address can use up the allowance and keep other users out.
include "/etc/nftables.d/*.nft"
The files that blastdoor allow writes. The include is inside the input chain after the rules above, and the files load in the order the glob sorts them.
output chain
Open. Outgoing traffic is not filtered.

A service is not reachable from the network until it's port is opened, whichever program listens on it.

Synopsis

blastdoor allow PORT[/tcp|/udp]
blastdoor deny PORT[/tcp|/udp]
blastdoor list
blastdoor reload
allow PORT[/PROTO]
Writes the line PROTO dport PORT accept to /etc/nftables.d/PORT-PROTO.nft, loads the whole ruleset again and says which port it allowed. The protocol is tcp unless given. Allowing a port twice rewrites the same file.
deny PORT[/PROTO]
Deletes /etc/nftables.d/PORT-PROTO.nft, loads the ruleset again and says which port it closed. It only removes files named that way, so a rule you wrote under another name and the built-in ssh rule stay.
list
Runs nft list chain inet filter input and shows the output. The exit status is 0 even when nft fails, for example when you are not root.
reload
Runs nft -f /etc/nftables.conf. Use it after you edit the ruleset or a file in /etc/nftables.d.

A port is a number from 1 to 65535 made of digits only, so 0, +80 and 70000 are refused. Leading zeros are dropped, so allow 080 writes 80-tcp.nft. The protocol is tcp or udp in lower case.

Examples

# blastdoor allow 8080
allowed 8080/tcp
# blastdoor allow 53/udp
allowed 53/udp
# blastdoor list
table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		iif "lo" accept
		ct state established,related accept
		ct state invalid drop
		meta l4proto { icmp, ipv6-icmp } accept
		udp sport 67 udp dport 68 accept
		tcp dport 22 ct state new limit rate 10/minute burst 5 packets accept
		udp dport 53 accept
		tcp dport 8080 accept
	}
}
# blastdoor deny 8080
closed 8080/tcp

A longer rule goes in the same directory in any file that ends in .nft. This one limits a database to one network:

# echo 'ip saddr 10.0.0.0/24 tcp dport 5432 accept' > /etc/nftables.d/postgres.nft
# blastdoor reload

Remove that rule by deleting the file and running blastdoor reload.

nft loads a file as one transaction. When any line fails nothing changes and the rules loaded before stay in place. allow writes the file before it loads, so after a failed load the file is still there. A broken file in /etc/nftables.d makes every later load fail, and blastdoor reports cannot load until you remove the file:

In file included from /etc/nftables.conf:11:9-107:
/etc/nftables.d/bad.nft:1:11-16: Error: Could not resolve service: Servname not supported for ai_socktype
tcp dport banana accept
          ^^^^^^
blastdoor: cannot load /etc/nftables.conf

At boot

/etc/rc loads /etc/nftables.conf after it applies /etc/sysctl.conf and before it starts the network. A ruleset that fails to load at boot prints nothing and the machine runs with no firewall. geiger reports that as warn blastdoor is not loaded, so run it after you edit the ruleset by hand. Nothing is filtered between the start of the kernel and that line.

Files and variables

/etc/nftables.conf
The ruleset. Edit it for built-in rules.
/etc/nftables.d/*.nft
One file for each opened port or custom rule.
BLASTDOOR_CONF, BLASTDOOR_DIR
Replace the two paths above.

/etc is in the root frame, so scram brings back the firewall of the time of a frame when it flashes to it.

Limits