Hotdry.
systems

macOS 26 私有域名解析失效:/etc/resolver 机制断裂与工程应对

分析 macOS 26 移除本地 DNS 解析策略导致的 .internal 等私有域名解析失败问题,提供临时修复方案与工程启示。

2026 年 3 月 macOS 26.3.1 版本推送后,大量开发者和运维人员发现本地 DNS 解析机制出现异常:原本通过 /etc/resolver/ 目录配置的私有域名(如 .internal.test.home.arpa)无法正常解析,导致本地开发环境、容器网络、Kubernetes 集群域名等场景受到直接影响。这一问题的根源在于 macOS 26 对 DNS 解析流程进行了底层改动,mDNSResponder 进程不再为非 IANA 顶级域名的自定义 TLD 查询调用 /etc/resolver/ 中配置的 unicast DNS 服务器,而是直接将其作为 mDNS(多播 DNS)处理并返回空结果。本文将深入分析该问题的技术细节、影响范围,并给出可行的工程应对方案。

问题现象与复现步骤

在 macOS 26 之前的版本中,开发者可以通过在 /etc/resolver/ 目录下创建以 TLD 命名的配置文件来指定特定的 DNS 解析服务器。例如,配置 nameserver 127.0.0.1 到文件 /etc/resolver/internal 中,可以让系统将所有 *.internal 域名的查询发送至本地运行的 dnsmasq 或其他 DNS 解析服务。这一机制被广泛用于本地开发、测试环境隔离以及私有网络域名解析。macOS 26 发布后,这一机制出现了静默断裂:配置文件依然存在,系统工具 scutil --dns 也能正确显示解析器注册信息,但实际进行域名查询时,查询请求从未被发送至配置的 DNS 服务器。

具体的复现步骤相对标准:首先启动一个本地 DNS 服务(如 Homebrew 安装的 dnsmasq),并配置其响应特定私有域名的查询请求;随后创建对应的 /etc/resolver/ 配置文件并刷新 DNS 缓存;接着使用系统级的解析接口(如 ping、Python 的 socket.getaddrinfo 或 curl)尝试访问该私有域名;最后观察解析是否成功。在 macOS 26 环境中,这些系统级解析调用会返回 “Unknown host” 错误,而直接使用 dig @127.0.0.1 指定 DNS 服务器的查询则能正常工作。这说明问题并非出在 DNS 服务器本身,而是系统级的解析路径出现了变化。

通过 dns-sd -G v4 工具可以观察到,mDNSResponder 对这些私有域名返回的是 "No Such Record" 类型的 mDNS 响应,并且 TTL 被设置为异常的大值(约 108000 秒),这表明 mDNSResponder 将这些查询当作本地多播域名处理,而非通过 unicast DNS 转发。使用 tcpdump 在回环接口监控 53 端口可以进一步确认:在执行系统级域名查询时,没有任何 UDP 数据包被发送至 /etc/resolver/ 中配置的 DNS 服务器,整个解析过程在 mDNSResponder 内部完成。

技术根源分析

理解这一问题的技术本质需要回顾 macOS DNS 解析架构的发展。mDNSResponder 是 macOS 的核心 DNS 解析进程,它同时负责传统 unicast DNS 查询、mDNS(Bonjour/multicast DNS)查询以及系统 DNS 缓存管理。在 macOS 26 之前,mDNSResponder 会检查 /etc/resolver/ 目录下的配置文件,当收到针对特定后缀的查询时,将请求发送至对应文件中指定的 DNS 服务器。这种设计允许用户在本地运行 dnsmasq 等服务来处理私有域名,而不必修改系统级的 DNS 服务器配置。

macOS 26 对这一行为进行了修改。其变更的核心逻辑是:对于不在 IANA 根区域数据(root zone)中的顶级域名,mDNSResponder 现在优先将其视为 mDNS 特殊域名处理,而非通过 unicast DNS 转发。这一变更的表面理由可能是加强 DNS 安全、避免私有域名与公共域名冲突,但在实际效果上,它破坏了自 macOS 10.6 以来长期存在的 /etc/resolver/ 机制。值得注意的是,受影响的不仅仅是 RFC 6761 明确保留的特殊用途域名(如 .test.localhost.invalid.example),还包括 .internal(IETF 草案中的特殊用途 TLD)、.home.arpa(RFC 8375 规定)以及完全自定义的任意 TLD(如 .lan.emflocal)。

从网络协议的角度看,这种行为变更违背了 RFC 6761 对 .test 域名的明确规定。该标准在第 6.2 节中指出,.test 域名被保留用于本地测试,解析器应当通过常规 DNS 机制进行解析,而非将其视为 mDNS 独占域名。macOS 26 的实现显然与这一标准存在冲突。更关键的是,问题的影响是静默的:用户通过 scutil --dns 依然可以看到解析器配置正确,没有任何错误日志或警告提示,导致问题排查极具迷惑性。

受影响场景与工程冲击

该问题的工程影响范围远超普通用户的预期。在现代软件开发流程中,私有域名解析是基础设施的核心组成部分。首当其冲的是使用 dnsmasq 搭建本地开发环境的开发者群体,他们在 /etc/resolver/ 中配置 .test.local 域名用于本地 Web 应用开发,macOS 26 升级后这些开发环境集体失效。Docker Desktop、Colima 等容器运行时在 macOS 上经常通过创建 /etc/resolver/ 条目来实现容器名称解析,该变更导致容器间服务发现无法正常工作。Kubernetes 本地开发工具(如 minikube、kind、k3d)普遍使用 *.cluster.local 等私有域名,同样受到严重影响。

企业环境中的影响更为复杂。许多组织使用 .internal.corp 等私有 TLD 构建内部网络,依赖 /etc/resolver/ 将这些域名解析指向内网 DNS 服务器。macOS 26 升级后,员工 Mac 设备无法解析内部业务系统域名,虽然 IT 部门可能通过 MDM 配置网络 profile 来补救,但这一变更仍然造成了大量临时性服务中断。VPN 客户端、Tailscale、ControlD 等网络工具也经常在 /etc/resolver/ 中写入配置以实现域名分流,升级后的行为变更同样影响了这些工具的正常运行。

临时修复方案

面对这一架构层面的变更,开发者和技术团队需要采取多层次的应对策略。最直接的临时方案是在 /etc/hosts 文件中手动添加静态域名映射,这种方式可以完全绕过 mDNSResponder 的 DNS 解析流程,直接由系统内核的 hosts 文件机制处理。然而,该方案对于动态变化频繁的场景(如 Docker 容器 IP 频繁变动)极不友好,每次 IP 变更都需要手动更新并使用 sudo 权限,在团队协作环境中更是难以维护。

更具工程化意义的方案是将私有域名迁移到真实公共域名的子域名下。例如,不使用 *.internal,而是使用 *.internal.example.com,其中 example.com 为团队拥有的真实域名。这样 /etc/resolver/example.com 配置文件指向内网 DNS 服务器即可正常工作,因为 .com 是标准的 IANA 顶级域名,mDNSResponder 会将其交给 unicast DNS 处理。这一方案需要 DNS 基础设施的配合(需要在内网 DNS 上配置对应的委派或转发规则),但从长期可维护性角度是较为稳健的选择。

对于依赖网络 profile 的企业环境,可以考虑通过 MDM 或手动安装 .mobileconfig 配置文件来定义搜索域名和 DNS 服务器。部分用户报告称,在升级前预先安装的自定义 DNS profile 在 macOS 26 上仍能正常工作,但升级后新建的 profile 可能遭遇与 /etc/resolver/ 相同的问题。如果 VPN 或 Tailscale 等工具在系统中运行,建议首先排查这些工具是否覆盖了自定义 DNS 配置,临时禁用有时可以帮助定位问题是否由第三方软件引起。

工程启示与长期建议

从软件工程的角度审视这一变更,有几个关键教训值得汲取。首先,系统级的基础设施假设需要版本化管理和回归测试。/etc/resolver/ 机制作为 macOS 的长期特性,被大量工具链视为稳定的运行前提,Apple 在引入破坏性变更时应当通过 release note、开发者文档或迁移指南给出充分预警,而非静默推送。其次,DNS 解析层面的行为变更缺乏有效的诊断工具,用户只能依赖排除法逐步定位问题,期望未来能够提供更透明的 mDNSResponder 行为日志或系统级的诊断接口。

对于技术团队而言,建议在文档中明确标注关键 macOS 版本号与 DNS 配置方案的兼容关系,并建立版本升级后的基础设施验证清单。对于持续集成环境中的 macOS 虚拟机或 CI runner,需要特别关注 DNS 解析是否正常工作,避免因基础环境变更导致构建失败。在可能的范围内,推动使用标准公共域名子域名的方案,可以从根本上规避这类系统层面的隐性风险。


参考资料

查看归档