macOS PF (Packet Filter) firewall configuration TUI
Project description
wj-firewall
A macOS PF (Packet Filter) firewall configuration tool with both an interactive terminal UI and a command-line interface.
wj-firewall is not a firewall itself — it configures macOS's built-in PF packet filter. It makes it easy to block incoming traffic on specific network interfaces while keeping others open. The typical use case is blocking incoming connections on Wi-Fi while keeping Tailscale or other trusted networks open, so services listening on 0.0.0.0 are only reachable from trusted networks.
Features
- Interactive TUI — curses-based terminal UI for visual interface management
- CLI — scriptable command-line interface for automation and quick changes
- Per-interface blocking — block incoming traffic on selected interfaces
- Port exceptions — allow specific ports through on blocked interfaces (TCP + UDP)
- ICMP control — optionally block ICMP (ping, traceroute) on blocked interfaces
- PF anchors — rules stored in
/etc/pf.anchors/wj-firewall, surviving OS updates - Zero dependencies — Python 3.12+ stdlib only
Requirements
- Python 3.12+
- macOS (uses PF and pfctl)
- Administrator privileges (sudo) for applying firewall rules
Installation
pip install wj-firewall
Or run directly with uv:
uvx wj-firewall
Quick Start
Interactive TUI
wj-firewall
You will be prompted for your password (sudo). The TUI shows all network interfaces and lets you:
- Space — toggle "block incoming" on the selected interface
- p — open port editing mode (add/remove port exceptions)
- i — toggle ICMP blocking on a blocked interface
- a — apply changes (writes anchor file and reloads PF)
- r — revert to last applied state
- q — quit (confirms if unsaved changes)
Command-Line Interface
# Show current firewall status
wj-firewall status
# Block incoming traffic on Wi-Fi
wj-firewall block en0
# Allow SSH and HTTP through on a blocked interface
wj-firewall allow en0 22 80
# Block ICMP (ping) on an interface
wj-firewall icmp en0 block
# Remove a port exception
wj-firewall deny en0 80
# Unblock an interface
wj-firewall unblock en0
How It Works
wj-firewall uses macOS PF anchors to manage firewall rules without touching the rest of your pf.conf. Rules are stored in /etc/pf.anchors/wj-firewall and referenced from pf.conf via anchor declarations. The tool automatically adds the anchor references if they are missing.
For each blocked interface, the following PF rules are generated:
- Pass outgoing — all outbound traffic and return traffic is allowed
- Pass DHCP — DHCP discovery is always allowed (so you can get an IP address)
- Pass ICMP — ping, traceroute, and PMTU discovery are allowed (unless ICMP is blocked)
- Pass ports — any port exceptions are allowed through (both TCP and UDP)
- Block everything else — all other incoming traffic is silently dropped
Rules use quick for first-match-wins evaluation and block drop (silent discard) to avoid triggering macOS Private Relay issues.
Development
# Set up development environment
make dev
# Run linting and type checking
make check
# Auto-format code
make format
# Build wheel and docs
make build
Licence
Released under the Unlicense — public domain.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wj_firewall-1.0.0b1-py3-none-any.whl.
File metadata
- Download URL: wj_firewall-1.0.0b1-py3-none-any.whl
- Upload date:
- Size: 38.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f7cc61563b0551c875faa9eda5200930436a561c6c84f52ddbc1fe4ac5553db
|
|
| MD5 |
6434aec94ab490c6accda9b1d821bc12
|
|
| BLAKE2b-256 |
38643e5515f8b340e8e2334fd5698266b54d6edf6bce72d3921604196c00602b
|