Skip to content

maromcik/nftblockd

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 environment variables.

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 -e .env

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

Example Commands:

  1. Fetch and apply an IPv4 blocklist from an HTTP endpoint:
nftblockd --url4 https://example.com/ipv4-blocklist
  1. 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
  1. Use environment variables from a custom .env file:
nftblockd --env-file path/to/env/file
  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

Configuration

nftblockd 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

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

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

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

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages