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

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

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

  • 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

它会在 eth2 上发送所有 192.168.1.x,除了 192.168.1.1,它仍然在内部路由。然后我可以对所有指向 eth1 上的虚假 192.168.1.2 的流量进行 NAT 转发,并在内部重新路由到 192.168.1.1?我实际上在努力使用 iptables,但这对我来说太难了。

此设置的目标是无需使用两台 PC 即可进行接口驱动程序测试。

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

编辑:

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

答案1

由于我看不到响应数据包,因此我扩展了 caladona 的答案。对于此示例:

  1. 在我的本地电脑上,我的网卡位于不同的子网上,192.168.1/24192.168.2/24
  2. 有一个外部路由器/PC可以访问两个子网。
  3. 我想通过本地电脑上的 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

这些规则的作用如下:

  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

最后,为了使这一切正常运作,外部路由器需要知道如何访问本地 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

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

ping 192.168.1.100
ping 192.168.2.100

答案2

我成功地在 Linux 上使用下面的方法测试了新的双端口 10Gbps 卡在“环回”模式下的吞吐量,即一个端口直接插入另一个端口。这只是为了强制数据包从线路中流出而采取的一点巫术,但如果你不这样做,Linux 只会通过内核短路流量(因此 OP 提出了这个问题)。在 Casey 的上述回答中,我不确定上面是否真的有必要有一个外部路由器,但下面的方法是完全独立的。这两个接口是 eth2 和 eth3。

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

ifconfig eth2 10.50.0.1/24
ifconfig eth3 10.50.1.1/24

接下来我们将设置一个双 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

现在告诉系统如何到达每个虚假网络,并预填充 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

这足以欺骗 Linux,使其真正将数据包放到网络上。例如:

ping 10.60.1.1

从 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

确保流量确实流向了网络:

tcpdump -nn -i eth2 -c 500

你也可以观察 /proc/interrupts 来确保卡正在被使用:

while true ; do egrep 'eth2|eth3' /proc/interrupts ; sleep 1 ; done

无论如何,我在搜索如何做到这一点时找到了这篇文章,感谢问答人员,并希望这可以帮助其他人在未来找到这篇文章。

答案3

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

创建命名空间(所有操作均需具备所需权限,例如以 root 身份完成):

ip netns add ns_server
ip netns add ns_client

请注意,现在必须在指定命名空间的上下文中访问接口状态/配置 - 因此,如果您运行裸机,它们将不会出现网际协议连接因为这是在默认命名空间的上下文中运行的。可以使用以下方法在命名空间中运行命令

ip netns exec <namespace-name> <command>

作为前缀。

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

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

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

ip netns exec ns_server iperf -s -B 192.168.1.1

和客户:

ip netns exec ns_client iperf -c 192.168.1.1 -B 192.168.1.2

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

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

ip netns del <namespace-name>

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

答案4

好的,我终于成功设置了我的配置。

这个想法是使用另一个虚假地址,强制将此虚假地址路由到接口 2,然后使用 NAT/iptables 将虚假地址与真实地址 2 进行转换。

我的设置实际上是由一个路由器组成的,我可以在 IF1(接口 1)和 IF2 之间进行 telnet

在我的设置中,FAKE_ADDR 和 IF1_ADDR 位于同一个子网。

ifconfig $IF1 $IF1_ADDR netmask 255.255.255.0
ifconfig $IF2 $IF2_ADDR netmask 255.255.255.0

iptables -t nat -A PREROUTING -d $FAKE_ADDR -i $IF2 -j DNAT --to-destination $IF2_ADDR
iptables -t nat -A POSTROUTING -s $IF2_ADDR -d $IF1_ADDR/24 -j SNAT --to-source $FAKE_ADDR

route add $FAKE_ADDR gw $ROUTER_ADDR

在路由器上:

route add $FAKE_ADDR gw $IF2_ADDR

如果我向 FAKE_ADDR 发送一些内容,数据包会通过 IF1 转发到路由器,再转发到 IF2,然后 FAKE_IP 会被 IF2_ADDR 替换。数据包由服务器处理,结果会从 IF2_ADDR 发送回 IF1_ADDR,而 IF2_ADDR 会被 FAKE_ADDR 替换。

也许可以使用仅使用一根交叉电缆的更简单的配置,但由于我没有尝试,所以我更愿意提供我的工作解决方案。

相关内容