# Whosthere: unprivileged LAN discovery in a Go TUI

> Whosthere maps the devices on your local network by combining mDNS, SSDP and ARP cache reads, all without root. It is a terminal-first tool for engineers who want a quick answer to what is on the wire.

**ramonvermeulen/whosthere** — Local Area Network discovery tool with an interactive Terminal User Interface (TUI) written in Go.  Discover, explore, and understand your LAN in an intuitive way. Knock Knock.. who's there? 🚪

- Repository: https://github.com/ramonvermeulen/whosthere
- Stars: 2,457 · Forks: 76
- Language: Go
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/ramonvermeulen-whosthere

## The question Whosthere answers, and who is asking it

The README frames the project around a single prompt: "Who's there on my network?" That is a narrower job than network monitoring or asset management. Whosthere is for the person who has just plugged a machine into a switch, joined a guest VLAN, or inherited a rack of unknown hardware and wants a list of live devices now, from a shell, without escalating to root. The README lists its audience implicitly through the feature set: an interactive TUI, a one-shot CLI scan, and a daemon with an HTTP API for people who want to feed results into something else. Network engineers, homelab operators and developers debugging a misbehaving LAN are the natural users. It is not a replacement for a vulnerability scanner, and it is not trying to be one.

## How the discovery pipeline works without elevated privileges

Three mechanisms run concurrently. The mDNS scanner uses the hashicorp/mdns dependency visible in go.mod, and the SSDP scanner uses golang.org/x/net, so both are ordinary user-space multicast listeners. The third mechanism is the interesting one: the sweeper attempts TCP and UDP connections across the local subnet purely to trigger ARP resolution, then reads the ARP cache to enumerate the devices that responded. That is why the README can claim no elevated privileges are required. The sweeper is a side effect generator, not a probe that needs a raw socket. Discovered entries are then enriched with OUI lookups so a MAC prefix resolves to a manufacturer name. The configuration file exposes each stage separately, so scanners.mdns.enabled, scanners.ssdp.enabled and scanners.arp.enabled can be toggled independently, and sweeper.interval defaults to 5m while scan_interval defaults to 20s. Port scanning is a separate, opt-in step triggered from the device details view, with its own port_scanner.timeout and a tcp list that ships with 28 common ports. The README is explicit that this should only be run against devices you have permission to scan.

## Installing Whosthere and running a first scan

The README offers four package-manager routes and a Go route. Homebrew, Nix and Arch are covered, and for anything else the Go toolchain works. The build from source path uses the Makefile in the repository root, which sets version, commit and build date through ldflags and builds with CGO disabled.

```bash
go install github.com/ramonvermeulen/whosthere@latest
```

After that, running the binary with no arguments opens the TUI. The README's usage section shows the bare command for interactive discovery. Inside the TUI, `/` starts a regex search, `j` and `k` move the selection, `enter` opens device details, and `y` and `Y` copy the selected IP and MAC. `CTRL+i` toggles the interface selector if you have more than one NIC.

For a scripted, non-interactive result, the CLI subcommand takes a timeout in seconds and can emit JSON:

```bash
whosthere scan -t 5 --json --pretty > devices.json
```

The README gives this exact pipeline. The `-t 5` sets a five second scan window, and the redirect writes a JSON document you can inspect or diff. If you need the tool running continuously, the daemon subcommand binds an HTTP API:

```bash
whosthere daemon --port=8080
```

Configuration precedence runs from command line flags down through environment variables prefixed with WHOSTHERE__, then a YAML file, then defaults. The config file is looked up first at the path given by --config or WHOSTHERE_CONFIG, then at $XDG_CONFIG_HOME/whosthere/config.yaml, then at ~/.config/whosthere/config.yaml. A minimal override looks like this:

```yaml
network_interface: eth0
scan_interval: 20s
scan_timeout: 10s
scanners:
  mdns:
    enabled: true
  ssdp:
    enabled: true
  arp:
    enabled: true
```

## Where Whosthere breaks down or is the wrong tool

The unprivileged ARP technique has a structural blind spot. A device that ignores the TCP or UDP connection attempts, or a host that is powered off during the sweep window, will not appear in the ARP cache and therefore will not be reported. The README does not document a fallback for silent hosts. The all_interfaces option carries a warning the README states plainly: when two interfaces share the same subnet, devices may be merged because they are identified by IP address. On a machine with a wired and wireless connection to the same /24, that means a single entry rather than two. The target_subnets option has a related quirk: when it is set, the sweeper skips the auto-detected interface subnet unless that subnet is listed explicitly, so a partial target list can silently exclude the network you are actually on. And scan_large_subnets is off by default with a warning that enabling it sends packets to more than 65535 IPs per subnet. Whosthere is the wrong tool for passive monitoring of a network you cannot touch, and it is the wrong tool if you need historical records of what was present last week: the README describes a discovery tool, not a time-series store.

## How it compares to nmap and arp-scan

nmap is the obvious alternative and the difference is in the approach rather than the feature list. nmap sends crafted probe packets and interprets the replies, which is why it needs elevated privileges for most scan types and why it can fingerprint operating systems and services. Whosthere never crafts a packet. It generates ordinary connection attempts and reads a kernel-maintained table. That constraint is the whole design: it buys you a tool that runs as a normal user and produces a browsable list, and it costs you the ability to detect hosts that do not answer. arp-scan is closer in spirit, since it also reads ARP, but it sends ARP requests directly and therefore needs raw socket access. Whosthere's daemon mode with an HTTP API is a differentiator against both: neither nmap nor arp-scan ships a long-running service with a JSON-friendly interface in the same binary as the interactive view.

## Maintenance, licensing and upgrade cost

The repository is not archived, and the last push was on 2026-09-28. The most recent release listed is v0.8.3 from 2026-07-23, with v0.8.2 and v0.8.1 earlier in 2026, so the release cadence over the past few months has been steady. The project is licensed under Apache-2.0, which permits commercial use and modification provided the licence and notices are preserved; the LICENSE file is at the repository root. Nothing in the README or the repository layout suggests a contributor licence agreement or a dual-licensing arrangement. Upgrade cost looks low for most users: configuration is a YAML file with documented defaults, and the README points to DefaultConfig() in internal/core/config/config.go as the fallback source of truth, so a config written against an older release can be checked against that function after an upgrade. The Go version in go.mod is 1.26.0, which sets a floor for anyone building from source. The Makefile's dev-deps target installs mdformat, markdownfmt, goreleaser and golangci-lint via pipx and brew, so contributors on non-macOS systems need to adapt that step; the Makefile carries a TODO noting that cross-platform dependency support is not there yet.

## Conclusion

Adopt Whosthere if you want a fast, unprivileged view of a home or lab LAN from a terminal, and you are comfortable reading a TUI. Do not adopt it as an authoritative asset inventory or as a scanner for networks you do not own: the README itself warns that the port scanner should only be pointed at devices you have permission to scan. Before relying on it, verify that the auto-detected interface is the one you expect, because the sweeper skips the detected subnet when target_subnets is set.

## FAQ

### Does Whosthere need root or administrator privileges to scan the LAN?

No. The README states that it performs unprivileged, concurrent scans: mDNS and SSDP are ordinary user-space listeners, and the sweeper triggers ARP resolution through TCP and UDP connection attempts before reading the ARP cache, so no elevated privileges are required.

### How do I install Whosthere on Linux?

The README lists Homebrew, Nix and Arch routes, and the Go toolchain as a fallback. The Arch command is yay -S whosthere-bin, the Nix command is nix profile install nixpkgs#whosthere, and go install github.com/ramonvermeulen/whosthere@latest works anywhere Go is available.

### Can Whosthere run as a background service with an API?

Yes. The daemon subcommand starts it in the background with an HTTP API, and the README gives whosthere daemon --port=8080 as the example invocation.

## Sources

- [Issues](https://github.com/ramonvermeulen/whosthere/issues)
- [License: Apache-2.0](https://github.com/ramonvermeulen/whosthere/blob/main/LICENSE)
- [ramonvermeulen/whosthere on GitHub](https://github.com/ramonvermeulen/whosthere)
- [README](https://github.com/ramonvermeulen/whosthere/blob/main/README.md)
- [Releases](https://github.com/ramonvermeulen/whosthere/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ramonvermeulen-whosthere
