Linux 源路由,强端系统模型/强主机模型?

Wil*_*ill 13 linux freebsd networking routing

多宿主 Linux 机器能否实现真正的强 ES 模型

特定用例

我有一个系统,有五个不同的接口,每个接口都连接到同一个子网,因此连接到 Internet 的网关相同。

  • 我想在同一个端口上分别监听每个接口,并确保数据包总是从它们进来的同一接口出去,并确保试图进入“错误”接口的数据包被丢弃。
  • 我希望能够绑定到每个接口,并与始终来自我绑定到的相同源 IP 的 Internet 目的地建立传出连接。例如,
    curl --interface interface_ip http://ipecho.net/plain
    应该始终显示与我绑定的相同 IP 地址--interface
  • 由于在这些接口之一上使用 DHCP,静态路由可能会出现问题。

RFC 1122

来自RFC 1122 - 互联网主机要求 - 通信层,第 3.3.4.2 节 - 多宿主要求

Internet 主机实现者使用了两种不同的多宿主概念模型,在以下讨论中进行了简要总结。本文件不支持首选哪种型号;每个似乎都有一个位置。这种矛盾反映在问题(A)和(B)是可选的。

  • ??强ES模型

      强 ES(终端系统,即主机)模型强调主机/网关 (ES/IS) 的区别,因此在上述问题 (A) 和 (B) 中将 MUST 替换为 MAY。它倾向于将多宿主主机建模为同一物理主机中的一组逻辑主机。

      关于 (A),Strong ES 模型的支持者指出,自动 Internet 路由机制无法将数据报路由到与目标地址不对应的物理接口。

      在强 ES 模型下,传出数据报的路由计算是映射:

         route(src IP addr, dest IP addr, TOS) -> gateway
    
    Run Code Online (Sandbox Code Playgroud)

    此处源地址作为参数包括在内,以便选择在相应物理接口上可直接访问的网关。请注意,此模型在逻辑上要求每个 IP 源地址通常至少有一个默认网关,最好有多个默认网关。


  • ??弱ES模型

      这种观点不强调 ES/IS 的区别,因此在问题 (A) 和 (B) 中将 MUST NOT 替换为 MAY。对于窃听网关路由协议的主机来说,这种模型可能更自然,并且对于具有嵌入式网关功能的主机来说是必需的。

      弱 ES 模型可能会导致重定向机制失败。如果数据报从与目的地址不对应的物理接口发出,第一跳网关将不会意识到何时需要发送重定向。另一方面,如果主机具有嵌入式网关功能,则它无需侦听重定向即可获得路由信息。

      在弱 ES 模型中,传出数据报的路由计算是映射:

         route(dest IP addr, TOS) -> gateway, interface
    
    Run Code Online (Sandbox Code Playgroud)

  • Linux 默认是弱 ES 模型,而 FreeBSD 和其他 Unix 变体充当强 ES 系统。有没有办法让它表现得更像一个强 ES 系统?

    sysctl需要设置什么或编译时配置才能使其在默认情况下表现得像 Strong ES,而无需为您添加的任何新接口添加特定的路由规则?我知道我们可以通过 进行严格的源路由过滤net.ipv4.conf.default.rp_filter = 1,但似乎还有更多。默认情况下如何进行基于源的路由?

    tel*_*coM 9

    仅添加防火墙规则是不够的。您希望系统路由流量,就好像它是两个恰好共享相同硬件和进程的独立系统:这就是 Strong ES 模型的实际意义。

    在 Linux 中瞄准强 ES 模型时,您首先需要这些 sysctl 设置:

    net.ipv4.conf.all.arp_filter=1 
    net.ipv4.conf.all.arp_ignore=1 # or even 2
    net.ipv4.conf.all.arp_announce=2
    
    Run Code Online (Sandbox Code Playgroud)

    这些设置将使 ARP 在强 ES 模型中表现得恰到好处,即当收到 ARP 请求时,只有具有确切请求地址的接口才会应答,并且仅当到源地址的流量实际上通过该特定地址发送出去时界面。

    然后,由于您有五个接口,您希望它们在路由方面的行为有所不同,因此您需要设置五个自定义路由表。您可以使用数字来识别它们,但通常为它们指定名称会更清晰。因此,为它们中的每一个选择 1 到 252 之间的数字,以及一些合适的名称。(数字 0、253、254 和 255 是保留的。)

    例如,让我们选择 100 = rtable0、101 = rtable1、102 = rtable2、103 = rtable3 和 104 = rtable4。将这些数字和名称添加到/etc/iproute2/rt_tables文件末尾:

    # ...default stuff above...
    100    rtable0
    101    rtable1
    102    rtable2
    103    rtable3
    104    rtable4
    
    Run Code Online (Sandbox Code Playgroud)

    然后,使用适合每个接口的最小路由条目集填充每个自定义路由表。(我正在用希望描述性命名的环境变量名称替换实际值。)

    ip route add $ETH0_NET dev eth0 proto static src $ETH0_IP table rtable0
    ip route add default via $ETH0_GW dev eth0 proto static src $ETH0_IP table rtable0
    
    ip route add $ETH1_NET dev eth1 proto static src $ETH1_IP table rtable1
    ip route add default via $ETH1_GW dev eth1 proto static src $ETH1_IP table rtable1
    
    # ... and so on, for all 5 interfaces
    
    Run Code Online (Sandbox Code Playgroud)

    最后,添加高级路由规则,将检查每个包的源地址并相应地选择要使用的路由表:

    ip rule add from $ETH0_IP table rtable0
    ip rule add from $ETH1_IP table rtable1
    #...
    
    Run Code Online (Sandbox Code Playgroud)

    为了使所有这些配置在重启持续,您可能需要编写自定义的启动脚本(或可能ifup-preifup-post脚本),以满足您的Linux发行版的约定。

    为了额外保险,您可以添加每个接口的 iptables 规则以静默丢弃可能在错误接口上接收到的任何传入数据包。如果一切顺利,这些数据包计数应保持为零:如果它们开始增加,您可能错过了配置中的某些内容。

    iptables -A INPUT -m addrtype --dst-type UNICAST -i eth0 ! -d $ETH0_IP -j DROP
    iptables -A INPUT -m addrtype --dst-type UNICAST -i eth1 ! -d $ETH1_IP -j DROP
    # ... and so on for each interface
    
    Run Code Online (Sandbox Code Playgroud)

    注意:我曾经根据 Rick Jones 和其他网络专家的旧互联网讨论实现了这样的设置。他们解释说,“虽然所有这些对于在 Linux 中实现强主机模型行为显然是必要的,但我不能保证它足以满足所有可能的用例”。它对我来说完美无缺;它对您来说可能足够也可能不够,具体取决于您将要使用它的目的。

    警告:设置此配置时,请确保您对系统具有某种本地或远程控制台访问权限。这种设置极有可能完全搞乱您的网络访问,而它只是完成了一半。

    虽然可以仅使用 (N-1) 个自定义路由表设置 N 个接口,但我个人的偏好是在使用高级路由时将所有路由配置移动到自定义表。有route -nip route show拿出基本上是空的,而系统显然具有网络连接将是一个非常大的线索,很特别的东西是怎么回事。尽管如此,当我设置这样的系统时,我还设置了一个/etc/motd关于高级路由生效的永久通知,以及设置它的实际脚本的位置。


    Hau*_*ing 2

    还有另一个选项可以对 ARP 处理进行更多控制。看一下arp_ignore