imsnif/bandwhich
Terminal bandwidth utilization tool
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1d ago
- ✓10 active contributors
- ✓MIT licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 69% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/imsnif/bandwhich)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/imsnif/bandwhich on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: imsnif/bandwhich
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/imsnif/bandwhich shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 1d ago
- 10 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 69% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live imsnif/bandwhich
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/imsnif/bandwhich.
What it runs against: a local clone of imsnif/bandwhich — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in imsnif/bandwhich | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of imsnif/bandwhich. If you don't
# have one yet, run these first:
#
# git clone https://github.com/imsnif/bandwhich.git
# cd bandwhich
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of imsnif/bandwhich and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "imsnif/bandwhich(\\.git)?\\b" \\
&& ok "origin remote is imsnif/bandwhich" \\
|| miss "origin remote is not imsnif/bandwhich (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/network/sniffer.rs" \\
&& ok "src/network/sniffer.rs" \\
|| miss "missing critical file: src/network/sniffer.rs"
test -f "src/display/ui.rs" \\
&& ok "src/display/ui.rs" \\
|| miss "missing critical file: src/display/ui.rs"
test -f "src/network/utilization.rs" \\
&& ok "src/network/utilization.rs" \\
|| miss "missing critical file: src/network/utilization.rs"
test -f "src/os/mod.rs" \\
&& ok "src/os/mod.rs" \\
|| miss "missing critical file: src/os/mod.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/imsnif/bandwhich"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
bandwhich is a terminal-based real-time network bandwidth monitor written in Rust that displays per-process, per-connection, and per-IP bandwidth utilization. It sniffs raw packets on a network interface and cross-references them with OS process tables (/proc on Linux, lsof on macOS, WinApi on Windows) to attribute network traffic to specific applications, with optional reverse DNS resolution for IP hostname mapping. Modular monolith: src/display/ handles TUI rendering (components/, ui.rs, raw_terminal_backend.rs using ratatui), src/network/ contains packet sniffing and DNS resolution (sniffer.rs, connection.rs, utilization.rs), and src/os/ abstracts platform-specific process lookup (separate linux.rs, windows.rs, lsof.rs for macOS/FreeBSD). The CLI argument parsing lives in src/cli.rs and entry point in src/main.rs, with async tokio runtime for concurrent sniffing and DNS operations.
👥Who it's for
System administrators, DevOps engineers, and network troubleshooters who need to quickly diagnose which processes are consuming bandwidth without installing heavyweight monitoring suites. Users who prefer lightweight CLI tools over GUI applications and need to understand network behavior on servers and workstations across Linux, macOS, Windows, and even Android.
🌱Maturity & risk
Production-ready but in passive maintenance: the project has been stable enough for inclusion in major Linux distributions (per INSTALL.md packaging status badge) and supports multiple OS/architecture targets. However, as stated in the README, it's in 'passive maintenance' mode with critical issues addressed but no active feature development, making it reliable for existing use cases but not for users expecting rapid innovation.
Low to moderate risk: the codebase is primarily Rust (memory-safe), has CI/CD via GitHub Actions (.github/workflows/), but depends on complex OS-level packet sniffing and lsof parsing which can break with OS updates. Single maintainer risk is acknowledged in the README with an explicit call for co-maintainers. The MINIMUM Rust version is 1.88.0 (relatively recent), so version constraint issues are minimal.
Active areas of work
The project is in maintenance mode per the README and .github/workflows/ show active CI testing but no release workflow is actively running. The CHANGELOG.md and version (0.23.1) indicate the last significant activity was stabilization work. Pull requests are welcome but the maintainer is seeking contributors for long-term involvement (see issue #275 mentioned in README).
🚀Get running
git clone https://github.com/imsnif/bandwhich.git
cd bandwhich
cargo build --release
# Requires elevated privileges (setcap on Linux or sudo/admin on other OSes)
sudo ./target/release/bandwhich
Daily commands:
cargo run --release -- [OPTIONS]
# Common options visible in src/cli.rs:
cargo run --release -- --help
# Run tests:
cargo test
# Run with UI tests (currently opt-in, see Cargo.toml ui_test feature):
cargo test --features ui_test
🗺️Map of the codebase
src/main.rs— Application entry point that orchestrates network sniffing, DNS resolution, and UI rendering—essential for understanding the overall execution flow.src/network/sniffer.rs— Core packet capture and connection tracking engine; all network data flows through this module before reaching display or output.src/display/ui.rs— Primary UI state management and event loop; handles terminal rendering, user input, and display updates in real-time.src/network/utilization.rs— Bandwidth calculation and aggregation logic; transforms raw packet data into human-readable per-process/connection statistics.src/os/mod.rs— OS abstraction layer (Linux, Windows, macOS) that provides process metadata and privilege elevation; platform-specific implementation branching point.src/network/dns/mod.rs— DNS resolution service that maps IPs to hostnames; manages concurrent DNS queries and caching to avoid blocking the sniffer.src/cli.rs— Command-line argument parsing and configuration; defines all user-facing modes and options (raw, no-resolve, interface selection, etc.).
🛠️How to make changes
Add support for a new operating system
- Create a new OS implementation module (e.g., src/os/macos.rs) with platform-specific packet capture and process lookup. (
src/os/macos.rs) - Implement the OS trait from src/os/mod.rs, handling sniffer initialization and connection-to-process mapping. (
src/os/mod.rs) - Add conditional compilation guards in src/main.rs to select the OS module at build time. (
src/main.rs) - Update Cross.toml with the new target triple and any required dependencies or runner images. (
Cross.toml)
Add a new display mode (e.g., JSON export, web UI)
- Create a new output formatter module (e.g., src/display/json_formatter.rs) that consumes Utilization data and produces formatted output. (
src/display/mod.rs) - Add a CLI flag in src/cli.rs to enable the new mode (e.g., --json, --web). (
src/cli.rs) - In src/main.rs, branch on the CLI mode and call your formatter instead of the UI event loop. (
src/main.rs) - Add integration tests in src/tests/cases/ with golden snapshots to validate output format. (
src/tests/cases/mod.rs)
Add a new sorting or filtering option in the UI
- Extend the UiState struct in src/display/ui_state.rs with a new sort/filter enum variant. (
src/display/ui_state.rs) - Handle the new sort/filter logic in src/display/components/table.rs when rendering rows. (
src/display/components/table.rs) - Bind a keyboard shortcut in src/display/ui.rs to toggle or cycle the new sort/filter option. (
src/display/ui.rs) - Add a test case in src/tests/cases/mod.rs that validates the UI output with the new sort/filter applied. (
src/tests/cases/mod.rs)
Optimize bandwidth calculation or aggregation
- Review and refactor the aggregation logic in src/network/utilization.rs (per-process, per-connection bucketing). (
src/network/utilization.rs) - Ensure the Sniffer in src/network/sniffer.rs emits connection events efficiently; profile packet processing overhead. (
src/network/sniffer.rs) - Run the existing snapshot tests in src/tests/cases/ to validate correctness after optimization. (
src/tests/cases/mod.rs) - Benchmark with real traffic using the raw mode output (--raw) to measure throughput improvements. (
src/cli.rs)
🔧Why these technologies
- Rust — Memory-safe systems programming; critical for real-time packet processing without segfaults or data races; zero-cost abstractions match C performance.
- libpcap (Linux) / WinPcap (Windows) — Industry-standard packet capture APIs; enables raw packet sniffing with minimal dependencies and maximum portability across OS versions.
- Async Tokio runtime — Efficient concurrent DNS resolution and potential future I/O operations without blocking the sniffer main loop.
- TUI/Termion for terminal rendering — Cross-platform terminal manipulation; handles cursor, colors, and responsive layout without external dependencies like ncurses.
- Snapshot testing (insta crate) — Golden snapshots catch unintended UI/output changes; CI-friendly validation of packet processing correctness.
⚖️Trade-offs already made
-
Require root/admin privileges for packet capture
- Why: Accessing raw socket data requires elevated privileges on all platforms; no user-space alternative exists for per-packet inspection.
- Consequence: Users must run with sudo or setcap on Linux; adoption friction for non-privileged environments (containers, sandboxes).
-
Synchronous lsof-based process lookup fallback on Unix
- Why: Avoids dependency on /proc filesystem (Linux-specific); provides compatibility across BSD/macOS
- Consequence: undefined
🪤Traps & gotchas
- Privilege escalation required: on Linux, must run with CAP_NET_RAW and CAP_NET_ADMIN capabilities (via setcap or sudo), not just regular user; see INSTALL.md for post-install setup. 2. Platform-specific packet capture: pnet raw socket capture may fail or behave differently on WSL2, Docker, or VMs; Linux uses AF_PACKET, Windows uses raw sockets via system calls. 3. DNS resolver initialization: trust-dns-resolver reads /etc/resolv.conf on Linux and system DNS on other OSes—misconfigured DNS can hang reverse lookups (runs in background task so doesn't block UI, but may cause memory bloat). 4. Rust MSRV is 1.88.0: projects pinning older toolchains (e.g.,
rustup default 1.70) will fail to build.
🏗️Architecture
💡Concepts to learn
- Packet Sniffing via Raw Sockets — bandwhich's core capability depends on AF_PACKET (Linux) or raw socket APIs (Windows) to capture all ingress/egress packets; understanding kernel-level packet capture is essential for debugging sniffer failures or porting to new OS.
- Process Introspection (/proc, lsof, WinApi) — Mapping network connections to processes requires reading /proc/net/tcp on Linux, parsing lsof output on macOS, or calling WinApi functions on Windows; this OS-specific logic is the bottleneck for cross-platform support.
- Reverse DNS Resolution — bandwhich performs background DNS PTR lookups to display hostnames instead of raw IPs; understanding DNS async patterns and best-effort retry logic prevents UI hangs and connection timeouts.
- Flow Aggregation & State Management — bandwhich must accumulate per-packet stats into per-connection flows and handle connection lifecycle (open, active, closed); the Connection and ConnectionToProcess structs implement this aggregation and are critical for accurate bandwidth attribution.
- Async Task Coordination in Tokio — bandwhich uses tokio spawn tasks for packet sniffing, DNS resolution, and UI rendering running concurrently; understanding channels, sync primitives, and task cancellation is vital for adding new async operations or debugging race conditions.
- Terminal Capability Detection & TUI Rendering — bandwhich adapts UI density based on terminal size (src/display/components/layout.rs) and uses ratatui's constraint system to reflow tables—understanding terminal capabilities prevents layout corruption on small terminals or exotic emulators.
- Conditional Compilation & Platform Abstractions — The src/os/ module uses cfg attributes to select platform-specific implementations at compile time; mastering Rust's conditional compilation is essential for adding support for new OSes or conditionally enabling debug logging.
🔗Related repos
imsnif/zellij— Same author; a terminal multiplexer also using ratatui/crossterm for TUI—good reference for advanced terminal rendering patterns used in bandwhichnicolaka/netshoot— Companion diagnostic container image bundling network troubleshooting tools; often used alongside bandwhich in containerized environments to correlate bandwidth with other metricsborinathan/bmon— Alternative bandwidth monitor in C; simpler UI, lower-level packet capture—useful for understanding different design trade-offs in the same problem domainraboof/nethogs— Similar per-process bandwidth monitor predating bandwhich; serves as a predecessor inspiration for the core feature (process attribution of network traffic)ratatui-org/ratatui— The TUI rendering library bandwhich depends on (0.30.0); understanding ratatui's widget system is essential for modifying display components
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for DNS resolution in src/network/dns/
The DNS module (src/network/dns/client.rs, resolver.rs) has no snapshot tests or integration tests visible in src/tests/cases/. Given that hostname resolution is a core feature shown in snapshots like 'traffic_with_host_names.snap', adding dedicated DNS resolver tests would catch regressions in hostname lookup behavior and ensure reliability across platforms.
- [ ] Create src/tests/cases/dns_resolution.rs with test cases for successful/failed DNS queries
- [ ] Add snapshot tests for DNS caching behavior and timeout scenarios
- [ ] Test resolver behavior with different system configurations (no_resolve_mode already exists, expand coverage)
- [ ] Add tests for src/network/dns/client.rs and src/network/dns/resolver.rs with mocked DNS responses
Add platform-specific unit tests for src/os/lsof.rs and src/os/lsof_utils.rs
The lsof utilities (src/os/lsof.rs, lsof_utils.rs) parse system process/connection data but have minimal visible test coverage. These modules are critical for accurate process-to-connection mapping on Unix systems. Adding snapshot tests for lsof output parsing would prevent parsing regressions.
- [ ] Create src/tests/cases/lsof_parsing.rs with snapshot tests for various lsof output formats
- [ ] Add test cases for edge cases: malformed lsof output, missing fields, large process counts
- [ ] Add rstest parameterized tests in src/os/lsof_utils.rs for utility functions like parsing IP/port strings
- [ ] Test platform-specific variations (Linux vs macOS vs FreeBSD lsof output differences)
Add comprehensive GitHub Actions workflow for testing cross-platform builds (Linux, macOS, Windows, Android)
While ci.yaml exists, the Cross.toml file and platform-specific dependencies (procfs for Linux, regex for macOS/FreeBSD, netstat2 for Windows, Android support in Cargo.toml) suggest the project supports multiple platforms. A dedicated cross-platform build workflow would catch platform-specific compilation errors early and validate the cross-compilation setup.
- [ ] Create .github/workflows/cross-platform-build.yaml that uses cross-rs for Linux ARM, Android, and other targets
- [ ] Add matrix builds for: x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-apple-darwin, x86_64-pc-windows-gnu, aarch64-linux-android
- [ ] Validate that platform-specific features compile correctly (procfs on Linux, netstat2 on Windows)
- [ ] Add build artifact caching and upload to speed up workflow execution
🌿Good first issues
- Add snapshot tests for src/os/lsof.rs parsing edge cases (function names and PID extraction): lsof output varies by BSD/macOS version and current tests in src/tests/ do not cover malformed or unusual process listings.
- Expand src/display/components/help_text.rs with additional keybinding documentation: currently minimal, could detail sorting options, filter modes, and pause/resume controls that are implemented but undocumented in-UI.
- Add Windows-specific integration tests for src/os/windows.rs netstat2 parsing: Linux has procfs tests but Windows path through sysinfo + netstat2 lacks concrete test coverage in src/tests/cases/.
⭐Top contributors
Click to expand
Top contributors
- @cyqsimon — 69 commits
- @dependabot[bot] — 18 commits
- @YJDoc2 — 4 commits
- @chiranjeevi-max — 2 commits
- [@Chiranjeevi U](https://github.com/Chiranjeevi U) — 2 commits
📝Recent commits
Click to expand
Recent commits
80628d2— chore(deps): bump actions/upload-artifact in the github-actions group (dependabot[bot])3870080— Set MSRV to dependency minimums (cyqsimon)cc137f5— Bump all dependencies (cyqsimon)cbcffe8— Merge pull request #491 from chiranjeevi-max/fix/input-sigint-handling (cyqsimon)3b03af8— docs: add comment explaining non-standard iterator semantics (chiranjeevi-max)5a870ff— fix: graceful shutdown on SIGINT (chiranjeevi-max)2227172— fix(test): skip SIGINT handler registration during tests (Chiranjeevi U)5909d45— fix(input): handle Ctrl+C via SIGINT signal instead of keypress (Chiranjeevi U)d71b7a9— Merge pull request #484 from imsnif/dependabot/github_actions/github-actions-44fbc26209 (cyqsimon)44b7e8a— chore(deps): bump the github-actions group across 1 directory with 3 updates (dependabot[bot])
🔒Security observations
The codebase demonstrates reasonable security practices for a network monitoring CLI tool. The main security considerations stem from the inherent requirements of the application: elevated privileges for packet capture and processing of untrusted network data. Critical areas include robust packet parsing validation, secure handling of privileged operations, and careful management of DNS resolution. The incomplete Cargo.toml build dependencies syntax requires immediate attention. No hardcoded secrets or obvious injection vulnerabilities were identified. Dependency versions are relatively recent and well-maintained, though privilege escalation code paths should be regularly audited given the elevated access requirements.
- Medium · Incomplete Cargo.toml Build Dependencies —
Cargo.toml - [build-dependencies] section. The build-dependencies section in Cargo.toml appears to have a syntax error with an unclosed bracket on the clap dependency. This could indicate incomplete configuration or potential for build issues. Fix: Complete the clap dependency declaration:clap = { version = "4.5.61" }with proper closing bracket and ensure all build dependencies are properly configured. - Medium · Privileged Access Requirements —
README.md - Post install (Linux) section, src/network/sniffer.rs. The application requires elevated privileges (setcap or sudo) on Linux systems to capture network packets. This is inherent to network sniffing but increases the attack surface if the binary is compromised. Fix: Implement principle of least privilege: document the specific capabilities needed (CAP_NET_ADMIN, CAP_NET_RAW), provide clear guidance on setcap usage, and consider capability dropping after initialization. Regularly audit privilege escalation code paths. - Medium · Network Data Processing from Untrusted Sources —
src/network/sniffer.rs, src/network/connection.rs, dependencies: pnet 0.35.0. The application processes raw network packets using pnet library. Malformed or malicious packets could potentially trigger buffer overflows or panics in packet parsing logic. Fix: Implement robust input validation for all packet parsing. Add fuzzing tests for packet processing. Keep pnet and related dependencies updated. Consider adding size bounds checking before processing network data. - Low · DNS Resolution from External Sources —
src/network/dns/resolver.rs, src/network/dns/client.rs, dependency: trust-dns-resolver 0.23.2. The application performs DNS lookups to resolve IP addresses to hostnames. This could be exploited for information disclosure or DNS poisoning attacks if not properly validated. Fix: Validate DNS responses against expected formats. Consider implementing DNS response validation and DNSSEC support. Implement timeouts to prevent hanging on unresponsive DNS servers. Add logging for suspicious DNS responses. - Low · Process Information Disclosure —
src/os/linux.rs, src/os/windows.rs, src/os/lsof.rs - process enumeration code. The application displays process information, connection details, and bandwidth usage. On multi-user systems, this could expose sensitive information about other users' network activity. Fix: Enforce strict permission checks to ensure only root/admin can run the tool or filter results to show only current user's processes. Document security implications of running with elevated privileges. Consider implementing access control lists. - Low · External Command Execution (lsof) —
src/os/lsof.rs, src/os/lsof_utils.rs. The application executes external commands like lsof to gather process and connection information. This could be a vector for privilege escalation or command injection if paths are not properly validated. Fix: Use absolute paths for external commands. Validate all command output before processing. Consider using native APIs instead of external commands where possible. Implement strict input validation for any user-controllable parameters passed to external commands. - Low · Dependency on Legacy Regex Processing —
src/os/lsof_utils.rs, dependency: regex 1.12.3. The codebase uses regex for parsing output from system commands. Regex DoS (ReDoS) attacks could potentially cause denial of service if malicious command output is processed. Fix: Review all regex patterns for potential ReDoS vulnerabilities. Use regex::bytes instead of string regex where possible. Implement timeouts for regex matching operations. Consider using simpler parsing methods for well-defined output formats.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.