server: relay a test device's adb endpoint, because mDNS does not cross subnets
The beacon this replaces was a separate service wildcard-bound to 0.0.0.0:443 - it silently occupied port 443 on the reserved measurement addresses, voiding the IPv4 interception proof for as long as it ran, and it accepted a port report from anyone who could reach it. So this lives where the repo's own post-mortem said it belongs: POST on the control plane authenticated by the device credential, GET on the admin UI behind the existing apiAdmin helper. No new listener, no new port, no wildcard. Entries expire after 24h (ECHOLOT_ADB_ENDPOINT_RETENTION_H) on both write and read - a LAN address is a breadcrumb for driving a test device, not measurement data worth keeping. Also records the BLE peer-comparison design: the case for it is that BLE is out-of-band, which is what makes client isolation measurable at all - silence over IP cannot distinguish an isolating AP from an absent peer, and a peer confirming out-of-band that it was listening turns that silence into proof. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ab6e278272
commit
ae63bd7c7f
@@ -143,6 +143,47 @@ curl -sk https://<host>:8443/v1/profile -H 'Authorization: Bearer <credential>'
|
||||
|
||||
The SPKI pin clients must verify is logged at startup (`pin-sha256`).
|
||||
|
||||
## Dev relay (adb endpoint)
|
||||
|
||||
Development scaffolding, not protocol: it appears in no capability list and in no measurement
|
||||
document, and `docs/probe-protocol.md` does not describe it.
|
||||
|
||||
It exists because **mDNS does not cross subnets**. Android's wireless debugging advertises adbd's
|
||||
port over mDNS and rotates that port every few minutes, so a developer on another subnet cannot
|
||||
discover it at all. An Echolot instance running on the test LAN can — and relays it here.
|
||||
|
||||
```
|
||||
POST /v1/devtools/adb-endpoint control plane, device credential (same Bearer as /v1/sessions)
|
||||
{"host":"10.13.102.128","port":45305,"device_name":"TB330FU","note":"…"}
|
||||
GET /admin/adb-endpoints admin UI, session cookie or HTTP Basic
|
||||
```
|
||||
|
||||
Read it back from the developer's machine (the admin listener is loopback-only, so over the same
|
||||
SSH tunnel as everything else):
|
||||
|
||||
```sh
|
||||
curl -s -u admin:<password> -H 'Accept: application/json' \
|
||||
http://127.0.0.1:8444/admin/adb-endpoints
|
||||
# → [{"device":"…","host":"10.13.102.128","port":45305,"device_name":"TB330FU",
|
||||
# "reported_at":"…","source_ip":"…","age_s":37}]
|
||||
```
|
||||
|
||||
The same list is a card on the admin dashboard, so it is usable without curl.
|
||||
|
||||
The newest report per submitting device wins — a rotated port makes the previous one wrong, not
|
||||
historical. The device id comes from the credential and `source_ip` from the connection, so neither
|
||||
is something a body can claim. `ECHOLOT_ADB_ENDPOINT_RETENTION_H` (default 24) bounds how long an
|
||||
entry lives; `0` keeps it until the device replaces it. The window exists because the value is a
|
||||
LAN address that stops being true within minutes: keeping it afterwards discloses the inside of
|
||||
someone's network in exchange for nothing.
|
||||
|
||||
**Why it lives on these two listeners and nowhere else.** Its predecessor was a separate Python
|
||||
service wildcard-bound to `0.0.0.0:443`. That silently occupied port 443 on the addresses reserved
|
||||
for measurement — voiding the IPv4 interception proof for as long as it ran — and it accepted a port
|
||||
report from anyone who could reach it. So: no new listener, no new port, no wildcard bind, and
|
||||
nothing unauthenticated. The submit side is rate-limited by the existing §2.5 actions bucket
|
||||
(`ECHOLOT_RATE_ACTIONS_PER_MIN`).
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
|
||||
Reference in New Issue
Block a user