一次曲折的 SoftEther VPN 调试之旅:从无法获取 IP 到路由迷踪
写在前面
最近在折腾家庭内网穿透,方案选定了在 OpenWrt 软路由上部署 SoftEther VPN Server。目标很简单:出门在外时,能像在家里一样,安全地访问内网的所有设备(192.168.xxx.0/24 网段)。
我的网络环境不算复杂但也略有特色:PVE 虚拟化环境,其中一台 OpenWrt 作为主路由,网口直通,负责拨号和 DHCP 服务。SoftEther Server 就安装在这台 OpenWrt 上。
一切似乎都很顺利,直到客户端拨号成功的那一刻——连接状态显示正常,但虚拟网卡就是拿不到期望的内网 IP 地址,只有一个 169.254.x.x 的自动分配地址。这通常意味着一件事:DHCP 请求失败了。
一场横跨多个技术层面的调试就此拉开序幕。
第一章:DHCP 请求的“黑洞”
最初的症状非常明确:客户端无法获取 IP。SoftEther 我配置的是“本地桥接”模式,理论上 VPN 客户端应该像一个物理设备一样被接入了我的局域网交换机,DHCP 请求理应能被 OpenWrt 的 DHCP 服务收到。
我的第一反应是:是不是 OpenWrt 的防火墙把 DHCP 的广播包给拦了?
为了验证这一点,我祭出了网络调试的瑞士军刀——tcpdump。通过 SSH 登录到 OpenWrt,我执行了以下命令,专门监听 br-lan 接口上的 DHCP 流量(端口 67 和 68):
1 | # 在 OpenWrt 上执行 |
让 VPN 客户端重新连接后,tcpdump 的输出给了我第一个决定性的线索:
1 | 16:17:38.509738 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from xx:3b:xx:xx:eb:05, length 300 |
分析:
br-lan接口上确实看到了来自 VPN 客户端虚拟 MAC 地址(xx:3b:xx:xx:eb:05)的 DHCP 请求广播包。- 但是,输出中完全没有看到来自我的 DHCP 服务器(
192.168.xxx.254)的任何响应包(Offer或ACK)。
这个发现意义重大。它排除了 SoftEther 本地桥接本身的问题,也排除了 VPN 客户端到 OpenWrt 之间的网络问题。数据包已经成功到达了局域网的“大门口”。问题变成了:为什么门口的 DHCP 服务员(dnsmasq)不理它?
第二章:沉默的 DHCP 服务器
既然 DHCP 包到了,但服务没响应,那么嫌疑人就转移到了 DHCP 服务器本身——在 OpenWrt 中,它是由 dnsmasq 进程负责的。
一个服务不响应,排查的第一步永远是:它到底还活着吗?
我通过 logread 命令来查看 dnsmasq 的系统日志:
1 | logread | grep dnsmasq |
结果令人震惊,也让整个调试豁然开朗:
1 | daemon.crit dnsmasq[1]: cannot read /tmp/dnsmasq.d/dnsmasq-ssrplus.d/gfw_list.conf... |
**真相??**:我的 DHCP 服务器根本就没在运行!它在启动时,因为一个名为 ssrplus 的第三方插件配置出错(试图读取一个不存在的文件),导致整个进程直接崩溃退出了。
一个“死掉”的服务自然不会响应任何请求。这就是 DHCP 请求石沉大海的根本原因。
后续的分析发现,这是一个典型的“时序问题”。有时 ssrplus 插件的后台进程会晚于 dnsmasq 的启动,导致 dnsmasq 启动时找不到由 ssrplus 生成的配置文件。而在我手动排查的过程中,ssrplus 可能已经完成了它的工作,当我再次尝试重启 dnsmasq 服务时 (/etc/init.d/dnsmasq restart),文件已经存在,服务就“奇迹般”地恢复了。
我一开就是这么以为的,那么现在既然dnsmasq已经在运行了,那么我发起vpn客户端的连接,应该就可以了,结果依旧获取不到ip地址,logread | grep dnsmasq检查log,却没有输出任何日志信息。
这说明,DHCP请求包在到达 br-lan 接口后,在被内核传递给 dnsmasq 这个应用程序之前,就被系统静默地丢弃了。
这是一个非常棘手的情况,通常与Linux内核的网络过滤子系统有关。当SoftEther这种非标准的网络程序直接向一个网桥设备(br-lan)注入数据包时,可能会触发一些内核的底层安全或过滤机制
,导致数据包无法被上层应用(如dnsmasq)正常接收。
最终解决方案:改用更稳定标准的TAP桥接模式
既然直接桥接到 br-lan 的“高级”模式遇到了这种疑难杂症,我们就改用在Linux系统上更稳定、更标准的桥接方法:TAP设备模式。
这种模式的原理是:
1. 让SoftEther创建一个标准的虚拟网卡(TAP设备)。

2. 然后我们用OpenWrt自带的、非常成熟的桥接功能,将这个虚拟网卡加入到br-lan中。

这样一来,所有网络数据都通过标准的内核接口来走,可以完美兼容OpenWrt的防火墙和网络服务。
第三章:柳暗花明,与新的谜团
在确保 dnsmasq 正常运行后,我再次尝试连接 VPN。这一次,客户端虚拟网卡上终于跳出了熟悉的内网 IP 地址——问题解决!
但喜悦只持续了半分钟。我发现,虽然能访问内网了,但这台连接了 VPN 的 PC 自己的互联网访问却断了。
这又是一个经典问题:VPN 的路由冲突。
默认情况下,VPN 客户端会非常“霸道”地接管系统的默认网关。也就是说,这台 PC 所有的流量(无论访问内网还是外网)都会被一股脑地塞进 VPN 隧道,发往我家的 OpenWrt。如果 OpenWrt 没有被正确配置为替这些 VPN 客户端做 NAT 转发,那么它们自然就无法访问互联网了。
我的需求是**分离隧道 (Split Tunneling)**:只有访问内网的流量走 VPN,访问互联网的流量还走本地网络。
第四章:寻找丢失的“默认网关”选项
根据经验,实现分离隧道最简单的方法是在 Windows 的网络适配器设置里,取消勾选“在远程网络上使用默认网关”。
但奇怪的是,当我找到 SoftEther 创建的虚拟网卡,进入 “TCP/IP 属性” -> “高级”,在“IP 设置”选项卡里,这个熟悉的选项竟然消失了。
这说明 SoftEther 的虚拟网卡驱动与标准的 Windows VPN 适配器行为不同,它把路由控制的权力收回到了 SoftEther Client 软件本身。
于是,我回到 SoftEther VPN Client Manager,右键点击我的 home vpn 连接,进入“属性”,再点击“高级设置”,终于在一个角落里找到了“元凶”:
在 “高级设置” -> “其他设置” 中,有一个选项叫 “**不保留路由表(A)**”。

它的逻辑是反的:
- 不勾选(默认):客户端会修改路由表,添加默认网关(导致断网)。
- 勾选:客户端不修改路由表,只添加访问内网必需的子网路由。
勾选“不保留路由表”,确定,重连。世界终于清静了。内网访问正常,外网访问也恢复了正常。
总结
这次看似简单的 VPN 配置问题,最终演变成了一场涉及网络抓包、服务状态检查、第三方插件排错和客户端路由策略设定的全链路调试。整个过程曲折但收获满满,也再次印证了几个朴素的IT运维真理:
- 眼见为实:当怀疑网络问题时,
tcpdump是最诚实的伙伴。它能明确告诉你数据包走到了哪里。 - 先看死活:在调试一个“不响应”的服务前,先用
ps或logread确认它是否真的在运行。一个沉默的服务,很可能是一个已经“死掉”的服务。 - 警惕“黑盒”:第三方插件和自定义脚本在带来便利的同时,也可能以意想不到的方式干扰核心服务。
- 理清需求:VPN 的网络问题,多半是路由问题。想清楚自己需要“完整隧道”还是“分离隧道”,是解决问题的关键。
从一头雾水到柳暗花明,这种抽丝剥茧、最终定位根源的过程,正是技术调试的魅力所在。
- 本文链接: http://dracewang.github.io/2025/12/15/一次曲折的SoftEtherVPN调试之旅:从无法获取IP到路由迷踪/
- 版权声明: 本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。