nftables 中的数据包处理顺序

Rah*_*hul 6 nftables

我正在从 iptables 转移到 nftables。我有一个关于 nftables 中数据包处理顺序的基本问题。

由于可以创建多个相同类型的表,例如 inet,并且还可以在每个表内创建具有不同或相同优先级的链,因此处理顺序是什么。

例如,如果我创建以下内容,顺序是什么。

table inet t1 {
    chain INPUT {
        type filter hook input priority 20; policy accept;
        ...
    }
}


table inet t2 {
    chain INPUT {
        type filter hook input priority 20; policy accept;
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我知道链连接到不同的输入,但我还没有理解拥有不同表背后的逻辑。

道歉是一个愚蠢或基本的问题

A.B*_*A.B 5

示例中的排序将是undefined,但将遍历两个链(除非数据包在第一个看到的链中被丢弃)。

Netfilter 和网络/路由堆栈提供排序

这是Netfilter 和 General Networking示意图中的数据包流

Netfilter 和通用网络中的数据包流

虽然它与由iptables的想法,当应用到整体行为是相同的nftables有轻微差异(例如:不相互分离碾压机过滤器,它的所有过滤器nftables用碾压机/输出除外,它或许应该被翻译成输入路由钩子输出,或者在下半部分中看到的ebtablesiptables之间的大部分桥接混合 不存在nftables存在但应避免通过直接在桥接系列中使用nftables直接,如果需要conntrack功能,则使用 kernel >= 5.3 (并且根本不使用内核模块br_netfilter)。

表的作用

在表中nftables不等同于表中的iptables的:它的东西少刚性。在nftables 中table是一个容器,用于组织链、集合和其他类型的对象,并限制它们的范围。与iptables相反,它是完全可以接受的,有时需要在同一个表中混合不同的链类型(例如:nat、filter、route):例如,这是他们可以访问公共的唯一方式,因为它的范围是表而不是全局的(就像iptables的伴侣ipset 一样)。

然后,对于特定处理或处理特定流量,具有相同系列的多个表(再次包括相同类型的链)也是完全可以接受的:在更改此表的内容时,没有更改其他表中规则的风险(尽管有仍然存在作为整体结果产生冲突影响的风险)。它有助于管理规则。例如,nftlb负载平衡器创建的表(在各种系列中)都命名为nftlb,旨在仅由其自身管理而不与其他用户定义的表发生冲突。

钩子之间和钩子内的排序

在给定的系列(netdev、bridge、arp、ip、ip6)中,注册到不同钩子(入口、预路由、输入、转发、输出、后路由)的链按照 Netfilter 提供的钩子顺序排序,如上图所示。Priority 的范围仅限于同一个钩子,在这里无关紧要。例如在转发数据包的情况下type filter hook prerouting priority 500仍然发生在之前type filter hook forward priority -500

在适用的情况下,对于给定系列的每个可能的钩子,每个链都将与在同一地点注册的其他链竞争。除了定义族外,表格在这里没有任何作用。只要优先级不同,在给定的钩子类型内,数据包就会从最低优先级到最高优先级遍历该钩子内的链。如果相同系列和钩子类型的两个链使用完全相同的优先级,则顺序变为未定义。创建链时,当前内核版本会在对应的链表结构中,在优先级相同的链之前还是之后添加链?下一个内核版本是否仍然保持相同的行为,或者一些优化会改变这个顺序吗?它没有记录。两个钩子仍然会被调用,但它们的调用顺序是未定义的。

这怎么可能?这是下面手册页的引述,只是为了澄清可以在同一个钩子中多次接受(或不接受)数据包:

accept

终止规则集评估并接受数据包。该数据包仍可以稍后被另一个钩子丢弃,例如,前向钩子中的接受仍然允许稍后在路由后钩子中丢弃数据包,或者具有更高优先级编号并随后在处理管道中进行评估的另一个前向基链。

例如,如果一条链接受某个数据包,而另一条链丢弃同一个数据包,则总体结果将始终是drop。但是一个钩子可能做了导致副作用的额外操作:例如,它可能将数据包的源地址添加到一个集合中,而另一个名为 next 的链丢弃了该数据包。如果顺序颠倒并先丢弃数据包,则不会发生这种“副作用”动作,并且不会更新集合。所以在这种情况下应该避免使用完全相同的优先级。对于其他情况,主要是在没有发生下降的情况下,这无关紧要。人们应该避免使用相同的优先级,除非知道这无关紧要。

与其他网络子系统的关系

在挂钩内,所有整数范围都可用于选择顺序,但某些特定阈值确实很重要。

来自nftables的 wiki,以下是对ip系列有效的遗留iptables钩子值,其中还包括其他子系统:

NF_IP_PRI_CONNTRACK_DEFRAG (-400):碎片整理的优先级
NF_IP_PRI_RAW (-300):放置在连接跟踪操作之前的原始表的传统优先级
NF_IP_PRI_SELINUX_FIRST (-225):SELinux 操作
NF_IP_PRI_CONNTRACK (-200):连接跟踪操作
NF_IP_PRI_MANGLE (-150):mangle 操作
NF_IP_PRI_NAT_DST (-100):目标 NAT
NF_IP_PRI_FILTER (0) : 过滤操作, 过滤表
NF_IP_PRI_SECURITY (50): 可以设置 secmark 的安全表的位置例如
NF_IP_PRI_NAT_SRC (100): 源NAT
NF_IP_PRI_SELINUX_LAST (225): SELinux at packet exit
NF_IP_PRI_CONNTRACK_HELPER (300):退出时的连接跟踪

其中只有少数真正重要:那些不是来自iptables。例如(非详尽)在ip家庭中:

  • NF_IP_PRI_CONNTRACK_DEFRAG (-400)要让链看到传入的 IPv4 片段,它应该以低于 -400 的优先级在预路由中注册。在此之后,只能看到重新组装的数据包(并且检查片段存在的规则永远不会匹配)。
  • NF_IP_PRI_CONNTRACK (-200):对于 conntracknat之前运行的链,它应该以低于 -200 的优先级在预路由输出中注册。例如,注册优先级NF_IP_PRI_RAW (-300)(或任何其他值 < -200 但仍然 > -400,如果要在所有情况下匹配端口)添加notrack语句以防止conntrack为该数据包创建连接条目。所以iptables的 raw/PREROUTING等效nftables只是具有足够优先级的过滤器预路由

杂项

我忽略了其他家族和特殊情况:例如inet家族同时注册在ipip6家族的钩子中。或者当 NAT 规则匹配时可能表现不同的类型 nat(它可能不会再次遍历同一钩子的其他nat链,我不完全确定,它可能取决于内核版本)并且真正依赖于conntrack(例如:优先级为 -200 的预路由)并且至少因为内核 4.18 仅与其他nat类型链竞争,而不与其他类型的链竞争(对于类型过滤器链,它总是以 -200 的优先级看到)。

当还使用iptables-legacy(或iptables-nft)时,所有这些仍然适用,优先级选择可能很重要。来自iptables-legacynftables 的NAT 规则不应与小于 4.18 的内核混合,否则可能会发生未定义的行为(例如:一个链将处理所有 NAT,另一个将无法处理,但要注册的第一个子系统,而不是优先级最低的链,获胜)。