OpenVPN 客户端彼此看不见:subnet 还是 net30?
客户端能到达服务器,却到不了彼此。用一次 ping 分开故障,再选择 subnet 拓扑、client-to-client 或桥接的 TAP 网段。
两个互不相关的故障会产生同一种抱怨。第一种情况下,某个客户端连隧道地址都到不了另一个客户端,因为地址不在同一个 subnet,或者服务器不转发对端之间的流量。第二种情况下 ping 通,但应用里的设备列表始终为空,因为发现依赖广播,而 3 层隧道运不了广播。一次 ping 就能把两者分开,而两者的修法毫不相似。
一次 ping 把问题一分为二
从一个客户端去 ping 另一个客户端的隧道地址,不是名字,也不是它的 LAN 地址。如果失败,问题在转发或地址规划上,修好之前发现无从谈起。如果成功,转发已经正常,剩下的缺口是广播或名字解析。
ip addr show tun0
先读客户端接口,因为掩码就说明了拓扑。/24 或其他子网掩码意味着共享地址池;带对端地址的 /30 意味着旧的点对点布局,每个客户端只有一个邻居,就是服务器。
net30 与 subnet,从客户端一侧读
| What you observe | net30 | subnet |
|---|---|---|
| Client netmask | /30 with a peer address | The pool's own mask |
| Peers a client can address directly | One, the server | Every client in the pool |
| Addressing | One /30 block per client, with the server as the only peer | One pool mask shared by all clients |
| Effect of client-to-client | Required for any peer traffic | Required for peer traffic, still no broadcast |
在 net30 下,服务器给 每个客户端一小块地址,所以除非服务器转发,通往另一个客户端隧道地址的路由并不存在。在 subnet 下整个地址池是一个网络,每个客户端都能访问其他任何一个,服务器在它们之间转发。这就是为什么服务器配置看起来健康、而对端之间 ping 却失败:没有任何东西坏掉,客户端只是不在同一个网络里。客户端看到一条可用的链路和一个不应答的对端地址,读起来像防火墙,实际是地址布局。
切换指令是服务器端的修改加重启,而且只对下一次连接生效,不影响已经建立的会话。判断改动之前先重连客户端。如果设备会从 Web 界面重新生成配置,就记下指令、文件和日期;有界面时通过界面修改,否则下一次保存重建配置会覆盖手工修改。
client-to-client 是另一道门
即使在同一个 subnet 内,只要没有设置 client-to-client,服务器就会丢弃从一个客户端来、发往另一个客户端的数据包。这个关键字把服务器变成对端流量的转发者,而不只是被动接受它的终点。这是修好拓扑之后人们常漏掉的第二个条件。
这一点并不延伸到广播。该设置只在客户端之间转发单播;它不会把隧道变成共享网段,无论怎么设置都不会把组播发现查询送到每个对端。
TUN 与 TAP,各自能承载什么
| Property | TUN | TAP |
|---|---|---|
| Layer | Layer 3, IP packets | Layer 2, Ethernet frames |
| Broadcast and multicast | Not carried | Carried |
| Bridging to the LAN | Not applicable | Required for a shared segment |
| Client platform support | Everywhere | Missing on Android and iOS, limited on macOS |
把 tap 设备桥接进 LAN,会让远程客户端进入办公室的广播域,从而彻底解决发现问题。代价是不实现 TAP 的平台、服务器上必须存在的网桥,以及一个故障域:办公室线上的广播风暴会打到每台远程笔记本。
对两三台需要名字解析的工作站来说,加一条 hosts 记录或一个单播地址,比网桥便宜得多。只有当无法替换的协议依赖 2 层发现时,才该动用 TAP,而不是更早。
没有网桥的同 subnet 客户端
从 LAN 网段分配地址并不会把客户端放到线上。服务器在隧道和以太网之间路由,所以该地址的 ARP 停在服务器接口上,LAN 的其余部分永远不知道它住在哪里。
ip neigh add proxy 10.50.1.250 dev eth0
Proxy ARP 补上这个缺口,让服务器替客户端应答。对一段地址,parpd 会随客户端来去管理条目;而 sysctl net.ipv4.conf.eth0.proxy_arp=1 为所有走到别处的流量应答,范围宽到足以在繁忙网段上制造自己的意外。
无论选哪条路,都要把隧道与线缆之间的 NAT 去掉。MASQUERADE 规则恰好掩盖了你正要回答的地址问题。它还会给下一个人留下一个从客户端一侧无法推演的拓扑。
动手之前,先在服务器上用 tcpdump -ni tun0 抓一次尝试,确认对端的数据包到底有没有到达。到达后被丢弃指向 client-to-client;从不到达指向拓扑或路由。OpenVPN 2.6 手册记录了两个关键字和默认拓扑,值得在照抄论坛帖子的一行之前先和自己的版本核对。
- tun 接口显示的是地址池掩码,而不是 /30 对端对。
- 在测试发现之前,直接 ping 另一个隧道地址应当成功。
- 只要对端需要交换数据包,服务器配置里就应包含
client-to-client。 - 请说出你正在测试的发现协议,而不是笼统地说应用失败。
- 只有当组里每个客户端平台都支持时才用 TAP。
- 同一 subnet 内可达性重要时,不要让 NAT 落在隧道与 LAN 之间。