Osk*_*erg 4 routing linux-kernel nftables
如下图所示,是否可以像这样通过 Linux 内核路由流量?我希望模拟“内部”网络之外的设备的精确副本,具有相同的 IP 范围,同时使内部和外部设备能够相互通信,而不知道对方具有与其自身相同的 IP。
例如:“内部”的设备 X 联系 192.168.3.5,该数据会转到中间人桥并转发到 IP 192.168.2.5 的“外部”设备 Y。然后响应被发送回中间人,并发送到 IP 192.168.2.5 的设备 X。
我知道这可以通过网络命名空间实现,并且可以进行有效的模拟。但是,我希望避免使用命名空间,而是针对不同的流量方向使用不同的路由表之类的东西。这可能吗?
如果我理解正确的话,由于 IP 范围重复,我无法使用 NAT。它是否正确?
我们首先配置 上的网络接口middleman
。我假设您已登录系统控制台,或者可以通过不涉及 或inner
网络的界面进行访问outer
。出于本答案的目的,我们假设接口middleman-eth0
onmiddleman
连接到“内部”网络并middleman-eth1
连接到“外部”网络。这为我们提供了以下网络拓扑:
我们需要确保我们已启用数据包转发middleman
:
sysctl -w net.ipv4.ip_forward=1
Run Code Online (Sandbox Code Playgroud)
我们应该从一个空的 netfilter 配置开始。运行iptables-save
不应产生任何输出。
为此, 和middleman-eth0
都middleman-eth1
具有相同的网络配置:
ip addr add 192.168.2.1/24 dev middleman-eth0
ip addr add 192.168.2.1/24 dev middleman-eth1
Run Code Online (Sandbox Code Playgroud)
如果您认为这看起来很奇怪,那么您是对的!目前,路由表middleman
如下所示:
192.168.2.0/24 dev middleman-eth1 proto kernel scope link src 192.168.2.1
192.168.2.0/24 dev middleman-eth0 proto kernel scope link src 192.168.2.1
Run Code Online (Sandbox Code Playgroud)
这不会特别有用。
我们将利用 Linux 对“虚拟路由和转发”(“VRF”)的支持。这允许我们在系统上创建多个隔离的路由域,以便传入的流量eth0
将看到与传入的流量不同的路由表eth1
。
我们首先创建 VRF 接口:
ip link add vrf-inner type vrf table 100
ip link set vrf-inner up
ip link add vrf-outer type vrf table 200
ip link set vrf-outer up
Run Code Online (Sandbox Code Playgroud)
这些命令设置两个 VRF 设备,将每个设备与特定的路由表相关联。
接下来,我们将每个物理接口连接到 VRF 设备:
ip link set dev middleman-eth0 master vrf-inner
ip link set dev middleman-eth1 master vrf-outer
Run Code Online (Sandbox Code Playgroud)
经过这些更改,主路由表现在为空:
middleman# ip route show
<no output>
Run Code Online (Sandbox Code Playgroud)
middleman-eth0
在表 100 中,我们看到与(“内部”网络)相关的规则:
middleman# ip route show table 100
broadcast 192.168.2.0 dev middleman-eth0 proto kernel scope link src 192.168.2.1
192.168.2.0/24 dev middleman-eth0 proto kernel scope link src 192.168.2.1
local 192.168.2.1 dev middleman-eth0 proto kernel scope host src 192.168.2.1
broadcast 192.168.2.255 dev middleman-eth0 proto kernel scope link src 192.168.2.1
Run Code Online (Sandbox Code Playgroud)
middleman-eth1
在表 200 中,我们看到(“外部”网络)的规则:
middleman# ip route show table 200
broadcast 192.168.2.0 dev middleman-eth1 proto kernel scope link src 192.168.2.1
192.168.2.0/24 dev middleman-eth1 proto kernel scope link src 192.168.2.1
local 192.168.2.1 dev middleman-eth1 proto kernel scope host src 192.168.2.1
broadcast 192.168.2.255 dev middleman-eth1 proto kernel scope link src 192.168.2.1
Run Code Online (Sandbox Code Playgroud)
此时,我们实际上有两个断开连接的网络,如下所示:
“内部”网络上的主机可以联系 192.168.2.1,并且他们将与 进行通信middleman-eth0
。“外部”网络上的主机也可以联系 192.168.2.1,但它们将与 进行通信middleman-eth1
。
我们现在需要做的就是设置映射,以便任何一方都可以使用192.168.3.0/24
另一方联系节点的地址。
首先,我们需要告诉所有节点它们192.168.3.0/24
通过以下方式路由到网络middleman
:这意味着在所有节点上,在“内部”和“外部”网络上,我们需要:
ip route add 192.168.3.0/24 via 192.168.2.1
Run Code Online (Sandbox Code Playgroud)
在 上middleman
,我们需要 (a) 将192.168.3.0/24
范围内的地址映射到范围中192.168.2.0/24
,并且 (b) 确保在路由连接时使用正确的路由表。为了实现(a),我们可以创建一些NETMAP
规则:
iptables -t nat -A PREROUTING -d 192.168.3.0/24 -j NETMAP --to 192.168.2.0/24
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -j NETMAP --to 192.168.3.0/24
Run Code Online (Sandbox Code Playgroud)
为了实现 (b),我们首先根据数据包的入口接口来标记数据包:
iptables -t mangle -A PREROUTING -i middleman-eth0 -d 192.168.3.0/24 -j MARK --set-mark 100
iptables -t mangle -A PREROUTING -i middleman-eth1 -d 192.168.3.0/24 -j MARK --set-mark 200
Run Code Online (Sandbox Code Playgroud)
然后使用这些标记来选择路由表:
ip rule add prio 100 fwmark 100 lookup 200
ip rule add prio 200 fwmark 200 lookup 100
Run Code Online (Sandbox Code Playgroud)
回想一下之前的内容,表 100 具有针对“内部”网络的规则,而表 200 具有针对“外部”网络的规则,因此这些规则表示“对于到达接口 的数据包middleman-eth0
,使用与 关联的路由表做出路由决策middleman-eth1
” ,反之亦然。
完成所有这些后,如果192.168.2.10
“内部”网络上的节点尝试 ping 192.168.3.10
:
192.168.3.0/24 via 192.168.2.1
路由条目,数据包被路由到中间人middleman-eth0
MANGLE
表链PREROUTING
并将 fwmark 设置为100
NAT
表链PREROUTING
并映射到目的地192.168.2.10
fwmark 100 lookup 200
规则192.168.2.0/24 dev middleman-eth1
,因此内核会将其发送到设备middleman-eth1
NAT
表链POSTROUTING
,其源映射到192.168.3.10
。192.168.2.10
。192.168.3.10
middleman-eth1
MANGLE
表链PREROUTING
并将 fwmark 设置为200
NAT
表链PREROUTING
并映射到目的地192.168.2.10
fwmark 200 lookup 100
规则192.168.2.0/24 dev middleman-eth0
规则,因此内核会将其发送到设备middleman-eth0
NAT
表链POSTROUTING
,其源映射到表链192.168.3.10
192.168.2.10
,该节点看到对其最初发出的请求的回复。如果在“内部”节点 0 ( 192.168.2.10
) 上,我们尝试使用 地址 ping “外部”节点 0 192.168.3.10
,则tcpdump -nn -i any icmp
在内部节点 0 上运行会显示:
07:01:58.125370 innernode0-eth0 Out IP 192.168.2.10 > 192.168.3.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125533 innernode0-eth0 In IP 192.168.3.10 > 192.168.2.10: ICMP echo reply, id 12999, seq 1, length 64
Run Code Online (Sandbox Code Playgroud)
我们看到middleman
:
07:01:58.125440 middleman-eth0 In IP 192.168.2.10 > 192.168.3.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125459 middleman-eth1 Out IP 192.168.3.10 > 192.168.2.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125514 middleman-eth1 In IP 192.168.2.10 > 192.168.3.10: ICMP echo reply, id 12999, seq 1, length 64
07:01:58.125518 middleman-eth0 Out IP 192.168.3.10 > 192.168.2.10: ICMP echo reply, id 12999, seq 1, length 64
Run Code Online (Sandbox Code Playgroud)
在“外部”节点 0 上我们看到:
07:01:58.125489 outernode0-eth0 In IP 192.168.3.10 > 192.168.2.10: ICMP echo request, id 12999, seq 1, length 64
07:01:58.125497 outernode0-eth0 Out IP 192.168.2.10 > 192.168.3.10: ICMP echo reply, id 12999, seq 1, length 64
Run Code Online (Sandbox Code Playgroud)
所以我认为我们已经实现了您的目标!
我使用mininet来测试这个配置;您可以在这里找到我的测试环境的完整源代码。这里有一个该配置的实际操作视频。
正如AB在评论中指出的,这个配置有问题!默认情况下,内核的连接跟踪逻辑仅查看源/目标地址和源/目标端口。innernode0
从端口 4000 到端口 80的连接outernode0
看起来与相反方向的连接相同...也就是说,假设我在所有节点上的端口 80 上运行一个 Web 服务器,这两个命令:
innernode0# curl --local-port 4000 192.168.3.10
Run Code Online (Sandbox Code Playgroud)
和:
outernode0# curl --local-port 4000 192.168.3.10
Run Code Online (Sandbox Code Playgroud)
将导致在以下位置出现单个连接跟踪条目middleman
:
middleman# conntrack -L
tcp 6 118 TIME_WAIT src=192.168.2.10 dst=192.168.3.10 sport=4000 dport=80 src=192.168.2.10 dstroot@mininet-vm:/proc/net=192.168.3.10 sport=80 dport=4000 [ASSURED] mark=0 use=1
Run Code Online (Sandbox Code Playgroud)
我们告诉 conntrack 子系统如何区分这些连接。我们可以通过向表中的链添加一对CT
规则来做到这一点:PREROUTING
RAW
iptables -t raw -A PREROUTING -s 192.168.2.0/24 -i middleman-eth0 -j CT --zone-orig 100
iptables -t raw -A PREROUTING -s 192.168.2.0/24 -i middleman-eth1 -j CT --zone-orig 200
Run Code Online (Sandbox Code Playgroud)
有了这些规则,我们现在可以在 conntrack 表中看到两个单独的连接:
middleman# conntrack -L
tcp 6 113 TIME_WAIT src=192.168.2.10 dst=192.168.3.10 sport=4000 dport=80 zone-orig=200 src=192.168.2.10 dst=192.168.3.10 sport=80 dport=40568 [ASSURED] mark=0 use=1
tcp 6 112 TIME_WAIT src=192.168.2.10 dst=192.168.3.10 sport=4000 dport=80 zone-orig=100 src=192.168.2.10 dst=192.168.3.10 sport=80 dport=4000 [ASSURED] mark=0 use=1
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
372 次 |
最近记录: |