缘起

因为一些众所周知的原因,这里不能把本文的前因后果说清楚。相信懂者自然懂,不懂的人,也大概率没必要继续看下去。

之前配置透明代理的时候,有两条类似下面的规则:

iptables -t mangle -A V2RAY_MASK -d 192.168.0.0/16 -p tcp -j RETURN
iptables -t mangle -A V2RAY_MASK -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN

这两条的目的,就是让目标为本地网络(192.168.x.x)的TCP请求跳过代理,直接连接。而UDP请求,除了端口为53(通常是DNS请求)的外,也跳过代理,直接请求。

这样一来,就实现了截获非本地网络的所有请求,以及本地网络的DNS请求,并全部走代理。其他的非DNS查询的本地网络请求,跳过代理。

这么一配置之后,我发现Docker容器的网络开始出问题了。具体表现为,只能使用host网络模式,其他模式都不行,网络不通。

初步分析及解决

初步分析了一下,会不会是因为Docker内部网桥上的局域网网段未像上面一样配置。打开Docker的配置一看,果然如此。于是参考上面的配置,将Docker的内部网段也设置为特殊处理。

iptables -t mangle -A V2RAY_MASK -d 172.16.0.0/12 -j RETURN

上述配置后,仍然不行,百思不解。

进一步分析

后来一个偶然发现,原来这里只配置 目标地址为局域网网段 ,并没有配置 源地址为局域网网段 的规则。

对于宿主机来说,只存在主动外发的数据包,因此配置了目标地址基本上就无差了。

但是对于宿主机上的容器来讲,有大量目标和来源地址都是局域网网段的数据包,需要外发或者在Docker虚拟的交换机上进行数据流动。如果只配置了目标地址为局域网网段的数据包跳过代理,那么源地址为局域网网段的数据包,仍然会走到代理中,导致无法正确路由。

解决方案

分析到这里,解决办法就自然而然产生了,只需要在上面的规则中,添加上老地址即可。参考配置如下

iptables -t mangle -A V2RAY_MASK -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A V2RAY_MASK -s 172.16.0.0/12 -j RETURN