linux - 使用Linux,如何指定在哪个以太网接口(interface)上传输数据

标签 linux routing networking tcp

我在一个基于 Linux 的服务器系统上工作,其中有两个网络接口(interface),都在同一个子网上(现在,我们只说它们是 172.17.32.10172.17 .32.11)。当我向网络上的主机发送数据时,我想指定在我的服务器上传输数据的接口(interface)。我需要能够在软件中从一个接口(interface)切换到另一个接口(interface)(或者甚至可能在两个接口(interface)上传输)(静态路由规则不适用于此应用程序)。

我在 StackOverflow 中发现了一个相关问题,建议使用 netlink 库动态修改路由。这在直觉上似乎应该可行,但我想知道是否还有其他选择可以实现相同的结果。

最佳答案

无意冒犯,但关于使用 bind() 的答案是完全错误的。 bind() 将控制放置在数据包 IP header 中的源 IP 地址。它不控制将使用哪个接口(interface)发送数据包:将查询内核的路由表以确定哪个接口(interface)到达特定目的地的成本最低。 (*见注释)

相反,您应该使用 SO_BINDTODEVICE sockopt。这做了两件事:

  • 无论内核路由表如何规定,数据包都将始终从您指定的接口(interface)传出。
  • 只有到达指定接口(interface)的数据包才会被传递到套接字。到达其他接口(interface)的数据包不会。

如果您想在多个接口(interface)之间切换,我建议为每个接口(interface)创建一个套接字。因为您也只会接收到您绑定(bind)的接口(interface)的数据包,所以您需要将所有这些套接字添加到您的 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() 到接口(interface) IP 地址可能会导致困惑但仍然正确的行为。例如,如果您 bind() 到 eth1 的 IP 地址,但路由表将数据包从 eth0 发送出去,那么一个数据包将出现在 eth0 线路上,但携带的是 eth1 接口(interface)的源 IP 地址.这很奇怪但被允许,尽管发送回 eth1 IP 地址的数据包将被路由回 eth1。您可以使用具有两个 iP 接口(interface)的 Linux 系统对此进行测试。我有一个,并且确实对其进行了测试,bind() 无法有效地将数据包引导出物理接口(interface)。

虽然技术上允许,但根据拓扑结构,这可能仍然行不通。为了抑制攻击者使用伪造 IP 源地址的分布式拒绝服务攻击,许多路由器现在执行反向路径转发 (RPF) 检查。源 IP 地址位于“错误”路径上的数据包可能会被丢弃。

关于linux - 使用Linux,如何指定在哪个以太网接口(interface)上传输数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/172905/

相关文章:

node.js - express 路线参数条件

ruby-on-rails - 在 rails3 中更改为生产模式时出现路由错误

networking - 将数据包信息写入文本文件

go - net.Conn 是否存在可恢复的读取错误?

c - 套接字 recv() 卡在带有 MSG_WAITALL 的大消息上

`read()` 后面可以直接跟 `write()` 吗? `write()` 后面可以直接跟 `read()` 吗?

linux - nohup 是如何工作的?

mysql - MariaDB 未启动 : "Plugin ' FEEDBACK' is disabled.“

networking - Kademlia 路由表和距离度量

linux - Perl 5.8 : possible to get any return code from backticks when SIGCHLD in use