如何避免在 Linux 中通过本地堆栈进行路由 [英] how to avoid routing through local stack in Linux

查看:25
本文介绍了如何避免在 Linux 中通过本地堆栈进行路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following environment: 2 hosts, each with 2 Ethernet interfaces connected to eachother (like on diagram below):

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

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

I would like to write client/server socket tool that will open both client and server sockets on host1. I would like client to send TCP packets through interface (1) and server to listen on interface (3), that packets will go through host2.

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

Normally Linux stack will route this packets through local TCP/IP stack without sending those to host2.

我尝试对服务器和客户端使用 SO_BINDTODEVICE 选项,似乎服务器确实绑定到接口 (3) 并且没有监听本地主机流量.我已经检查了来自 host1 的客户端不能被接受,而来自 host2 的客户端可以.

I have tried to use SO_BINDTODEVICE option for both server and client and it seems that server indeed is binded to interface (3) and is not listening localhost traffic. I have checked that client from host1 could not be accepted whereas client from host2 does.

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

Unfortunately client packets are not send out (even tcpdump on interface(1) don't see packets) through interface (1) to interface (2). Of course routing is correct (i can ping (2) from (1), (4) from (1), (4) from (3) and so on).

我的问题是这是否可以在不使用自定义 TCP/IP 堆栈的情况下实现?

My question is if this is possible to be implemented without using custom TCP/IP stack?

也许我应该尝试将目标 IP 地址(来自客户端)更改为来自外部网络(然后将使用默认网关从接口 (1) - 接口 (2) 发送),然后在后路由中将它们再次更改为原始那些?这样的解决方案可行吗?

Maybe I should try to change destination IP address (from client) to be from outside network (and then will be sent using default gateway from interface (1) - interface (2)) and then in postrouting change those again to original ones? Is such solution possible to work?

我在 Debian 下用 C 语言编写我的应用程序.

I am writting my application in C under Debian.

添加更多细节和说明:

  1. 当然,(1)--(2) 和 (3)--(4) 对都是不同的子网
  2. 我想要实现的是(1)-->(2)-->(4)-->(3)
  3. host2 是黑盒,所以我不能在那里安装任何数据包转发器(它将打开接口 (2) 上的侦听套接字并将它们转发到 (3) 到 (4)) - 这正是我想要避免的

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

The main problem seems to be local delivery. When I open socket on host1 and want to connect to socket, that is listening on other address of the same host kernel just uses local stack to deliver packets. See netfilter diagram below:

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

数据包正在通过 [5] NF_IP_LOCAL_OUT 和 [2] NF_IP_LOCAL_IN 而我想强制它们通过 [4].

Packets are going through [5] NF_IP_LOCAL_OUT and [2] NF_IP_LOCAL_IN whereas I want to force them to go through [4].

推荐答案

未经测试(应该可以,但我可能遗漏了一些东西):

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

Linux has several routing tables. Table local contains some routes that the kernel adds automatically for every IP address added to the host. You can see them with ip route show table local. Routes labeled as local indicate local routes that go through the loopback interface. You could delete that route and add a normal unicast route to replace it:

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 缓存:

Now your 1st box will try to send IP datagrams to that IP address as if it was a remote address, e.g: it will use ARP. So, your 2nd box will have to either reply to the ARP requests if it is acting as a router or is doing proxy-ARP, or you will have to add an association to the ARP cache:

arp -s <ip> <MAC>

然后,您可能必须在接口上禁用 rp_filter:

Then, you will probably have to disable rp_filter on the interfaces:

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

再说一遍,如果这不起作用,您可能可以使用 ebtables 使用 L2 NAT 设置一些东西.

Them again, if this doesn't work, you could probably set up something with L2 NAT, using ebtables.

这篇关于如何避免在 Linux 中通过本地堆栈进行路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆