banner
NEWS LETTER

一次曲折的 SoftEther VPN 调试之旅:从无法获取 IP 到路由迷踪

Scroll down

一次曲折的 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
2
# 在 OpenWrt 上执行
tcpdump -i br-lan -n port 67 or port 68

让 VPN 客户端重新连接后,tcpdump 的输出给了我第一个决定性的线索:

1
2
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)的任何响应包(OfferACK)。

这个发现意义重大。它排除了 SoftEther 本地桥接本身的问题,也排除了 VPN 客户端到 OpenWrt 之间的网络问题。数据包已经成功到达了局域网的“大门口”。问题变成了:为什么门口的 DHCP 服务员(dnsmasq)不理它?

第二章:沉默的 DHCP 服务器

既然 DHCP 包到了,但服务没响应,那么嫌疑人就转移到了 DHCP 服务器本身——在 OpenWrt 中,它是由 dnsmasq 进程负责的。

一个服务不响应,排查的第一步永远是:它到底还活着吗?

我通过 logread 命令来查看 dnsmasq 的系统日志:

1
logread | grep dnsmasq

结果令人震惊,也让整个调试豁然开朗:

1
2
daemon.crit dnsmasq[1]: cannot read /tmp/dnsmasq.d/dnsmasq-ssrplus.d/gfw_list.conf...
daemon.crit dnsmasq[1]: FAILED to start up

**真相??**:我的 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设备)。
image-20251215131453006
2. 然后我们用OpenWrt自带的、非常成熟的桥接功能,将这个虚拟网卡加入到br-lan中。

image-20251215131622929

这样一来,所有网络数据都通过标准的内核接口来走,可以完美兼容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)**”。

image-20251215131746275

它的逻辑是反的:

  • 不勾选(默认):客户端会修改路由表,添加默认网关(导致断网)。
  • 勾选:客户端修改路由表,只添加访问内网必需的子网路由。

勾选“不保留路由表”,确定,重连。世界终于清静了。内网访问正常,外网访问也恢复了正常。

总结

这次看似简单的 VPN 配置问题,最终演变成了一场涉及网络抓包、服务状态检查、第三方插件排错和客户端路由策略设定的全链路调试。整个过程曲折但收获满满,也再次印证了几个朴素的IT运维真理:

  1. 眼见为实:当怀疑网络问题时,tcpdump 是最诚实的伙伴。它能明确告诉你数据包走到了哪里。
  2. 先看死活:在调试一个“不响应”的服务前,先用 pslogread 确认它是否真的在运行。一个沉默的服务,很可能是一个已经“死掉”的服务。
  3. 警惕“黑盒”:第三方插件和自定义脚本在带来便利的同时,也可能以意想不到的方式干扰核心服务。
  4. 理清需求:VPN 的网络问题,多半是路由问题。想清楚自己需要“完整隧道”还是“分离隧道”,是解决问题的关键。

从一头雾水到柳暗花明,这种抽丝剥茧、最终定位根源的过程,正是技术调试的魅力所在。

其他文章
目录导航 置顶
  1. 1. 一次曲折的 SoftEther VPN 调试之旅:从无法获取 IP 到路由迷踪
    1. 1.1. 写在前面
    2. 1.2. 第一章:DHCP 请求的“黑洞”
    3. 1.3. 第二章:沉默的 DHCP 服务器
    4. 1.4. 第三章:柳暗花明,与新的谜团
    5. 1.5. 第四章:寻找丢失的“默认网关”选项
    6. 1.6. 总结
请输入关键词进行搜索