我在一个基于Linux的服务器系统上工作,其中有两个网络接口,都在同一个子网上(现在,我们只说它们是172.17.32.10
&172.17.32.11
)。当我将数据发送到网络上的主机时,我想指定数据在服务器上的哪个接口上传输。我需要能够在软件中从一个接口切换到另一个接口(甚至可能在两个接口上都传输)(静态路由规则不适用于此应用程序)。
我在StackOverflow中发现了一个相关的问题,建议使用netlink库动态修改路由。从直觉上看,这似乎应该奏效,但我想知道是否还有其他选择可以实现同样的结果。
无意冒犯,但关于使用bind()的答案是完全错误的。bind()将控制放置在数据包IP头中的源IP地址。它不控制哪个接口将用于发送数据包:将咨询内核的路由表,以确定哪个接口到达特定目的地的成本最低。(*见注释)
相反,您应该使用SO_BINDTODEVICE
sockopt。这做了两件事:
- 无论内核路由表怎么说,数据包都将始终从您指定的接口出口
- 只有到达指定接口的数据包才会被传递到套接字。到达其他接口的数据包不会
如果有多个接口需要切换,我建议每个接口创建一个套接字。因为您也只会接收到绑定到的接口的数据包,所以您需要将所有这些套接字添加到您的select()
/poll()
/无论您使用什么。
#include <net/if.h>
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name));
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
(void *)&ifr, sizeof(ifr)) < 0) {
perror("SO_BINDTODEVICE failed");
}
(*注)CCD_ 6到接口IP地址可能导致混淆但仍然正确的行为。例如,如果您将bind()
发送到eth1的IP地址,但路由表将数据包发送到eth0,则数据包将出现在eth0线上,但携带eth1接口的源IP地址。这很奇怪,但这是允许的,尽管发送回eth1 IP地址的数据包会被路由回eth1。您可以使用带有两个iP接口的Linux系统对此进行测试。我有一个,并对它进行了测试,bind()
在将数据包引导出物理接口方面并不有效。
尽管在技术上是允许的,但根据拓扑结构,这可能仍然不起作用。为了抑制攻击者使用伪造IP源地址的分布式拒绝服务攻击,许多路由器现在执行反向路径转发(RPF)检查。源IP地址在"错误"路径上的数据包可能会被丢弃。