如何在 Linux 网络命名空间之间转发流量?

Sha*_*000 5 linux networking iptables network-namespaces

我能够设置一个网络命名空间并启动一个在命名空间内侦听 127.0.0.1 的服务器:

# ip netns add vpn
# ip netns exec vpn ip link set dev lo up
# ip netns exec vpn nc -l -s 127.0.0.1 -p 80 &

# ip netns exec vpn netstat -tlpn

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:80            0.0.0.0:*               LISTEN      5598/nc
Run Code Online (Sandbox Code Playgroud)

之后,我可以连接到命名空间内的服务器:

# ip netns exec vpn nc 127.0.0.1 80 -zv
localhost [127.0.0.1] 80 (http) open
Run Code Online (Sandbox Code Playgroud)

但是我无法连接到命名空间之外的服务器:

# nc 127.0.0.1 80
(UNKNOWN) [127.0.0.1] 80 (http) : Connection refused
Run Code Online (Sandbox Code Playgroud)

如何配置 iptables 或命名空间将流量从全局命名空间转发到 vpn 命名空间?

A.B*_*A.B 11

第一:我认为您无法通过使用 127.0.0.0/8 和/或环回接口(如 lo)来实现这一点。您必须使用其他一些 IP 和接口,因为 127.0.0.0/8 和环回有一些特定的硬连线。

那么肯定有不止一种方法,但这里有一个例子:

# ip netns add vpn
# ip link add name vethhost0 type veth peer name vethvpn0
# ip link set vethvpn0 netns vpn
# ip addr add 10.0.0.1/24 dev vethhost0
# ip netns exec vpn ip addr add 10.0.0.2/24 dev vethvpn0
# ip link set vethhost0 up
# ip netns exec vpn ip link set vethvpn0 up
# ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.134 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.100 ms
Run Code Online (Sandbox Code Playgroud)

第一个命令凭空创建一对通过虚拟以太网电缆连接的虚拟以太网接口。第二个命令将这些接口之一移动到 netns vpn 中。把它看作是 socketpair(2) 或 pipe(2) 之类的东西:一个进程创建一对,然后分叉,每个进程只保留一对的一端,他们​​可以通信。

通常(LXC,virt-manager,...)当你有很多网络时,还有一个桥接器可以将所有东西放在同一个局域网中。

一旦到位,对于主机来说,它就像任何路由器一样。启用 ip 转发(如果可以,请限制更多:至少 vethhost0 和主界面需要它):

# echo 1 > /proc/sys/net/ipv4/conf/all/forwarding
Run Code Online (Sandbox Code Playgroud)

添加一些 DNAT 规则,例如:

# iptables -t nat -A PREROUTING ! -s 10.0.0.0/24 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用以下命令在 vpn 中添加默认路由:

# ip netns exec vpn ip route add default via 10.0.0.1
Run Code Online (Sandbox Code Playgroud)

或者,改为添加 SNAT 规则,让所有内容都被视为来自 vpn 内的 10.0.0.1。

# iptables -t nat -A POSTROUTING -d 10.0.0.2/24 -j SNAT --to-source 10.0.0.1
Run Code Online (Sandbox Code Playgroud)

有了这个,您可以从任何其他主机进行测试,但不能从主机本身进行测试。为此,还需要添加一个类似于之前 DNAT 的 DNAT 规则,但在 OUTPUT 中并更改(否则任何传出的 http 连接也会更改)到您自己的 IP。假设您的 IP 是 192.168.1.2:

# iptables -t nat -A OUTPUT -d 192.168.1.2 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
Run Code Online (Sandbox Code Playgroud)

现在,如果您不使用环回 ip,而是从主机连接到自身,它甚至可以工作,但属于具有上述 nat 规则的主机的任何其他 IP。假设您的 IP 是 192.168.1.2:

# ip netns exec vpn nc -l -s 10.0.0.2 -p 80 &
[1] 10639
# nc -vz 192.168.1.2 80
nc: myhost (192.168.1.2) 80 [http] open
#
[1]+  Done                    ip netns exec vpn nc -l -s 10.0.0.2 -p 80
Run Code Online (Sandbox Code Playgroud)