Elixir module for Linux nftables. NFTables provides both high-level helper functions for common firewall operations and flexible rule building with composable functions.
Add nftables to your dependencies in mix.exs:
def deps do
[
{:nftables, "~> 0.7.0"}
]
endsudo apt-get update
sudo apt-get install -y \
libnftables-dev \
libcap-dev \
zigmix deps.get
mix compileThe port executable requires CAP_NET_ADMIN to communicate with the kernel firewall:
# After compilation
sudo setcap cap_net_admin=ep deps/nftables_port/priv/port_nftables
chmod 700 deps/nftables_port/priv/port_nftablesNote - before running examples on a remote machine, be aware you are able block your remote access. You may want to start by experimenting in a VM or local machine.
import NFTables.Expr
{:ok, pid} = NFTables.Port.start_link()
def ssh(rule), do: rule |> tcp() |> dport(22)
response =
NFTables.add(table: "filter", family: :inet)
|> NFTables.add(chain: "INPUT", hook: :input)
|> NFTables.add(rule: expr() |> ssh() |> accept())
|> NFTables.submit(pid: pid)
IO.inspect(response)- High-Level APIs - Simple functions for blocking IPs, managing sets, creating rules
- Pure Functional Expr API - composable expression builder with no side effects
- Sysctl Management - Read/Write access to network kernel parameters
- Batch Operations - Atomic multi-command execution
- Query Operations - List tables, chains, rules, sets, and elements
- Builder Pattern - Clear separation between building and executing rules
- Elixir Port-based Architecture - Fault isolation (crashes don't affect BEAM VM)
- Security - Port runs with minimal privileges (CAP_NET_ADMIN only)
- Flowtables - Hardware-accelerated packet forwarding for established connections
- Meters/Dynamic Sets - Per-key rate limiting with composite key support
- Raw Payload Matching - Offset-based packet header access for custom protocols
- Socket Matching & TPROXY - Transparent proxy support without destination changes
- OSF (OS Fingerprinting) - Passive operating system detection via TCP SYN analysis
The NFTables library depends on NFTables.Port which is an elixir wrapper, and a program written in Zig which accepts json structures and sends them to Linux nftables using the libnftables (C library). The Elixir module manages the Zig program as a Port.
{:ok, pid} = NFTables.Port.start_link()
# Send JSON commands (for structured operations)
json_cmd = ~s({"nftables": [{"list": {"tables": {}}}]})
{:ok, json_response} = NFTables.Port.call(pid, json_cmd)Visit the NFTables.Port GitHub project for details. Take some time to review the Security document found there.
NFTables.Port takes JSON requests and passes them on to the Linux nftables service. The Elixir NFTables library is a set of tools to query and build rule sets which can be applied via NFTables.Port.
Generate JSON using NFTables library
json =
NFTables.add(table: "filter", family: :inet)
|> NFTables.add(chain: "INPUT", hook: :input, policy: :drop)
|> NFTables.add(rule: tcp() |> dport(22) |> accept())
|> NFTables.to_json()Putting these together
{: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)Using this we can manage a local firewall from Elixir.
A couple possibilities:
- dynamic firewall which process events and updates firewall based on the events.
- distributed firewall on multiple nodes.
- Linux kernel >= 3.18 (nf_tables support)
- Zig >= 0.11.0
- Elixir >= 1.14
- Erlang/OTP >= 24
The following development packages must be installed:
libnftables-dev>= 0.9.0 - Netfilter nftables userspace library (includes JSON API)libcap-dev>= 2.25 - POSIX capabilities library
sudo apt-get update
sudo apt-get install -y \
libnftables-dev \
libcap-dev \
zigCheck that all dependencies are available:
# Check Zig
zig version
# Check nftables library
pkg-config --modversion libnftablesThe Zig port is automatically compiled when you build the Mix project:
# Fetch dependencies
mix deps.get
# Compile (includes Zig compilation)
mix compileThe compiled port_nftables binary will be placed in deps/nftables_port/priv/port_nftables.
To build just the Zig port:
cd deps/nftables_port/priv/port_nftables/native
zig buildThe binary will be in .../native/zig-out/bin/port_nftables.
The port binary needs CAP_NET_ADMIN capability to manage firewall rules:
sudo setcap cap_net_admin=ep deps/nftables_port/priv/port_nftablesVerify:
getcap priv/port_nftables
# Should show: priv/port_nftables = cap_net_admin+epOnce port_nftables has CAP_NET_ADMIN capability set, it can be used to set network related parameters (like enable ip_forwarding) and configure nftables (create/delete/update tables, chains, rules, etc...). Considering this it would be wise to protect this executable.
the nftables_port executable should fail to run if it has any rwx permissions for other. if this is the case you will see a message similar to:
\\
\\SECURITY ERROR: Executable has world permissions enabled!
\\
\\Current permissions: 755
\\
\\This executable has CAP_NET_ADMIN capability and MUST NOT be
\\world-readable, world-writable, or world-executable.
\\
\\To fix, run:
\\ chmod 750 {s}
\\ # or
\\ chmod 700 {s}
\\
\\The mode must end in 0 (no permissions for "other").
\\Access should be controlled via user/group ownership.
\\
\\Refusing to start for security reasons.
\\
minimally for production, do the following:
- create a special user that the nftables_port will run as such as
exfw. Feel free to be more creative with the name. chown exfw nftables_port# make the executable belong to the new userexfwchmod 700 nftables_port# make the executable only runnable by the userexfw
see the project examples directory
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
See LICENSE for details.