Commit graph

92 commits

Author SHA1 Message Date
Andrew Pimenov
8d4c8bee8b enrich traceroute hops with ASN, AS name, country and PTR fallback
TraceHop.asn/as_name existed in the model since the start but nothing ever
populated them. New probes/hop_asn.py fires one Team Cymru DNS query pair
per unique hop IP (in-run deduped, no rate limit unlike the cached_json()
providers) after the latency/path/TLS fan-out, plus a PTR lookup for hops
whose reverse_dns is still empty because the backend that produced them
doesn't resolve hostnames itself (icmp_win/icmplib/mtr, unlike system
traceroute text).

New path.detour_country finding flags a route that spends two or more
consecutive hops in a country that's neither the client's nor the
destination's. Wires up providers.cymru_asn_zone, which was configured but
referenced nowhere, and adds cymru_origin6_zone for the IPv6 branch Phase 8
will need.

Part of plans/zesty-zooming-wilkinson.md (gitignored).
2026-08-12 21:17:00 +03:00
Andrew Pimenov
76cfd4605c detect CGNAT, NAT64, and first-hop-vs-path issues separately
- net.cgnat: three evidence paths (local IP, gateway, traceroute hop) for
  RFC 6598 100.64.0.0/10, since the local address alone misses the common
  home-router case
- net.nat64: RFC 7050 ipv4only.arpa AAAA probe (new probes/nat64.py) instead
  of checking the client's own address against 64:ff9b::/96, which never
  fires since that prefix is a synthesis target, not something the client's
  egress address falls into
- path.first_hop_loss/slow/unexpected: path_findings() takes an optional
  LocalNet/Thresholds so loss or latency at hop 1 is attributed to the
  user's own router/Wi-Fi instead of blending into the ISP-facing mid-path
  logic

All four findings are always-on additions to existing report sections, no
new CLI flags. Part of the larger extension batch tracked in
plans/zesty-zooming-wilkinson.md (gitignored, local planning doc).
2026-08-12 21:06:01 +03:00
Andrew Pimenov
938c715a04 fix international-loop detection: drop dead ip_country parameter 2026-08-10 21:18:28 +03:00
Andrew Pimenov
342d92e709 render TLS, DNS advanced, path diversity, prefix bench, DPI sections in reports 2026-08-09 17:56:07 +03:00
Andrew Pimenov
fc502f1756 add finding rules for TLS, prefix bench, DPI, DNS advanced, path diversity 2026-08-09 17:49:30 +03:00
Andrew Pimenov
1874f3f3c2 add Cloudflare CF-RAY edge/anycast path diversity probe 2026-08-09 17:45:37 +03:00
Andrew Pimenov
63e7597520 add system DNS vs DoH comparison and transparent proxy detection 2026-08-09 17:45:33 +03:00
Andrew Pimenov
a000a12b19 add single-host DPI/TCP-RST self-diagnostic probe 2026-08-09 17:45:27 +03:00
Andrew Pimenov
10fa9f8052 add AS prefix latency benchmark probe 2026-08-09 17:43:10 +03:00
Andrew Pimenov
e34d8f27f4 add TLS handshake RTT / TTFB probe 2026-08-09 17:42:02 +03:00
Andrew Pimenov
c63c179b57 add config sections for TLS, prefix bench, DPI check, DNS advanced, path diversity 2026-08-09 17:37:48 +03:00
Andrew Pimenov
33d7d2d942 add L4-L7 diagnostic models (TLS, DPI, DNS, anycast, prefix bench) 2026-08-09 17:35:37 +03:00
Andrew Pimenov
51d82d997f add jitter matrix (p95/p99/cv) to ping stats 2026-08-09 17:34:06 +03:00
Andrew Pimenov
387e58949f add specific unit tests for parse_traceroute 2026-08-09 16:21:23 +03:00
Andrew Pimenov
9a01b2abe2 add test coverage for throughput_from_samples 2026-08-09 16:20:50 +03:00
Andrew Pimenov
f80ebfe217 add tests for parse_server_timing_cfl4 edge cases 2026-08-09 16:20:23 +03:00
Andrew Pimenov
7fb13a87ef add tests for identity_changes 2026-08-09 16:20:11 +03:00
Andrew Pimenov
19c06279fe add test coverage for fetch_internetdb 2026-08-09 16:19:59 +03:00
Andrew Pimenov
058b873445 add tests for decode_dnsbl fallback and mixed responses 2026-08-09 16:18:57 +03:00
Andrew Pimenov
d5b8d27bfd add test coverage for fetch_abuseipdb 2026-08-09 16:18:46 +03:00
Andrew Pimenov
053e42c811 expand classify_ip_type test coverage 2026-08-09 16:17:49 +03:00
Andrew Pimenov
1554af5943 add tests for summarize_dnsbl 2026-08-09 16:17:35 +03:00
Andrew Pimenov
0be881b96a add tests for merge_geo edge cases and improve ip_geo coverage 2026-08-09 16:16:47 +03:00
Andrew Pimenov
bc5b01ae58 add test coverage for refresh_netsets 2026-08-09 16:16:32 +03:00
Andrew Pimenov
15d4d745c4 improve test coverage for latency_changes 2026-08-09 16:15:18 +03:00
Andrew Pimenov
2a72bdb441 cover empty exception message branch in run_speed_cascade 2026-08-09 16:15:08 +03:00
Andrew Pimenov
8e7d5bba5b add tests for tier_cloudflare 2026-08-09 16:14:55 +03:00
Andrew Pimenov
24f08acd79 add test coverage for tier_ookla 2026-08-09 16:14:42 +03:00
Andrew Pimenov
d42a236d3a add test coverage for finding_changes 2026-08-09 16:14:16 +03:00
Andrew Pimenov
b3971375c2 add tests for speed_changes 2026-08-09 16:14:00 +03:00
Andrew Pimenov
be99c19cfd add async tests for query_dnsbl 2026-08-09 16:13:42 +03:00
Andrew Pimenov
2473822b93 add tests for finalize_hop 2026-08-09 16:13:29 +03:00
Andrew Pimenov
8aa806881e add test coverage for tier_fastcom 2026-08-09 16:13:19 +03:00
Andrew Pimenov
fb3c6ca77f optimize overall_verdict by combining severity iterations 2026-08-09 16:10:45 +03:00
Andrew Pimenov
f59f860327 group build_trace_result arguments into TraceConfig dataclass 2026-08-09 16:08:52 +03:00
Andrew Pimenov
4c290ec309 refactor build_reputation to use ReputationContext dataclass 2026-08-09 16:08:29 +03:00
Andrew Pimenov
fc37ff369d extract NDT7 consent check into a helper function 2026-08-09 16:07:44 +03:00
Andrew Pimenov
d2ab0caafd refactor gather_vpn_signals to use VpnContext dataclass 2026-08-09 16:07:27 +03:00
Andrew Pimenov
5f51e70d5e extract BgpContext dataclass for build_bgp_intel 2026-08-09 16:06:55 +03:00
Andrew Pimenov
fd72604240 add --interface flag to force outbound probing through a specific adapter
Every probe used to follow whatever the OS default route picked, with no way
to point the tool at a specific adapter for comparison (VPN vs raw) or to
confirm which one actually carries traffic on a multi-adapter machine.

New iface.py resolves an adapter name or IP to a BindTarget (pure, tested):
exact/case-insensitive/unique-substring name match, rejects APIPA-only,
link-local-only and down adapters. Wired through every httpx provider client,
the Ookla binary tier, ndt7, and the whole ping/traceroute cascade (icmplib,
mtr, unix traceroute, TCP connect, scapy) plus --watch. Windows icmp_win now
uses IcmpSendEcho2Ex (adds SourceAddress) only when a bind is forced, so the
unforced path is unchanged. Windows tracert has no IPv4 source-address option
(verified from its own usage text) so that tier is dropped when forced,
noted in the report rather than silently measuring the wrong path.

An unresolvable/down adapter aborts with every adapter listed; a resolvable
adapter with no route to the internet degrades gracefully instead of
aborting - that's a real diagnostic answer, not an error. netinfo's
observation of the OS's actual default route stays untouched, so the report
can show the forced adapter and the OS default side by side.

Verified live: forcing Tailscale (no internet route on this box) triggered
the preflight warning and degraded correctly; forcing Ethernet ran clean
end-to-end including a full speedtest+MTR cycle.

Also noted, not fixed: probes/traceroute.py's icmplib tier imports
async_traceroute, which doesn't exist in icmplib 3.0.4 - that tier has
always raised ImportError and silently fallen through. Found while
verifying the icmplib source-binding wiring live.
2026-08-09 13:36:06 +03:00
Andrew Pimenov
51c01bd8c3 fix default gateway detection picking wrong route with multiple adapters
_default_gateway() took whichever 0.0.0.0 line route print printed first,
not the one Windows actually uses (lowest metric). With a VPN adapter
installed (Radmin VPN, Tailscale, ...) its default-ish route can print
before the real one. Verified live: was reporting Radmin VPN's 26.0.0.1
while Ethernet (the interface actually carrying traffic, confirmed via
primary_interface_ip()) has gateway 192.168.3.1; now reports that correctly.
Parsing extracted into pure _parse_windows_default_gateway(), tested against
a captured multi-adapter route print sample.
2026-08-09 13:00:24 +03:00
Andrew Pimenov
4888862305 fix false-positive sustained-loss verdict on long runs of silent hops
path_findings() flagged ICMP rate limiting as real loss whenever two
consecutive traceroute hops both went silent, but real transit paths
routinely have long runs of silent hops (10 in a row, confirmed on a live
--full run) while the destination itself answers cleanly. Only flag loss
that persists all the way to the last hop in the trace; a run that clears
before the end is now ignored regardless of how many hops it spans.
2026-08-09 13:00:19 +03:00
Andrew Pimenov
4ffc39906b add --format/--ru/--json flags to control which report artifacts get written
Every run used to write all three files (en.md, ru.md, json) unconditionally.
Default is now English Markdown only, sourced from output.formats in
config.yaml; --format/--ru/--json pick exactly what a run writes, and any
explicit --format replaces the default rather than adding to it (all/none
supported). write_report() moved from a fixed 3-positional-arg signature to
a {format: text} mapping so writes are conditional instead of always-three.
The en/ru Markdown cross-link header is now only set when both languages are
actually being written.
2026-08-09 13:00:13 +03:00
Andrew Pimenov
483989c1bc rename package netcheck to netsleuth (name taken on pypi) 2026-08-09 11:43:00 +03:00
Andrew Pimenov
168cd14f51 ip_geo: russian dual-stack mismatch note alongside english 2026-08-09 11:27:20 +03:00
Andrew Pimenov
2e84c434c0 exporter: translate module skip/warning reasons into russian 2026-08-09 11:11:08 +03:00
Andrew Pimenov
d53ab9a0d6 exporter: render russian markdown report alongside english
Thread a lang parameter through render_markdown and every section
helper so the same report dict can render an English or Russian
report; inline _t() calls carry the strings, findings fall back from
_ru fields to their English siblings. write_report now emits a third
.ru.md file alongside .json and .md, and render_markdown can stamp a
sibling cross-link line right after the H1.
2026-08-09 11:06:24 +03:00
Andrew Pimenov
4c2da2e831 dns_leak: russian note alongside english 2026-08-09 04:10:44 +03:00
Andrew Pimenov
9e5ea923aa reputation: russian rationale alongside english 2026-08-09 04:10:08 +03:00
Andrew Pimenov
db407595d6 interpret: russian title/detail/advice alongside english findings 2026-08-09 04:09:01 +03:00