nftblock
nftblock watches Blockmerge's newline-delimited mixed IPv4/IPv6 CIDR files and owns a single
inet nftblock table. Every accepted reload is parsed completely first and then sent through
libnftnl/libmnl as one atomic, paged netlink transaction. A parse, allocation, or kernel error
leaves the active table unchanged. The daemon never invokes the nft executable.
The table contains separate interval sets for inbound/outbound IPv4/IPv6 traffic and base chains for input, forward, and output. Normal SIGINT/SIGTERM shutdown deliberately preserves the table.
Configuration
Start with config/nftblock.toml. Zones can be defined directly in it:
[]
= ["eth0"]
= { = [], = true }
= ["eth1"]
Alternatively, omit [zones] and set zones = "/data/zones.json" in [files] (or pass
--zones/NFTBLOCK_ZONES). config/zones.example.json accepts either
the shown map or { "zones": [{ "name": "WAN", "interfaces": ["eth0"] }] }. Inline and file
definitions are mutually exclusive; an explicit CLI/environment zones path selects the file.
Zone alternatives are expanded as separate nftables rules (OR); ingress and egress constraints in
one forward mapping are paired as a cross product (AND).
Unknown zones, interface-less non-local zones, local zones in forward rules, and chain-inappropriate
fields are rejected before netlink is opened. Flowtables are queried directly over netlink. If one
contains any protected interface, startup/reconciliation fails unless
allow_flowtable_bypass = true is explicitly set.
All file paths, table settings, timing settings, and the flowtable override have CLI flags and
NFTBLOCK_* environment overrides. Use nftblock --help for their exact names. Validate and show
the expanded mappings without changing the firewall:
nftblock --config ./config/nftblock.toml --check
Blocklist syntax remains producer-neutral:
# generated 2026-08-18T12:00:00Z
192.0.2.0/24
2001:db8::/32
Blank lines and comments are ignored. Any other line must be a CIDR. Networks are normalized and exact duplicates are removed. Blockmerge must remove overlaps before publishing a list; nftblock does not perform producer-side aggregation.
Container
The container needs the host network namespace and CAP_NET_ADMIN; it does not need privileged
mode. Mount the Blockmerge output directory read-only so inotify can observe destination renames.
Both Debian and Alpine images install only the libnftnl and libmnl runtime libraries—nft is
not installed. Build both variants with Docker Bake, or build either Dockerfile directly:
docker buildx bake
docker build -f Dockerfile.debian -t nftblock:debian .
docker build -f Dockerfile.alpine -t nftblock:alpine .
Tests
cargo test
sudo ./tests/netns.sh
The Rust suite covers parsing, interval encoding, configuration rendering, atomic rename event classification, failed-batch retention, and multi-page construction. The namespace test exercises the native input, forward, and output rules without touching the host ruleset.