Ramblings of an aging IT geek
← Ramblings of an aging IT geek
linux

i finally moved off iptables, and i'm not going back

Rewriting a tangle of iptables rules as a single nftables ruleset, and why the unified address families and sets make it worth the relearning.

A terminal showing firewall rules on a Linux box

I'd been putting this off for years. The iptables rules on my main server had grown by accretion: a base set, some Docker-shaped chaos, a few hand-added DNAT lines I no longer trusted, and a parallel ip6tables config that was always slightly out of sync with the v4 one. It worked, mostly, in the way that load-bearing duct tape works. Debian moving to nft as the default backend was the nudge I needed to actually do the migration rather than just nodding at it.

The thing that finally sold me on nftables isn't speed, though the in-kernel handling is tidier. It's that one ruleset covers both v4 and v6. With the inet family you write a rule once and it applies to both, which immediately deletes the entire category of bug where IPv6 was wide open because I'd forgotten to mirror a rule.

Here's the shape of it, and it reads like actual configuration rather than a pile of -A incantations:

table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;
    ct state established,related accept
    iif "lo" accept
    tcp dport { 22, 80, 443 } accept
    ip protocol icmp accept
    ip6 nexthdr icmpv6 accept
  }
}

That { 22, 80, 443 } is an anonymous set, and named sets are even better: you can maintain a blocklist as a set and add to it without re-evaluating a chain of twenty rules. The whole thing is one file, one nft -f, atomic apply. No more half-applied rulesets when a line fails in the middle.

iptables-translate got me most of the way mechanically, but the rules it spits out are a literal transliteration and miss the point. The win is in rewriting them to actually use the new idioms. I kept the old rules around for a week, watched the logs, and then deleted them with the small satisfaction of paying off a debt I'd carried too long.