网络拓扑
- wan1 198.18.1.2 (默认路由)
- wan2 198.18.2.2 (路由表: 10010)
- WireGuard 监听 2333
- 路由规则 from 192.168.2.2 lookup 10010
理论上,从wan2进来的连接,回复的时候会从wan2发出去,但是WireGuard并不遵循源进源出,它会直接使用默认路由回复,使用源ip 198.18.1.2从wan1发出去,导致握手失败
解决方法
在握手包从wan2进来的时候,用ct mark进行标记
1 | chain mangle_prerouting { |
回复的时候,给这条连接打上fwmark,策略路由走路由表10010出去
1 | chain mangle_output { |
1 | ip rule add fwmark 0x271a lookup 10010 |
然后会发现,根本没有用,因为源ip不是进来时的目标ip(198.18.2.2),连接跟踪会把回复当成新连接,所以不能正确打上fwmark
要用DNAT解决这个问题,握手包进来的时候直接DNAT到198.18.1.2:2333,这样连接跟踪就能正确识别,回复的时候还会自动SNAT成正确的源ip
1 | chain dstnat { |
至此,源进源出应该能正确工作了
ipv6在我的环境中,不存在上面的问题,它能自动选择正确的源ip回复,原因未知
参考
https://jeffz.page/posts/2015670204
https://github.com/openwrt/packages/issues/9538
https://wiki.nftables.org