Linux Network Namespace 入门

隔离你的网络环境:Linux Network Namespace 入门

你可能想知道,在同一个 Linux 系统里,不同的程序能不能拥有各自独立的网络设置?比如,让一个程序只能访问特定网站,而另一个程序可以自由访问所有网络资源,并且它们之间互不干扰。这正是 Linux Network Namespace 的核心功能。

什么是 Network Namespace?

在 Linux 系统中,默认情况下,所有网络相关的配置,包括网卡、IP 地址、路由规则、防火墙设置等,都属于一个叫做 “init” Network Namespace 的默认环境。当你运行程序时,它们通常在这个默认空间里,共享着相同的网络配置。

Network Namespace 允许你创建完全独立且隔离的网络环境。这意味着每个 Namespace 都拥有:

  • 独立的网络接口: 比如 eth0lo 等,在一个 Namespace 里看到的网卡,在另一个 Namespace 里是不可见的。
  • 独立的 IP 地址: 不同 Namespace 可以使用相同的 IP 地址,因为它们互不影响。
  • 独立的路由表: 决定数据包如何传输到目的地。
  • 独立的 ARP 表: 用于将 IP 地址解析为物理 MAC 地址。
  • 独立的防火墙规则 (iptables): 每个 Namespace 都能有自己一套防火墙策略,彼此独立。

为什么需要 Network Namespace?

Network Namespace 在很多场景下都非常有用:

  • 容器技术: Docker、Kubernetes 等工具正是利用 Network Namespace 为每个容器提供了隔离的网络环境。
  • 网络功能虚拟化 (NFV): 将路由器、防火墙等网络设备以软件形式运行,每个都在独立的 Namespace 中。
  • 测试与开发: 在不影响主系统网络的情况下,安全地测试新的网络配置或应用程序。
  • 安全隔离: 限制应用程序的网络访问范围,提高系统安全性。

网络配置实践解析

现在,我们一步步执行命令,了解如何建立一个独立网络环境并使其与主系统通信的。

1. 创建并进入一个独立网络环境
[root@localhost ~]# ip netns ls

这个命令用来列出当前系统中的所有 Network Namespace。刚开始执行时,可能没有输出,因为你可能只在使用默认的主 Namespace。

[root@localhost ~]# ip netns add game

这条命令创建了一个名为 “game” 的新 Network Namespace。现在,系统有了一个全新的、独立的网络配置区域。

[root@localhost ~]# ip netns ls
game

再次列出 Namespace,你会看到 “game” 已经出现在列表中。

[root@localhost ~]# ip netns exec game bash

ip netns exec 命令的作用是在指定的 Network Namespace 中执行命令。这里,我们告诉系统在 “game” Namespace 里启动一个新的 bash 会话。

此刻,你所处的是一个完全隔离的网络环境。在这个 bash 会话里,你看到和操作的所有网络设备、IP 地址、路由表等,都只属于 “game” Network Namespace。

[root@localhost ~]# ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

进入 “game” Namespace 后执行 ip link,你会发现只有一块名为 lo (回环网卡) 的网卡。这是因为每个新 Namespace 默认只包含一个回环网卡,它是完全独立的,看不到主 Namespace 的其他网卡,比如 ens33

[root@localhost ~]# exit
exit

输入 exit 命令,你将退出 “game” Namespace 内的 bash 会话,返回到主 Namespace。

[root@localhost ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:fd:5b:bb brd ff:ff:ff:ff:ff:ff
... (省略部分输出)

回到主 Namespace 后再次执行 ip link,你会看到熟悉的 ens33virbr0 等网卡,这表明你已回到主系统的网络环境。

[root@localhost ~]# ip netns exec game ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

这个命令再次确认了 “game” Namespace 中只有 lo 网卡。

[root@localhost ~]# ip netns exec game route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref     Use Iface

在 “game” Namespace 中查看路由表,发现它是空的。这意味着 “game” Namespace 目前不知道如何将数据包发送到它自己网络之外的目的地。

[root@localhost ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref     Use Iface
0.0.0.0         192.168.1.2     0.0.0.0         UG    100     0       0 ens33
192.168.1.0     0.0.0.0         255.255.255.0   U     100     0       0 ens33
192.168.122.0   0.0.0.0         255.255.255.0   U     0       0 virbr0

这是主 Namespace 的路由表,包含连接到互联网和本地网络的路由信息。

[root@localhost ~]# ip netns exec game iptables -nL
... (输出为空)
[root@localhost ~]# ip netns exec game iptables -nL -t nat
... (输出为空)

这些命令显示了 “game” Namespace 中的防火墙 (iptables) 规则,它们也是空的,进一步证明了 Namespace 的隔离性。


2. 连接两个网络环境:使用 veth 网卡对

现在,“game” Namespace 是一个独立但无法与外界通信的网络环境。为了让 “game” Namespace 能够与主 Namespace 通信,我们需要建立一个连接。这个连接就是通过 veth (Virtual Ethernet) pair 实现的。

一个 veth pair 是一对虚拟网卡。它们像一根虚拟的网线,一端在主 Namespace,另一端在 “game” Namespace。任何通过一端发送的数据包都会从另一端接收到。

[root@localhost ~]# ip link add veth1_out type veth peer name veth1_in

这条命令创建了一个 veth pair。

  • veth1_out:是这个 veth pair 的一端,它将保留在主 Namespace
  • veth1_in:是这个 veth pair 的另一端,我们计划将其移动到 “game” Namespace。
[root@localhost ~]# ip -br a
...
veth1_in@veth1_out DOWN
veth1_out@veth1_in DOWN

这时,你会在主 Namespace 看到新创建的 veth1_inveth1_out。它们的名字后面带有 @ 和对方的名字,表示它们是相互连接的。

[root@localhost ~]# ip link set veth1_in netns game

这是关键一步!它将 veth1_in 这块网卡从主 Namespace 移动到 “game” Namespace。现在,veth1_out 仍在主 Namespace,而 veth1_in 已经进入 “game” Namespace。

[root@localhost ~]# ip link
...
6: veth1_out@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:dc:ea:58:9f:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0

在主 Namespace 中,你现在只能看到 veth1_out 了。

[root@localhost ~]# ip netns exec game ip link ls
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1_in@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:3a:95:ba:87:ae brd ff:ff:ff:ff:ff:ff link-netnsid 0

在 “game” Namespace 中,你现在不仅有 lo 网卡,还看到了 veth1_in 网卡。这表明 veth pair 的两端已经分别位于不同的 Namespace 中。


3. 配置 IP 地址并启用网卡

为了让 veth 网卡能够传输数据,我们需要为它的两端都分配 IP 地址,并将其激活。

[root@localhost ~]# ip netns exec game ip addr add 192.168.110.2/24 dev veth1_in

这条命令在 “game” Namespace 中,给 veth1_in 网卡分配了 IP 地址 192.168.110.2,子网掩码为 /24

[root@localhost ~]# ip netns exec game ip link set veth1_in up
[root@localhost ~]# ip netns exec game ip link set lo up

这两条命令分别激活了 “game” Namespace 中的 veth1_in 网卡和 lo 网卡。只有激活的网卡才能发送和接收数据。

[root@localhost ~]# ip addr add 192.168.110.1/24 dev veth1_out

这条命令在主 Namespace 中,给 veth1_out 网卡分配了 IP 地址 192.168.110.1,子网掩码为 /24

[root@localhost ~]# ip link set veth1_out up

激活主 Namespace 中的 veth1_out 网卡。

现在,veth1_out (192.168.110.1) 在主 Namespace,veth1_in (192.168.110.2) 在 “game” Namespace,它们位于同一个 192.168.110.0/24 子网,可以通过这对虚拟网卡直接通信了。


4. 测试网络连通性
[root@localhost ~]# ping -c 5 192.168.110.2

这条命令在主 Namespace 中,尝试 ping “game” Namespace 中的 192.168.110.2。如果配置正确,你会看到 ping 成功,这表示主 Namespace 可以通过 veth1_outveth1_in 通信。

[root@localhost ~]# ip netns exec game ping -c 4 192.168.110.1

这条命令在 “game” Namespace 中,尝试 ping 主 Namespace 中的 192.168.110.1。同样,如果成功,说明 “game” Namespace 可以通过 veth1_inveth1_out 通信。


5. 让独立网络环境连接外部网络:配置路由和 IP 转发

尽管 “game” Namespace 现在可以和主 Namespace 通信了,但它还不能直接访问互联网或主 Namespace 之外的其他网络。这是因为 “game” Namespace 的路由表是空的。我们需要告诉它,如果想访问它不明确目的地的网络,应该把数据包发给谁。

[root@localhost ~]# ip netns exec game ip route add default via 192.168.110.1

这条命令在 “game” Namespace 中添加了一条默认路由。它的作用是:“如果 ‘game’ Namespace 要发送数据包到一个它不明确目的地的网络,那么就把这个数据包发送给 192.168.110.1(也就是主 Namespace 中的 veth1_out)。”

现在,veth1_out 就像一个网关,负责将 “game” Namespace 的数据包转发出去。

[root@localhost ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@localhost ~]# cat /etc/sysctl.conf
# ...
net.ipv4.ip_forward=1

net.ipv4.ip_forward 是一个内核参数,它控制着 Linux 系统是否允许进行 IP 转发。默认情况下,这个功能是关闭的。当你将其设置为 1 时,就允许你的 Linux 主机充当路由器,将从一个网络接口收到的数据包转发到另一个网络接口。

在这里,我们开启了主 Namespace 的 IP 转发功能。这意味着,当 “game” Namespace 的数据包通过 veth1_in 发送到主 Namespace 的 veth1_out 时,主 Namespace 会检查自己的路由表,并将这些数据包转发到正确的目的地(比如互联网)。

[root@localhost ~]# ip netns exec game ping -c 4 192.168.1.148
PING 192.168.1.148 (192.168.1.148) 56(84) bytes of data.
... (ping 成功)

最后,在 “game” Namespace 中 ping 主 Namespace 的 IP 地址 192.168.1.148 (你的 ens33 网卡 IP)。这次 ping 成功了!

这是因为:

  1. “game” Namespace 中的 ping 命令会向 192.168.1.148 发送数据包。
  2. “game” Namespace 发现 192.168.1.148 不在 192.168.110.0/24 这个子网内,所以它会根据默认路由将数据包发送给 192.168.110.1 (也就是主 Namespace 的 veth1_out)。
  3. 主 Namespace 的 veth1_out 收到数据包后,由于 net.ipv4.ip_forward 已经开启,它会查看自己的路由表。
  4. 主 Namespace 发现 192.168.1.148 在它的 ens33 网卡所在的子网,于是将数据包通过 ens33 发送出去。
  5. 192.168.1.148 收到数据包并回复,回复的数据包也会经过主 Namespace 的路由转发,最终回到 “game” Namespace。

通过这些步骤,你成功地创建了一个独立的 Network Namespace “game”,并利用 veth 网卡对和 IP 转发功能,让它能够与主系统以及外部网络进行通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值