nftblockd is a robust Rust-based tool designed for managing IP blocklists in nftables. It provides an efficient and
secure mechanism to fetch, validate, deduplicate, and apply IPv4 and IPv6 subnets to a blocklist table in nftables.
The tool is geared toward optimizing network security with ease and reliability.
- IPv4 and IPv6 Support: Handles both IPv4 and IPv6 blocklists.
- Automatic Blocklist Fetching: Fetches blocklists from user-specified or environment-configured endpoints.
- Validation and Deduplication: Ensures subnets are valid, deduplicated, and free of redundancies using a trie-based algorithm.
- High Performance: Uses optimized data structures and algorithms for subnet deduplication.
- Integration with
nftables: Directly applies blocklist rules tonftables. - Anti-Lockout Mechanism: Protects the specified critical IPs from being locked out of the firewall by mistake.
- Periodic Update Support: Periodically fetches and updates the blocklists according to a user-configured interval.
- Smart Logging: Configurable logging levels via environment variables.
- Install Dependencies
Ensure you have Rust installed on your system. If not, you can install it via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh- Clone the Repository:
git clone https://github.com/maromcik/nftblockd.git
cd nftblockd- Build the Binary, use Cargo to build the project:
Standard build using glibc
cargo build --releaseMore portable build using musl
rustup target add x86_64-unknown-linux-musl
cargo build --release --target=x86_64-unknown-linux-musl- Run the Binary:
Run the compiled binary (glibc):
./target/release/nftblockdRun the compiled binary (musl):
./target/x86_64-unknown-linux-musl/release/nftblockdEither use the nftables Ansible role from ansible-collections or deploy it on your own.
Download the binary and run it:
wget https://gitlab.ics.muni.cz/api/v4/projects/7885/packages/generic/nftblockd/latest/nftblockd
nftblockd -e .envInstead of the keyword latest, you can specify the desired tag
The general usage structure for nftblockd is:
nftblockd [OPTIONS]| Flag or Argument | Description | Default or Mandatory |
|---|---|---|
-4, --url4 <IPv4_URL> |
The endpoint URL to fetch the IPv4 blocklist. | Optional |
-6, --url6 <IPv6_URL> |
The endpoint URL to fetch the IPv6 blocklist. | Optional |
-i, --interval <INTERVAL> |
Time interval (in seconds) for periodic blocklist updates. | 30 (Default) |
-e, --env-file <ENV_FILE> |
Specifies an .env file containing environment variable configurations for the tool. |
Optional |
-d, --delete |
Deletes the existing blocklist table and stops the execution. | Flag, Optional |
- Fetch and apply an IPv4 blocklist from an HTTP endpoint:
nftblockd --url4 https://example.com/ipv4-blocklist- Apply both IPv4 and IPv6 blocklists periodically with a 60-second interval:
nftblockd --url4 https://example.com/ipv4-blocklist --url6 https://example.com/ipv6-blocklist --interval 60- Use environment variables from a custom
.envfile:
nftblockd --env-file path/to/env/file- Delete the blocklist table manually:
nftblockd --deleteYou can view logs using the journalctl -ekf | grep nftblockd command.
journalctl -ekf | grep nftblockd
Jul 23 18:03:21 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=91.191.209.13 DST=147.251.6.171 LEN=40 TOS=0x00 PREC=0x00 TTL=247 ID=38244 PROTO=TCP SPT=52783 DPT=3397 WINDOW=1024 RES=0x00 SYN URGP=0
Jul 23 19:12:42 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=188.166.78.140 DST=147.251.6.171 LEN=44 TOS=0x00 PREC=0x00 TTL=247 ID=54321 PROTO=TCP SPT=34686 DPT=22533 WINDOW=65535 RES=0x00 SYN URGP=0
Jul 23 21:45:02 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=83.222.190.242 DST=147.251.6.171 LEN=44 TOS=0x00 PREC=0x00 TTL=248 ID=34085 PROTO=TCP SPT=57526 DPT=8137 WINDOW=1025 RES=0x00 SYN URGP=0
Jul 23 21:54:17 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=83.222.190.242 DST=147.251.6.171 LEN=44 TOS=0x00 PREC=0x00 TTL=248 ID=33107 PROTO=TCP SPT=57526 DPT=8103 WINDOW=1025 RES=0x00 SYN URGP=0
Jul 24 04:03:47 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=79.124.62.122 DST=147.251.6.171 LEN=40 TOS=0x00 PREC=0x00 TTL=247 ID=33224 PROTO=TCP SPT=0 DPT=5060 WINDOW=1024 RES=0x00 SYN URGP=0
Jul 24 06:04:13 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=152.32.150.29 DST=147.251.6.171 LEN=44 TOS=0x08 PREC=0x20 TTL=44 ID=0 DF PROTO=TCP SPT=38265 DPT=25105 WINDOW=1024 RES=0x00 SYN URGP=0
Jul 24 09:59:09 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=83.222.191.42 DST=147.251.6.171 LEN=40 TOS=0x00 PREC=0x00 TTL=247 ID=12192 PROTO=TCP SPT=61000 DPT=25708 WINDOW=1024 RES=0x00 SYN URGP=0
Jul 24 10:01:26 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=83.222.191.42 DST=147.251.6.171 LEN=40 TOS=0x00 PREC=0x00 TTL=247 ID=48645 PROTO=TCP SPT=61000 DPT=25741 WINDOW=1024 RES=0x00 SYN URGP=0
Jul 24 11:55:34 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=167.99.117.14 DST=147.251.6.171 LEN=44 TOS=0x00 PREC=0x00 TTL=243 ID=54321 PROTO=TCP SPT=54545 DPT=8000 WINDOW=65535 RES=0x00 SYN URGP=0
Jul 24 11:55:34 proxy-dev kernel: nftblockd;prerouting;dropped: IN=eth0 OUT= MAC=bc:24:11:a3:0e:dc:ec:13:db:94:82:c0:08:00 SRC=167.99.117.14 DST=147.251.6.171 LEN=44 TOS=0x00 PREC=0x00 TTL=243 ID=54321 PROTO=TCP SPT=54546 DPT=8000 WINDOW=65535 RES=0x00 SYN URGP=0nftblockd supports configuring various parameters through environment variables. Here's a list of the configurable
variables:
| Environment Variable | Description | Default Value |
|---|---|---|
NFTBLOCKD_IPV4_URL |
The IPv4 blocklist fetching URL. | None |
NFTBLOCKD_IPV6_URL |
The IPv6 blocklist fetching URL. | None |
NFTBLOCKD_REQUEST_HEADERS |
A json in the format { "header_key1" : "header_value1", "header_key2" : "header_value2" } |
None |
NFTBLOCKD_ANTI_LOCKOUT_IPV4 |
A whitespace separated list of IPv4 anti-lockout IPs (e.g., admin IP). | None |
NFTBLOCKD_ANTI_LOCKOUT_IPV6 |
A whitespace separated list of IPv6 anti-lockout IPs (e.g., admin IP). | None |
NFTBLOCKD_CUSTOM_BLOCKLIST_PATH_IPV4 |
A path to a file with IPv4 address to be blocked in the custom local blocklist | None |
NFTBLOCKD_CUSTOM_BLOCKLIST_PATH_IPV6 |
A path to a file with IPv6 address to be blocked in the custom local blocklist | None |
NFTBLOCKD_BLOCKLIST_SPLIT_STRING |
The string that is used to split the fetched blocklist | Any whitespaces |
NFTBLOCKD_REQUEST_TIMEOUT |
A global timeout for requests | 10 |
NFTBLOCKD_RETRY_INTERVAL |
Retry interval in seconds in case of fatal errors | 1 |
NFTBLOCKD_RETRY_COUNT |
Number of retry attempts in case of fatal errors | 5 |
NFTBLOCKD_INTERVAL |
Interval (in seconds) for updating blocklists. | 30 |
NFTBLOCKD_LOG_LEVEL |
Logging level. Options: debug, info, warn, error. |
info |
NFTBLOCKD_TABLE_NAME |
The name of the nftables blocklist table. |
nftblockd |
NFTBLOCKD_PREROUTING_CHAIN_NAME |
The name of the nftables prerouting chain in the blocklist table. |
prerouting |
NFTBLOCKD_POSTROUTING_CHAIN_NAME |
The name of the nftables postrouting chain in the blocklist table. |
postrouting |
NFTBLOCKD_BLOCKLIST_SET_NAME |
The name of the blocklist set within the table. | blocklist_set |
NFTBLOCKD_ANTI_LOCKOUT_SET_NAME |
The name of the blocklist set within the table. | anti_lockout_set |
NFTBLOCKD_CUSTOM_BLOCKLIST_SET_NAM |
The name of a custom, local blocklist set within the table. | custom_blocklist_set |
You can use these variables via an .env file for easy configuration:
NFTBLOCKD_IPV4_URL=https://example.com/ipv4-blocklist
NFTBLOCKD_IPV6_URL=https://example.com/ipv6-blocklist
NFTBLOCKD_INTERVAL=60
NFTBLOCKD_ANTI_LOCKOUT_IPV4=192.168.1.1 10.0.0.0/24
NFTBLOCKD_ANTI_LOCKOUT_IPV6=2001:db8::1
To ensure nftblockd runs persistently on your system, even after reboots or network interruptions, you can configure
it as a systemd service. Below is an example systemd service configuration and a detailed explanation of the file
structure.
Save the following configuration as /etc/systemd/system/nftblockd.service:
[Unit]
Description=Update IP blocklist for nftables with nftblockd
Wants=network-online.target nftables.service
After=network-online.target nftables.service
[Service]
Type=simple
Restart=always
RestartSec=60
EnvironmentFile=/opt/nftables/blocklist/nftblockd.env
ExecStart=/usr/local/sbin/nftblockd
ExecReload=/usr/local/sbin/nftblockd
ExecStopPost=/usr/local/sbin/nftblockd -d
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=sysinit.target
And create the env file.
cat /opt/nftables/blocklist/nftblockd.env
NFTBLOCKD_IPV4_URL=https://example.com/ipv4-blocklist
NFTBLOCKD_IPV6_URL=https://example.com/ipv6-blocklist
NFTBLOCKD_INTERVAL=60
-
Save the Service File:
- Save the example configuration as
/etc/systemd/system/nftblockd.service.
- Save the example configuration as
-
Reload
systemd:- Ensure
systemdrecognizes the new service:
- Ensure
sudo systemctl daemon-reload- Enable the Service:
- Automatically start the service at boot:
sudo systemctl enable nftblockd- Start the Service:
- Manually start the service:
sudo systemctl start nftblockd- Check Service Status:
- To verify it is running:
sudo systemctl status nftblockd- View Logs:
- Check logs using
journalctl:
- Check logs using
journalctl -u nftblockd.serviceAfter enabling and running the service, you can analyze its logs using:
journalctl -u nftblockd.service -n 100 -fExample output:
May 23 12:16:13 <hostname> nftblockd[498270]: [2025-05-23T10:16:13Z INFO nftblockd::blocklist] blocklist fetched from: http://localhost/ipv4.txt
May 23 12:16:13 <hostname> nftblockd[498270]: [2025-05-23T10:16:13Z WARN nftblockd::subnet] invalid ip: 192.168.0.2/16; not a network
May 23 12:16:13 <hostname> nftblockd[498270]: [2025-05-23T10:16:13Z INFO nftblockd::blocklist] blocklist fetched from: http://localhost/ipv6.txt
May 23 12:16:13 <hostname> nftblockd[498270]: [2025-05-23T10:16:13Z INFO nftblockd] the `blocklist` table successfully loaded
May 23 12:16:13 <hostname> nftblockd[498270]: [2025-05-23T10:16:13Z INFO nftblockd] finished
-
Fetch Blocklist:
- Fetches IPv4 and IPv6 blocklists from user-defined endpoints.
-
Validate Blocklist:
- Parses the blocklists and ensures all subnets are well-formed and valid.
-
Deduplicate Subnets:
- Removes redundant subnets using a trie-based algorithm. Ensures performance via prefix grouping.
-
Transform for
nftables:- Converts validated subnets into
nftables-compatible expressions.
- Converts validated subnets into
-
Apply Rules:
- Applies the blocklist to the configured
nftablestable and set, while respecting the anti-lockout rules.
- Applies the blocklist to the configured
main.rs:- Handles CLI, environment parsing, and the main tool logic.
subnet.rs:- Contains subnet parsing, blocklist validation, and subnet transformations.
iptrie.rs:- Implements the trie-based deduplication algorithm for IPv4 and IPv6 subnets.
network.rs:- Defines the abstraction for IPv4 and IPv6 blocklist networks.
blocklist.rs:- Performs blocklist updating.
anti_lockout.rs:- Ensures certain administrator-defined IPs cannot be blocked by mistake.
nftables.rs:- APIs responsible for constructing and applying rules to
nftables.
- APIs responsible for constructing and applying rules to
- Run Tests: The project includes unit tests for validation, deduplication, and transformations.
cargo test- Static Analysis:
Use
clippyto catch potential issues during development:
cargo clippy --all-targets -- -D warnings - Formatting: Format all Rust code prior to committing:
cargo fmtWe welcome contributions to nftblockd. Feel free to open issues or submit pull requests. Follow the steps below to
contribute:
- Fork this repository.
- Create a feature branch (
git checkout -b feature-name). - Commit your changes (
git commit -m 'Add a feature'). - Push to your branch (
git push origin feature-name). - Open a pull request.
This project is licensed under the MIT License.
This project uses the following third-party libraries:
clap: For command-line argument parsing.ureq: For HTTP requests.logandenv_logger: For logging support.ipnetwork: For managing IPv4/IPv6 subnets.itertools: For enhanced iterator functionality in Rust.
If you have further questions or want to report a bug, feel free to open an issue or reach out!