为什么在路由型 OpenVPN 隧道里按名字查找会失败
路由型 TUN 隧道只承载单播 IP,因此广播式名字查询从来没有进入它的路由。桥接消除边界,推送 DNS 才是更便宜的修法。
一台主机能按地址回应 ping,却按名字查找全部失败。隧道是通的、路由也存在,于是很自然得出结论:VPN 配置错了。更有用的结论是:那次查找本来就不可路由——路由型隧道只承载单播 IP,而该查询是广播,在寻找对端并不存在的网段。一旦看清这个层次错配,各种修法自己就按成本排好了序。
误解:名字失败就说明隧道坏了
症状之所以有说服力,是因为名字层以上的东西全都正常。地址有路由、接口是通的、对端能回 ping。失败的是一种发现机制,它从来没有跨越点对点链路的路由;这和说隧道坏了是两句不同的话。把这两句话分开,诊断就完成了一大半。
把它当作隧道故障,只会得到帮不上忙的配置改动。加选项、换加密、重装客户端,广播依旧停在原处。
先说清失效的是哪种机制,再说修法。用广播的查找需要网段,用解析器的查找需要一个可以问的地址。
TUN 承载什么、不承载什么
TUN 设备是一个 IP 接口,正因如此它才可路由。OpenVPN 交给客户端一个地址和一组路由,此后客户端把数据报发给对端。这个模型里没有任何东西造出一条让每个主机都能听到每一帧的共享链路。
发现流量完全不适配这个模型。较早的 Windows 名字查询、SSDP 通告和 mDNS 请求是发给网段内所有主机的,而不是发给某一个目的地。路由型链路没有所有主机可以发。这几种机制都预设了一个共享介质。
所以隧道可以完全健康,而发现彻底失败。当有人说 VPN 挂了时,该抓住的正是这句话。
桥接靠消除边界起作用
TAP 设备承载帧,桥把它接到真实的 LAN 网段上。客户端于是拥有该网段的地址,也能听到它的广播流量。桥接看起来治好了名字问题,原因就在这里。它同时也让客户端的地址配置依赖那个网段。
真正的疗法是消除路由边界,而不是在隧道里新增某种名字能力。网段广播的东西现在也一并跨越了链路。
对小型实验室来说这是公平的交换。对分散的团队则很少如此。
推送 DNS 与 WINS 是更窄的修法
给客户端一个明确可问的地方。dhcp-option DNS 和 dhcp-option DOMAIN 把内部名字指向认识该区域的服务器;仍依赖 NetBIOS 的 Windows 客户端也可以用同样方式拿到 WINS 服务器。隧道保持路由型,网段留在它该在的地方。
有两点决定这样做是否可行。被指定的服务器必须对该区域作出应答,查询也必须被允许穿过隧道。
从客户端而不是从服务器自己的 shell 去测解析器。本地能用的解析器,说明不了隧道里跑的是什么。
查清是哪一层失败
先 ping 地址,再解析名字,并读出是哪个服务器应答的。不托管该区域的服务器给出的否定应答,和根本没离开本机的查询看起来不一样。名字能解析却拒绝连接,完全是第三种问题。
组播挡在同一堵墙后面。像 224.0.0.251 这样的组默认不会被转发进路由型隧道,而只有一条到该组的路由还不够,还需要懂组播的路径或 LAN 上的反射器。