对于表示抱歉,但我认为这应该在这里…

我创建了一个 veth 对,该对的一端位于网络命名空间中。我将地址 10.1.2.50/24 分配给命名空间内的对端,将地址 10.1.2.1/24 分配给根命名空间内的对端。我设置了一个 iptables 规则来伪装来自与 veth 对关联的子网的流量:

sudo iptables -t nat -A POSTROUTING -s 10.1.2.0/24 ! -o my-veth -j MASQUERADE

这听起来合理吗?我可以伪装通过 veth 对的流量而不创建桥接吗?

在命名空间外部,我可以 ping 10.1.2.50;在命名空间内部,我可以 ping 10.1.2.1 和主机的公共 IP。但在命名空间内部,我无法 ping 互联网上的公共 IP(它会一直挂起,等待响应)。我该如何调试?

我的设置如下。我像这样创建了配对:

ip link add my-veth type veth peer name my-ceth

我将该对的一端放在命名空间中:

ip link set my-ceth netns my-ns

我在命名空间内部和外部分配了 IP 地址:

ip addr add 10.1.2.1/24 dev my-veth
nsenter --net=/run/netns/my-ns ip addr add 10.1.2.50/24 dev my-ceth

我调出了命名空间内部和外部的设备:

ip link set my-veth up
nsenter --net=/run/netns/my-ns ip link set my-ceth up

我在命名空间内设置了默认路由:

nsenter --net=/run/netns/my-ns ip route add default via 10.1.2.1

我在命名空间外创建了一个 iptables 规则,以对来自命名空间的流量进行 NAT:

iptables -t nat -A POSTROUTING -s 10.1.2.0/24 ! -o my-veth -j MASQUERADE

我的ip addr样子是这样的:

133: my-veth@if132: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f6:b9:cb:fe:44:4a brd ff:ff:ff:ff:ff:ff link-netns my-ns
    inet 10.1.2.1/24 scope global my-veth
       valid_lft forever preferred_lft forever
    inet6 fe80::f4b9:cbff:fefe:444a/64 scope link 
       valid_lft forever preferred_lft forever

在命名空间内:

132: my-ceth@if133: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether e2:c6:18:68:c8:14 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.2.50/24 scope global my-ceth
       valid_lft forever preferred_lft forever

我的ip route样子是这样的:

default via 192.168.88.1 dev wlo1 proto dhcp metric 600 
10.1.2.0/24 dev my-veth proto kernel scope link src 10.1.2.1 

在命名空间内:

default via 10.1.2.1 dev my-ceth 
10.1.2.0/24 dev my-ceth proto kernel scope link src 10.1.2.50 

我的iptables -t nat --list-rules命名空间外部如下所示:

-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 10.1.2.0/24 ! -o my-veth -j MASQUERADE
-A DOCKER -i docker0 -j RETURN

但我无法从命名空间内部 ping 通公共 IP:

$ sudo ip netns exec my-ns ping 93.184.215.14
PING 93.184.215.14 (93.184.215.14) 56(84) bytes of data.

任何帮助都非常感谢!

1

  • 您确实应该检查防火墙(iptables 和 nftables)的过滤部分(针对“转发”流量)。


    – 


最佳答案
1

这一切看起来都大体正确。我已将您的步骤浓缩为以下脚本,其中我做了一些不会对操作产生影响的更改:

  • 我已将您使用的 替换nsenter为更简单的替代方法,即ip -n <namespace>在适当的地方,或ip netns exec
  • netns我使用选项将“创建 veth 对”步骤和“将对的一端添加到网络命名空间”步骤合并为一个步骤ip link add
  • LOG在规则之前添加了一条规则MASQUERADE只是为了在内核日志中看到匹配的流量。
#!/bin/bash

set -e

# make sure we haven't already run this script
if ip netns exec my-ns true > /dev/null 2>&1; then
  echo "ERROR: namespace already exists" >&2
  exit 1
fi

ip netns add my-ns

ip link add my-veth type veth peer name my-ceth netns my-ns

ip addr add 10.1.2.1/24 dev my-veth
ip link set my-veth up

ip -n my-ns addr add 10.1.2.50/24 dev my-ceth
ip -n my-ns link set my-ceth up
ip -n my-ns route add default via 10.1.2.1

iptables -t nat -A POSTROUTING -s 10.1.2.0/24 -j LOG
iptables -t nat -A POSTROUTING -s 10.1.2.0/24 ! -o my-veth -j MASQUERADE

运行此脚本后,我可以从网络命名空间 ping 外部地址:

# ip netns exec my-ns ping -c1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=58 time=16.9 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 16.853/16.853/16.853/0.000 ms

4

  • “它对我有用”实际上并不能解决任何问题。


    – 

  • @larsks 这很有帮助,也很慷慨。感谢您对使用 ip 命令的指点。iptables 日志行对我特别有用。我将尝试在安装了 ubuntu 的 VM 上执行相同操作。我现在的猜测是,我的问题与 docker 在我的系统上安装的 iptables 规则存在某种冲突。


    – 

  • @TomYan 它至少与尖刻的评论一样有用,甚至可能更有用。


    – 


  • @AlexFlint 您可以研究启用跟踪功能以识别哪些规则与您的流量匹配。如何做到这一点取决于您使用的是旧版 iptables 还是 iptables-nft(或直接使用 nft)。


    –