如何避免在Linux中通过本地堆栈进行路由

我有以下的环境:2个主机,每个主机有2个以太网接口(如下图所示):

+---------+ +---------+ | (1)+---------------+(2) | | host1 | | host2 | | | | | | (3)+---------------+(4) | +---------+ +---------+ 

我想编写客户端/服务器套接字工具,将打开host1上的客户端和服务器套接字。 我希望客户端通过接口(1)和服务器发送TCP数据包在接口(3)上侦听,数据包将通过主机2。

通常,Linux堆栈将通过本地TCP / IP堆栈路由这些数据包,而不会将这些数据包发送到host2。

我曾尝试使用SO_BINDTODEVICE选项的服务器和客户端,似乎服务器确实是绑定到接口(3),并没有监听本地主机的stream量。 我检查过来自host1的客户端不能被接受,而来自host2的客户端却不能接受。

不幸的是,通过接口(1)到接口(2)不会发送客户端数据包(即使接口(1)上的tcpdump也看不到数据包)。 当然路由是正确的(我可以ping(2)从(1),(4)从(1),(4)从(3)等)。

我的问题是,如果这是可能的,而不使用自定义的TCP / IP协议栈来实现?

也许我应该尝试将目标IP地址(从客户端)更改为从外部networking(然后将使用默认网关从接口(1) – 接口(2))发送,然后在正在改变那些又改为原来的? 这样的解决scheme是可行的吗?

我在Debian下用C写我的应用程序。

添加更多的细节和说明:

  1. 当然对(1) – (2)和(3) – (4)是不同的子网
  2. 我想要达到的是(1) – >(2) – >(4) – >(3)
  3. host2是黑匣子,所以我不能安装任何数据包转发器(这将打开在接口(2)上的侦听套接字,并转发到(3)通过(4)) – 这是我想要避免的

主要问题似乎是本地交付。 当我打开host1上的套接字并想连接到套接字时,正在监听同一主机内核的其他地址,只是使用本地堆栈来传递数据包。 见下面的netfilter图:

  --->[1]--->[ROUTE]--->[3]--->[4]---> | ^ | | | [ROUTE] v | [2] [5] | ^ | | v | 

数据包正在经历[5] NF_IP_LOCAL_OUT和[2] NF_IP_LOCAL_IN,而我想迫使他们通过[4]。

Solutions Collecting From Web of "如何避免在Linux中通过本地堆栈进行路由"

未经测试(应该可以工作,但我可能错过了一些东西):

Linux有几个路由表。 表本地包含内核为添加到主机的每个IP地址自动添加的一些路由。 你可以用ip route show table local来查看它们。 标记为本地的路由表示通过回送接口的本地路由。 您可以删除该路由并添加一条普通的单播路由来替换它:

 ip route del table local <ip> dev <NIC> ip route add table local <ip> dev <NIC> ip route flush cache 

现在你的第一个盒子将尝试发送IP数据报到该IP地址,就好像它是一个远程地址,例如:它将使用ARP。 所以,如果您的第二个盒子充当路由器或正在执行代理ARP,则您必须回复ARP请求,否则您将不得不添加关联到ARP缓存:

 arp -s <ip> <MAC> 

那么,你可能必须禁用接口上的rp_filter

 echo 0 > /proc/sys/net/ipv4/conf/<NIC>/rp_filter 

他们再次,如果这不起作用,你可能可以设置L2 NAT的东西,使用ebtables

对于一个非常类似的任务,我使用这样的脚本:

 ip rule add from all lookup local # add one more local table lookup rule with high pref ip rule del pref 0 # delete default local table lookup rule ip rout add ${ip3} via ${ip2} src ${ip1} table 100 # add correct route to some table ip rule add from all lookup 100 pref 1000 # add rule to lookup new table before local table 

您可以为(1) – (2)和(3) – (4)对分配不同的子网,并使host2转发(2)到(3)的数据包。 host1上的客户端将连接到(2)的地址,因此本地网络堆栈不会知道目标服务器实际上是在本地运行。