为什么 net.bridge.bridge-nf-call-{arp,ip,ip6} 表默认为 1?

为什么 net.bridge.bridge-nf-call-{arp,ip,ip6} 表默认为 1?

至少在 Arch Linux 中,这是默认设置。我认为这使得桥接行为变得不直观,因为它应该像非托管交换机一样工作,并且现在正在丢弃数据包,因为我们大多数前向链的默认策略都是丢弃。

这些默认值背后有什么原因吗?

答案1

此功能允许增加使用ebtables随着使用iptables在网桥路径中实现状态防火墙网桥(而不是路由器)。它已经存在很长时间了(2002)最初没有切换并且是桥接代码的一部分:如果桥接和netfilter 支持已启用,也是如此。

然后2003年添加了开关。当然出于兼容性原因,默认设置为启用。

然后内核为 3.18br_netfilter由于该功能可能导致问题,该功能被分离到其自己的内核模块中。人们担心兼容性,并且已经计划弃用它nftables

请注意,这会破坏兼容性 [...] 但是,可以通过 modprobing br_netfilter 轻松消除损坏。

最重要的是,nftables 的计划是不依赖这个软件层,而是将连接跟踪集成到桥接层中以启用状态过滤和 NAT,这正是桥接 netfilter 用户似乎需要的。

现在必须加载内核模块才能使该功能正常工作。但是,它的主要已知客户通常会在任何网桥状态防火墙设置中找到iptables目标physdev哪个br_netfilter出于兼容性原因再次自动加载

所以在一个简单的系统上,br_netfilter不应该被加载,也不应该有任何系统控制net.bridge: bridge-nf-call-arptables, bridge-nf-call-ip6tables, bridge-nf-call-iptables(以及bridge-nf-filter-pppoe-tagged, bridge-nf-filter-vlan-tagged, bridge-nf-pass-vlan-input-dev)内可用的内容根本不应该出现。

但现在,这个内核模块有了一个新的主要客户:Docker。遇到此问题的常见方式是运行 Docker 时,因为Docker 显式加载br_netfilter能够控制容器之间的内部通信,同时默认情况下过滤并丢弃转发的数据包。因此,人们往往会发现它正在使用,即使是在没有预料到的情况下,或者认为这种行为是预期的行为,但实际上它不应该再出现。

由于默认设置是系统范围的,除了 Docker 管理的网桥之外,它还会影响系统上的所有其他网桥:不仅是初始主机命名空间中的网桥,还包括任何其他网络命名空间。

同样地,iptables'physdevbr_netfilter仅当其自己的模块 ( ) 本身被加载时才自动加载xt_physdev(以前比这更频繁)这个补丁)。请注意如何在修补描述是这样写的:

更好的解决方法是将“call-iptables”默认值更改为 0 并强制执行显式设置为 1,但这破坏了向后兼容性

所有这些使得这个问题的答案是:

这是出于向后兼容性的原因。


补充笔记。

xt_physdev在当前未加载内核模块的系统上br_netfilter,仅允许运行用户名称空间的普通用户可以执行以下操作:

$ unshare -urnm
# iptables -A FORWARD -m physdev --physdev-is-bridged
# exit
$ 

并且可能会中断系统上安装的任何其他技术(虚拟机、容器...)的 LAN 连接,这些技术没有使用特殊且仅在外观上无用的规则来保护自己免受攻击

iptables -P FORWARD DROP

Netfilter 文档页面描述了这些效果,解释了桥接路径、路由路径、ebtables 和 iptables 之间的交互: 基于 Linux 的桥上的 ebtables/iptables 交互。这第 7 部分特别有用,因为它描述了应该添加什么样的保护,例如:

iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -d 172.16.1.0/24 -j ACCEPT
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE

上面,第一条规则没有多大意义,因为同一 LAN 中的地址之间的数据包不会在 IP 层转发(即路由),而是在以太网层作为帧转发(桥接/交换),因此该规则永远不应该匹配,因为它们不被视为路由而是桥接并且iptables预计仅在第 3 层工作:IPv4。但是,当br_netfilter加载时,就需要这些类型的“无用规则”,否则仅用于路由的操作将在桥接路径的第 2 层发生(如下所示:NAT 将由同一 LAN 中的两个节点之间的桥接完成,无需第一个规则)。

人们(多年来)一直在努力摆脱br_netfilter,但这需要功能对等。这或多或少是通过内核 5.3 实现的 IP 和 IPv6(我猜是 ARP),nftables和内核模块nf_conntrack_bridge这允许nftablesbridge家庭中(不是在ipip6inet家族喜欢的br_netfilter触发器)使用连线

这提供了“br_netfilter”基础设施的替代品。

状态过滤

Bridge 系列从 Linux 内核 5.3 开始支持连接跟踪。

您只需匹配规则集中的 conntrack 状态信息即可启用它。

对于熟悉 iptables 的人:这提供了 br_netfilter 的替代品和 iptables 的 -m physdev 匹配

但其他涉及 VLAN 封装/解封装,尤其是 PPPoE 协议的功能还没有准备好。


此外,从内核 5.3 开始,可以停用网络命名空间范围的功能,并使其仅在每个网络命名空间甚至每个网桥上处于活动状态。但是,对于创建的每个新命名空间(包括初始网络命名空间都是这样的需要),这需要在其内部尽早运行,如下所示:

sysctl -w net.bridge.bridge-nf-call-arptables=0
sysctl -w net.bridge.bridge-nf-call-iptables=0
sysctl -w net.bridge.bridge-nf-call-ip6tables=0

然后对于需要它的精心挑选的桥,在桥创建时 ( ip link add ...) 或稍后 ( ip link set ...):

ip link set somebridge type bridge nf_call_iptables 1

Docker 及其默认设置iptablessetup 无法处理这个问题,因此 Docker 无法同时在具有此类设置的主机上运行,​​但 Docker-in-Docker (实际上是在其他容器技术中,如 LXC 而不是 Docker,出于同样的原因)可能会是很好,因为每个新命名空间中的默认值仍然向后兼容。

相关内容