多宿主 Linux 机器能否实现真正的强ES模型?
###具体用例
我有一个具有五个不同接口的系统,每个接口都连接到同一子网,因此有相同的互联网网关。
- 我想在同一端口上分别侦听每个接口,并确保数据包始终从它们进入的同一接口发出,并确保尝试进入“错误”接口的数据包被丢弃。
- 我希望能够绑定到每个接口,并与始终源自我绑定的同一源 IP 的 Internet 目标建立传出连接。例如,
卷曲——接口接口IPhttp://ipecho.net/plain
应始终显示与我绑定的相同 IP 地址--interface
。
- 由于在这些接口之一上使用 DHCP,静态路由可能会出现问题。
RFC 1122
从RFC 1122- 互联网主机的要求 - 通信层,第 3.3.4.2 节 – 多宿主要求:
互联网主机实现者使用了两种不同的多宿主概念模型,在下面的讨论中进行了简要总结。本文档对首选模型不持任何立场;每个似乎都有一个地方。这种矛盾心理反映在问题(A)和(B)是可选的。
- 强ES模型
-
强 ES(终端系统,即主机)模型强调主机/网关 (ES/IS) 区别,因此将在上述问题 (A) 和 (B) 中用 MUST 代替 MAY。它倾向于将多宿主主机建模为同一物理主机内的一组逻辑主机。
关于 (A),Strong ES 模型的支持者指出,自动 Internet 路由机制无法将数据报路由到与目标地址不对应的物理接口。
在Strong ES模型下,传出数据报的路由计算是映射:route(src IP addr, dest IP addr, TOS) -> gateway
这里包含源地址作为参数,以便选择在相应物理接口上可直接访问的网关。请注意,该模型在逻辑上要求每个 IP 源地址通常至少有一个默认网关,并且最好有多个默认网关。
- 弱ES模型
-
这种观点不再强调 ES/IS 的区别,因此在问题 (A) 和 (B) 中用 MUST NOT 代替 MAY。对于窃听网关路由协议的主机来说,此模型可能是更自然的模型,并且对于具有嵌入式网关功能的主机来说是必需的。
ES模型弱可能会导致Redirect机制失效。如果数据报从与目的地址不对应的物理接口发出,则第一跳网关将无法意识到何时需要发送重定向。另一方面,如果主机具有嵌入式网关功能,则它无需侦听重定向即可拥有路由信息。
在Weak ES模型中,传出数据报的路由计算是映射:route(dest IP addr, TOS) -> gateway, interface
Linux 默认是弱 ES 模型,而 FreeBSD 和其他 Unix 变体则充当强 ES 系统。有什么办法让它表现得更像一个 Strong ES 系统吗?
需要设置什么sysctl
或编译时配置才能使其在默认情况下表现得像 Strong ES,而不为您添加的任何新接口添加特定的路由规则?我知道我们可以通过 进行严格的源路由过滤net.ipv4.conf.default.rp_filter = 1
,但似乎远不止于此。如何默认进行基于源的路由?
答案1
对于这一点来说,仅添加防火墙规则是不够的。您希望系统像两个独立的系统一样路由流量,并且恰好共享相同的硬件和进程:这实际上就是强 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
这些设置将使 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
然后,使用适合每个接口的最小路由条目集填充每个自定义路由表。 (我将实际值替换为希望描述性命名的环境变量名称。)
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
最后,添加高级路由规则,该规则将检查每个包的源地址并相应地选择要使用的路由表:
ip rule add from $ETH0_IP table rtable0
ip rule add from $ETH1_IP table rtable1
#...
为了使所有这些配置在重新启动后保持不变,您可能必须编写自定义启动脚本(或者可能ifup-pre
是ifup-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
笔记:我曾经根据 Rick Jones 和其他网络专家的旧互联网讨论实现了这样的设置。他们转述说:“虽然这一切都清楚地表明必要的要在 Linux 中实现强主机模型行为,我不能保证它是充足的对于所有可能的用例”。它对我来说完美无缺;它对你来说可能足够,也可能不够,具体取决于你要用它做什么。
警告:确保在设置此配置时您可以通过某种本地或远程控制台访问系统。这种设置极有可能完全搞乱您的网络访问,而它只完成了一半。
虽然可以仅使用 (N-1) 个自定义路由表来设置 N 个接口,但我个人的偏好是在使用高级路由时将所有路由配置移至自定义表。当系统显然具有网络连接时,具有route -n
或ip route show
基本上是空的将是一个非常重要的线索,表明正在发生一些非常特殊的事情。尽管如此,当我设置这样的系统时,我还设置了一个/etc/motd
关于高级路由生效的永久通知,以及设置它的实际脚本的位置。
答案2
还有另一个选项可以对 ARP 处理进行更多控制。看一下arp_ignore
。