VPN 内的 mDNS:为什么 .local 名称无法解析
路由型 VPN 承载单播数据包,而不是链路本地组播。检查哪些名称能解析、查询为何从未到达,以及哪种命名设计真正可行。
办公室的打印机在桌面的每个应用里都能看到,一连上 VPN 就消失了,尽管你能 ping 通你知道它拥有的地址。隧道里没有任何东西坏掉:发现和可达性是两项不同的服务,默认情况下只有一项能穿过路由型隧道。下面的检查会先把两者分开,然后再去添加路由。路由救不了一个从未离开链路的查询。
先分清今天什么能解析,什么只是看起来解析了
先把两个问题分开:针对主机名的单播查询问的是解析器,而对 _ipp._tcp 的浏览问的是本地链路。在 Linux 上,avahi-browse -a 显示组播 DNS 能看到什么,resolvectl query name.local 显示解析器栈如何处理这个名字。在 macOS 上,dns-sd -B _ipp._tcp 无需先有地址即可列出已发现的服务。
如果地址有回应而名字没有,说明路由正常、发现不正常。即使没有安装 avahi-browse,.local 名称也能通过 nss-mdns 在主机本身上得到应答,所以对该名字成功的 getent 或 ping 并不能证明发现穿过了隧道;浏览结果和解析器结果是两类不同的证据。应用会缓存发现到的内容,这就是故障常常在连接数小时后而非连接时出现的原因。退出并重新打开应用,然后检查缓存条目里存的是名称还是地址,因为发现停止很久之后地址仍然可用。
为什么查询从未穿过隧道
组播 DNS 把查询发往 224.0.0.251,位于本地网络控制块内,使用 UDP 端口 5353。路由器不转发该地址块的地址,因此查询停留在被发送的那条链路上。发送方还会把 IP TTL 或 IPv6 跳数限制设为 255,以便接收方拒绝已经过路由器的数据包;协议正是借此发现链路外的伪造,而不是靠它保持本地。本地性来自目的地址,而不是来自一跳的 TTL。
隧道类型同样重要。tun 风格的接口只承载 IP 数据包,别的什么都不承载,因此没有任何组播组能穿过去。tap 风格的网桥扩展的是广播域本身,这就是为什么一些旧设计选择桥接而不是路由,并继承了桥接带来的所有问题。
可信 LAN 例外不会改变这一切,因为它决定的是哪些流量可以使用隧道,而不是教隧道转发组播。数据包依然没有可供被听见的共享网段。
选择你维护得起的命名设计
对公司资源而言,持久的答案是 VPN 推送的解析器所服务的路由型主机名,并配合 拆分 DNS,让内部名称走内部服务器,其余名称不走。Windows 把它呈现为名称解析策略表,macOS 使用按接口划分作用域的解析器,大多数客户端都有等效的推送设置。设备在内部 DNS 中保留常规名称,发现不再是路径的一部分。
发现代理或 mDNS 反射器可以弥合这一缺口,这是一种真正的设计,有自己的主机、自己的暴露面和自己对客户端的要求。它不会因为你加了路由就出现。绝不要把 .local 查询转发给公共解析器:该域被 RFC 6762 保留给本地组播使用,向外发送只会带来缓慢失败和不必要的数据暴露。
验证服务,而不是名称
浏览列表里出现名称,只能证明发现这一步,不能证明服务有应答。打开打印队列或 Web 界面,完成一次真实操作,然后在重连后再重复一次。
发现会激进地缓存名称,所以过期条目看起来可能像成功。如果出现证书或身份验证提示,那是下一层,属于另一个问题。记下你改的是哪个机制,解析器还是发现,这样下一个人就不必把整个问题重开一遍。