一、问题背景
我的使用场景如下:
- 公司电脑通过 OpenVPN 连接回家里的 ikuai 路由器
- ikuai 局域网网段:
192.168.78.0/24 - ikuai IP:
192.168.78.1 - 家里有一台 绿联 NAS
- NAS 内运行 KVM 虚拟机
- Ubuntu 虚拟机:
- 网卡:virtIO
- Bridge:
vnet-bridge0 - IP:
192.168.78.19 - 默认网关:
192.168.78.1
二、异常现象
出现的问题非常“拧巴”:
- 公司电脑 ✅ 可以 ping 通
192.168.78.1 - 公司电脑 ✅ 可以 ping 通局域网内其他实体主机(如
192.168.78.239) - Ubuntu 虚拟机 ✅ 可以 ping 通路由器
- 公司电脑 ❌ ping 不通 Ubuntu 虚拟机
- 公司电脑 ❌ SSH 连接 Ubuntu
直觉上非常容易误判为:
- Ubuntu 防火墙问题
- SSH 服务问题
- 虚拟机网络配置错误
但实际上,这些都不是根因。
三、真实网络拓扑(非常关键)
真实的数据路径如下:
1 |
|
这是一个 VPN + 路由器 + NAS 虚拟化桥接网络 的组合场景。
四、一个关键事实:去程是通的,回程是断的
通过在 Ubuntu 虚拟机上抓包:
1 | sudo tcpdump -i any icmp or tcp port 22 |
可以确认:
- 当公司电脑 ping / SSH Ubuntu 时
- Ubuntu 是能收到数据包的
- 但始终没有成功返回响应
这说明:
网络不是“完全不通”,而是“单向可达”
五、没有 SNAT 时,发生了什么?
1. Ubuntu 看到的源地址
没有做任何 NAT 时:
- Ubuntu 收到的数据包源 IP 是:
1 | 10.1.1.x (OpenVPN 客户端地址池) |
2. Ubuntu 的路由认知
Ubuntu 只知道:
- 本地网段:
192.168.78.0/24 - 默认网关:
192.168.78.1
它并不知道:
10.1.1.0/24是通过 OpenVPN 隧道进来的- 回包需要“特殊路径”
于是它的行为是完全正确的:
1 | 把回包交给默认网关(ikuai) |
六、关键误区:为什么“同一个 ikuai”却回不去?
一个非常容易产生的误解是:
ikuai 既是默认网关,又是 OpenVPN Server,
为什么它不知道这是 VPN 回包?
原因在于:
1️⃣ L3 路由 vs VPN 会话是两套系统
- Ubuntu → ikuai 的回包:
- 是 三层(L3)无状态 IP 报文
- OpenVPN 隧道:
- 是 依赖四层以上(UDP/TCP + 会话状态)的有状态通道
在没有 NAT 的情况下:
- ikuai 收到的只是:
1 | 来自 LAN,目标是 10.1.1.x 的普通 IP 包 |
- 无法自动映射到某一个 VPN 会话
- 即使 VPN Server 就运行在 ikuai 上
七、为什么 SNAT 能一招解决问题
核心思想
不要让虚拟机看到 VPN 客户端的真实 IP
通过 SNAT:
1 | 10.1.1.x → 192.168.78.1 |
Ubuntu 实际看到的是:
- 源地址:
192.168.78.1
于是回包变成:
1 | Ubuntu → 192.168.78.1 |
ikuai 此时能做什么?
- 回包命中 连接跟踪表(conntrack)
- ikuai 清楚知道:
- 这是自己 NAT 过的一条连接
- 原始流量来自 OpenVPN 接口
- 自动执行:
- 反向 NAT
- 回送至对应 VPN 隧道
👉 无状态问题,被转化成了有状态问题
八、最终解决方案(ikuai SNAT)
在 ikuai 防火墙 → NAT → 源地址转换 中新增规则:
| 字段 | 值 |
|---|---|
| 动作 | 源地址 NAT |
| 进接口 | OpenVPN(如 sovpn) |
| 出接口 | LAN(如 lan1) |
| 源地址 | 10.1.1.0/24 |
| 目的地址 | 192.168.78.0/24 |
| NAT 地址 | 192.168.78.1 |
| 协议 | 任意 |
规则生效后:
- ping 正常
- SSH 正常
- 其他服务端口均可访问
九、为什么 ping 不能用于判断“哪里不通”
ping 的本质是:
1 | Echo Request → Echo Reply |
任何一侧失败,结果都是:
1 | Request timeout |
它无法告诉你:
- 是没发出去
- 还是发出去了回不来
在 VPN / 虚拟化场景中,正确的排障方式是:
tcpdump抓包(是否到达)- NAT / conntrack 状态
- 路由与回程路径分析
十、方法论总结(最重要)
这次问题的本质不是:
- Ubuntu 配错
- SSH 配错
- 虚拟机配置错
而是一个非常典型的工程问题:
VPN + 虚拟化桥接网络下,
回程路径缺失会话映射
记住一句话即可:
只要看到:VPN 能进、实体机能通、虚拟机不通,
先想回程路径,再想防火墙。
十一、延伸思考
类似问题同样会出现在:
- Docker Bridge
- KVM / libvirt
- 多 VPN 并存
- 多 WAN 场景
解决思路永远是三选一:
- SNAT(最简单、最稳定)
- 明确的反向路由
- 策略路由 + 会话绑定
记录一次真实问题,比十篇教程更有价值。