Skip to main content
Admin Modules

Network Discovery (Sonar)

Live network map with active scanning and admin tools — 75+ devices across Milky Way, Andromeda (via Tailscale), mesh nodes, and external hosts. Powered by Sonar container.

February 28, 2026

Network Discovery (Sonar)

The network discovery module provides a real-time device inventory across the entire homelab infrastructure, powered by the Sonar scanner container on Altair-Link. It combines passive API queries with active scanning (nmap, arp-scan) and includes on-demand network admin tools — all accessible from /admin/network-map.

Network Map (/admin/network-map)

The main page renders a grid of glass-style device cards, each showing:

  • Status dot — green (online), red (offline), or amber (unknown)
  • Device name — friendly name from known_devices.json, DHCP hostname, or raw IP
  • IP address — local network IP or Tailscale IP
  • MAC address — with OUI vendor identification
  • Type badge — router, switch, wap, workstation, hypervisor, nas, drone, vps, etc.
  • Connection type — Wired, 2.4GHz, 5GHz, 6GHz (ASUS clients only)
  • Subnet router badge — for Tailscale nodes advertising routes
  • Last seen — relative timestamp
  • Action buttons — Port Scan, Traceroute, DNS Lookup (pre-fills tools drawer)

Filter Tabs

Five tabs across the top filter the device grid by network:

  • All — every device from every source
  • Milky Way — 10.42.0.0/24 devices (cyan accent)
  • Andromeda — 192.168.20.0/24 devices via Tailscale routing (purple accent)
  • Tailscale — VPN mesh nodes (violet accent)
  • External — Sentinel VPS and other external probes (orange accent)

The search bar filters across hostname, IP, MAC, vendor, and device type. Filtering is instant (client-side, no API call).

Stats Bar

A stats row at the top shows: total device count, online count, offline count, and per-network device counts. These update on every poll cycle.

Scanner Status

The header shows a connection indicator (green dot = connected, red = disconnected), the timestamp of the last successful scan, and the scan duration in milliseconds. A refresh button triggers an immediate rescan via POST /api/net-scanner/trigger.

Auto-Refresh

The page polls GET /api/net-scanner/devices every 30 seconds using setInterval. The poll initializes on astro:page-load (View Transitions compatible) and clears on astro:before-swap. If the scanner is unreachable, the page falls back to cached data and shows a disconnected indicator.

Tools Drawer

A slide-in panel on the right side provides 5 network admin tools. Opened via the “Tools” button in the header, or by clicking action buttons on device cards.

Available Tools

ToolEndpointDescription
Ping SweepPOST /tools/ping-sweepSweep a subnet for live hosts (nmap -sn)
Port ScanPOST /tools/port-scanScan ports on a host (SYN or service detection)
TraceroutePOST /tools/tracerouteRoute trace or MTR to a host
DNS LookupPOST /tools/dnsDNS query (A, AAAA, MX, NS, CNAME, TXT, PTR, SOA, SRV)
Nmap ScanPOST /tools/nmapFull nmap scan with configurable type and ports

Tool Results

Results render as structured tables:

  • Nmap/Port Scan — port, protocol, state (color-coded), service, version
  • Traceroute — hop number, IP, latency or loss percentage
  • DNS — record list
  • Ping Sweep — host list with state

Device Card Actions

Each device card has three action buttons that pre-fill the tools drawer:

  • Port Scan — opens tools with target IP and port-scan selected
  • Traceroute — opens tools with target IP and traceroute selected
  • DNS — opens tools with target IP/hostname and DNS selected

Sonar Scanner Service (Backend)

Sonar is a Docker container (Arcturus-Prime-sonar) running on Altair-Link (10.42.0.199) with host networking. It has full network visibility via the host’s LAN interface and Tailscale mesh.

  • Image: Alpine 3.21 + Python 3.13 + network tools
  • Container: Arcturus-Prime-sonar, network_mode: host, CAP_NET_RAW + CAP_NET_ADMIN
  • Port: 8096 (bound on host)
  • Tunnel: playground-switch.Arcturus-Prime.com (Cloudflare tunnel on Altair-Link)

Data Sources (6 Scanners)

SourceNetworkMethodIntervalData Provided
OPNsenseMilky Way (10.42.0.0/24)REST API — ARP table + DHCP leases60sIP, MAC, hostname, vendor, lease type
ARP scanMilky Way (10.42.0.0/24)arp-scan --localnet120sIP, MAC, vendor
NmapMilky Way + Andromedanmap -sn ping sweep300sIP, hostname, MAC (local only)
TailscaleVPN meshtailscale status --json subprocess60sTailscale IP, hostname, OS, relay, subnet routes
VPS ProbeExternalTCP connect to configured ports300sReachability, open ports
ASUS RouterAndromeda (192.168.20.0/24)asusrouter library — client list120sIP, MAC, hostname, WiFi band, signal

Note: Nmap reaches the Andromeda network (192.168.20.0/24) via Tailscale subnet routing through Tarn-Host. This provides host discovery even without ASUS credentials.

Device Resolution

The scanner deduplicates devices by IP address, preferring the entry with more data. It then enriches results with known_devices.json — a manually maintained file mapping IPs and MACs to friendly names and device types. The resolver:

  1. Flattens results from all scanners
  2. Deduplicates by IP (keeps most complete entry)
  3. Enriches from known_devices.json (MAC match first, then IP)
  4. Sorts: online first, then by IP numerically

Network Classification

The nmap scanner classifies discovered hosts by IP range:

  • 10.42.0.0/24 → Milky Way
  • 192.168.20.0/24 → Andromeda
  • 100.64.0.0/10 → Tailscale

Tools Security

All network tools use safe execution:

  • asyncio.create_subprocess_exec (never shell=True)
  • Strict regex validation for IPs, CIDRs, hostnames, ports
  • asyncio.Semaphore(3) concurrency limit
  • Hard timeouts (5-300s per tool)
  • All behind API key authentication

Installed Tools

nmap (+ NSE scripts), masscan, arp-scan, mtr, traceroute, dig, whois, ping, iperf3, iproute2.

API Routes

The Arcturus-Prime frontend communicates through a proxy layer that injects the scanner API key server-side.

Proxy (Dev)

In development, the Vite dev server proxy in astro.config.mjs handles:

/api/net-scanner/* → 10.42.0.199:8096/api/scan/*

The proxy rewrites the path and injects X-Api-Key from NET_SCANNER_API_KEY env var.

SSR Route (Production)

In production, src/pages/api/net-scanner/[...path].ts handles the proxy:

  • Checks admin auth via resolveAuthState
  • Forwards to NET_SCANNER_URL (default https://playground-switch.Arcturus-Prime.com)
  • Injects X-Api-Key from env
  • 120s timeout (tools can take time), no caching
  • Wildcards all sub-paths including /tools/*

Discovery Endpoints

MethodFrontend PathScanner PathAuthPurpose
GET/api/net-scanner/health/api/scan/healthNoneScanner status + per-source health
GET/api/net-scanner/devices/api/scan/devicesAPI KeyFull device list, optional filters
GET/api/net-scanner/summary/api/scan/summaryAPI KeyDevice counts by network
POST/api/net-scanner/trigger/api/scan/triggerAPI KeyForce immediate rescan

Tools Endpoints

MethodFrontend PathScanner PathAuthPurpose
POST/api/net-scanner/tools/nmap/api/scan/tools/nmapAPI KeyOn-demand nmap scan
POST/api/net-scanner/tools/traceroute/api/scan/tools/tracerouteAPI KeyTraceroute or MTR
POST/api/net-scanner/tools/dns/api/scan/tools/dnsAPI KeyDNS lookup
POST/api/net-scanner/tools/port-scan/api/scan/tools/port-scanAPI KeyPort scan
POST/api/net-scanner/tools/ping-sweep/api/scan/tools/ping-sweepAPI KeyPing sweep
GET/api/net-scanner/tools/interfaces/api/scan/tools/interfacesAPI KeyNetwork interfaces

Query parameters for /devices: ?network=milky-way|andromeda|tailscale|external and ?status=online|offline.

Module Configuration

The module manifest at src/config/modules/network-discovery.ts (v2.0.0) registers:

  • Nav item: id network-discovery, href /admin/network-map, icon fa-satellite-dish, group infra
  • Required env vars: NET_SCANNER_URL, NET_SCANNER_API_KEY
  • Required role: admin

Environment Variables

Arcturus-Prime (CF Pages)

VariablePurposeDefault
NET_SCANNER_URLSonar service URLhttps://playground-switch.Arcturus-Prime.com
NET_SCANNER_API_KEYAPI key for scanner auth(none)

Sonar Container (.env)

VariablePurposeDefault
OPNSENSE_HOSTOPNsense IP:port10.42.0.1
OPNSENSE_API_KEYOPNsense API key(disabled if empty)
OPNSENSE_API_SECRETOPNsense API secret(disabled if empty)
ASUS_HOSTASUS router IP192.168.20.1
ASUS_USERNAMERouter admin user(disabled if empty)
ASUS_PASSWORDRouter admin password(disabled if empty)
VPS_HOSTSentinel VPS IP178.156.247.186
VPS_PORTSPorts to probe22,3001
API_KEYService auth tokenchangeme
NMAP_ENABLEDEnable nmap scannertrue
NMAP_SUBNETSLocal subnets to scan10.42.0.0/24
NMAP_TAILSCALE_SUBNETSRemote subnets via Tailscale192.168.20.0/24
NMAP_INTERVALNmap scan interval (seconds)300
ARP_ENABLEDEnable ARP scannertrue

Deployment

Sonar runs as a Docker container on Altair-Link. To update:

cd ~/Development/Arcturus-Prime-net-scanner
scp Dockerfile docker-compose.yml requirements.txt known_devices.json [email protected]:/opt/Arcturus-Prime-sonar/
scp -r app/ [email protected]:/opt/Arcturus-Prime-sonar/app/
ssh [email protected] "cd /opt/Arcturus-Prime-sonar && sudo docker compose up -d --build"

Key Files

FilePurpose
src/pages/admin/network-map.astroAdmin page with device grid + tools drawer
src/pages/api/net-scanner/[...path].tsSSR proxy route
src/config/modules/network-discovery.tsModule manifest (v2.0.0)
~/Development/Arcturus-Prime-net-scanner/Sonar service source
known_devices.jsonDevice name/type overrides

Known Issues

  • ASUS Andromeda — GT-AXE16000 credentials not yet configured. Nmap provides IP-only discovery as a fallback; ASUS would add MAC addresses, hostnames, and WiFi band info for ~30-35 devices.
  • Tailscale last_seen — Some nodes report 0001-01-01T00:00:00 when they haven’t been seen yet.
  • OPNsense ARP format — Returns a plain list, not {"rows": [...]}. Scanner handles both formats.
networkdiscoveryscannersonarnmaparp-scandevicestopologyopnsensetailscaletoolsinfrastructure