Skip to content
maromcikPublic

About

Rust based tool that fetches IP blocklists and configures nftables via API.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Repository files navigation

nftblockd

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.


Key Features

  • 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 to nftables.
  • 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 the configuration file.

Building

  1. 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
  1. Clone the Repository:
git clone https://github.com/maromcik/nftblockd.git
cd nftblockd
  1. Build the Binary, use Cargo to build the project:

Standard build using glibc

cargo build --release

More portable build using musl

rustup target add x86_64-unknown-linux-musl
cargo build --release --target=x86_64-unknown-linux-musl
  1. Run the Binary:

Run the compiled binary (glibc):

./target/release/nftblockd

Run the compiled binary (musl):

./target/x86_64-unknown-linux-musl/release/nftblockd

Installation

Either use the nftables Ansible role from ansible-collections or deploy it on your own.

Deployment

Download the binary and run it:

wget https://gitlab.ics.muni.cz/api/v4/projects/7885/packages/generic/nftblockd/latest/nftblockd
nftblockd -c config.yaml

Instead of the keyword latest, you can specify the desired tag

Usage

The general usage structure for nftblockd is:

nftblockd [OPTIONS]

Command-Line Options:

Flag or Argument Description Default or Mandatory
-c, --config <CONFIG_FILE> Specifies a YAML configuration file for the tool. Optional
-d, --delete Deletes the existing blocklist table and stops the execution. Flag, Optional

Example Commands:

  1. Run with the default configuration (built-in defaults):
nftblockd
  1. Use a custom YAML configuration file:
nftblockd --config path/to/config.yaml
  1. Delete the blocklist table manually:
nftblockd --delete

Logging

You 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=0

Controlling the daemon with nftblockctl

nftblockctl is a companion CLI for interacting with a running nftblockd daemon. It communicates with the daemon over gRPC via the Unix socket at /run/nftblockd.sock, so it can be used to inspect and control the blocklist without restarting the service.

The general usage structure is:

nftblockctl <COMMAND> [OPTIONS]

Subcommands:

Command Description
reload Reloads configuration and triggers an immediate re-fetch of the blocklists and re-applies the nftables ruleset.
flush Deletes the entire blocklist table from nftables (the daemon keeps running). It does not reload configuration.
status Prints the daemon status summary (status_code, status, message).
stats Prints drop statistics (packets/bytes) for the main and custom blocklists, split by chain and IP family.

Each subcommand accepts the -j, --json flag to print the response as JSON instead of the human-readable format.

Example Commands:

  1. Check the daemon status:
nftblockctl status
  1. Show drop statistics as JSON:
nftblockctl stats --json
  1. Reload the blocklist after changing its source:
nftblockctl reload

Configuration

nftblockd is configured via a YAML file, passed with -c/--config. All options are optional and fall back to the defaults shown below.

Durations use humantime format (e.g. "500ms", "30s", "5m", "1h").

YAML Key Description Default Value
log_level Logging level. Options: debug, info, warn, error. info
download_blocklist.ipv4_url The IPv4 blocklist fetching URL. None
download_blocklist.ipv6_url The IPv6 blocklist fetching URL. None
download_blocklist.interval Interval for updating blocklists. 30s
download_blocklist.timeout A global timeout for blocklist requests. 10s
download_blocklist.split_string The string that is used to split the fetched blocklist. Any whitespace
download_blocklist.headers A map of HTTP header key/value pairs sent with blocklist requests. None
custom_blocklist.set_name The name of the custom, local blocklist set within the table. custom_blocklist_set
custom_blocklist.ipv4_path A path to a file with IPv4 addresses to be blocked in the local blocklist. None
custom_blocklist.ipv6_path A path to a file with IPv6 addresses to be blocked in the local blocklist. None
custom_blocklist.split_string The string that is used to split the custom blocklist files. Any whitespace
anti_lockout.set_name The name of the anti-lockout set within the table. anti_lockout_set
anti_lockout.ipv4 A list of IPv4 anti-lockout IPs/subnets (e.g., admin IPs). None
anti_lockout.ipv6 A list of IPv6 anti-lockout IPs/subnets (e.g., admin IPs). None
nftables.table_name The name of the nftables blocklist table. nftblockd
nftables.prerouting_chain The name of the nftables prerouting chain in the blocklist table. prerouting
nftables.postrouting_chain The name of the nftables postrouting chain in the blocklist table. postrouting
nftables.blocklist_set_name The name of the downloaded blocklist set within the table. blocklist_set
retry.count Number of retry attempts in case of fatal errors. 10
retry.interval Retry interval in case of fatal errors. 2s
retry.fail_wait Wait time before retrying after a fatal error. 60s

A fully documented example is also available in config.example.yaml.

Example config.yaml

log_level: info

download_blocklist:
  ipv4_url: "https://example.com/ipv4-blocklist"
  ipv6_url: "https://example.com/ipv6-blocklist"
  interval: "60s"
  timeout: "10s"
  # split_string: ","
  # headers:
  #   Authorization: "Bearer <token>"

custom_blocklist:
  set_name: custom_blocklist_set
  ipv4_path: ipv4.txt
  ipv6_path: ipv6.txt
  # split_string: ","

anti_lockout:
  set_name: anti_lockout_set
  ipv4:
    - "192.168.1.1"
    - "10.0.0.0/24"
  ipv6:
    - "2001:db8::1"

nftables:
  table_name: nftblockd
  prerouting_chain: prerouting
  postrouting_chain: postrouting
  blocklist_set_name: blocklist_set

retry:
  count: 10
  interval: "2s"

System integration with systemd

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.


Example systemd Service File

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
ExecStart=/usr/local/sbin/nftblockd -c /opt/nftables/nftblockd/nftblockd.yml
ExecReload=/usr/local/sbin/nftblockctl reload
ExecStopPost=/usr/local/sbin/nftblockd -d -c /opt/nftables/nftblockd/nftblockd.yml
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=sysinit.target

And create the YAML configuration file.

cat /opt/nftables/blocklist/nftblockd.yaml
download_blocklist:
  ipv4_url: "https://example.com/ipv4-blocklist"
  ipv6_url: "https://example.com/ipv6-blocklist"
  interval: "60s"

Steps to Enable and Start the Service

  1. Save the Service File:

    • Save the example configuration as /etc/systemd/system/nftblockd.service.
  2. Reload systemd:

    • Ensure systemd recognizes the new service:
sudo systemctl daemon-reload
  1. Enable the Service:
    • Automatically start the service at boot:
sudo systemctl enable nftblockd
  1. Start the Service:
    • Manually start the service:
sudo systemctl start nftblockd
  1. Check Service Status:
    • To verify it is running:
sudo systemctl status nftblockd
  1. View Logs:
    • Check logs using journalctl:
journalctl -u nftblockd.service

Example Logs

After enabling and running the service, you can analyze its logs using:

journalctl -u nftblockd.service -n 100 -f

Example 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

Internals and Workflow

High-Level Workflow:

  1. Fetch Blocklist:

    • Fetches IPv4 and IPv6 blocklists from user-defined endpoints.
  2. Validate Blocklist:

    • Parses the blocklists and ensures all subnets are well-formed and valid.
  3. Deduplicate Subnets:

    • Removes redundant subnets using a trie-based algorithm. Ensures performance via prefix grouping.
  4. Transform for nftables:

    • Converts validated subnets into nftables-compatible expressions.
  5. Apply Rules:

    • Applies the blocklist to the configured nftables table and set, while respecting the anti-lockout rules.

Code Structure:

  • main.rs:
    • Handles CLI, configuration 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.

Development

  1. Run Tests: The project includes unit tests for validation, deduplication, and transformations.
cargo test
  1. Static Analysis: Use clippy to catch potential issues during development:
cargo clippy --all-targets -- -D warnings 
  1. Formatting: Format all Rust code prior to committing:
cargo fmt

Contribution

We welcome contributions to nftblockd. Feel free to open issues or submit pull requests. Follow the steps below to contribute:

  1. Fork this repository.
  2. Create a feature branch (git checkout -b feature-name).
  3. Commit your changes (git commit -m 'Add a feature').
  4. Push to your branch (git push origin feature-name).
  5. Open a pull request.

License

This project is licensed under the MIT License.


Acknowledgements

This project uses the following third-party libraries:

  • clap: For command-line argument parsing.
  • ureq: For HTTP requests.
  • log and env_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!

About

Rust based tool that fetches IP blocklists and configures nftables via API.

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages