fwctl is a dependency-free Linux console program for understanding what an
iptables firewall is doing, with special attention to ports published by
Docker. It correlates live sockets, Docker port mappings, firewall policies,
chain reachability, and DOCKER-USER rules instead of showing each source in
isolation.
The tool was created for remotely administered hosts. Read-only inspection is
the default, and every firewall mutation is delegated to /usr/bin/ipup.
- IPv4 and IPv6
INPUT,FORWARD, andOUTPUTpolicies. - Host listening sockets and whether their bind address and
INPUTrules make them reachable from another machine, including sockets bound to a specific IP. - Every running Docker container's published IPv4 and IPv6 port mappings.
- A prominent alert when Docker publishes a port on any non-loopback host
address without an effective
DOCKER-USERdrop. The report distinguishes all-address, public IP, private IP, link-local, and loopback binds. - Whether
FORWARDactually reachesDOCKER-USER. A rule in an unreferenced chain is reported as bypassed, not as protection. - The live chain jump graph and complete filter/NAT rulesets.
- Linux with the iptables Docker firewall backend.
- Python 3.10 or newer.
iptables,ip6tables,ss, and Docker CLI access.- Root privileges for changing rules. Status commands can run with whatever visibility the current account has.
No third-party Python package is required.
Install the console:
sudo install -o root -g root -m 0755 fwctl.py /usr/local/sbin/fwctlThe mutation commands require the command API shown in
examples/ipup. Merge that API and the marked
FWCTL-DOCKER-BLOCKS section into the host's existing /usr/bin/ipup; do not
blindly replace a production firewall script with the example.
On the original deployment, the current ipup was backed up before the API was
added. Preserve the same backup discipline on other hosts.
Run the high-level audit:
fwctl statusstatus exits with code 2 when it detects a listener or Docker mapping
reachable from another machine through the host firewall. This makes it
suitable for monitoring:
fwctl alertInspect the actual chain topology and rules:
fwctl graph
fwctl rules
fwctl rules --family iptables --table filter
fwctl rules --family ip6tables --table natBlock a Docker-published TCP port by its host-side/original port:
sudo fwctl docker-block 8000This command performs no direct mutation from Python. It calls:
/usr/bin/ipup docker-block 8000ipup then:
- Ensures
FORWARDreachesDOCKER-USERfor IPv4 and IPv6. - Inserts a
conntrack --ctorigdstport 8000 -j DROPrule at the start ofDOCKER-USERwithout flushing any chain. - Adds the equivalent persistent rules to its marked managed section.
The original destination match matters because Docker DNAT happens before the
packet reaches DOCKER-USER. A host mapping such as 8000:22 is seen there as
container port 22, not destination port 8000.
List blocks persisted by the command API:
sudo ipup docker-blocksRemove a managed block:
sudo fwctl docker-unblock 8000 --yesRemoving a rule may expose the container immediately, so --yes is mandatory.
The docker-block and docker-unblock commands do not execute the normal
zero-argument ipup path and do not flush INPUT, FORWARD, or connection
tracking. Host SSH normally traverses INPUT, while Docker publications
traverse FORWARD and DOCKER-USER.
Still, verify which port carries the remote session before blocking anything. If SSH itself is published through Docker on the selected host port, blocking that port will terminate new SSH access. Keep an independent administrative session open while validating changes.
- Managed Docker blocks currently target TCP. UDP publications are displayed but the mutation command does not add UDP rules.
- The listener analysis explains ordinary bind addresses and common
INPUTaccept/drop rules. Usefwctl rulesfor the authoritative full ruleset when rules include unusual extensions, marks, sets, or policy routing. - The status report analyzes the host bind and local firewall. Upstream firewalls and network routing can still affect actual reachability; confirm Internet access with a probe from outside the host when it matters.
fwctldoes not disable Docker's firewall management and does not edit Docker-owned chains.
Run the standard-library test suite:
python3 -m unittest discover -s tests -vThe mutation-boundary tests verify that Python delegates changes exclusively
to /usr/bin/ipup and refuses an unblock without explicit confirmation.
Developed at the Stratosphere Laboratory at the Czech Technical University in Prague.