我正在尝试使用 Linux 机测试网络设备(防火墙),该机有两张网卡,一个接口连接到 WAN 区域,另一个接口连接到 LAN 区域。
配置与此类似
|ETH0| <-> | FW | <-> ETH1
因此,我可以从两个接口 ping 相应的防火墙接口。但我无法触发类似以下操作:
ping -I eth0 ip.from.eth1
并得到任何答案。
这可能吗?或者我应该使用linux 网络命名空间解决方案或者任何用户级 TCP 栈(虚拟机除外)
答案1
使用网络命名空间解决方案。绝对如此。这是必需的。
尝试做任何其他事情都注定会失败,除非您具备弄乱表格local
和策略路由以使其正常工作的知识。向接口发送任意垃圾是一回事,让另一个接口以您想要的方式响应才是真正的问题:内核将立即在local
路由表中识别出自己的 IP,这是默认要查询的第一个表格(请参阅ip rule
)。请注意,手册页说(或曾经说过)此表无法修改,规则无法更改,但可以做到,只是您的情况可能会有所不同。
因此,为了使其在没有命名空间的情况下工作,您需要这些丑陋的黑客,这些黑客不能保证工作(并且我还没有测试过):
将本地表移至更高优先级。请注意,手册页指出这是不可能的。
ip rule add prio 100 lookup local ip rule del prio 0
请注意,乱改此规则是破坏所有网络连接的快速方法。如果本地表不存在,内核将无法识别其任何 IP 地址,因此您甚至无法 ping 127.0.0.1。
为您的两个接口创建两个路由表。我们决定表 10 用于 eth0,表 11 用于 eth1。创建到另一端的路由。
ip route add eth1's ip dev eth0 table 10 ip route add eth0's ip dev eth1 table 11
现在为这些表添加规则。我们
iif lo
从 eth0 的 IP 发送的任何内容( ,作为例外,表示“本地生成”)都应使用表 10。确保 的优先级低于lookup local
的优先级。ip rule add from eth0's_ip iif lo lookup 10 prio 10 ip rule add from eth1's_ip iif lo lookup 11 prio 11
至少在 IP 级别上,这应该足以完成您想要做的事情。
只是为了了解发生了什么:
- 当内核从 eth0 接口接收到从 eth1 的 IP 到 eth0 的 IP 的 icmp echo 数据包时,它将首先查找目标地址,以确定此目标 IP 是否是其自己的(如果不是,则应将数据包转发到哪里)。因此,它会查看我们的两个规则,发现它们不匹配(数据包未发送,正在接收,因此
iif lo
失败),然后返回到local
表,也就是最初排在第一位的那个表。该local
表告诉我们 eth0 的 IP 实际上属于此主机,因此它可以处理它。 - 内核生成响应,然后继续路由此响应。响应是本地生成的 icmp echo reply 数据包,其中 eth0 的 IP 为源地址,eth1 的 IP 为目标地址。因此我们的规则
from eth0's_IP iif lo
匹配,table 10
将参考该规则,该规则表示通过 eth0 路由 eth1 的 IP。如果我们的规则不存在,内核将查找表local
,该表表示 eth1 的 IP 属于此主机,因此数据包将通过环回接口。
实际情况比这要复杂一些。例如,内核通常配置为执行反向路径过滤,因此它会在从 eth0 收到数据包时检查,如果我们反转源地址和目标地址并执行路由,则生成的数据包应该通过 eth0 路由,如果不是,则该地址被视为伪造的,数据包将被丢弃。如果您的路由是对称的,那么这不是问题,幸运的是,在这种情况下,路由是对称的。local
作为一种优化,内核还可以直接查阅表而不查阅策略路由数据库(ip 规则)。如果它在处理数据包的任何时候这样做,那么您就完蛋了。
编辑:如果您确实想这样做,您可能需要激活 sysctl 旋钮“accept_local”。这是内核local
直接查找表而无需询问的一种情况。
所以真的不要这样做。使用网络命名空间解决方案。它保证有效。只需将其中一个接口移动到另一个命名空间,并将每个命名空间配置为两个通过防火墙通信的独立主机。
答案2
我能想到的唯一可行的方法是设置到每个网络的静态路由,这些路由的度量值低于默认路由,以便通过防火墙到达另一个适配器。例如(虽然我在 Windows 机器上):
ROUTE ADD <eth0 network> MASK <eth0 mask> <eth1 gateway> METRIC <low value> IF <eth1>
ROUTE ADD <eth1 network> MASK <eth1 mask> <eth0 gateway> METRIC <low value> IF <eth0>
但如果这种方法可行,我仍会感到惊讶,因为似乎操作系统在某种程度上知道不应该这样做,或者这样做只会破坏盒子上的所有路由……