Skip to content

evilbotnet/netsurvey

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

netsurvey

A single-binary home-lab network survey and inventory tool. It discovers every device on your LAN, keeps a curated inventory that scans never clobber, runs OS updates across your Linux boxes over SSH, and stores the occasional credential encrypted — all from one static Go binary with an embedded web UI.

Built for a mixed lab — a UniFi gateway, single-board computers, a NAS, a few servers, IoT gadgets, and assorted microcontrollers — where SSH-based and agentless discovery both matter.

Dashboard

Screenshots use a synthetic demo dataset, not a real network.

Why

Home labs rot: software goes out of date, services get stood up and forgotten, and nobody remembers what 192.168.1.139 actually is. netsurvey gives you one always-current picture plus the levers to act on it.

What it does

  • Agentless discovery, multiple sources merged into one registry:
    • Ping sweep (unprivileged ICMP, TCP fallback) — also primes the ARP cache so it finds devices that drop pings.
    • ARP/neighbor table read — catches everything the sweep touched.
    • mDNS / DNS-SD — names and service types (printers, speakers, the _ssh._tcp boxes) even when port scanning is blocked.
    • nmap (optional, auto-detected) — port/service detection on full scans.
    • UniFi Dream Router API — the authoritative client list, including devices that are asleep during the scan (via the all-known-clients API).
    • SSH enrichment — OS, kernel, uptime, package counts, pending updates, listening ports, docker containers, for any host you enroll.
  • Inventory with a clean web UI: filterable device table, per-device detail, a staleness/updates dashboard, and curated fields (name, location, owner, tags, presence mode) that re-scans never overwrite.
  • SSH key bootstrap + update runner: push a managed key to a host, then run apt/dnf updates with dry-run, concurrency limits, and live per-host logs in the browser.
  • Minimal encrypted secret store (age): stash the odd web-UI password or API key, unlocked per-session with a passphrase, never written in clear.
  • Remote command execution: presets + a free-form box per host, gated by login + CSRF + an unlocked secret store, with every run logged.

Screenshots

Device inventory — every device merged from all sources, with curated names, type pills, and last-seen status:

Devices

Device detail — discovered identity, nmap-detected services with versions, mDNS advertisements, the remote-command panel, the curated metadata form, and per-device encrypted secrets:

Device detail

Update runner — dry-run or apply OS updates across SSH-enrolled hosts
Updates
Scan history — every scan, per-source counts, duration
Scans
Settings — UniFi API key setup with in-app instructions
Settings
Dashboard — counts, new/stale devices, pending updates
Dashboard

Install

Requires nothing at runtime (pure-Go static binary). To build:

brew install go          # or your platform's Go ≥ 1.26
make build               # produces ./netsurvey
make cross               # static binaries for every lab arch in ./dist

nmap is optional but recommended for port/service detection: brew install nmap (macOS) or apt install nmap (Debian/Pi).

Quick start

./netsurvey scan                 # discover the LAN, print a table
./netsurvey serve                # web UI at http://127.0.0.1:8472

On first visit the web UI asks you to set a password (argon2id). Trigger a scan from the dashboard, then start naming and tagging devices.

Enroll a host for SSH facts + updates

./netsurvey bootstrap pi@192.168.1.50 --install-sudoers
./netsurvey scan                 # now collects OS/package facts for it
./netsurvey update --hosts pi5 --dry-run    # preview pending updates
./netsurvey update --hosts pi5 --apply      # apply them

Bootstrap generates a managed homelab-ops ed25519 key on first run, asks for the host password once (never stored), installs the key, verifies it, and optionally installs a tightly-scoped sudoers.d rule for the update commands. Host keys are trusted on first use (known_hosts in the data dir).

Run commands on a host

Once a host is bootstrapped, its detail page gains a Remote command panel: one-click presets (uptime, df -h, docker ps, failed units, journal tail, …) plus a free-form command box. Output appears inline and every run is logged. The CLI equivalent:

./netsurvey exec pi5 'docker logs --tail 50 pihole'
./netsurvey exec 192.168.1.50 'systemctl restart node_exporter'

Because this is effectively remote code execution into your hosts, the web panel is guarded by three factors: a logged-in session, a CSRF token, and an unlocked secret store this session (a deliberate second factor — a stolen/idle session alone can't run commands). Each command runs under a per-host timeout and is recorded with its output.

Connect the UniFi Dream Router

In the web UI under Settings → UniFi, follow the in-app steps to create a local API key on the UDR, paste it in, and Test & save. netsurvey then pulls the live client list plus the long-memory all-known-clients list — which backfills devices that are powered off or asleep during a scan, and is the authoritative source if your network restricts client-to-client traffic.

Store a secret

On a device's detail page, unlock the secret store with a passphrase (the first one initializes it), then add label/value pairs. Values are age scrypt-encrypted; the unlocked key lives in memory only and clears after 15 minutes idle. CLI equivalent: netsurvey secret set --device pi5 web-ui.

Commands

netsurvey scan      [--full] [--no-nmap] [--subnet CIDR] [--json]
netsurvey list      [--filter TEXT] [--all] [--json]
netsurvey serve     [--listen ADDR] [--scan-interval DUR] [--subnet CIDR]
netsurvey bootstrap <user@host> [--install-sudoers] [--forget]
netsurvey update    --hosts a,b | --all-managed [--dry-run|--apply] [--parallel N]
netsurvey exec      <device|ip> <command...>
netsurvey secret    set|get|ls|rm [--device NAME] [--user U] <label>
netsurvey version

--data-dir DIR (or $NETSURVEY_DATA_DIR) overrides the data directory (default ~/.local/share/netsurvey), which holds the SQLite database, the managed SSH key, and known_hosts.

Identity & curation model

Devices are keyed on MAC. An observation with only an IP resolves through recent IP history, or becomes a provisional device that's absorbed once a MAC is learned for that IP. Randomized (phone) MACs are quarantined into an "ephemeral" bucket so they don't pollute the inventory. Intermittent devices (ESP32s, etc.) can be marked intermittent so they stop triggering staleness alerts.

Scans only ever write disc_* fields; your edits live in separate curated columns and win on display. Re-scanning a device you've named never loses the name.

Security

  • Binds 127.0.0.1 by default. Binding to a LAN address (--listen 0.0.0.0:8472) is refused until a UI password is set.
  • Single-user password (argon2id), in-memory sessions, SameSite=Strict cookies, CSRF tokens on mutating requests.
  • SSH host keys are trust-on-first-use; a changed key hard-fails with a bootstrap --forget hint.
  • The sudoers rule bootstrap installs is scoped to the exact apt/dnf update commands, nothing else.
  • Secrets are age-encrypted; plaintext is never written to disk.

The Windows desktop and UniFi gear are inventoried but out of scope for the SSH update runner — they show as "unmanaged".

Data & secrets — what stays on your machine

netsurvey keeps all of your network data and credentials in its data directory (default ~/.local/share/netsurvey/), which is outside this repository. Nothing sensitive lives in the source tree, and the .gitignore is written so that even an accidental in-repo data dir (e.g. --data-dir .) won't be committed.

What's sensitive, and never belongs in version control:

Artifact Holds
netsurvey.db MACs, IPs, hostnames, device names/notes, UI password hash, the UniFi API key (settings table), and the age-encrypted secrets blob
homelab_ops_ed25519 the managed SSH private key — it can log into every host you've bootstrapped
known_hosts SSH host fingerprints for your hosts
config.toml optional headless config; may contain the UniFi API key (kept 0600)

The repo ships config.toml.example (no real values) to document the format. The embedded internal/oui/data/oui.txt.gz is the only data file that is committed — it's the public Wireshark vendor database the build needs, not anything about your network.

Before pushing, a quick sanity check:

git status --ignored      # confirm db/keys/config show as ignored, not staged
git ls-files | grep -Ei '\.(db|age|pem|key)$|ed25519|known_hosts|config\.toml$'   # should print nothing

Running as a service

See deploy/netsurvey.service (systemd, e.g. on the NUC or a ZimaBoard) and deploy/com.netsurvey.plist (macOS launchd).

Development

make test     # unit tests (parsers, merge logic, crypto, package managers)
make vet

Live-network behavior (real ping/mDNS/SSH/UniFi) isn't unit-tested; the parsers and merge/identity logic are, with fixtures.

About

Single-binary home-lab network survey & inventory tool — agentless discovery (ARP/mDNS/nmap/UniFi/SSH), curated inventory, remote updates & command exec, encrypted secrets.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors