app: long runs that watch, and a relay for the port that keeps moving

Long mode starts listeners at t=0 and keeps them running past the
battery: a network-change watcher that finally fills networks[].changes[]
(defined since the schema's first draft, never populated), an RSSI log, a
ping series giving loss and jitter over minutes, and mDNS listening for
the whole window. This is the class of fault a short run cannot see - a
link that drops for four seconds between two probes is reported healthy
by both of them. run.mode records which question was asked, because
silence means different things in the two modes.

The adb relay replaces the retired beacon: AdbRelay watches adbd's own
mDNS with the resolve-once discipline the beacon learned the hard way
(resolving re-arms adbd and pops a notification), a foreground service
keeps it alive with the screen off, and the heartbeat re-posts the cached
endpoint rather than re-resolving. It exists because mDNS does not cross
subnets and the wireless-debug port rotates every few minutes.

Also records why LLDP/CDP cannot follow SSDP into long mode: both are raw
L2 frames, so they need CAP_NET_RAW - root tier, not app, and Shizuku's
shell user does not have it either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrambossek
2026-08-02 14:43:33 +02:00
co-authored by Claude Opus 5
parent ae63bd7c7f
commit 0071e00003
24 changed files with 1834 additions and 107 deletions
+20
View File
@@ -1379,6 +1379,26 @@ poisons `/releases/latest` for the string-comparing updater the moment anyone ta
The stale `server-v0.9.2` release (same code lineage, wrong number, created during the confusion)
remains in Gitea but is harmless now that v0.11.3 outranks it as latest.
## LLDP and CDP are root-tier, and that is a hard boundary (2026-08-02)
Asked for alongside SSDP in long mode; they belong to a different tier and no amount of app-side
cleverness moves them. LLDP is an EtherType `0x88CC` frame to `01:80:C2:00:00:0E`; CDP is an
LLC/SNAP frame to `01:00:0C:CC:CC:CC`. Neither is IP, so neither is ever delivered to a socket an
app can open — receiving them needs `AF_PACKET` with `CAP_NET_RAW`, which is root. Shizuku does
not bridge this either: the ADB shell user (uid 2000) has no `CAP_NET_RAW`, and stock devices do
not ship `tcpdump`. Android's unprivileged ICMP sockets are what make `icmp.ping4` work without
root; there is no equivalent back door for raw L2 receive.
Worth building in the root module when it lands, because the payoff is large: LLDP names the
switch, the port and the VLAN a device is attached to, which is the best available answer to
"where in this building am I actually plugged in", and CDP does the same on Cisco gear. Until
then they are recorded as absent capabilities rather than left to look unimplemented.
What IS reachable at app tier, and what long mode now listens for instead: SSDP (passive NOTIFY
plus periodic M-SEARCH), LLMNR, NetBIOS-NS and WS-Discovery — all IP multicast/broadcast, all
sockets an app may open. The security reading matters as much as the inventory: LLMNR and
NetBIOS-NS being live on a segment is a finding in itself, since both are trivially spoofable.
## Design note: what BLE between two devices is actually for (2026-08-02, not built)
Two or more phones running Echolot, talking over Bluetooth LE. The schema already anticipates