dezhban

module
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: MIT

README

Dezhban

Persian dežbān (دژبان) — "gatekeeper / garrison guard."

dezhban makes sure your traffic can only leave this machine through your VPN. If the VPN drops, your connection is cut instantly instead of silently falling back to your real IP. If the VPN redials somewhere you've told it to refuse, everything stops. On macOS it's a menubar app you click; everywhere else, and for anyone who prefers it, it's a CLI and background service.

  [ your machine ] --- VPN tunnel up ---> [ the internet ]

      VPN drops: nothing to react to, the standing rule
      already blocks every non-tunnel path
              |
              v
  [ egress cut, instantly ]   (a plain kill switch would leak right here)

[!WARNING] dezhban deliberately cuts network access. A wrong VPN endpoint, a crash before teardown, or running it over a remote session can lock you out of your own machine. The escape hatch is the menubar app's Panic button, or sudo dezhban panic from a terminal — either works with no daemon running. Read docs/usage/getting-started.md before arming it for real.

Platform support

macOS Linux Windows
App Menubar + window
CLI ✅ (experimental)
Enforcement backend pfctl nft WFP

Windows is an early target: go vet gates it in CI, but the control socket's whole authorization model is unix permissions, which Windows has no equivalent of yet, so there's no passwordless path there today. Use the CLI, and expect rough edges.

Install (macOS)

curl -fsSL https://raw.githubusercontent.com/Behnam-RK/dezhban/main/scripts/install.sh | sudo bash

Then open Dezhban from Applications (or Spotlight). That's the only terminal step, ever — not because the app can't be double-clicked, but because there's no Apple Developer certificate to sign it with yet, so Gatekeeper would otherwise block it. curl genuinely doesn't trip that check (it's documented Apple behavior, not a workaround), so this line installs the app with zero Gatekeeper friction and asks for your password exactly once. Details, the .pkg alternative, and Linux/Windows installers: docs/usage/install.md.

Using the app

Open the app and everything else happens by clicking:

  • Menubar dropdown — the safety core. One glance tells you the posture (e.g. "Guard — NL via Mullvad"); Block now / Unblock, the VPN switch window with a live countdown, and Panic. These never require the main window to be open.
  • Overview — live status, the daily controls, and guided recovery: if the service isn't installed or is stopped, there's an inline button for exactly that, not an error message.
  • Settings — a full config editor: VPN tunnel/endpoints, autodetection, blocked countries, both windows' durations, local-network access, start at boot, launch at login. One confirmation per batch of changes, not one per field.
  • Logs & Diagnostics — read-only doctor, recent logs, a live log stream.
  • Privileged actions (install, start/stop, panic) prompt with Touch ID where available; routine block/unblock/switch need no prompt at all.

A GUI user never needs a terminal again — including for upgrades, which the app checks for and applies in place.

Headless / CLI

Linux, servers, and anyone who prefers a terminal on any OS:

sudo dezhban setup                # interactive wizard — build the config, no JSON by hand
dezhban validate                  # confirm it (--config is optional)
dezhban monitor                   # live IP/country/tunnel/verdict, no firewall touched

sudo dezhban run                  # run the daemon (root; drives the firewall)
sudo dezhban panic                # always-available teardown, no daemon needed

Full walkthrough: docs/usage/getting-started.md. Complete command reference: docs/usage/cli.md. Tab-completion: source <(dezhban completion zsh).

Postures at a glance

One enforcement model — the guard. What changes is the posture:

  STANDBY  --arm-->  GUARD  <==>  FULL BLOCK   (blocked / allowed country)
                        |
                        +--switch or redial-->  SWITCH WINDOW
                                                    (bounded, self-closing)
  • STANDBY — no rules, network fully open, nothing is being blocked. The resting state before any tunnel has been observed. Arms itself when a VPN connects.
  • GUARD — the healthy state. Only the tunnel may carry traffic off the machine, so a drop is cut instantly (zero leak window with vpn.redialWindow: "0"; by default a bounded redial window follows the cut so the VPN can redial).
  • FULL BLOCK — the VPN's exit landed in a blocked country. All user traffic is cut, but the endpoint handshake stays open so the tunnel can recover.
  • SWITCH WINDOW — the one sanctioned relaxation, bounded and self-closing, from exactly two triggers: an explicit operator command, or the automatic redial window.

Full state machine and exact rulesets: docs/concepts/modes.md.

Configuration

JSON, with durations as strings (e.g. "30s"). Sample configs live in configs/ (dezhban.example.json is fully automatic; dezhban.vpn-guard.json pins the tunnel interface and endpoints explicitly). Full field reference: docs/usage/config.md.

Documentation

See docs/README.md for the full set, grouped by audience — using it, the mental model, and contributing.

License

MIT © 2026 Behnam RK

Directories

Path Synopsis
cmd
dezhban command
Command dezhban is a cross-platform network kill switch: it watches the machine's public IP, resolves its country, and drives the OS firewall to cut traffic when the country matches a blocklist.
Command dezhban is a cross-platform network kill switch: it watches the machine's public IP, resolves its country, and drives the OS firewall to cut traffic when the country matches a blocklist.
internal
armed
Package armed persists the one fact that lets the daemon arm at boot instead of live-probing for a tunnel: "a configured VPN has been observed up at least once on this host." That is exactly the arming rail ADR-0002 specified — "the daemon arms only when a tunnel is both configured and has been observed up at least once" — and the persistence its own Consequences section flagged as required and never built: "the 'observed once' bit must persist across daemon restarts to avoid re-entering standby on every reboot." See docs/adr/0002-standby-no-tunnel-posture.md and docs/adr/0008-arm-at-boot.md.
Package armed persists the one fact that lets the daemon arm at boot instead of live-probing for a tunnel: "a configured VPN has been observed up at least once on this host." That is exactly the arming rail ADR-0002 specified — "the daemon arms only when a tunnel is both configured and has been observed up at least once" — and the persistence its own Consequences section flagged as required and never built: "the 'observed once' bit must persist across daemon restarts to avoid re-entering standby on every reboot." See docs/adr/0002-standby-no-tunnel-posture.md and docs/adr/0008-arm-at-boot.md.
command
Package command is the daemon's ROOT control channel: a root-owned command file that the `dezhban switch`/`vpn` CLIs write and the running daemon consumes on a tick.
Package command is the daemon's ROOT control channel: a root-owned command file that the `dezhban switch`/`vpn` CLIs write and the running daemon consumes on a tick.
config
Package config defines dezhban's runtime configuration and loading.
Package config defines dezhban's runtime configuration and loading.
control
Package control is the daemon's live control channel: a unix socket the daemon listens on and the CLI dials, so routine posture changes (block / unblock / switch window) work without re-elevating to root on every call.
Package control is the daemon's live control channel: a unix socket the daemon listens on and the CLI dials, so routine posture changes (block / unblock / switch window) work without re-elevating to root on every call.
decision
Package decision maps monitor readings to an enforcement verdict.
Package decision maps monitor readings to an enforcement verdict.
firewall
Package firewall drives the OS firewall to cut and restore network egress.
Package firewall drives the OS firewall to cut and restore network egress.
help
Package help turns the repo's documentation into what the macOS app bundles and displays.
Package help turns the repo's documentation into what the macOS app bundles and displays.
learned
Package learned persists VPN server endpoints that the daemon discovered at runtime (during a switch window, or via live socket discovery under normal guard), so a VPN that has been connected once stays reachable across restarts without the user hand-typing its server address.
Package learned persists VPN server endpoints that the daemon discovered at runtime (during a switch window, or via live socket discovery under normal guard), so a VPN that has been connected once stays reachable across restarts without the user hand-typing its server address.
logging
Package logging builds dezhban's structured logger.
Package logging builds dezhban's structured logger.
monitor
Package monitor resolves the machine's public IP and its country, on a polling loop, with multi-provider redundancy.
Package monitor resolves the machine's public IP and its country, on a polling loop, with multi-provider redundancy.
netdetect
Package netdetect discovers VPN tunnel interfaces for the interface-aware guard, so operators need not hand-name them.
Package netdetect discovers VPN tunnel interfaces for the interface-aware guard, so operators need not hand-name them.
privilege
Package privilege reports whether dezhban has the OS privileges needed to modify the firewall (root on unix, Administrator on Windows).
Package privilege reports whether dezhban has the OS privileges needed to modify the firewall (root on unix, Administrator on Windows).
redial
Package redial bounds the automatic redial window: how long it may be, how often, and when it must be refused outright.
Package redial bounds the automatic redial window: how long it may be, how often, and when it must be refused outright.
render
Package render turns a state.Snapshot into the sentences an operator reads: a short headline and a supporting detail, plus a stable machine key that classifies the two.
Package render turns a state.Snapshot into the sentences an operator reads: a short headline and a supporting detail, plus a stable machine key that classifies the two.
runner
Package runner ties the three layers into the live daemon: it polls the Monitor, asks the Decider for a verdict, and drives the firewall Backend — always cleaning up on exit.
Package runner ties the three layers into the live daemon: it polls the Monitor, asks the Decider for a verdict, and drives the firewall Backend — always cleaning up on exit.
setup
Package setup holds the first-run wizard's decisions: what it asks, in what order, which answers unlock which follow-ups, and how the answers become a config.
Package setup holds the first-run wizard's decisions: what it asks, in what order, which answers unlock which follow-ups, and how the answers become a config.
state
Package state publishes the daemon's live posture to an on-disk JSON file so out-of-process observers (the macOS menubar app, `status --json`) can read exactly what the daemon decided without running their own poller.
Package state publishes the daemon's live posture to an on-disk JSON file so out-of-process observers (the macOS menubar app, `status --json`) can read exactly what the daemon decided without running their own poller.
svc
Package svc runs dezhban as a managed background service on each OS, using one cross-platform API (github.com/kardianos/service) that maps to launchd on macOS, systemd/upstart/sysv on Linux, and the Windows Service manager.
Package svc runs dezhban as a managed background service on each OS, using one cross-platform API (github.com/kardianos/service) that maps to launchd on macOS, systemd/upstart/sysv on Linux, and the Windows Service manager.
token
Package token is the daemon's shared secret with a trusted local client.
Package token is the daemon's shared secret with a trusted local client.
update
Package update implements `dezhban upgrade`: checking GitHub for a newer release, downloading and verifying it, and — on macOS only — applying the signed .pkg and restarting into it.
Package update implements `dezhban upgrade`: checking GitHub for a newer release, downloading and verifying it, and — on macOS only — applying the signed .pkg and restarting into it.
vocab
Package vocab reads the banned-word table out of docs/concepts/glossary.md and matches text against it.
Package vocab reads the banned-word table out of docs/concepts/glossary.md and matches text against it.
vpnimport
Package vpnimport extracts VPN server endpoints from common client config formats so a profile can be created without hand-copying the server address.
Package vpnimport extracts VPN server endpoints from common client config formats so a profile can be created without hand-copying the server address.
tools
helpgen command
Command helpgen renders the documentation the macOS app bundles.
Command helpgen renders the documentation the macOS app bundles.
relsign command
Command relsign signs a file with the dezhban release ed25519 private key.
Command relsign signs a file with the dezhban release ed25519 private key.
taskmenu command
taskmenu is the interactive picker behind a bare `task` on a TTY: pick a flow, answer the prompts for the vars it takes, and it execs `task <name> KEY=VAL…`.
taskmenu is the interactive picker behind a bare `task` on a TTY: pick a flow, answer the prompts for the vars it takes, and it execs `task <name> KEY=VAL…`.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL