强制本地 IP 流量到外部接口

cal*_*doa 34 networking linux ip command-line-interface iptables

我有一台带有多个接口的机器,我可以根据需要进行配置,例如:

  • eth1:192.168.1.1
  • eth2:192.168.2.2

我想通过另一个接口转发发送到这些本地地址之一的所有流量。例如,对位于 192.168.1.1 的 iperf、ftp、http 服务器的所有请求不应仅在内部路由,而是通过 eth2 转发(外部网络将负责将数据包重新路由到 eth1)。

我尝试并查看了几个命令,例如 iptables、ip route 等……但没有任何效果。

我能得到的最接近的行为是:

ip route change to 192.168.1.1/24 dev eth2
Run Code Online (Sandbox Code Playgroud)

它在 eth2 上发送所有 192.168.1.x,除了仍然在内部路由的 192.168.1.1。然后我可以将所有流量定向到 eth1 上的假 192.168.1.2,然后在内部重新路由到 192.168.1.1 吗?我实际上正在与 iptables 斗争,但这对我来说太难了。

此设置的目标是在不使用两台 PC 的情况下进行接口驱动程序测试。

我正在使用 Linux,但如果您知道如何使用 Windows,我会购买它!

编辑:

外网只是eth1和eth2之间的交叉网线。假设我的机器上有一个 http 服务器。现在我想从同一台机器访问这个服务器,但我想强制 TCP/IP 流量通过这个 eth1/eth2 电缆。我应该如何为此配置我的接口?

Ste*_*let 34

我在 Linux 上成功地使用了以下内容在“环回”模式下在新的双端口 10Gbps 卡上测试吞吐量,即一个端口直接插入另一个端口。这只是为了将数据包从网络中强制发送出去而已,但如果不这样做,Linux 只会使通过内核的流量短路(因此是 OP 的问题)。在上面凯西的回答中,我不确定是否真的有必要在上面安装外部路由器,但以下内容是完全独立的。这两个接口是 eth2 和 eth3。

为接口提供 IP,并将它们放在不同的网络上:

ifconfig eth2 10.50.0.1/24
ifconfig eth3 10.50.1.1/24
Run Code Online (Sandbox Code Playgroud)

接下来我们将设置一个双 NAT 场景:两个新的假网络用于到达另一个网络。在出路时,将 NAT 源发送到您的假网络。在途中,确定目的地。对于另一个网络,反之亦然:

# nat source IP 10.50.0.1 -> 10.60.0.1 when going to 10.60.1.1
iptables -t nat -A POSTROUTING -s 10.50.0.1 -d 10.60.1.1 -j SNAT --to-source 10.60.0.1

# nat inbound 10.60.0.1 -> 10.50.0.1
iptables -t nat -A PREROUTING -d 10.60.0.1 -j DNAT --to-destination 10.50.0.1

# nat source IP 10.50.1.1 -> 10.60.1.1 when going to 10.60.0.1
iptables -t nat -A POSTROUTING -s 10.50.1.1 -d 10.60.0.1 -j SNAT --to-source 10.60.1.1

# nat inbound 10.60.1.1 -> 10.50.1.1
iptables -t nat -A PREROUTING -d 10.60.1.1 -j DNAT --to-destination 10.50.1.1
Run Code Online (Sandbox Code Playgroud)

现在告诉系统如何访问每个假网络,并预填充 arp 条目(确保替换您的 MAC 地址,不要使用我的):

ip route add 10.60.1.1 dev eth2
arp -i eth2 -s 10.60.1.1 00:1B:21:C1:F6:0F # eth3's mac address

ip route add 10.60.0.1 dev eth3 
arp -i eth3 -s 10.60.0.1 00:1B:21:C1:F6:0E # eth2's mac address
Run Code Online (Sandbox Code Playgroud)

这足以愚弄 Linux 以实际将数据包放到网络上。例如:

ping 10.60.1.1
Run Code Online (Sandbox Code Playgroud)

离开 eth2,源 IP 10.50.0.1 被 NAT 转换为 10.60.0.1,当它进入 eth3 时,目标 10.60.1.1 被 NAT 转换为 10.50.1.1。回复也经历了类似的过程。

现在使用 iperf 来测试吞吐量。绑定到正确的 IP,并确定您正在联系哪个 IP(另一端的假地址):

# server
./iperf -B 10.50.1.1 -s

# client: your destination is the other end's fake address
./iperf -B 10.50.0.1 -c 10.60.1.1 -t 60 -i 10
Run Code Online (Sandbox Code Playgroud)

确保流量真正流出线路:

tcpdump -nn -i eth2 -c 500
Run Code Online (Sandbox Code Playgroud)

您还可以查看 /proc/interrupts 以确保该卡正在被使用:

while true ; do egrep 'eth2|eth3' /proc/interrupts ; sleep 1 ; done
Run Code Online (Sandbox Code Playgroud)

无论如何,我发现这篇文章正在寻找如何做到这一点,感谢问答人员,并希望这有助于其他人在未来找到这篇文章。

  • +1 很棒的解决方案 - 这甚至不需要激活 ip 转发!这正是我现在所需要的(通过环回进行 10GB 测试)。 (2认同)

小智 27

一如既往 - 我有点晚了 - 但现在可以使用网络命名空间来隔离接口并防止任何本地转发(和摆弄 iptables :))。

创建命名空间(所有的都使用所需的权限完成,例如作为 root):

ip netns add ns_server
ip netns add ns_client
Run Code Online (Sandbox Code Playgroud)

请注意,现在必须在分配的命名空间的上下文中访问接口状态/配置 - 因此,如果您运行裸ip 链接,它们将不会出现,因为这是在默认命名空间的上下文中运行的。在命名空间内运行命令可以使用

ip netns exec <namespace-name> <command>
Run Code Online (Sandbox Code Playgroud)

作为前缀。

现在为接口分配命名空间,应用配置并设置接口:

ip link set eth1 netns ns_server
ip netns exec ns_server ip addr add dev eth1 192.168.1.1/24
ip netns exec ns_server ip link set dev eth1 up
ip link set eth2 netns ns_client
ip netns exec ns_client ip addr add dev eth2 192.168.1.2/24
ip netns exec ns_client ip link set dev eth2 up
Run Code Online (Sandbox Code Playgroud)

现在您可以在命名空间内执行应用程序 - 为 iperf 服务器运行

ip netns exec ns_server iperf -s -B 192.168.1.1
Run Code Online (Sandbox Code Playgroud)

和客户:

ip netns exec ns_client iperf -c 192.168.1.1 -B 192.168.1.2
Run Code Online (Sandbox Code Playgroud)

流量现在将通过物理接口发送,因为整个网络堆栈、接口、路由……都被命名空间隔离,因此内核无法将流量中使用的地址与本地(可用)接口进行匹配。

如果您完成了实验,只需删除命名空间:

ip netns del <namespace-name>
Run Code Online (Sandbox Code Playgroud)

接口将重新分配给默认命名空间,并且在命名空间内完成的所有配置都将消失(例如,无需删除分配的 IP 地址)。


cmc*_*nty 15

我扩展了 caladona 的答案,因为我看不到响应数据包。对于这个例子:

  1. 在我的本地 PC 上,我在不同的子网上有 NIC,192.168.1/24192.168.2/24
  2. 有一个可以访问两个子网的外部路由器/PC。
  3. 我想通过本地 PC 上的 NIC 发送双向流量。
  4. 配置要求每个子网有两个未使用的 IP 地址。

本地 PC iptable 路由设置为 SNAT 和 DNAT 传出流量到“假”IP。

iptables -t nat -A POSTROUTING -d 192.168.1.100 -s 192.168.2.0/24 -j SNAT --to-source      192.168.2.100
iptables -t nat -A PREROUTING  -d 192.168.1.100 -i eth0           -j DNAT --to-destination 192.168.1.1
iptables -t nat -A POSTROUTING -d 192.168.2.100 -s 192.168.1.0/24 -j SNAT --to-source      192.168.1.100
iptables -t nat -A PREROUTING  -d 192.168.2.100 -i eth1           -j DNAT --to-destination 192.168.2.1
Run Code Online (Sandbox Code Playgroud)

规则执行以下操作:

  1. 在传出数据包上将 192.168.2.1 源重写为 192.168.2.100
  2. 在传入数据包上将 192.168.1.100 目标重写为 192.168.1.1
  3. 在传出数据包上将 192.168.1.1 源重写为 192.168.1.100
  4. 在传入数据包上将 192.168.2.100 目的地重写为 192.168.2.1

总而言之,本地系统现在可以与地址为 192.168.1.100 和 192.168.2.100 的“虚拟”机器通信。

接下来,您必须强制本地 PC 使用外部路由器来访问您的假 IP。为此,您可以通过路由器创建到 IP 的直接路由。您要确保将数据包强制发送到目标子网的对面。

ip route 192.168.1.100 via $ROUTER_2_SUBNET_IP 
ip route 192.168.2.100 via $ROUTER_1_SUBNET_IP
Run Code Online (Sandbox Code Playgroud)

最后,要使这一切正常进行,外部路由器需要知道如何访问本地 PC 上的伪造 IP。您可以通过为您的系统打开代理 ARP 来进行瘦身。

echo 1 | sudo tee /proc/sys/net/ipv4/conf/all/proxy_arp
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Run Code Online (Sandbox Code Playgroud)

通过此设置,您现在可以将假 IP 视为本地 PC 上的真实系统。将数据发送到 .1 子网将强制数据包从 .2 接口传出。将数据发送到 .2 子网将强制数据包从 .1 接口传出。

ping 192.168.1.100
ping 192.168.2.100
Run Code Online (Sandbox Code Playgroud)