docker 容器中不需要的伪装

docker 容器中不需要的伪装

虽然我没有在主机或两个容器上添加任何 iptables 规则,但是来自一个 docker 容器的数据包被修改并赋予了 docker 网络网关的 IP:

容器 1:

bash-5.0# ip route
default via 172.16.238.2 dev eth0
10.6.0.0/24 via 172.16.238.1 dev eth0
172.16.238.0/24 dev eth0 scope link  src 172.16.238.7

bash-5.0# ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    23: eth0@if24: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
        link/ether 02:42:ac:10:ee:07 brd ff:ff:ff:ff:ff:ff
        inet 172.16.238.7/24 brd 172.16.238.255 scope global eth0
           valid_lft forever preferred_lft forever

bash-5.0# ping 1.1.1.1
PING 1.1.1.1 (1.1.1.1): 56 data bytes
--- 1.1.1.1 ping statistics ---
7 packets transmitted, 0 packets received, 100% packet loss

容器 2:

root@c8d6fa7eab4d:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
3: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 100.71.37.47/32 scope global wg0
       valid_lft forever preferred_lft forever
17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:10:ee:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.16.238.2/24 brd 172.16.238.255 scope global eth0
       valid_lft forever preferred_lft forever

root@c8d6fa7eab4d:/# tcpdump -i eth0 dst 1.1.1.1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:34:06.910548 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 36, length 64
16:34:07.910920 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 37, length 64
16:34:08.911322 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 38, length 64
16:34:09.911709 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 39, length 64
16:34:10.912143 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 40, length 64
16:34:11.912504 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 41, length 64
16:34:12.912932 IP 172.16.238.1 > one.one.one.one: ICMP echo request, id 5632, seq 42, length 64
^C
7 packets captured
9 packets received by filter
0 packets dropped by kernel

主持人:

root@raspberrypi:~# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  -- !172.16.238.0/24      172.16.238.2
MASQUERADE  all  -- !172.16.238.0/24      172.16.238.2
MASQUERADE  all  --  172.17.0.0/16        anywhere
MASQUERADE  all  --  172.16.238.0/24      anywhere
MASQUERADE  all  -- !172.16.238.0/24      172.16.238.2
MASQUERADE  all  --  10.6.0.0/24          anywhere             /* wireguard-nat-rule */
MASQUERADE  all  -- !172.16.238.0/24      172.16.238.2
MASQUERADE  all  --  172.16.238.0/24      anywhere
MASQUERADE  tcp  --  172.16.238.4         172.16.238.4         tcp dpt:https
MASQUERADE  tcp  --  172.16.238.4         172.16.238.4         tcp dpt:http
MASQUERADE  tcp  --  172.16.238.4         172.16.238.4         tcp dpt:domain
MASQUERADE  udp  --  172.16.238.4         172.16.238.4         udp dpt:domain
MASQUERADE  tcp  --  172.16.238.5         172.16.238.5         tcp dpt:https
MASQUERADE  tcp  --  172.16.238.5         172.16.238.5         tcp dpt:http
MASQUERADE  tcp  --  172.16.238.5         172.16.238.5         tcp dpt:domain
MASQUERADE  udp  --  172.16.238.5         172.16.238.5         udp dpt:domain

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere
DNAT       tcp  --  anywhere             192.168.178.2        tcp dpt:https to:172.16.238.4:443
DNAT       tcp  --  anywhere             192.168.178.2        tcp dpt:http to:172.16.238.4:80
DNAT       tcp  --  anywhere             192.168.178.2        tcp dpt:domain to:172.16.238.4:53
DNAT       udp  --  anywhere             192.168.178.2        udp dpt:domain to:172.16.238.4:53
DNAT       tcp  --  anywhere             192.168.178.3        tcp dpt:https to:172.16.238.5:443
DNAT       tcp  --  anywhere             192.168.178.3        tcp dpt:http to:172.16.238.5:80
DNAT       tcp  --  anywhere             192.168.178.3        tcp dpt:domain to:172.16.238.5:53
DNAT       udp  --  anywhere             192.168.178.3        udp dpt:domain to:172.16.238.5:53
# Warning: iptables-legacy tables present, use iptables-legacy to see them

root@raspberrypi:~# iptables-legacy -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT

答案1

容器间连接 (ICC) 默认启用,并且自动将容器链接在一起无需使用--link或定义network

如果你想禁用它,请icc: false在 Docker 守护进程配置中设置(/etc/daemon.json

未定义或设置为 true 会使 Docker 守护进程在创建容器的同时创建连接的网络。这些网络就是您看到的 iptables 规则的来源。

更多内容请见官方 Docker桥接网络教程

答案2

我遇到了同样的问题,对我来说,我相信这与以下因素有关:

https://github.com/moby/moby/issues/43440

问题是我创建了一个 Docker 网络,然后删除它并再次创建另一个。Docker 足够智能,可以重用相同的 IP 范围(在我的情况下为 172.18.0.0/16),但防火墙似乎会跟踪前一个 Docker 网络:

# iptables -t nat -S 
...
-A POSTROUTING -s 172.18.0.0/16 ! -o br-4a99e748fcc1 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-9dbbf26e610f -j MASQUERADE
...

其中 br-4a99e748fcc1 确实是现有的接口,但 br-9dbbf26e610f 是剩余的接口……(已从firewalld 中删除但并未永久抑制)。

# ip add show br-9dbbf26e610f
Device "br-9dbbf26e610f" does not exist.

如果我删除了错误的行,一切都会恢复正常:NAT发夹(源IP被网关地址替换)不再发生:

# iptables -t nat -D POSTROUTING -s 172.18.0.0/16 ! -o br-9dbbf26e610f -j MASQUERADE

这完全说得通:规则规定,任何数据包

  • 源自源范围 172.18.0.0/16
  • 不通过 br-9dbbf26e610f 出去

应该经过伪装......当然,没有数据包通过那个不存在的接口出去(!)所以这会导致伪装 Docker 网络中的所有 IP。

编辑:firewall-cmd--reload 再次创建规则!

正如上面的 Docker 问题中所述,我最终决定firewall-cmd从区域中删除僵尸接口docker。这必须在 Docker 守护进程关闭时完成,因为否则它似乎会跟踪这些僵尸接口……

systemctl stop docker

for interface in $(firewall-cmd --zone=docker --list-interfaces)
do
    if ! ip link ls "${interface}" >/dev/null 2>&1
    then
        firewall-cmd --zone=docker --remove-interface="${interface}"
        firewall-cmd --runtime-to-permanent
        firewall-cmd --reload
    fi
done

systemctl start docker

相关内容