springzfx / cgproxy

Transparent Proxy with cgroup v2。透明代理,配合v2ray/Qv2ray食用最佳

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

容器(docker)桥接(bridge)模式时的代理问题

unknowndevQwQ opened this issue · comments

我已经按照 #3 设置了内核参数,但还是会发生这种情况
复现问题的步骤:

  1. 启用 cgproxy 和 docker,启用 cgproxy 网关代理并且设置 "cgroup_proxy": ["/system.slice/containerd.service","/system.slice/docker.service","/"]
  2. 重启机器
  3. 在这时 docker 内容器查询 dns 没有经过 cgproxy(但是设置了代理 dns)
  4. 重启 cgproxy 后发现 docker 内容器无法解析 dns

可能有用的文件
cgp.log
tproxy.json.txt

一点额外信息:
发行版是 Arch
安装了 nftables 和 iptables-nft

commented

docker默认网络桥接(--net=bridge)
桥接有特殊的工作方式,目前的解决方法为:

sudo sysctl -w net.bridge.bridge-nf-call-iptables=0
sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=0

这时走的是网关代理。
如果 --net=host的话,则是/system.slice/docker.service下的流量


edit: 原因是docker加载的br_netfilter模块造成的, 见下文

docker默认网络桥接(--net=bridge)
桥接有特殊的工作方式,目前的解决方法为:

sudo sysctl -w net.bridge.bridge-nf-call-iptables=0
sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=0

这时走的是网关代理。
如果 --net=host的话,则是/system.slice/docker.service下的流量

好的,那么 systemd-nspawn 里用的 bridge 联网的容器也可以用这个方法解决问题吗? 可以

我的问题解决了,不过在搜索时发现了另一个可能的解决方式 :
iptables -t raw -I PREROUTING -i BRIDGE -s x.x.x.x -j NOTRACK(暂未尝试)
但是这玩意没解决我的问题,因为在这之后什么也没有发生(顺便 systemd-nspawn 里的容器也出现类似问题了)

来源:
https://blog.csdn.net/quqi99/article/details/7447233 (用 ctrl + F 搜寻 net.bridge.bridge-nf-call-iptables=1)

顺带一提可能的坑,设置 bridge-nf-call-xtables 后有可能需要重启一下 docker 才会生效

说一下,这个不是网桥的问题,而是 br_netfilter 的问题。docker 会加载这个模块,见 moby/moby#13162 。systemd-nspawn 不加载这个模块,所以(不通过其它途径加载这个模块的话)不应当受影响。

另外 sysctl.d(5) Example 2 有在模块加载时使用 udev 自动应用 sysctl 设置的方案。

PS: 我看了许久,还是没弄明白这里讨论的问题是什么……

说一下,这个不是网桥的问题,而是 br_netfilter 的问题。docker 会加载这个模块,见 https://github.com/moby/moby/pull/13162。systemd-nspawn 不加载这个模块,所以(不通过其它途径加载这个模块的话)不应当受影响。

建议在句号前加一个空格,现在看起来这个链接把句号也加进去了

PS: 我看了许久,还是没弄明白这里讨论的问题是什么……

只是想让 docker 和 nspawn 里的容器正常走代理而已……

只是想让 docker 和 nspawn 里的容器正常走代理而已……

什么叫「正常」……要走透明代理的话,直接在网关的 PREROUTING 链上操作不就好了吗?

只是想让 docker 和 nspawn 里的容器正常走代理而已……

什么叫「正常」……要走透明代理的话,直接在网关的 FORWARD 链上操作不就好了吗?

但是我不会这个操作……
于是就成这样了

commented

正如依云姐所指出的,br_netfilter模块使得bridge的二层包经过了iptables,docker加载这个的目的是为了避免hairpin nat(一个无关紧要的东西),但是TPROXY不支持接收这类型的包,因此无法代理。
解决的方法还是上面的,禁用这种行为就好了,甚至可以直接手动unload这个模块。

sudo sysctl -w net.bridge.bridge-nf-call-iptables=0
sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=0
sudo sysctl -w net.bridge.bridge-nf-call-arptables = 0