app: name what a VPN blocked, and prove v6 broken before saying so

Constraints are detected up front (one throwaway bind per network) and land
in run.constraints, a measurement.vpn_constrained finding, the $7.3 verdict
(INCONCLUSIVE outright) and a banner on the run screen - a VPN'd run looked
exactly like a clean run of a healthy network before this.

v6.broken returns to the registry now that it can be earned: V6ConnectProbe
(v6.brokenness) makes a real TCP connection over IPv6 to the enrolled
server, and only both transports failing on a network that advertises IPv6
justifies the claim. TCP succeeding turns the finding into 'ICMPv6 is
filtered, IPv6 works' at high confidence instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrambossek
2026-08-02 12:31:44 +02:00
co-authored by Claude Opus 5
parent 987b2ceb47
commit 20cfecf566
8 changed files with 337 additions and 21 deletions
+10 -2
View File
@@ -95,14 +95,22 @@ rolled up under *connectivity* instead — the third occurrence of rule 1 being
| `v6.no_default_route` | medium | The device has a global IPv6 address but no IPv6 default route. | Guesswork: this is read from the routing table, not inferred from silence. |
| `v6.route_without_address` | medium | The network advertises an IPv6 default route but the device has no global IPv6 address. | A working IPv6 setup: SLAAC did not produce a usable address on this link. |
| `v6.no_icmp_reply` | low | IPv6 is configured but ICMPv6 echo gets no reply. | Nothing on its own: IPv6 may work fine with ICMP filtered. |
| `v6.broken` | high | IPv6 is advertised on this network but carries no traffic. | ICMP filtering as the benign explanation: a TCP connection over IPv6 failed too. |
| `v6.not_offered` | info | This network does not offer IPv6. | — |
`v6.no_icmp_reply` was `v6.broken` until a phone reported it while loading an IPv6-only site over
TCP perfectly well. The only evidence behind it is ICMPv6 echo, which is widely filtered on
networks where IPv6 works — so the finding now states what was observed and names both
explanations instead of choosing one. It is still worth reporting: filtered ICMPv6 breaks Path MTU
Discovery. Corroborating it with a real IPv6 connection would let the two cases be separated, and
is the proper fix.
Discovery.
`v6.broken` returned once that corroboration existed: the `v6.brokenness` test attempts a real TCP
connection over IPv6 to the configured server, and only when *both* transports fail on a network
that advertises IPv6 is the brokenness claim made — at high severity, because every dual-stack
destination pays a timeout before falling back to IPv4. When the TCP connect *succeeds*,
`v6.no_icmp_reply` is emitted at high confidence instead, now able to say plainly that ICMPv6 is
filtered while IPv6 works. With no server configured there is no corroboration target and the
two-explanation `v6.no_icmp_reply` stands unchanged.
`v6.not_offered` is **info and must stay info**. Most networks still do not offer IPv6 and that is
not a fault; reporting it as a warning lights a yellow verdict on a healthy network, which teaches