Libraries
NFTables
activeBuild and apply Linux nftables firewall rules from Elixir, locally or on remote hosts.
What it is
NFTables is an Elixir interface to Linux nftables. It offers high-level helpers for common firewall tasks (blocking addresses, managing sets, creating rules) alongside composable functions for building arbitrary rules, and it can query tables, chains, rules, sets and elements, and read and write network sysctl parameters.
The aim is to manage a firewall from Elixir code: for example, a dynamic firewall that updates its rules in response to events, or a firewall spread across several nodes.
Example
Rules are built with pipeable expressions and submitted as one batch:
import NFTables.Expr
import NFTables.Expr.{Port, TCP, Verdict}
{:ok, pid} = NFTables.Port.start_link()
NFTables.add(table: "filter", family: :inet)
|> NFTables.add(chain: "INPUT", hook: :input, policy: :drop)
|> NFTables.add(rule: tcp() |> dport(22) |> accept())
|> NFTables.submit(pid: pid)
Replacing submit/2 with to_json/1 produces the nftables JSON instead of applying it, which needs no privileges and no kernel.
How it is built
Building a ruleset and applying it are separate concerns.
- Building is pure Elixir. A host that only builds rulesets, or sends them elsewhere, needs nothing else.
- Applying goes through the optional
nftables_portpackage: a small Zig program that accepts JSON and hands it to the kernel through libnftables, managed from Elixir as a Port. A crash there cannot take down the BEAM, and only that executable holdsCAP_NET_ADMIN. It refuses to start if it has any permissions for "other", and the documentation recommends running it as a dedicated user.
Commands are batched, so a set of changes applies atomically. Advanced features include flowtables, meters and dynamic sets, raw payload matching, socket matching with TPROXY, and OS fingerprinting.
Managing remote firewalls
A wire protocol lets a client on one host send rulesets to a service on another that applies them. The client needs neither the port nor its capabilities.
- Over standard I/O:
NFTables.Session.Stdio.serve/1runs the service one JSON message per line, so it can be carried bysshto a release on the firewall host. - As a supervised service: a host that applies rules regularly runs one
NFTables.Session.Servicein its supervision tree, and every connection attaches to it. - Over SSH without a shell: for a central host managing many firewalls, each firewall can run an SSH daemon built on Erlang's
:sshthat offers only the protocol's subsystem to the keys it authorizes.
The service writes only tables it manages: the ones it created and the ones explicitly adopted. A commit can ask to be confirmed: confirm_within: 60 applies the change at once and reverts it after 60 seconds unless the client confirms it, so a change that cuts off the connection that made it undoes itself.
Requirements
Linux with nf_tables, Elixir 1.18 or later, and on the applying host libnftables-dev 1.0.9 or later (the first release whose JSON parser accepts the dynamic set flag), libcap-dev, netbase and Zig 0.15. Confirm-or-revert needs libnftables 1.1.0 or later. Some expressions need a newer kernel; the test suite asks the running kernel what it supports and skips, with the kernel's own error as the reason, any test whose feature is refused.
A caution from the documentation: experimenting on a remote machine can lock you out of it. A VM or a local machine is a safer place to start.
Status
NFTables is published on Hex at version 0.9 and is pre-1.0. A coverage report generated from the specification, the tests and the code is kept in the repository and checked in CI.