【问题标题】:Using Linux, how to specify which ethernet interface data is transmitted on使用 Linux,如何指定在哪个以太网接口上传输数据
【发布时间】:2010-09-15 10:23:43
【问题描述】:

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

我在 StackOverflow 中发现了一个相关问题,该问题建议使用 netlink 库即时修改路由。这从直觉上看起来应该可以工作,但我想知道是否还有其他选择可以实现相同的结果。

【问题讨论】:

    标签: linux routing networking tcp


    【解决方案1】:

    无意冒犯,但关于使用 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() 到 eth1 的 IP 地址,但路由表将数据包发送到 eth0,那么 eth0 线路上会出现一个数据包,但带有 eth1 接口的源 IP 地址。这很奇怪,但允许,尽管发送回 eth1 IP 地址的数据包将被路由回 eth1。您可以使用具有两个 iP 接口的 Linux 系统对此进行测试。我有一个,并进行了测试,bind() 无法有效地将数据包引导出物理接口。

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

    【讨论】:

    • 我已经删除了我的答案,你的答案明显更好。
    • 在将 struct ifr 传递给 setsockopt 之前,您必须运行 ioctl(s, SIOCGIFINDEX, &amp;ifr) 以根据其名称确定接口索引。
    猜你喜欢
    • 1970-01-01
    • 2013-06-20
    • 1970-01-01
    • 2018-07-29
    • 2010-11-12
    • 2019-04-16
    • 2011-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多