我们有许多用于转发连接的 iptables 规则,这些规则非常稳定并且运行良好。
例如,端口 80 转发到同一台机器(Web 服务器)上的端口 8080。当给定的 Web 服务器重新启动时,我们会将请求转发到端口 8080 上的另一个 IP,该 IP 会显示维护页面。在大多数情况下,这个其他 IP 位于单独的服务器上。
这一切都运行良好,直到我们安装了 bridge-utils 并改为使用网桥 br0 而不是 eth0 作为接口。
我们改用桥接接口的原因是为了访问 ebtables 的 MAC SNAT/DNAT 功能。我们没有其他理由在服务器上添加桥接接口,因为它们实际上并不跨多个接口桥接连接。
我知道这是在服务器上添加网桥的一个奇怪的原因,但是我们在新项目中使用 MAC SNAT/DNAT 功能,并且由于我们已经非常熟悉 iptables,因此 ebtables 似乎是最安全、最快和最简单的方法。
问题是,自从转换为 br0 接口以来,iptables PREROUTING 转发到外部服务器不再起作用。
内部 PREROUTING 转发工作正常(例如:请求从端口 80 进入,转发到端口 8080)。
OUTPUT 链也有效(例如:我们可以通过本地目标 IP:8080 从盒子向外连接,OUTPUT 链将其映射到不同服务器上的维护服务器 IP、端口 8080,并返回网页)。
但是,如果目标 IP 是外部的,则进入该框的任何流量似乎都会在 PREROUTING 规则之后消失。
以下是我们的设置示例:
旧设置:
iptables -t nat -A PREROUTING -p tcp --dport 9080 -j DNAT --到目的地$MAINTIP:8080 iptables -a FORWARD --接口 eth0 -j ACCEPT iptables -t nat -A POSTROUTING --出接口 eth0 -j MASQUERADE echo 1 > /proc/sys/net/ipv4/ip_forward
新设置:(也尝试了各种格式的旧设置……,尝试记录 eth0 和 br0 数据包)
iptables -t nat -A PREROUTING -p tcp --dport 9080 -j DNAT --到目的地$MAINTIP:8080 iptables -a FORWARD --in-interface br0 -j ACCEPT iptables -t nat -A POSTROUTING --出接口 br0 -j MASQUERADE echo 1 > /proc/sys/net/ipv4/ip_forward
在更改为 br0 之前,客户端请求将转到服务器 A 的端口 9080,然后被伪装到不同的服务器 $MAINTIP。
如上所述,如果 $MAINTIP 在同一台机器上,则此方法可以正常工作,但如果在另一台服务器上,则在新的 br0 设置下,数据包永远不会发送到 $MAINTIP。
我们希望数据包从它们进入的相同接口(MASQUERADED)出去,就像在我们切换到使用单 NIC 桥接器(br0/bridge-utils)之前一样。
我尝试在 iptables 的所有阶段添加日志记录。出于某种原因,iptables TRACE 目标在此设置下不起作用,因此我无法获取 TRACE 日志,但数据包显示在 PREROUTING 表中,但之后似乎被悄无声息地丢弃了。
我阅读了这份优秀的文档,对 iptables 和 ebtables 之间的流程有了更好的理解: http://ebtables.sourceforge.net/br_fw_ia/br_fw_ia.html
据我了解,网桥似乎没有将数据包从它们进入的同一接口转发出去,而是将它们丢弃。如果我们添加了第二个接口,我想它会将数据包从该接口(网桥的另一侧)转发出去 - 这就是网桥的工作方式 ;-)
是否可以按照我们希望的方式使其工作,并像以前一样通过它们进入的相同接口 PREROUTE/FORWARD 那些数据包?
我希望有一些 ebtables 规则可以与 iptables PREROUTING/FORWARD/POSTROUTING 规则协同工作,以使 iptables 转发按照通常的方式工作,并将路由数据包发送出 br0(eth0)而不是丢弃它们。
欢迎评论、批评和任何建议!
谨致问候,尼尔
答案1
当在桥上进行过滤时,我认为您需要对接口输入/输出使用不同的匹配,就您而言,我正确理解您的设置,例如
iptables -t nat -A PREROUTING -p tcp --dport 9080 -j DNAT --to-destination $MAINTIP:8080
iptables -a FORWARD -m physdev --physdev-in eth0 -j ACCEPT
iptables -t nat -A POSTROUTING -m physdev --physdev-out eth0 -j MASQUERADE
我不认为您需要启用 ip_forward ...这毕竟是一座桥梁
最后但并非最不重要的
echo 1 > net.bridge.bridge-nf-call-iptables
确保此功能已启用,但它应该是默认启用的。
答案2
我很久以前就遇到过同样的问题。hairpin
桥接端口接口上有一个神奇的选项,它实现了这种奇怪的行为。如果禁用hairpin
,则帧将不会通过接收这些帧的接口转发回去。
关于这个问题还有一件有趣的事情:当接口移出到 promisc 模式时,一切都运行正常。最有趣的部分是,当您运行 tcpdump 尝试解决问题时,就会发生这种情况。