docs: log the prober fold and server v0.9.2 feature work
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8118e213ae
commit
d574c76630
+62
-1
@@ -1284,4 +1284,65 @@ signature against the key in the source it just built.
|
|||||||
`RELEASE_SIGNING_KEY` (Settings → Actions → Secrets) with the contents of
|
`RELEASE_SIGNING_KEY` (Settings → Actions → Secrets) with the contents of
|
||||||
`~/.echolot/release-signing-key` from the dev PC. Ordering is safe: the currently deployed
|
`~/.echolot/release-signing-key` from the dev PC. Ordering is safe: the currently deployed
|
||||||
v0.3.x updater does not verify, so it will happily install the first signed release; every
|
v0.3.x updater does not verify, so it will happily install the first signed release; every
|
||||||
release after that is verified.
|
release after that is verified. **Done 2026-08-02** — the secret is in place. (The "v0.3.x"
|
||||||
|
above should read "the currently deployed release": deployments had moved on to v0.9.x by the
|
||||||
|
time signing landed; the point — the deployed updater predates verification and will accept the
|
||||||
|
first signed release — is unchanged.)
|
||||||
|
|
||||||
|
## Prober fold: traceroute.udp4 and the mDNS inventory go production (2026-08-02, app 0.2.2)
|
||||||
|
|
||||||
|
The two highest-value validated capabilities moved from the prober into `core-probe`:
|
||||||
|
|
||||||
|
- **`traceroute.udp4`** (`TracerouteProbe`): UDP traceroute reading ICMP time-exceeded off the
|
||||||
|
socket error queue via `Os.recvmsg(MSG_ERRQUEUE)` through the reflection facade — no root, no
|
||||||
|
raw socket, no JNI, ~250 ms for six hops. Emits the schema's `TracerouteEvidence` (rtt in ns).
|
||||||
|
`OsAbi` came with it, including the measured fact that `Os.getsockoptInt` exists on neither
|
||||||
|
known device, so PMTU must always be read from the errqueue (`ee_info`), never
|
||||||
|
`getsockopt(IP_MTU)`. The load-bearing line survived the port: EAGAIN out of the reflected
|
||||||
|
`recvmsg` means "queue empty", not failure.
|
||||||
|
- **`local.mdns_inventory`** (`MdnsInventoryProbe`): MulticastLock + NSD discovery, the service
|
||||||
|
inventory that doubles as the VLAN-leakage detector. Both hardware lessons kept: the
|
||||||
|
`_services._dns-sd._udp.` meta-query returns 0 beside live services on both devices (so the
|
||||||
|
concrete types are the measurement and the meta-query result is itself evidence), and the
|
||||||
|
listen window is 10 s because 4 s missed services.
|
||||||
|
|
||||||
|
Still to fold, in order: the Shizuku dump *parsers* (the raw `link.ip_monitor` captures already
|
||||||
|
hold two divergent vendor formats that could feed `link.ra_source` and `sec.arp_watch`);
|
||||||
|
`multinetwork.request_and_bind` (extend ConstraintDetector to *request* transports rather than
|
||||||
|
only probing present ones); `peer.ble_advertise` (needs three new permissions and a peer mode to
|
||||||
|
exist first).
|
||||||
|
|
||||||
|
## Server v0.9.2: trains, real TTL/DSCP/ECN, rate limits (2026-08-02)
|
||||||
|
|
||||||
|
The spec-vs-implementation gap audit closed its top items; protocol_version 1.0.0 → 1.0.1
|
||||||
|
(additive — below 1.0.0 the minor is the breaking axis, and nothing here breaks an old client):
|
||||||
|
|
||||||
|
- **Upstream trains** (§3.2, types 0x03/0x04/0x05): per-train bounded columnar buffer (8192
|
||||||
|
rows, head kept on overflow with `Truncated` set — mirrors the schema's `evidence_truncated`
|
||||||
|
honesty), TRAIN_REPORT split across ≤1200-byte datagrams, grant-free with the §3.4 argument
|
||||||
|
spelled out (a 17-byte report row answers a ≥36-byte HMAC-valid packet). Unknown train id
|
||||||
|
gets a zero-row report: "nothing arrived" is an answer. Also surfaced as `udp.trains` in the
|
||||||
|
observations API.
|
||||||
|
- **Real TTL/DSCP/ECN observation** (§3.3): the read loop is `ReadMsgUDPAddrPort` with
|
||||||
|
IP_RECVTTL/IP_RECVTOS/IPV6_RECVHOPLIMIT/IPV6_RECVTCLASS cmsgs on Linux; `0xFF` stays the
|
||||||
|
"not observed" sentinel elsewhere. This unblocks `sec.dscp_ecn_survival` both directions,
|
||||||
|
paired with the new `dscp` parameter on `downtrain` (validated 0–63, refused not clamped,
|
||||||
|
`dscp_applied` in the response).
|
||||||
|
- **Rate limiting** (§2.5, was entirely absent): token buckets keyed per credential AND per
|
||||||
|
source IP; 429 + Retry-After on session/action creation (`/v1/profile` stays ungated), silent
|
||||||
|
drop on the data plane — charged after the HMAC gate so a spoofed flood cannot drain a
|
||||||
|
victim's budget, before the replay window so a dropped seq stays usable. UDP ceilings default
|
||||||
|
above the largest legitimate run (a 200 Mbps throughput test), because a rate limit that
|
||||||
|
clips a real measurement produces a confidently wrong number.
|
||||||
|
- **`action_id` in every granted packet** (§5/§9): payload bytes [8:16] across all granted
|
||||||
|
types, so overlapping actions are attributable. Verified the deployed Kotlin client parses
|
||||||
|
only ECHO_RESP and MTU_ACK payloads, so the reshuffle strands nobody.
|
||||||
|
- **Canary log retention**: the stated 24 h privacy default is now enforced
|
||||||
|
(`ECHOLOT_DNS_LOG_RETENTION_H`), where before the log was time-unbounded.
|
||||||
|
- **`POST /admin/enroll-tokens`** now answers the spec's JSON shape under content negotiation;
|
||||||
|
the README's curl works as documented.
|
||||||
|
- Spec §2.3 registry gained `downtrain` and `tcp-echo`, which the server had been advertising
|
||||||
|
as strings a conformant client must ignore.
|
||||||
|
|
||||||
|
Client-side counterparts still to build: sending 0x03 trains + parsing 0x05 reports
|
||||||
|
(`train.udp_updown`), and passing `dscp` on downtrain actions.
|
||||||
|
|||||||
Reference in New Issue
Block a user