无意冒犯,但关于使用 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");
}
(*注)
Bind()
到接口 IP 地址可能会导致混乱但仍然正确的行为。例如,如果你bind()
的 IP 地址为 eth1,但路由表将数据包发送到 eth0,那么 eth0 线路上会出现一个数据包,但带有 eth1 接口的源 IP 地址。这很奇怪,但允许,尽管发送回 eth1 IP 地址的数据包将被路由回 eth1。您可以使用具有两个 iP 接口的 Linux 系统对此进行测试。我有一个,并且确实对其进行了测试,并且bind()
无法有效地将数据包引导出物理接口。
尽管在技术上是允许的,但根据拓扑结构,这可能仍然不起作用。为了抑制攻击者使用伪造 IP 源地址的分布式拒绝服务攻击,许多路由器现在执行反向路径转发 (RPF) 检查。源 IP 地址位于“错误”路径的数据包可能会被丢弃。