求助个透明网关问题

177 天前
 kyonn

有一台 linux 机器, 配置了一个 bridge0 网卡,绑定一个物理网卡, ip 为 192.168.20.10. 在上面开了个 fakeip 类型的透明网关虚拟机, ip 为 192.168.20.5, 虚拟机网卡桥接到宿主机 bridge0 网卡.

宿主机上还启用了 docker, docker 使用自定义虚拟网卡 br-xxx.

现在发现个问题: 宿主机 docker 容器无法正常走梯子, 宿主机本身走梯子流量正常. 因为梯子流量走的都是 fakeip, 下面以 7.0.0.11 举例, 抓包发现如下现象:

  1. 宿主机 docker 容器 ping 7.0.0.11, icmp 流量先到 br-xxx 网卡, 再经过 src nat 从宿主机 bridge0 网卡发出到路由器网关 192.168.20.1. 网关因为配置了 7.0.0.0/8 的路由, 会将流量再转发给 192.168.20.5, 即又发给了 宿主机, 再转到宿主机的透明网关虚拟机. 透明网关虚拟机回复 icmp 报文,

问题出在这里, 抓包发现透明网关的 icmp 响应 目的 mac 是宿主机的 bridge0, 而不是路由器网关, 这就导致 icmp 没办法经过路由器原路 返回到 宿主机, 再返回给宿主机的容器.

而宿主机直接 ping 7.0.0.11 没问题, 报文也是一样的回复路径, 但是由于目的 mac 是宿主机的 bridge0, 也算被宿主机收到了.

感觉有点像 hairpin-nat 这种类型的问题, 请问应该修改哪个环节的配置解决该问题?

1650 次点击
所在节点    程序员
14 条回复
kyonn
177 天前
问题原因应该是 透明网关发现 icmp 的源 ip 是宿主机 bridge0 网卡, 所以目的 mac 就直接用 bridge0 网卡的, 而不是回复给路由器网关.
kyonn
177 天前
宿主机直接加一条静态路由 : route add -net 7.0.0.0 netmask 255.0.0.0 gw 192.168.10.5 可以解决问题.

想知道比较正确的做法应该是怎样的?
kyonn
177 天前
宿主机上还有其他虚拟机, 这些虚拟机的容器内 到 7.0.0.11 是可达的, 抓包发现路径也跟前面的一样, 响应报文不会经过路由器网关. 也就是说, 报文的去程和回程也是不同的, 但是可达.
yinmin
177 天前
你这个是不对称路由,不稳定的,应该避免。

方法一:
路由器 192.168.20.1 加 MASQUERADE:
iptables -t nat -A POSTROUTING -s 192.168.20.0/24 -d 7.0.0.0/8 -j MASQUERADE

方法二:
每个客户端机器都加静态路由:
ip route add 7.0.0.0/8 via 192.168.20.5 (linux)
route add 7.0.0.0 mask 255.0.0.0 192.168.20.5 (windows)
kyonn
177 天前
@yinmin 有些难以取舍. 还有别的方法吗?

方法一多加了一层 NAT, 性能倒是其次, 关键是 透明网关 上的统计信息无法再看到实际的源 ip 了.
方案二每台机器都要配置, 最早还开了 dchp option121 直接下发 7.0.0.0/8 的静态路由给所有客户端, 后来发现米家的中枢网关会被这条下发的静态路由规则搞死, 上不了网, 因此就把 option 121 关掉了.
yinmin
177 天前
方式三:将客户端机器的网关配置成透明网关 ip
kyonn
177 天前
@yinmin 好的, 多谢.
yinmin
173 天前
@kyonn 以前我发现 tplink 这种硬路由设置不对称路由蛮正常的,但是软路由就是不正常,最近好像突然搞明白了原因。

你试试在主路由 192.168.20.1 不加 MASQUERADE ,改成 NOTRACK ,试试是否 OK:
iptables -t raw -A PREROUTING -s 192.168.20.0/24 -d 7.0.0.0/8 -j NOTRACK
kyonn
171 天前
@yinmin 不太行, 主路由上之前已经有了条 mangle rule, 把目标是 7.0.0.0/8 的路由标记, 转发给一个新的路由表处理. 这个路由表再转发给 透明网关.
yinmin
171 天前
@kyonn 不冲突的呢,这是在 raw 表,告诉 iptables 不用 track 。

原因是:默认 iptables 转发也会跟踪 tcp 状态的,不对称路由只有单程无法跟踪到 tcp 状态,导致主路由 iptables 阻断连接。这条命令让 iptables 转发数据即可,别跟踪状态,与路由无关。
kyonn
171 天前
@yinmin 我把之前在主机上添加的路由规则删了, 去主路由上加了你说的规则, 不起作用, 还是不通.
yinmin
171 天前
家宽硬路由器只在 nat 时才会跟踪连接状态,不会在静态路由时去跟踪 tcp 连接状态,所以很多硬路由能跑不对称路由。

软路由大都使用 iptables 或 nftables ,这个防火墙比较严格,在静态路由的时候也会去跟踪 tcp 状态,所以很多软路由不能跑不对称路由。解决方案有 2 种: MASQUERADE 或者 NOTRACK 。
yinmin
171 天前
静态路由要保留、去掉 MASQUERADE 加 NOTRACK ,如果不行的话,-A 改成-I ,也就是插入 raw 第一条
yinmin
171 天前
接#13 客户端的静态路由去掉,主路由加静态路由,然后先加 MASQUERADE 能通,说明主路由 OK ,然后 MASQUERADE 改 NOTRACK 。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1116990

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX