# NFTables - Elixir Interface to nftables
Elixir module for Linux nftables. NFTables provides both high-level helper functions for common firewall operations and flexible rule building with composable functions.
## Quickstart Guide
### Installation
Add `nftables` to your dependencies in `mix.exs`:
```elixir
def deps do
[
{:nftables, "~> 0.6.5"}
]
end
```
### Install dependencies
```bash
sudo apt-get update
sudo apt-get install -y \
libnftables-dev \
libcap-dev \
zig
```
### Build
```bash
mix deps.get
mix compile
```
### Setting Capabilities
The port executable requires `CAP_NET_ADMIN` to communicate with the kernel firewall:
```bash
# After compilation
sudo setcap cap_net_admin=ep deps/nftables_port/priv/port_nftables
chmod 700 deps/nftables_port/priv/port_nftables
```
### Build a Rule
**Note** - 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.
```elixir
alias NFTables.Builder
import NFTables.Expr
{:ok, pid} = NFTables.start_link()
def ssh(rule), do: rule |> tcp() |> dport(22)
response =
Builder.new()
|> Builder.add(table: "filter", family: :inet)
|> Builder.add(chain: "INPUT", hook: :input)
|> Builder.add(rule: expr() |> ssh() |> accept())
|> Builder.commit(pid: pid)
IO.inspect(response}
```
## Features
- **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
### NFTables_Port
The NFTables library depends on [NFTables.Port](https://hex.pm/packages/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.
```elixir
{: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](https://github.com/dcoai/nftables_port) project page for details. Take some time to review the [Security](https://github.com/dcoai/nftables_port/dev_docs/security.md) document found there.
### NFTables
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**
```elixir
json =
Builder.new()
|> Builder.add(table: "filter", family: :inet)
|> Builder.add(chain: "INPUT", hook: :input, policy: :drop)
|> Builder.add(rule: tcp() |> dport(22) |> accept())
|> Builder.to_json()
```
**Putting these together**
```elixir
{:ok, pid} = NFTables.Port.start_link()
json_cmd =
Builder.new()
|> Builder.add(table: "filter", family: :inet)
|> Builder.add(chain: "INPUT", hook: :input, policy: :drop)
|> Builder.add(rule: tcp() |> dport(22) |> accept())
|> Builder.to_json()
{:ok, json_response} = NFTables.Port.call(pid, json_cmd)
```
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.
## System Requirements
- Linux kernel >= 3.18 (nf_tables support)
- Zig >= 0.11.0
- Elixir >= 1.14
- Erlang/OTP >= 24
### Required System Libraries
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
### Installation on Debian/Ubuntu
```bash
sudo apt-get update
sudo apt-get install -y \
libnftables-dev \
libcap-dev \
zig
```
### Verify Installation
Check that all dependencies are available:
```bash
# Check Zig
zig version
# Check nftables library
pkg-config --modversion libnftables
```
## Building
The Zig port is automatically compiled when you build the Mix project:
```bash
# Fetch dependencies
mix deps.get
# Compile (includes Zig compilation)
mix compile
```
The compiled `port_nftables` binary will be placed in `deps/nftables_port/priv/port_nftables`.
### Manual Build
To build just the Zig port:
```bash
cd deps/nftables_port/priv/port_nftables/native
zig build
```
The binary will be in `.../native/zig-out/bin/port_nftables`.
### Setting Capabilities
The port binary needs CAP_NET_ADMIN capability to manage firewall rules:
```bash
sudo setcap cap_net_admin=ep deps/nftables_port/priv/port_nftables
```
Verify:
```bash
getcap priv/port_nftables
# Should show: priv/port_nftables = cap_net_admin+ep
```
### Security considerations
Once 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:
1. create a special user that the nftables_port will run as such as `exfw`. Feel free to be more creative with the name.
2. `chown exfw nftables_port` # make the executable belong to the new user `exfw`
3. `chmod 700 nftables_port` # make the executable only runnable by the user `exfw`
## Useage Examples
see the project `examples` directory
## Contributing
Contributions are welcome! Please:
1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Ensure all tests pass
5. Submit a pull request
## License
See [LICENSE](LICENSE) for details.
## Resources
- [nftables documentation](https://wiki.nftables.org/)
- [libnftables JSON API](https://wiki.nftables.org/wiki-nftables/index.php/JSON_API)
- [nft man page](https://www.netfilter.org/projects/nftables/manpage.html)
- [Netfilter project](https://www.netfilter.org/)