18 Commits
Author SHA1 Message Date
Joachim Wiberg a9c722fcd5 netbrowse: link neighbor cards to the resolved host, not adminurl's
avahi resolves mDNS hostname conflicts at runtime by appending -2, -3, …
but the advertiser writes its adminurl TXT record with the configured
hostname and never updates it. A device renamed infix-2.local thus keeps
advertising adminurl=http://infix.local, so its card linked to the other
device. Rebase the adminurl onto the actually-resolved host (keeping
scheme, port, and path); a no-op in the common single-device case.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-06-14 18:28:22 +02:00
Joachim Wiberg cfcc83f15d netbrowse: add operational backend and fix TXT record parsing
Add a second discovery backend that reads mDNS neighbor data directly
from the sysrepo operational datastore via `copy operational-state -x
/mdns`, selectable with --backend operational.

Add an auto backend (the new default) that tries the operational data
first and falls back to avahi-browse if the `copy` command is
unavailable or mDNS is disabled (visible via "enabled": false in the
JSON).  This makes the service work correctly in all configurations
without manual tuning.

Refactor TXT record parsing into parseTxt() and service/host assembly
into buildHosts(), shared by both backends.  Extract fetchOpRoot() and
parseOperational() so scanOperational() and scanAuto() share the same
JSON fetch/decode and host-building logic without duplication.

Fix a bug where TXT values containing semicolons were truncated
(parts[9] → strings.Join(parts[9:], ";")), and apply decode() to TXT
values so avahi \DDD escapes are resolved.  Add Apple device model
support via the am= (RAOP/AirPlay 1) and model= (AirPlay 2) TXT keys.

Display the last-updated timestamp in 24-hour format regardless of the
browser's locale.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-22 20:23:44 +01:00
Joachim Wiberg 0489fb5403 netbrowse: skip loopback addresses when displaying device IP
avahi-browse returns 127.0.0.1 (or ::1) when resolving services on the
same machine netbrowse is running on. These addresses are meaningless
for display and misleading as click targets. Skip the entire 127.x/::1
range and link-local (fe80:) when choosing the preferred address for a
host card; the card addr field is simply omitted if no routable address
is seen.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-09 19:25:28 +01:00
Joachim Wiberg 585907daae netbrowse: show IP, product/version on cards; sun/moon theme icons
- IP address shown in soft parens on the card header line, e.g.
  "infix.local (192.168.1.10)"; IPv4 preferred over IPv6, link-local
  skipped
- Product name and OS version (from mDNS TXT records "product=" and
  "ov=") shown as a secondary line below the header when available
- Theme toggle icons changed from ◐/●/○ to ◐/☽/☀ (system/dark/light)
- browse.go: introduce Host struct (addr, product, version, other, svcs)
  replacing the flat []Service map; scan() now returns map[string]Host
- Search also matches against IP, product, and version fields

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-09 19:25:27 +01:00
Joachim Wiberg 62559655dc netbrowse: modernize UI with card layout and theme support
Replace the Go template + table layout with a fetch-based design:
serve browse.html as static HTML, add /data JSON endpoint.

New UI features:
- Card-per-device grid with color-coded service badges
- Dark/light/system theme toggle (persisted to localStorage)
- Live search (press / to focus)
- Auto-refresh toggle with 30 s countdown, off by default
- Empty/error states and device count in footer
- IBM Plex Mono throughout

Download the latin-subset woff2 files (weights 400/500/600) from
fonts.gstatic.com (IBM Plex Mono v20) and serve them locally via
the existing //go:embed static mechanism, eliminating the Google
Fonts dependency for air-gapped and offline deployments.

  Source:  https://github.com/IBM/plex
  Files:   fonts.gstatic.com/s/ibmplexmono/v20/
  License: SIL Open Font License 1.1 (static/fonts/LICENSE.txt)
	     Copyright © 2017 IBM Corp.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-09 19:25:27 +01:00
Joachim Wiberg c68db78309 netbrowse: fix device detection in default view
Apple devices (e.g. Apple TV) publish vv=1 in their AirPlay/RAOP TXT
records, causing a false positive with our Infix platform marker.
Tighten the filter to require vv=1 together with at least one management
service type (ssh, https, http, netconf, restconf), which Apple devices
never advertise. Keep on=Infix as a fallback for older firmware that
predates vv=1.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-09 19:25:26 +01:00
Joachim Wiberg 87c671b4cc netbrowse: fix DNS-SD service name decoding
avahi's parseable output uses \DDD decimal escape sequences, not octal.
The previous decoder treated them as octal, causing digits 8 and 9 to
fall through undecoded (e.g. \058 → ':' and \091 → '[' were shown
literally). Also handle \X non-digit escapes (e.g. \. → '.') used for
dots in service instance names.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-09 19:25:26 +01:00
Joachim Wiberg ba801be402 package/netbrowse: bump to v2.0
Replaces gunicorn+flask app with Go program, same function otherwise.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-09 19:24:34 +01:00
Joachim WibergandMattias Walström a37dd412e1 netbrowse: add /netbrowse route and RESTCONF mDNS xlate
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-06-04 13:38:03 +02:00
Joachim Wiberg b33294950f netbrowse: prestudy of available txt records, use adminurl for Infix
This commit includes a small prestudy, done over a period of two weeks,
to gather information about common txt records used by hosts.  The most
well-documented is the Apple Printing Spec, which among other things
defines adminurl.  A proposed version 1 of the Infix txt record spec is
included in the document.  I'm recommending alternative 2:

"vv=1" "vendor=Qemu" "product=VM" "ty=x86-64" "vn=KernelKit" "on=Infix" "ov=v24.03.0"

Including this information would enable quickly scanning a network to
see if the latest version of the software has been deployed.  Please
note, I've not included the U-Boot firmware version in this proposal,
but it could be included as "vs=2023.10-kkit3", or similar.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg 92d3db46a7 netbrowse: convert to gunicorn and factor out mdns-alias app
Converting to gunicorn, which is the recommended production server for
Flask apps, means app main() function is no longer called at startup, so
we have to factor out the mDNS CNAME functionality for infix.local and
network.local to a separate app.

We take this opportunity to collapse the structure, move non-class
methods to __init.py__, and rename the AvahiAlias class.  A prototype
for replacing the overhead of mdns-alias with a C daemon is in its
early stages.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg 5d128d74f5 netbrowse: migrate from setup.py to pyproject.toml
This change also requires another restructure for netbrowse itself, hence
the relocation of files in the tree.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg d2b370b44d netbrowse: open links to mDNS hosts in new tab
Also, disable debug logging.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg eef60de999 netbrowse: add cool little favicon
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg 83d18eb988 netbrowse: convert to jinja2 templates and address review comments
- Convert to use jinja2 templates instead of HTML/CSS inline
 - Address review comments:
   - Support for a foldout of details with link being key
   - Support for a Show All checkbutton
 - Styling and neat background by kjpargeter[1]

[1]: https://www.freepik.com/free-vector/network-connections-background_2533758.htm

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg 64d63c08df netbrowse: convert to flask
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg 282e7b08a3 netbrowse: drop misc services, keep http/https, ssh/sftp, netconf
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00
Joachim Wiberg c1836af7cc package/netbrowse: new package
- Advertises the build-time $hostname.local as a CNAME to the A and
   AAAA records already advertised by Avahi
 - Advertises a special network.local CNAME and provides a fastcgi
   service on unix:/tmp/netbrowse.sock for browsing mDNS services

This commit also activates netbrowse by default with nginx listeing
to port 80 on IPv4 and IPv6 /browse by default but also / if called
with server name network.local.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-04-15 15:36:41 +02:00