VPN 地址与 LAN 的 DHCP 租约:隧道的 IP 由谁分配
VPN 客户端显示的地址从不出现在 LAN 的租约文件里。读取客户端、IKEv2 配置载荷和网关地址池,找出真正的分配者。
连接客户端后,看网卡而不是 Wi-Fi 图标。像 10.80.0.14 这样的地址可能存在于隧道上,而办公 LAN 中没有任何 DHCP 服务器记录过这条租约。究竟是哪个进程挑了这个号码,决定了排查该从哪里开始。
在客户端上,一切都长得一样:一个 IPv4 地址、一个掩码,有时还有默认网关。只有当你追问这个地址由谁应答、由谁留存记录时,差别才会显现。
从客户端一侧读取隧道地址
读整个代码块而不是第一行,Windows 就会显出区别。ipconfig /all 会输出网卡描述、物理地址和一行 DHCP 信息。PPP 或 IKEv2 拨号适配器通常报告 DHCP 已禁用,因为连接是在拨号过程中协商地址的,而不是从 LAN 服务器租用。启用 DHCP 的隧道适配器并不常见,值得单独查一查。
Linux 把同样的信息拆到两个工具里。ip -4 addr show dev tun0 给出地址和前缀长度。nmcli -f IP4 connection show work 揭示这个值来自连接配置文件、链路层上的 DHCP 交换,还是被推送的配置。WireGuard 是最清楚的例子:接口出现时 wg-quick 会应用配置文件中的 Address 行,连接时没有任何对端参与分配。
前缀也能说明问题。/32,或者 255.255.255.255 的掩码,意味着网关期望路由到单一主机地址;而更宽的掩码则暗示隧道后面某处存在链路内子网。
IKEv2 配置载荷携带什么
IKEv2 为这项工作准备了专门机制。RFC 7296 第 3.15.1 节所述的配置载荷会携带 INTERNAL_IP4_ADDRESS、INTERNAL_IP4_NETMASK、INTERNAL_IP4_DNS 以及对应的 IPv6 属性。客户端没有偏好时发送长度为零的属性,响应方则返回希望使用的值。这次交换在已经加密的 IKE_AUTH 内完成,因此 DHCP 广播永远不会穿过隧道。
由此得出两个结论。第一,地址由响应方或它咨询的任一授权后端选定,这正是地址池可以放在网关、RADIUS 应答或身份提供方的映射里的原因。第二,DNS 属性与地址属性相互独立。收到 10.80.0.14 并不能说明返回了哪个解析器,甚至不能说明是否有解析器返回。
网络掩码属性在实践中是可选的。很多部署只返回地址,让客户端自行安装主机路由,因此同一个池在一个客户端上看起来像 /32,在另一个客户端上却像 /24。
LAN 的 DHCP 作用域与 VPN 池在哪里相撞
麻烦始于两个分配者指向同一网段。为 10.20.30.0/24 服务的 DHCP 服务器完全不知道为 10.20.30.128/25 配置的 VPN 池,因此当网关把同一地址交给远程客户端时,没有任何东西阻止它把 10.20.30.140 租给一台打印机。冲突会静默数日,然后以偶发重复的形式暴露出来。
路由式的站点到站点设计从结构上就避开了冲突。分支机构的计算机会保留本地 DHCP 服务器给它的地址。两个网关上的隧道接口各自携带链路地址,路由表决定数据包怎么走。远程访问客户端的地址属于第三类,不应与网关的链路地址混在一起。
把隧道桥接到 LAN 就消除了这种分离。如果设计确实需要单一广播域,VPN 端点就必须参与和 DHCP 服务器相同的分配决策,例如通过中继或共享的权威来源,而不是自己直接发放地址。
验证地址归哪个进程所有
改动作用域之前先证明归属。在客户端记下地址和前缀。在 LAN 上检索租约数据库。在网关上列出它被配置来发放的地址池。在租约文件里查到的地址属于 DHCP 服务器,说明隧道是被桥接或中继的;只在网关地址池里查到的地址属于隧道端点。
# client: address and prefix on the tunnel interface
ip -4 addr show dev tun0
# LAN DHCP server: is this address leased to anyone?
grep -c '10.80.0.14' /var/lib/dhcp/dhcpd.leases
# gateway: pools that remote-access clients draw from
sudo swanctl --list-pools
答案清楚后记下四件事:哪个组件分配客户端地址、为它保留了哪个网段、回程流量如何到达该网段、哪些资源接受它。这四项就能把一行虚拟网卡信息变成可运维的事实。
顺便把 DNS 属性的检查也重做一遍。只发地址不给解析器的池,会让客户端继续用自己的本地 DNS,这与发放了 LAN 已在使用的地址的池是两种不同的故障。