Files
offscale-mobile/modules/officer-net/gocore
pastilhasandClaude Opus 5 a8e9dd712c fix(dns): iOS never matched the domains control overrides
Reported from an iPad on 2026-08-18: officer.pertento.ai, gitea.pertento.ai and
*.edge.pertento.ai all failed with "couldn't establish a secure connection", while
desktop clients on the same tailnet reached them with a valid certificate.

The provider DID apply dnsSettings — it just scoped them to the MagicDNS suffix
alone. Everything Headscale overrides lives under an unrelated domain: dns.extra_records
serves an A record for a name like officer.pertento.ai, and dns.nameservers.split
gives one domain its own resolver. Neither is under the tailnet suffix, so iOS never
sent those queries to us. The device asked public DNS instead and got the public
answer — which for these names is a TAILNET address belonging to a DIFFERENT machine
(100.64.0.4 rather than the bridge at 100.64.0.12). TLS then failed against a host
holding no certificate for that name, which is exactly what Safari reported.

Nothing was missing from the server: CorpDNS is true, so the netmap already carried
the split routes and the extra records. The data simply had no way across to Swift.

So Go gains DNSMatchDomains(), returning the split-DNS route keys, the tailnet search
domains, and the PARENT zone of each extra record — the parent because a record is a
host, and one entry then covers its siblings without the device being told about each
one. Swift builds matchDomains from the suffix plus those, and remembers them exactly
as it remembers the suffix, because the fast path applies settings before any netmap
exists and would otherwise reintroduce this bug on every reconnect. Forgotten with the
suffix when the profile changes: those domains belong to the tailnet that sent them.

Deliberately NOT the catch-all [""], which the COMMS note suggested as an option. That
is already in this file and reserved for exit-node mode. Off an exit node it would put
every lookup on the phone through a resolver that cannot always forward — the failure
Android hit, and worse than this one: a broken tailnet name is an app that will not
load, a broken everything is a phone with no internet.

Android needs no change: it has no matchDomains equivalent and already routes all DNS
at the core.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 05:53:27 +01:00
..