使用 TPROXY 透明代理后 docker 无法联网

原 iptables 设置

ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100

iptables -t mangle -N V2RAY
iptables -t mangle -A V2RAY -d 127.0.0.1/32 -j RETURN
iptables -t mangle -A V2RAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A V2RAY -d 192.168.0.0/16 -p tcp -j RETURN
iptables -t mangle -A V2RAY -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
iptables -t mangle -A V2RAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A V2RAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j V2RAY

iptables -t mangle -N V2RAY_MASK
iptables -t mangle -A V2RAY_MASK -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY_MASK -d 255.255.255.255/32 -j RETURN
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 
iptables -t mangle -A V2RAY_MASK -j RETURN -m mark --mark 0xff
iptables -t mangle -A V2RAY_MASK -p udp -j MARK --set-mark 1
iptables -t mangle -A V2RAY_MASK -p tcp -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -j V2RAY_MASK

问题定位

容器中非本地网段 tcp/udp 均无法访问

开启 iptables 响应日志后,用以下命令记录路由信息

iptables -t <table> -A <chain> -j LOG --log-prefix "<table>:<chain>"

发现数据包在进入 mangle:OUTPUT 后被丢弃,SRC 是 172.17.0.0/16 网段

因为 docker0 使用了 nat 作为网桥,并且规则在 nat:POSTROUTING 中定义,而 nat:POSTROUTING 是 iptables 最后一条链,因此只有在网卡发出前才会进行 IP 地址的转换

所以在进入 mangle:PREROUTING 后,实际上 SRC 仍是 172.17.0.0/16,由于不知名的原因无法被代理

解决方案

其实,作为容器的 docker 本就不应该被代理,因此只需要在 mangle:PREROUTING 中将 SRC = 172.17.0.0/16 网段的数据包直接 RETURN

iptables -t mangle -A V2RAY -s 172.17.0.0/16 -j RETURN

注意事项

docker 网段可能有所不同,可以通过 ifconfig 查看