macOS: port native CLAT DNS-target fallback to master

This commit is contained in:
Dev Scribe authored and Cuong Manh Le committed 2026-09-25 13:20:27 +07:00
1 parent 6e66ea82b4
commit 55190faaee
24 files changed
+2311 -35

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
# IPv6-only DNS-target validation
Relates to #617. Native CLAT/PF behavior is not proven by parser tests or cross-compilation. This change must not disable IPv6 DNS enforcement, change PF routing, or reclassify every failed DHCP command as empty DNS.
## Regression gates
- Ordinary static IPv4 DNS and successful DHCPv4 discovery retain their existing behavior.
- An explicit non-owned IPv6 loopback resolver (`::1`), alone or mixed with other static DNS, prevents the expanded fallback. Its settings and backup must remain unchanged through reconciliation and cleanup.
- The target-specific DHCP lookup shares a two-second deadline across both commands, with a 100 ms pipe-cleanup grace. Timeout remains an error, not confirmed absence. This does not impose a deadline on legacy global discovery or every operation under the target lock.
- An unknown, truncated, malformed, timed-out or permission-denied native-state read authorizes no new DNS mutation.
- A CLAT-looking address alone is insufficient. Positive native publication must match the current default interface/service, with no contradictory native IPv4 state.
- Confirmed IPv6-only state can reach the existing listener-aware target installation path despite unavailable DHCPv4 data.
- Repeated reconciliation is idempotent. Existing targets, external DNS changes, default-service switches, DHCP return and restart/stop cleanup preserve ownership.
- A failed preservation snapshot cannot authorize the new fallback write.
- Logs distinguish configured IPv6 blocking, observed rule counters, missing evidence, counter resets and successful local receipt. Shared counters cannot identify which packet was blocked.
- Diagnostics are bounded, omit raw PF dumps/query names and do not cause DNS/PF changes or repeated repair actions.
## Native comparison
Use an owned disposable Mac with a local console, an identified baseline/candidate and the same profile/listener. Save exact original DNS settings. Do not run host-mutating tests on shared CI hosts; native unit tests must intercept the first mutation boundary.
1. Verify a healthy baseline on ordinary IPv4/DHCP, then establish actual host-side CLAT using an owned hotspot or isolated NAT64/PREF64 fixture. Record the interface/service mapping, native state, routes, static DNS, raw scutil DNS and both DHCP commands' exit/output. A carrier label or synthetic address assignment is not a fixture.
2. Confirm upstream and direct-listener resolution independently. Keep a pre-existing manual loopback DNS override from masking the target decision, without deleting unrelated configuration.
3. Compare startup already attached, disconnected startup followed by attachment, and a same-process transition to the IPv6-only network. Test sleep/wake separately and exclude intentionally offline/sleep periods from recovery measurements.
4. On the candidate, require the appropriate temporary target and fresh system-resolution success while still on CLAT. Record any independent PF-probe failure rather than treating working system DNS as proof of repaired transparent interception.
5. Return to IPv4/DHCP; verify target removal/restoration. Repeat with explicit static DNS, an existing tracked target, external DNS changes and an injected unknown/read-error state. Stop/uninstall must not leave DNS pointing to a dead listener.
6. Read the retained diagnostics after a failed probe and after restored receipt. Distinguish missing rules/read errors from a present IPv6 block with cumulative traffic counters. A reload or rising shared counter does not prove a particular probe's fate.
Preserve captures privately and record the exact artifact. A successful owned-lab case supports the scoped fix; a customer retest remains a separate validation gate.
+38
View File
@@ -254,6 +254,44 @@ A probe-triggered reload does not count as a missing-anchor repair.
See [PF DNS interception](pf-dns-intercept.md) and [DNS intercept mode](dns-intercept-mode.md) for the rule lifecycle.
## IPv6-only target fallback and PF diagnostics
On macOS, a failed DHCPv4 read remains unknown unless configd positively publishes
CLAT for the current primary service/interface and the live interface addresses
agree. A CLAT-looking address alone is insufficient. Unknown or unsupported native
state leaves DNS unchanged. The fallback reuses the existing listener-aware target
and cleanup paths; it does not change PF enforcement or treat every command error
as empty DNS. Native output compatibility and the real hotspot scenario require
[owned-Mac validation](ipv6-only-dns-target-qa.md).
`DNS intercept IPv6 block diagnostic` is a change-only debug event after unsuccessful
probes and their first restored receipt. It reads only the ctrld anchor using
`pfctl -a com.controld.ctrld -vvsr`, at most once per minute. The command has a
500 ms deadline and a 64 KiB output cap. A restored receipt inside the interval can
refer to the cached capture; `capture_cached`, `capture_age_ms` and
`capture_generation` make this explicit. Collection is synchronous before the
caller can repair: the 500 ms bound covers the command, not its pipe-cleanup grace
or the subsequent kernel route/interface reads.
`pf_read_status` distinguishes unavailable/failed/unrecognized data from recognized
rules and counters. `ipv6_dns_udp_rule_observed` and its TCP equivalent mean the
exact generated rule was observed, not that it received the probe. A missing rule
match does not prove that no other IPv6 blocking exists. Packet fields are emitted
only when their counters are known. Delta status is `unknown`, `reset` or
`shared_traffic`; decreases are never reported as negative packet counts.
Counters include all matching traffic, not just the probe, and unobserved reloads
can reset them between captures. A counter increase does not establish that CLAT
translated or PF blocked a particular packet. The event names the probe transport,
resolver target/family, recovery generation and default-route interfaces.
`clat_address_present` is an address hint, not the positive native evidence used to
authorize DNS changes. Raw rules, customer query names and interface-address lists
are not included.
These debug events do not guarantee journal retention. !1020 separately handles
retained DNS-target decision failures. Reload completion, a configured block rule,
and successful local probe receipt remain distinct observations.
## Reproduction boundaries
Compare the affected release with the exact candidate artifact on an owned host.