mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-10-12 01:58:46 +02:00
macOS: port native CLAT DNS-target fallback to master
This commit is contained in:
1 parent
6e66ea82b4
commit
55190faaee
24 files changed
+2311
-35
No files matched your search
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user