IPv6 & WireGuard 大战看不见的敌人
前情提要
我的需求是从外面方便地访问家里的另一台电脑(能 ssh 上就行),并且我不喜欢多装太多服务在工作电脑上。
家里的电脑是一台 kali,是我们预备连接的 server。外面这台我经常带着跑的是 windows 系统,是 client。为了简单起见,我后面直接叫它们 kali 和 windows。
<<<<<<< HEAD


b554a624d262f3d101562d676a05454784af0fc4
嘉宾介绍
首先是一个符合国情的需求:两台电脑都要有梯子。我在两边都装了 Clash Verge Rev,并且开了 TUN 模式,按照规则转发。梯子常年开着,这意味着两边的虚拟网卡都被 Clash 接管。
kali 的环境
租房处提供的路由器,普通的 DHCP。经过测试,kali 在这里没有独立的 IPv4 地址,是通过 NAT 出去的,一家人穿一条裤子出门。但是!好消息是它有独立的 IPv6 地址。这意味着我有机会不经过 NAT 转换,直接点对点连上这台电脑。
windows 的环境
这个就比较复杂了。分类讨论下来场景有三类:
- 在家的时候,和 kali 在一个局域网下,同一局域网下很容易 ssh 上。
- 在学校的时候,连接的是学校内网。
- 为了不在学校而又能模拟学校内网连接的情况,我在家进行测试的时候会让 windows 连手机流量热点(中国联通),并打开 EasyConnect VPN(SangFor)。
排查 - IPv6
问题描述
- 在学校工位,通过 IPv6 地址,连不上 kali。
- 在家使用手机流量热点,并打开学校 VPN,同样连不上 kali。
以上描述的都是 ssh 的行为(实际上 ping 也一致)。
Test-Connection 测试
下面开始测试。
1 | PS C:\windows\system32> # 纯联通连接 |
总结下来是这样的:
| 网络环境 | 联通 | 联通+Clash | 联通+Clash+SangFor |
|---|---|---|---|
| TestConnection | × | √ | √ |
这并没有解决我 ssh 的问题,按道理讲如果是通的,那么打开了 Clash 我就该 ssh 上。而且,直连 IPv6 本来就应该可以连上,为什么现在居然连不上呢??
所以接下来我们一步一步排查。
联通直连 IPv6
首先要尝试回答的问题是,为什么不开 Clash 的时候连不上这个 IPv6 地址?
根据 gemini 的建议,使用 tracert 跟踪只在联通网络下连接 kali 的路径,检查是哪里断开了。在这个时候我才发现,原来 kali 所在的网络(家庭路由器)是移动的,而我的手机流量是联通的。
可能的情况有四种:
- 第 1-2 跳就断开了,说明是本地路由器的拦截或错误配置(发送端)
- 第 3-5 跳断开,说明联通内部路由表丢弃了发往移动 IP 段的包,是运营商路由故障(联通内部)
- IP 地址前缀从 2408(联通) 变为 2409(移动)的时候断开了,说明跨运营商互联有问题(联通->移动)
- 追踪到了目标附近,最后一跳断开,说明目标服务器屏蔽了访问(接收端)。
我的试验结果是这样的:
1 | PS C:\windows\system32> tracert -6 2409:8a1e:7a56:e440:dbb:887:564d:7218 |
可见是最后一跳出问题,也即服务端拦截。
那么,究竟是移动的路由器拦截了,还是 kali 自己的防火墙拦截了呢?
再次进行测试:在 kali 上使用 tcpdump 监听 443 端口的包。此时,有两种情况:
- 如果观察到收到了包但是拒绝了,那就是 kali 的防火墙拦截
- 如果屏幕一片死寂,那就是路由器拦截
实际情况是二。
<<<<<<< HEAD


=======


b554a624d262f3d101562d676a05454784af0fc4
联通+Clash 连 IPv6
观察到之前使用 Clash 连接的时候是成功的,那么我想要验证它成功的方式。
还是沿用刚才的检测法,在 Clash 进行 Test-NetConnection 的时候,在 kali 这边用 tcpdump 看有没有包。
<<<<<<< HEAD


b554a624d262f3d101562d676a05454784af0fc4
好耶,成功了!kali 呢?
——没有包!
此刻才基本确定,并非 Clash 有神力连上了我的 kali,而是它报!喜!不!报!忧!我们可以连接一个完全不存在(没开放)的端口进行测试,结果如下:
<<<<<<< HEAD


b554a624d262f3d101562d676a05454784af0fc4
孩子呢,你一天到晚不好好学习,就知道哄你个大大哄你个妈妈。
这完全解释了为啥 ssh 连不上,因为事实上就是没连上。Clash 开启了 TUN 模式之后,在 Windows 发出 TCP SYN 包之后,Clash 直接在本地给 Windows 回了一个 SYN-ACK,故 Windows 视角下,误认为连接已经成功了。但实际上,此时真实的流量可能正在代理服务器上重试,或者因为规则不对直接被丢弃了,压根没出路由器。
<<<<<<< HEAD


b554a624d262f3d101562d676a05454784af0fc4
排查 - wireguard
ok,那现在咋办呢?
我们尝试使用 wireguard,它会尝试创建一个 VPN。原理是这样的:kali和windows身份发生了翻转,kali开始向windows发出请求,由于是kali先发出请求的,联通路由器认为可以放行。接下来,windows 顺着这个连接的回包就将被认为是可信的。
只要这个隧道维持着(通过 PersistentKeepalive 定期发个小包),这扇门就为 windows 开着。
wireguard 使用 UDP 包装流量;如果采用 TCP,可能导致“TCP 重传风暴”,也就是丢包的时候内部 TCP 疯狂重传,外部 TCP 也疯狂重传,两层协议的拥塞控制算法叠加起来,网络带宽不堪重负。
再次测试连通性。windows 端也安装了一个 wireguard,首先确保其连接在内网基础上可通,证明 wg 并没有配错。然后撤掉内网,改成联通网络上测试。
<<<<<<< HEAD




b554a624d262f3d101562d676a05454784af0fc4
windows 一直在尝试发握手请求。中间,wireguard 甚至显示连接已经建立了。但事实上,kali 依旧不为所动,一个包也没有。
这一通操作下来,发现 VPN 也并不能绕过路由器防火墙。wireguard 连 kali 的想法算是泡汤了,不在 windows 上多装一个软件的想法也泡汤了(不然可以直接用 clash verge rev 对 wireguard 的协议连)。
至此打道回府,老老实实装一个 tailscale 了事了。
tailscale 配置
tailscale 实际上也是基于 wireguard 实现的,但是它的打洞能力非常强,可以在 kali 发了出站包之后马上让 windows 的撞进来,从而建立连接。就算 P2P 打洞不成功,它能强制流量从最近的中转服务器那里绕一圈,就算是以延迟高一点为代价,也终归能连上。
注意在配置之前关掉 wireguard,关掉 TUN(否则网卡会打架),然后双方验证一下,就能连上了。我实际测了一下,叠一个学校 VPN 也没问题。
<<<<<<< HEAD


b554a624d262f3d101562d676a05454784af0fc4
补配一下 Clash verge rev 规则。windows 这边我用的是:
1 | function main(config) { |
kali 这边是:
1 | function main(config) { |
后话
我的排查就这么虎头蛇尾地结束了,实际踩的坑要多得多得多,比如冤枉学校 VPN 没有 IPv6 或者封禁端口或者封禁 UDP(可能确实封禁了吧,但是还没到这一关就死了啊),然后费劲换端口啊啥的。
事实证明不能盲信 LLM,还得自己多动脑啊。
附录:wireguard 配置
事实上,与全文的逻辑顺序不同,真实的时间线是我最开始先配了 wireguard,再开始测试 IPv6 连接。
在 kali 侧,只需设置流量转发时从 10.66.66.1 出去的流量直接走 DIRECT 即可(相当于它们不经过 clash 转发,而是直接发给 wg 服务)。
作为和 kali 的 wireguard 的对应,在 windows 上面进行配置的时候除了多装一个 wg 之外,另一个可选项是直接配置 clash verge rev 的规则,因为它内置了对于 wireguard 协议的支持。那么 windows 作为 client,虚拟节点可以配成 10.66.66.2。
这边也贴一下 windows 侧 wireguard 配置:
clash verge rev 有个很坑的一点,就是在左边的 Merge 里面写 rule 的话,只能完全覆盖,不能追加。问大模型所得到的答案是完全牛头不对马嘴的,这个信息是在 clash verge rev 的更新日志中提供的。
<<<<<<< HEAD


b554a624d262f3d101562d676a05454784af0fc4
1 | function main(config) { |

