netwp

module
v1.20.0 Latest Latest
Warning

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

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

README

netwp

🇺🇸 English · 🇧🇷 Português

CI CodeQL Dependabot Go version Release Wiki Buy Me a Coffee

netwp: Internet / Rede Well Played ("rede" is Portuguese for network).

A terminal network manager written in Go: active local-network device discovery (ARP), live monitoring, a full dashboard, bandwidth testing, and interface inspection. Windows-first, portable to Linux.

New to networking? Start with the beginner's guide (pt-BR) instead: it explains every term and table column in plain language. The wiki has a full command reference, FAQ, and troubleshooting.

Table of Contents

Features

Discovery & monitoring. Active ARP scan with hostname (reverse DNS, then mDNS/NetBIOS fallback), vendor by OUI, device-class guess, per-device RTT and TTL (with an OS-family hint) and open-port detail (sensitive ones like SSH/SMB/RDP flagged), all continuously tracked in a live TUI with new-device alerts.

Dashboard. Wi-Fi, real-time bandwidth, speedtest and devices in one live view, with Wi-Fi channel recommendations from nearby AP congestion.

Interface & network config. Read-only IP inspection everywhere; static/DHCP configuration on Windows. Linux support via raw ARP (AF_PACKET).

Persistence & tooling. Device aliases that survive DHCP IP changes, JSON export (netwp scan --json), and self-update (netwp update / netwp version).

Install

No Go toolchain? Grab a prebuilt binary from the Releases page instead (Windows and Linux amd64).

Requires Go 1.24+ for the options below.

Quick install (no clone needed)

go install fetches the module, builds it, and drops the binary in $(go env GOPATH)\bin. Put that folder on your PATH and call it as netwp from any terminal (Windows resolves the .exe automatically):

go install github.com/gsjonio/netwp/cmd/netwp@latest
netwp

Pin a specific release instead of @latest if you want reproducible builds, e.g. go install github.com/gsjonio/netwp/cmd/netwp@v0.1.0.

Build from source

Clone the repo if you want to read or change the code, cross-compile, or run the test suite:

git clone https://github.com/gsjonio/netwp.git
cd netwp
go build -o netwp.exe ./cmd/netwp
go test ./...

For a smaller binary, strip the symbol table and DWARF info (about 12 MB down to 8.8 MB):

go build -ldflags "-s -w" -o netwp.exe ./cmd/netwp

go install -ldflags "-s -w" ./cmd/netwp (run from inside the cloned repo) does the same, straight into $(go env GOPATH)\bin.

Privileges by command
Command Windows Linux
scan · monitor · dashboard no privilege needed needs CAP_NET_RAW
ports · speedtest · alias · version · update no privilege needed no privilege needed
iface (inspect only) no privilege needed no privilege needed
iface static / iface dhcp needs an elevated terminal not implemented

Windows uses the SendARP/IcmpSendEcho APIs for scan, so the read-only commands never need admin. On Linux, grant the raw-ARP scanner capability once instead of running as root every time:

sudo setcap cap_net_raw+ep $(which netwp)
Updating

Check what you have with netwp version. If you have the Go toolchain (whichever way you installed netwp), the easiest path is:

netwp update

It's a thin wrapper around go install github.com/gsjonio/netwp/cmd/netwp@latest: the same command as below, without retyping the module path. Overwriting the running binary works even on Windows.

Otherwise, update the same way you installed:

  • Quick install: re-run go install github.com/gsjonio/netwp/cmd/netwp@latest (or the specific tag you want). It overwrites the old binary.
  • Build from source: git pull then rebuild (go build/go install).
  • Prebuilt binary: download the new one from the Releases page and replace the old file. There's no self-update mechanism for this path.

Architecture

netwp is hexagonal (Ports & Adapters). internal/core is the pure domain: the use cases (device discovery, classification, scan diffing, the connectivity doctor) and the small port interface each one depends on. It never imports net, os/exec, or syscall, only plain data types, so the whole domain runs against fakes in tests without touching a real network card.

Adapters in internal/adapter/* implement those ports against the real system. The platform-specific ones (ARP scan, ICMP ping, interface config, Wi-Fi info) are chosen at build time by Go build tags, never at runtime: on Windows the ARP scan is SendARP and ping is IcmpSendEcho; on Linux the scanner is a raw AF_PACKET socket. The core cannot tell which one it is talking to.

cmd/netwp is the composition root: it wires concrete adapters into the core use cases and dispatches the CLI. internal/tui renders core types to the terminal (the scan table, the live monitor, and the dashboard).

A scan flows one way: cmd builds a core.Discovery from the adapters and calls Run; the use case enriches each host (hostname, vendor, open ports, RTT, mDNS services) concurrently, classifies it, and hands the result to internal/tui.

Project Structure

The layout follows the standard Go cmd + internal split:

cmd/netwp         composition root: CLI dispatch + adapter wiring
internal/core     pure domain: use cases + port interfaces (no OS/net imports)
internal/adapter  adapters that touch the OS/network (arpscan, icmpping,
                  netinfo, oui, tcpprobe, namelookup, wifi, ...)
internal/tui      terminal rendering: scan table, monitor, dashboard

Usage

Command What it does
(none) / help / -h / --help Print usage
scan / scan --json / scan --diff / scan --ports=<list> / scan --class=<class> One-shot scan, with per-device RTT; --json for machine-readable output, --diff to print only what changed since the last scan, --ports=22,80,443 to probe a custom TCP port set, --class=media to show only devices of one class (router/computer/mobile/media/printer/iot)
monitor / monitor --alert-down=<rate> / monitor --quiet Live TUI: devices joining/leaving in real time (q to quit); --alert-down flags a download rate drop, e.g. --alert-down=50Mbps; --quiet runs headless (no UI), one line per event to stdout for a service or logfile
dashboard Full dashboard: Wi-Fi + live bandwidth + speedtest + devices + an operations log
speedtest / speedtest --json Download/upload throughput; --json for machine-readable output
iface Inspect the active interface's IP config
iface static <ip>/<bits> <gw> [dns...] Set a static address (asks to confirm)
iface dhcp Switch back to DHCP (asks to confirm)
alias set <ip|mac> <name> / ls / rm <ip|mac> Nickname a device / list / remove
class set <ip|mac> <class> / ls / rm <ip|mac> Pin a device's class when the guess is wrong (router/computer/mobile/media/printer/iot)
watch add <ip|mac> / ls / rm <ip|mac> Alert (highlight + bell) when a device leaves during monitor/dashboard
ports <ip> / ports <ip> --json Open ports + RTT + TTL for one device; --json for machine-readable output
wake <ip|mac|alias> Send a Wake-on-LAN magic packet to power on a device
doctor / doctor --json Diagnose connectivity: interface, gateway, internet, DNS, Wi-Fi; --json for machine-readable output
events [n] / events --device=<x> Print the last n join/leave events (default 20); --device=<alias-or-mac> filters to one device
version Installed version
update Update to the latest version (needs Go)
uninstall Remove netwp's local data (asks to confirm); prints how to remove the binary
netwp scan --json | ConvertFrom-Json | Where-Object reachable
netwp alias set 192.168.1.20 "Living Room TV"

The CLI is built on cobra: every command has its own --help (e.g. netwp scan --help), and netwp completion <bash|zsh|fish|powershell> generates a shell-completion script.

Notes

See SECURITY.md for scanning safety and reporting a vulnerability.

Data & storage
  • Vendor names come from the full IEEE MA-L registry, gzipped and embedded in the binary (internal/adapter/oui/data). Refresh it with the command in oui.go.
  • Device aliases live in <user-config-dir>/netwp/aliases.json, keyed by MAC so a nickname survives a DHCP-assigned IP change. Plain text, safe to edit by hand.
  • alias set <ip> resolves the MAC from the last scan's cache (lastscan.json), so aliasing right after a scan is instant. Pass a MAC instead of an IP to skip the network entirely.
Platform support
  • Windows is the primary, most-verified platform: ARP scan via SendARP, ICMP via IcmpSendEcho, neither needing admin rights. iface static/iface dhcp do need an elevated terminal and always ask for a typed "yes"; verified end-to-end on real hardware.
  • Linux support works but is less battle-tested: the raw-ARP scanner (AF_PACKET) needs CAP_NET_RAW and has been run for real on a Linux kernel (WSL2), but only against WSL2's default NAT network, not a full physical LAN. iface static/dhcp isn't implemented on Linux. CI builds and tests natively on Ubuntu every push.
  • The dashboard's Wi-Fi panel supports English and Portuguese netsh wlan output; only the Portuguese labels are verified against live output.
How some things work

New to terms like MAC, TTL, or "unknown device"? The beginner's guide (pt-BR) explains what everything on screen means. The notes below are implementation trivia for people who already know networking.

Discovery & classification
  • Hostname resolution falls back to mDNS/NetBIOS when reverse DNS has nothing; some devices still won't show a name. Mechanics are in CONTRIBUTING.md.
  • RTT and TTL come from the same ICMP echo per device, so a firewalled device (answers ARP but not ICMP) shows online with neither.
  • A machine with more than one active interface (e.g. Ethernet and Wi-Fi at once) is recognized as "This device" on all of them.
  • The CLASS guess combines advertised mDNS services (a Chromecast, printer, or iPhone announces what it is), then ~29 probed ports, then vendor. When it's still wrong (a phone with a random MAC and no open ports), pin it with netwp class set <ip|mac> <class>; a manual pin always wins.
Monitor & dashboard
  • Press / to filter the device table by a substring of any field (IP, alias, hostname, vendor, MAC, class); Enter keeps the filter, Esc clears it. The online/known counts still reflect the whole network.
  • Press s to cycle the sort column (IP, RTT, name, class); online devices always sort ahead of offline ones, so s orders within each group. The active column shows in the footer.
  • Two events ring the terminal bell and highlight their log line: an unrecognized device joining (no alias set), and a netwp watch-listed device leaving. Everything else stays quiet.
  • The DEVICES panel shows a per-class breakdown of what's online (e.g. "2 Media · 1 Router"), skipping "This device" and unclassified hosts.
  • The LOG panel (bottom) traces the dashboard's own work: scans starting and finishing, speedtests, and internet/Wi-Fi state changes. On a short terminal it shrinks, then hides, so the device table and footer keep priority. (Distinct from the ACTIVITY panel, which lists device joins/leaves.)
  • The Wi-Fi channel suggestion is a simple congestion count over visible APs, not an RF planner.
  • netwp monitor --alert-down=<rate> (e.g. 50Mbps) highlights the bandwidth line when download drops below that threshold. Omit it and monitor behaves exactly as before.
  • monitor/dashboard (and monitor --quiet) log every join/leave to <user-config-dir>/netwp/events.jsonl; netwp events [n] reads them back. The file is bounded: once it passes ~1 MB it is trimmed to the most recent 5000 events, so a long-running monitor can't grow it without limit.
Commands
  • netwp scan --diff compares against the previous scan (identity by MAC) and prints only what changed, including possible IP/MAC conflicts.
  • netwp ports <ip> re-probes one device directly instead of a full scan, with no port history across runs.
  • netwp wake only powers on a device that was left with Wake-on-LAN enabled (a BIOS/OS setting). It broadcasts and gets no reply, so it reports "sent", not "woke". An alias or a cached IP resolves even while the target is off.
  • netwp doctor checks top-down (interface → gateway → internet → DNS); the topmost ✗ is usually the root cause and explains the ones below it.
  • The speed test hits Cloudflare's anycast speed.cloudflare.com; netwp speedtest prints which edge answered.

Want to contribute? See CONTRIBUTING.md. This project follows the Code of Conduct.

Support

netwp is free and open source. If it saves you time, you can support its development with a coffee. Thank you! ☕

Buy Me a Coffee

License

MIT.

Directories

Path Synopsis
cmd
netwp command
Command netwp is a terminal network manager.
Command netwp is a terminal network manager.
internal
adapter/aliasstore
Package aliasstore persists user-defined device nicknames, keyed by MAC so a label survives DHCP address changes.
Package aliasstore persists user-defined device nicknames, keyed by MAC so a label survives DHCP address changes.
adapter/arpscan
Linux implementation: raw ARP requests over an AF_PACKET socket, since Linux has no admin-free ARP API like Windows' SendARP.
Linux implementation: raw ARP requests over an AF_PACKET socket, since Linux has no admin-free ARP API like Windows' SendARP.
adapter/classstore
Package classstore persists user-pinned device classes, keyed by MAC so a manual override ("this is my phone") survives DHCP changes and outlives the automatic guess.
Package classstore persists user-pinned device classes, keyed by MAC so a manual override ("this is my phone") survives DHCP changes and outlives the automatic guess.
adapter/eventlog
Package eventlog appends device presence-change events (join/leave) to a JSONL file, and reads back the most recent ones for `netwp events`.
Package eventlog appends device presence-change events (join/leave) to a JSONL file, and reads back the most recent ones for `netwp events`.
adapter/httpspeed
Package httpspeed implements core.SpeedTester against Cloudflare's public speed-test endpoint.
Package httpspeed implements core.SpeedTester against Cloudflare's public speed-test endpoint.
adapter/macstore
Package macstore is a MAC-keyed JSON map: the file-backed persistence shared by the alias, class-override, and watch stores.
Package macstore is a MAC-keyed JSON map: the file-backed persistence shared by the alias, class-override, and watch stores.
adapter/namelookup
Package namelookup resolves a device's hostname when reverse DNS comes up empty: most residential devices (phones, TVs, IoT) never register a PTR record but do answer multicast DNS or NetBIOS name queries.
Package namelookup resolves a device's hostname when reverse DNS comes up empty: most residential devices (phones, TVs, IoT) never register a PTR record but do answer multicast DNS or NetBIOS name queries.
adapter/netinfo
Package netinfo reads local network interface information.
Package netinfo reads local network interface information.
adapter/oui
Package oui resolves a MAC address to its manufacturer using the IEEE OUI registry embedded at build time.
Package oui resolves a MAC address to its manufacturer using the IEEE OUI registry embedded at build time.
adapter/scancache
Package scancache remembers the last scan's IP-to-MAC map so that aliasing a device by IP can skip a fresh ARP sweep.
Package scancache remembers the last scan's IP-to-MAC map so that aliasing a device by IP can skip a fresh ARP sweep.
adapter/tcpprobe
Package tcpprobe implements core.Prober with a light TCP connect scan of a few well-known ports.
Package tcpprobe implements core.Prober with a light TCP connect scan of a few well-known ports.
adapter/watchstore
Package watchstore persists the set of "watched" device MACs: devices the user wants to be alerted about when they leave.
Package watchstore persists the set of "watched" device MACs: devices the user wants to be alerted about when they leave.
adapter/wifi
Package wifi reports the active wireless connection and nearby access points.
Package wifi reports the active wireless connection and nearby access points.
adapter/wol
Package wol implements core.Waker: it powers on a sleeping device by broadcasting a Wake-on-LAN magic packet.
Package wol implements core.Waker: it powers on a sleeping device by broadcasting a Wake-on-LAN magic packet.
tui
Package tui renders discovery results as a legible terminal table.
Package tui renders discovery results as a legible terminal table.

Jump to

Keyboard shortcuts

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