没有冒犯之意,但关于使用bind()的答案是相当错误的。bind()将控制放置在数据包IP头中的源IP地址,而不是控制发送数据包所使用的接口:内核的路由表将被查询以确定哪个接口对于到达特定目标具有最低成本。(*请参见注释)
相反,您应该使用SO_BINDTODEVICE套接字选项。这样做两件事:
数据包将始终从您指定的接口出站,而不管内核路由表说什么。
只有到达指定接口的数据包才会传递给套接字。到达其他接口的数据包将不会传递。
如果您有多个要切换的接口,建议为每个接口创建一个套接字。因为您只收到绑定到的接口的数据包,所以需要将所有这些套接字添加到您的select() / poll() /您使用的任何内容中。
#include
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() 到 eth1 的 IP 地址,但路由表将数据包发送到 eth0,则数据包将出现在 eth0 线上,但携带着 eth1 接口的源 IP 地址。这很奇怪,但是允许的,尽管发送回 eth1 IP 地址的数据包将被路由回 eth1。你可以使用具有两个网卡接口的 Linux 系统进行测试。我有一个,也进行了测试,bind() 无法有效地将数据包引导到物理接口。
虽然从技术上讲是允许的,但基于拓扑结构的原因,这种方案有时可能并不可行。为了防止分布式拒绝服务(DDoS)攻击,攻击者使用伪造的 IP 源地址,许多路由器现在执行反向路径转发 (RPF) 检查。源 IP 地址在“错误”路径上的数据包可能会被丢弃。