Skip to content

dcoai/nftables

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

def deps do
  [
    {:nftables, "~> 0.7.0"}
  ]
end

Install dependencies

sudo apt-get update
sudo apt-get install -y \
  libnftables-dev \
  libcap-dev \
  zig

Build

mix deps.get
mix compile

Setting Capabilities

The 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_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.

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)

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 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

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.

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

sudo apt-get update
sudo apt-get install -y \
  libnftables-dev \
  libcap-dev \
  zig

Verify Installation

Check that all dependencies are available:

# Check Zig
zig version

# Check nftables library
pkg-config --modversion libnftables

Building

The Zig port is automatically compiled when you build the Mix project:

# 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:

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:

sudo setcap cap_net_admin=ep deps/nftables_port/priv/port_nftables

Verify:

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 for details.

Resources