The Problem

Terminal‑based network monitors usually answer a single question – “what’s using my bandwidth?” – and then stop. Analysts who need to triage encrypted traffic, attribute connections to processes, or spot subtle patterns such as DNS‑tunnelling or command‑beaconing must switch to separate tools, export captures, and manually correlate data. This fragmentation slows incident response and limits visibility for SREs and homelabbers who need live, contextual insight without leaving the terminal.

What This Does

NetWatch is a single binary that combines a bandwidth meter, a lightweight Wireshark‑style TUI, and a basic intrusion‑detection view.

  • Entry points – src/main.rs and src/lib.rs start the application; src/app.rs orchestrates the runtime.
  • Packet capture – on Linux the src/ebpf/mod.rs and src/ebpf/conn_tracker.rs use eBPF (via libbpf-rs) to intercept sockets without promiscuous mode. Platform‑specific back‑ends live in src/platform/linux.rs, src/platform/macos.rs, and src/platform/windows.rs.
  • Deep‑packet inspection – protocol decoders under src/dpi/ handle TLS, HTTP, DNS, QUIC, SSH, MQTT, and others. Each module parses the wire format and emits structured events.
  • Process attribution – src/collectors/connections.rs links each socket to the owning process via /proc (Linux) or equivalent APIs, exposing the binary name and PID in the UI.
  • Telemetry & UI – ten tabbed panels (dashboard, connections, topology, egress, insights, etc.) are rendered by src/ui/ modules (dashboard.rs, connections.rs, topology.rs, …). The dense view (src/ui/dense/) shows four zero‑chrome graphs; the lite view (src/ui/lite.rs) collapses to an 80×24 snapshot.
  • Policy & incident flags – src/collectors/incident.rs and src/collectors/health.rs detect patterns such as port‑scans, unusual outbound DNS, and data exfiltration attempts, surfacing them in the UI and offering a one‑key freeze that emits a portable evidence bundle.

The codebase contains 148 files, 87 in src/, with dedicated modules for config, geo‑lookup, quarantine, and remote monitoring (src/remote/). CI runs GitHub Actions (.github/workflows/ci.yml, .github/workflows/release.yml) and the project is licensed MIT with a Cargo.lock present.

How It Is Wired

BlockDescription
ENTRY → FUNCTION → OUTSIDEsrc/main.rs calls app::run() (src/app.rs). That function initialises the TUI (src/ui/mod.rs), loads configuration (src/config.rs), and spawns collector tasks. Collectors read from the eBPF ring buffer (src/ebpf/mod.rs) and from src/collectors/packets/mod.rs, which filters and formats packets using the dpi modules. Process names are resolved in src/collectors/connections.rs. UI threads subscribe to a shared src/state::State and redraw on each update.
HUBS / CYCLESsrc/collectors/mod.rs aggregates all per‑protocol collectors and exposes a single Collector struct. No circular dependencies were detected; the module graph is a tree rooted at src/collectors/mod.rs. Changing a dpi decoder only requires editing the corresponding src/dpi/*.rs file; the collector and UI remain unaffected.
Widest blast radiussrc/collectors/mod.rs and src/state.rs – a change here ripples to every panel and to the evidence‑bundle generator. The eBPF hook (src/ebpf/mod.rs) also has broad impact because all packet flow passes through it, but the code is deliberately thin and well‑documented.
Outside‑process effectsThe binary writes no persistent state by default; the only filesystem interaction is a temporary evidence archive generated on the “V” keypress (src/app.rs → src/collectors/incident.rs). Network‑level effects are read‑only packet inspection; no packets are injected.

How To Use It

Setup

git clone https://github.com/moses-y/netwatch
cd netwatch
cargo build --release   # produces target/release/netwatch

Configuration The binary operates with zero configuration. If a custom capture interface or BPF filter is desired, edit src/config.rs (defaults to the primary interface and a permissive filter). Environment variables are not required; the README does not list any.

Running it

# dense view – fills a large terminal
./target/release/netwatch --view dense

# lite view – single 80×24 screen
./target/release/netwatch --lite

# toggle evidence freeze (press “V” while running)

The CLI is defined in src/main.rs; flags --view dense, --lite, and --help are parsed there.

Real‑World Use

During a suspected data‑exfiltration incident, an analyst starts NetWatch in dense mode. The connections table quickly reveals a low‑volume UDP flow from python3 to an unfamiliar external IP. Selecting the row and pressing “V” freezes the current capture and emits a tarball containing the pcap slice, process metadata, and a summary of the detected pattern. The analyst attaches that bundle to the ticket, and the team confirms the host was running a compromised script that was beaconing over DNS.

Code Health & Issues

  • Static analysis (performed on the repository structure):
  • 3 test files exist under tests/; CI runs them on every push.
  • Cargo.lock is present, ensuring reproducible builds.
  • License (MIT) and SECURITY.md are included.
  • No missing critical files (.github/workflows, CHANGELOG.md, CONTRIBUTING.md).
  • The README notes “650+ tests”, but the counted test artefacts in the clone are the three files listed above; the discrepancy likely reflects integration‑test scripts outside the counted set.
  • SDLC observations:
  • Documentation is split between docs/ (architecture tour, reference, eBPF deep‑dive) and markdown files in the root; the coverage is adequate for a project of this size.
  • No secrets or configuration files are committed; the only secrets‑relevant file is scripts/demo/tls12-decrypt.tape, which is a demo artifact.

The Bottom Line

NetWatch delivers a rare combination of live packet decoding, process attribution, and pattern detection inside a single, zero‑config TUI. The Rust implementation is well‑structured, with clear module boundaries and a modest test surface. It is especially suited for blue‑teamers, SREs, and homelabbers who need immediate, contextual network visibility without leaving the terminal. The main trade‑off is platform‑specific eBPF support (full on Linux, limited on macOS/Windows), but the codebase already provides fall‑back collectors for those environments.