[HN Gopher] Show HN: Whosthere: A LAN discovery tool with a mode...
___________________________________________________________________
Show HN: Whosthere: A LAN discovery tool with a modern TUI, written
in Go
Author : rvermeulen98
Score : 185 points
Date : 2026-01-23 11:54 UTC (11 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| rvermeulen98 wrote:
| I've been working on a LAN discovery tool with a Terminal User
| Interface (TUI) written entirely in Go. It's called Whosthere,
| and it's designed to help you explore devices on your local
| network without requiring elevated privileges.
|
| It works by combining several discovery methods:
|
| - mDNS and SSDP scanning
|
| - ARP cache reading (after triggering ARP resolution via TCP/UDP
| sweeps)
|
| - OUI lookups to identify device manufacturers
|
| It also includes:
|
| - A fast, keyboard-driven TUI (powered by tview)
|
| - An optional built-in port scanner
|
| - Daemon mode with a simple HTTP API to fetch devices
|
| - Configurable theming and behavior via a YAML config file
|
| Why I built it:
|
| Mainly to learn, I've been programming in Go for about a year now
| and wanted to combine learning Go with learning more about
| networking in one single project. I've always been a big fan of
| TUI applications like lazygit, k9s, and dive. And then the idea
| came to build a TUI application that shows devices on your LAN. I
| am by no means a networking expert, but it was fun to figure out
| how ARP works, and discovery protocols such as mDNS and SSDP.
|
| Example usage:
|
| ---
|
| # install via HomeBrew brew tap ramonvermeulen/whosthere brew
| install whosthere
|
| # or with go install go install
| github.com/ramonvermeulen/whosthere@latest
|
| # run as TUI whosthere
|
| # run as daemon whosthere daemon --port 8080
|
| ---
|
| I'd love to hear your feedback, if you have ideas for additional
| features or improvements that is highly appreciated! Current
| platform support is Linux and MacOS.
| nickcw wrote:
| Very nice tool :-)
|
| It would be great it it could show the reverse lookup of the
| IPs as on my LAN everything has a name and if it hasn't then it
| is probably an interloper!
| genericacct wrote:
| Installed on raspbian, works wonders, much better than the
| thing i vibecoded yesterday. One feature I'd like: recording
| new arrivals to a log with all the info so it can be used as a
| barebones IDS
| N3802E wrote:
| This looks great! I've been searching for something like this
| for ever.
|
| Some feedback of what I found on my network, as compared to
| some other scanners I've used.
|
| I've never seen anything that can beat Advanced IP Scanner at
| finding hostnames. I've never even found a way to get arp or
| nmap to get close to Advanced IP Scanner; I've tried dozens of
| suggested commands of each, all with no luck. Here's the
| results of my scans:
|
| Alive hosts: 309
|
| Unkown: 201
|
| With hostnames: 80
|
| https://www.advanced-ip-scanner.com/
|
| ####################################
|
| I also tried a program called Angry IP Scanner:
|
| Hosts scanned: 510
|
| Hosts alive: 315
|
| With hostnames: 75
|
| https://angryip.org/
|
| ####################################
|
| whosthere
|
| Devices: 318
|
| With hostnames: 54
| alphax314 wrote:
| Looks great!! I had the same idea a few days ago and am so glad
| you posted this now! I will be using it and will let you know
| of any feedback. So far works great on my network!
| M95D wrote:
| Why the X11 dependency if it's a TUI? I was expecting ncurses.
| bestham wrote:
| It says in the read me that X11 is required for clipboard
| functionality.
| Anonbrit wrote:
| It says 'Open ports: (None)' for all devices on my network,
| despite there being open ports on many of them (MacOS Tahoe 26.2
| / installed via go)
| rvermeulen98 wrote:
| It doesn't start port scanning by default, maybe this is a
| feature I can build in the future. When you are on the `detail`
| view of a device, you can press `p` and that will open a pop-up
| to perform the port scan. Also the list of ports that will be
| scanned is a default list of common ports, and can be
| configured via the configuration yaml.
| 47282847 wrote:
| In that case maybe print something different for unscanned
| hosts than ,,Open ports: None"?
|
| Nice tool!
| coolius wrote:
| this is great! i had to tweak the config file on macos because it
| was using some weird interface (utun4) instead of en0. otherwise
| awesome tool, i am definitely going to be using this more often.
| rvermeulen98 wrote:
| Thanks, I am glad you like it! I couldn't find a Go API that
| just returns the OS "default" network interface, so struggled a
| bit with a correct implementation for that part.
|
| When reading some blog posts, I found often a solution where it
| sends out an UDP dial to for example 8.8.8.8:53 because you can
| then get the network interface back from the connection it's
| local address. As fallback I implemented to pick the first non-
| loopback interface that is up.
|
| Would be open to suggestions to do this in a better way!
| fellerts wrote:
| I think this package does exactly what you need:
| https://pkg.go.dev/github.com/google/gopacket/routing. Works
| on my machine (error handling left to the reader)
| router, _ := routing.New() iface, _, _, _ :=
| router.Route(net.ParseIP("8.8.8.8"))
| fmt.Println(iface.Name)
|
| this prints my Ethernet interface as expected. It doesn't
| make any requests, it just figures out where to route a
| packet. I guess it interfaces with the OS routing table.
| rvermeulen98 wrote:
| Thanks for sharing! This is definitely something I will
| look into, I am all in favor to simplify the current
| implementation of finding the "default" OS network
| interface.
| contingencies wrote:
| You'd better use the default route and not some random
| IP, particularly DNS IPs which people often meddle with.
| # IPv4 default route only uname Darwin$ route
| -n get 0.0.0.0 | grep interface | cut -d ':' -f2
| Linux$ route -nv |grep ^0.0.0.0 | awk '{print $NF}'
| petcat wrote:
| I love the resurgence of TUI apps, but I wonder what the
| definition of "modern TUI" means in these cases. Does it
| basically mean just not using curses?
| Daviey wrote:
| It means it has a dependency on X11. $ go
| install github.com/ramonvermeulen/whosthere@latest #
| golang.design/x/clipboard clipboard_linux.c:14:10: fatal
| error: X11/Xlib.h: No such file or directory 14 |
| #include <X11/Xlib.h> | ^~~~~~~~~~~~
| compilation terminated.
| fellerts wrote:
| That has nothing to do with the UI framework. The X11
| dependency comes as part of the clipboard integration (which
| I'd argue should be optional or even removed). Still, I
| wouldn't call it modern if Wayland is outright not supported.
| rvermeulen98 wrote:
| I think this is only a problem when building from source,
| right? It is indeed because of the dependency on
| https://github.com/golang-design/clipboard.
|
| I hesitated a bit bringing in this feature. On one hand, I
| really like to have clipboard support, on the other hand, I
| don't like that it requires you to change from static to
| dynamic linking (and have the x11 dependency).
|
| Maybe I could write an install.sh script for installation
| that detects the OS and fetches the correct version/tarball
| from the Github release.
| Daviey wrote:
| That library isn't going to support Wayland any time
| soon, and requiring CGO isn't ideal IMO. See this bug,
| https://github.com/golang-design/clipboard/issues/6
|
| How about this PR?
| https://github.com/ramonvermeulen/whosthere/pull/29
|
| It switches to using github.com/dece2183/go-clipboard,
| which supports Mac, Windows, Linux (X11 + Wayland) and
| Android.
| rvermeulen98 wrote:
| Thanks a lot for your contribution, this is something I
| will look into in the upcoming days. I totally agree that
| CGO isn't ideal, I had to make the build/release process
| also a lot more complicated purely for that clipboard
| requirement (see GHAs and the different goreleaser
| files).
|
| On the other hand, I also don't want whosthere to be
| depended on a fork that isn't maintained anymore. I will
| think about this trade-off, but I am also interested how
| others look at this problem.
| ok123456 wrote:
| What's modern about Wayland?
| petcat wrote:
| Yikes, so it's a "TUI" app... that still requires a display
| server? So I can't run this TUI over SSH or a virtual
| terminal. Wondering what the point of a tui is that still
| requires a gui environment to run?
| Daviey wrote:
| Sorry, I was unhelpfully flippant. You totally can, and I
| don't want to distract from the great app that has been
| shared. This bug was just a compile time issue, which
| needed X libs to bake in clipboard support which is
| optional at runtime.
| sigmonsays wrote:
| this stopped me from go installing it too on nixos. I'm not
| gonna put the effort in to run it.
|
| There should be a build tag to disable clipboard, that'd be
| the easiest way around this.
| Daviey wrote:
| Same, I also had the same issue on NixOS :)
| 84634E1A607A wrote:
| Overall good work. I'd request an `-i` command-line parameter to
| specify the interface to scan (and I'd prefer ALL params being
| able to be read from command line params). I think it just
| performs a full scan initially on my laptop, following scans
| either didn't success or didn't involve TCP connect scan (I don't
| see ARP requests after the initial scan).
| rvermeulen98 wrote:
| That's correct. To avoid overloading the local network, the
| initial scan has a built-in safeguard:
|
| 1. It only scans the subnet of the configured network
| interface.
|
| 2. The scan is limited to a maximum size of a /16 subnet.
|
| 3. It runs just once every 5 minutes (this interval should be
| made configurable, currently still hardcoded).
|
| If a subnet larger than /16 is configured, whosthere will log a
| warning and only scan the first /16 portion of that subnet. As
| of now the network interface itself is configured via the YAML
| file. I agree it would be a good idea to add command-line flags
| for more of these settings to make them easier to adjust.
| mrcaramelpants wrote:
| Surely a missed opportunity to name it "whogoesthere"
| adzm wrote:
| I was thinking more along the lines of whodat
| kapitanjakc wrote:
| Good stuff, this saves me the trouble of going through router
| GUI. And remembering if it was 192.168.1.1 or 0.1 or what were
| the admin/root passwords.
| girishso wrote:
| Great tool, only thing I miss is it doesn't show SAMBA names.
| hk1337 wrote:
| > Apple could not verify "whosthere" is free of malware that may
| harm your Mac or compromise your privacy.
|
| Couldn't run it on macOS Tahoe. I believe this requires me
| lowering the security to allow it, which is something I would
| rather not doing.
| rawgreaze wrote:
| This is basically how every custom app works on Mac. You have
| to go to Settings -> Security & Privacy and click "Allow
| whosthere"
| rvermeulen98 wrote:
| Would it help to get it on the "official" homebrew, instead
| of a custom tap/cask? Might try to do an application for that
| somewhere in the upcoming weeks.
| phubbard wrote:
| this can be fixed by
|
| xattr -c `which whosthere`
| est wrote:
| I hope browsers could support mDNS or SSDP. We need an Intranet
| browser!
| Havoc wrote:
| Busy building something similar with a view towards customising
| it for my LAN.
|
| Specifically it needs to pull additional detail out of proxmox
| servers and opnsense plus deduce where things are physically
| based on latency.
|
| Thats a whole lot easier if it doesn't need to work universally &
| you can hardcode some assumptions
| Evidlo wrote:
| I'm also working on a Go TUI tool. Any reason you went with tcell
| instead of charmbracelet ecosystem?
| rvermeulen98 wrote:
| I started off using tview/tcell, and only later found out about
| bubbletea and the charmbracelet ecosystem. Then I didn't really
| find a solid reason to switch over to bubbletea. So far I
| really enjoyed the experience building the app with tview, the
| only real limitation I ran into was switching the theme at
| runtime, for which I had to build a custom mechanism.
| GeoffKnauth wrote:
| Using brew, I got "Apple could not verify `whosthere' is free of
| malware that may harm your Mac or compromise your privacy." [Move
| to Trash] [Done]
| cedws wrote:
| It just means that the binary is not notarised. You can go into
| Privacy & Security to override.
| sneak wrote:
| Unsigned binaries on macOS have slowly but surely been
| marginalized more and more with scarier and scarier warnings
| and harder hoops to jump through. You can enable execution in
| the system settings "Privacy and Security" pane.
|
| I'm sure this has nothing to do with Apple's subscription-based
| (and government ID requiring) developer program membership
| which is the only way to get such signatures.
| vzaliva wrote:
| I am not a golang user. If I install as recommended via `go`
| command on Linux how do I make sure it is updated when new
| versions are released? I wish it has a .deb package..
| zahlman wrote:
| > I wish it has a .deb package..
|
| Generally speaking, the Debian package management system is
| _really_ not a place I would look for prompt updates when new
| versions of software are released.
| mzajc wrote:
| Why not? It works roughly the same as any other binary
| distribution format. Given that the project is written in go,
| it's also unlikely to have many dynamically linked
| dependencies.
| foresto wrote:
| You might be confusing the .deb package format with the
| release cadence of the Debian Stable distribution.
| sneak wrote:
| "go install" does not have an update mechanism. I imagine most
| people using it would consider such an anti-feature; it is not
| a package manager.
|
| I certainly don't want programs I "go install" to change
| underneath me without notice or review. That's basically
| handing ownership of your computer to a remote developer.
| yobert wrote:
| Just `git pull` and `go build` should work!
| zahlman wrote:
| Does the Go standard library have unusually good TUI support or
| something? Am I just imagining the pattern of new TUIs being
| written in Go?
| jen20 wrote:
| The standard library doesn't have much for this, but Bubble Tea
| https://github.com/charmbracelet/bubbletea is behind many of
| the better Go TUIs. This one is using
| https://github.com/rivo/tview.
| pstuart wrote:
| The charmbracelet folk are quite, um, charming, but when I
| tried to work with bubble tea on a multi pane project I found
| it unwieldy -- tview seemed much more straightforward.
| awesome_dude wrote:
| Bubbletea has the unfortunate side effect of enforcing
| style/architecture on a project
|
| Much like cobra (or was it viper) did for CLI switches
|
| This is cool if that's what you like, but if you have your
| own thinking on layout/architecture then you're in for a
| world of pain.
|
| I use rivo/tview in my projects, and like it, but it's not
| without its "quirks"
| pstuart wrote:
| No, it really doesn't have anything TUI focused in stdlib. I
| get the reason why but it would be cool if they had something
| foundational in golang.org/x/
|
| This project appears to be using github.com/rivo/tview which is
| is really solid.
| cpuguy83 wrote:
| It compiles fast, starts up fast, and doesn't have a ton of
| hoops to jump through (ie borrower/checker in rust).
| apitman wrote:
| Have you tried it on Tailscale at all? Could be super useful but
| sadly TS doesn't support mDNS:
| https://github.com/tailscale/tailscale/issues/1013
| jasonjmcghee wrote:
| Big missed opportunity to call it "Whose LAN is it anyway?"
| sneak wrote:
| Love it! I already have some ideas for additional improvements,
| might jump in and contribute a PR or two.
|
| Great work.
| ryancnelson wrote:
| is the only way to export the results "run in daemon mode and
| curl yourself"?
| mmh0000 wrote:
| There's a famous quote: Those who cannot remember
| nmap are condemned to remake it poorly
|
| Rootless nmap scan of a /24 in under 10 seconds:
| nmap -T5 -sn -PR --script broadcast-dns-service-
| discovery,broadcast-upnp-info 10.0.0.0/24 ...SNIP...
| Nmap done: 256 IP addresses (30 hosts up) scanned in 9.99 seconds
|
| https://nmap.org/book/toc.html
| zbentley wrote:
| I like nmap and use it often. The linked tool seems to be doing
| different or additional things vs nmap.
|
| What makes you think it's not learning from/remembering nmap?
| mmh0000 wrote:
| That nmap command does the same thing as the author's
| command, except for the UI, for which there are dozens of
| nmap-uis available.
| sally_glance wrote:
| But you've got to admit that OPs tool does it quicker,
| except if you like to memorize flags or already have a
| script specifically for this. And it's much nicer on the
| eye than most (all?) nmap-guis out of the box.
| jarek83 wrote:
| Looks nice. I'd love to have a way to select anything on the
| screen or at least have a button to copy more info, like
| manufacturer name of a found device.
| adi_kurian wrote:
| Looks great. Discovery.app is also useful if you're mostly
| dealing with Apple / Bonjour-heavy networks.
| https://apps.apple.com/us/app/discovery-dns-sd-browser/id138...
| pimlottc wrote:
| I read the title as "W host here"
___________________________________________________________________
(page generated 2026-01-23 23:00 UTC)