[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)