Files
martillo-maldito/README.md
T
midefosandClaude Opus 5.5 13ca4518b4 feat: IPv6 bans, timeout-less set migration, typed errors, clap/thiserror 2
- Detect an existing ipset without timeout support and migrate it in place
  (temporary set + copy members + ipset swap + destroy) without unblocking.
- IPv6: "<set>6" (family inet6) + ip6tables match-set rule; ban/unban pick
  the set by address family. IPv4 keeps working if IPv6 is unavailable.
- Remove unwrap()/panics: MartilloMaldito::new/with_config and every public
  method return Result<_, MartilloError>; ignore multiport/range rules when
  parsing secured ports; handle an empty DOCKER-USER chain.
- Ipset::save_all / save-ipsets for ipset-persistent (/etc/iptables/ipsets).
- structopt -> clap 4, thiserror 1 -> 2. CLI exits 1 on errors.
- Kernel tests skip without CAP_NET_ADMIN; run them with `unshare -rn`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 01:36:54 +01:00

5.2 KiB

Martillo Maldito

Martillo Maldito is an iptables wrapper that simplifies firewall rule management in an intuitive and structured way. This CLI allows you to manage secured ports, block IPs, save rules, and more.


Features

  • Ban/unban IPv4 and IPv6 addresses with ipset (optional timeout).
  • Retrieve all banned IPs.
  • Query and manage secured ports.
  • Allow or deny access by IP for specific ports.
  • Rule persistence.
  • Optional Docker integration.

Requirements

  • Rust 1.80 or higher.
  • iptables, ip6tables and ipset installed on the system.
  • Proper permissions to manage iptables rules (e.g., running as root, or CAP_NET_ADMIN).

Banning with ipset

Bans are stored in two hash:ip sets with timeout support: banned (IPv4) and banned6 (IPv6), each matched by a -m set --match-set <set> src -j DROP rule at the top of INPUT (or DOCKER-USER with --docker) in iptables/ip6tables. Sets and rules are created on first use.

If a set already exists without timeout support (older versions created it like that, and ipset add ... timeout N then fails), it is migrated automatically without unblocking anyone: a temporary set with timeout is created, the members are copied, ipset swap puts it in place and the old one is destroyed.

If IPv6 is not available (no ip6tables, no IPv6 in the kernel), IPv4 bans keep working and banning an IPv6 address returns an error.


Installation

  1. Clone the repository:

    git clone https://github.com/your_user/martillo_maldito.git
    cd martillo_maldito
    
  2. Build the project:

    cargo build --release
    
  3. Optionally, copy the executable to a directory in your PATH:

    cp target/release/martillo_maldito /usr/local/bin/
    

Usage

General Syntax

martillo_maldito <command> [options]

Available Commands

1. Retrieve all banned IPs

martillo_maldito get-banned-ips [--docker | -d]

Options:

  • --docker, -d: Includes rules in Docker environments.

Ban / unban an IP

martillo_maldito ban-ip --ip <ip> [--timeout <seconds>] [--docker | -d]
martillo_maldito unban-ip --ip <ip> [--docker | -d]

IPv6 addresses go to the banned6 set. Without --timeout the ban is permanent. Every command prints true/false (or JSON) on stdout; on failure the error is printed on stderr and the exit code is 1.

Save the ipsets

martillo_maldito save-ipsets [--file /etc/iptables/ipsets]

Writes every set in the format restored at boot by ipset-persistent.

2. Retrieve all secured ports

martillo_maldito get-secured-ports [--docker | -d]

3. Retrieve all secured ports with allowed IPs

martillo_maldito get-secured-ports-with-allowed-ips [--docker | -d]

4. Check if a port is secured

martillo_maldito is-port-secured --port <port> [--docker | -d]

Options:

  • --port, -p: Specifies the port to check.
  • --docker, -d: Includes rules in Docker environments.

5. Secure a port

martillo_maldito secure-port --port <port> [--position <position>] [--docker | -d]

Options:

  • --port, -p: Specifies the port to secure.
  • --position, -P: Specifies the rule position in iptables.
  • --docker, -d: Includes rules in Docker environments.

6. Unsecure a port

martillo_maldito unsecure-port --port <port> [--docker | -d]

Options:

  • --port, -p: Specifies the port to unsecure.
  • --docker, -d: Includes rules in Docker environments.

7. Allow an IP for a port

martillo_maldito allow-ip-for-port --ip <ip> --port <port> [--position <position>] [--docker | -d]

Options:

  • --ip, -i: Specifies the IP to allow.
  • --port, -p: Specifies the port to allow the IP on.
  • --position, -P: Specifies the rule position.
  • --docker, -d: Includes rules in Docker environments.

8. Remove an allowed IP from a port

martillo_maldito remove-allow-ip-port --ip <ip> --port <port> [--docker | -d]

Options:

  • --ip, -i: Specifies the IP to remove.
  • --port, -p: Specifies the port to remove the IP from.
  • --docker, -d: Includes rules in Docker environments.

9. Save rules

martillo_maldito save-rules

Saves all current iptables rules for future restoration.


Examples

  1. Retrieve all banned IPs:

    martillo_maldito get-banned-ips
    
  2. Secure port 8080 with Docker enabled:

    martillo_maldito secure-port -p 8080 -d
    
  3. Allow access to IP 192.168.1.10 on port 22:

    martillo_maldito allow-ip-for-port -i 192.168.1.10 -p 22
    
  4. Save all current rules:

    martillo_maldito save-rules
    

Tests

cargo test                                   # kernel tests are skipped without CAP_NET_ADMIN
unshare -rn cargo test                       # run them too, isolated, without sudo
cargo build --release && unshare -rn env SELF_ISOLATED=1 ./tests/integration_netns.sh

Disclaimer

This repository is designed solely for experimental or educational purposes. It is not intended for use in production environments or critical projects. Use at your own risk.