What changed: the DNS layer was the real work. PolicyResolver hooks
reqwest’s own resolver, so every address in the OS answer is validated and
reqwest only ever dials the validated set. That closes the classic
check-then-resolve-again hole — there is no second resolution to race (no
TOCTOU). One private address in the answer fails the whole thing:
round-robin DNS makes “usually public” no defense. Redirects are now
followed — up to 5 hops, each revalidated through the same policy — because a
redirect is a target the target chose. A refused or looping hop leaves the
last 3xx as http_fail evidence. And a DNS refusal classifies
rejected_local via a cause-chain walk, not an ambiguous connect.
Proof — live: http://localhost:… registers fine (it looks like a name),
then every probe lands transport + rejected_local — the refusal is
committed evidence, not a silent skip. A redirect chain → pass, a loop →
http_fail/302. Unit-side: the is_local range matrix including v4-mapped
v6, mixed-answer validate_addrs, and a real localhost refusal.