Linux TCP 有效载荷过滤器

Linux TCP 有效载荷过滤器

我使用 nftables,但它没有像 iptables 的字符串或 u32 匹配这样的内容,因此无法可靠地收集有效负载偏移量。如果不通过 nftables 的原始有效负载,我如何才能有效地分析 TCP 有效负载而不会出现任何用户空间瓶颈?(出于性能原因,nfqueue 不是一个答案)

是否有任何技术可以在内核级别进行此类过滤?即使标记合适的数据包对我来说也足够了 - 其余的工作可以在防火墙上轻松完成。

答案1

已经有可用的内核代码能够处理任意字符串匹配,并且在数据包路径期间仍然处于内核上下文中,为什么不重用它呢? iptables不会去任何地方。什么可能或许某天消失是遗留的内核 APIiptables,只留下iptables-nft仍然可以使用表格模块,例如细绳匹配模块。 使用iptables-旧版或者iptables-nft沿着nftables将得到以下相同的结果。

可以使用标记在数据包路径中的各个网络子系统之间传递消息,包括来自nftablesiptables然后返回iptablesnftables

钩内优先级表格可以帮助:

nftables 家庭 典型的钩子 nft 关键字 价值 Netfilter 内部优先级 描述
[...]
inet、ip、ip6 全部 曼格尔 -150 NF_IP_PRI_MANGLE Mangle 操作
inet、ip、ip6 预路由 目的地地址 -100 NF_IP_PRI_NAT_DST 目标 NAT
inet、ip、ip6、arp、netdev 全部 筛选 0 NF_IP_PRI_过滤器 过滤操作,过滤表
[...]

只需注册nftables每人两次iptables' 内置链参与:之前具有优先级iptables',一旦优先权紧随其后iptables例如,使用带有iptables优先级 0,可以使用 -5 和 5 来包围它。更多详细信息这些 Unix/Linux SE Q/A,我在这里做出解答。


人工示例(改编自iptables-extensions(8))混合nftablesiptables,系统应丢弃本地发起的针对特定 DNS 地址的 DNS 请求www.netfilter.org,按钩子优先级顺序呈现(警告:仅限 UDP,由于范围固定,仅在传出数据包中不存在任何 IPv4 或 IPv6 选项/标头时才有效,但可以放宽范围以适应这种情况):

nft add table inet mytable
nft add chain inet mytable outputbefore '{ type filter hook output priority -5; policy accept; }'
nft add rule inet mytable outputbefore udp dport 53 meta mark set 1

iptables -I OUTPUT -m mark --mark 1 -m string --algo bm --from 40 --to 57 --hex-string '|03|www|09|netfilter|03|org|00|' -j MARK --set-mark 2
ip6tables -I OUTPUT -m mark --mark 1 -m string --algo bm --from 60 --to 77 --hex-string '|03|www|09|netfilter|03|org|00|' -j MARK --set-mark 2

nft add chain inet mytable outputafter '{ type filter hook output priority 5; policy accept; }'
nft add rule inet mytable outputafter meta mark 2 drop

这里的目标是iptables只处理nftables只做最少的工作:通过标记发出返回值,留下nftables负责数据包的命运:

  • nftables将数据包的标记设置为 1 以“询问”iptables做某事
  • iptables(或者ip6tables) 仅在“收到”标记 1 时才执行字符串匹配,以节省 CPU 使用,并且如果在这种情况下字符串匹配,则“回答”2
  • nftables仅当数据包“收到”值为 2 的标记时才丢弃该数据包(从而删除iptables规则也会禁用该效果)

笔记:

  • 警告

    之间的沟通机制nftablesiptables是通过数据包标记(或者也可以通过连接跟踪connmarks)。虽然可以只写入和读取标记的几个位(通过使用标记上的可选掩码和适当的按位操作),但标记的每个用户都必须遵守标记中位所有权的某些分配约定。如果没有这一点,工具在处理标记时会相互干扰。例如防火墙使用标记来处理规则中的重定向,因此此示例可能与以下情​​况不兼容防火墙,即使在使用时使用自己的表nftables后端。

  • 一些简单的情况可以使用原始载荷

    上述这个具体的例子固定的抵消,可以实现nftables。当有任意偏移量来查找数据时(最好与 iptables 一起使用)细绳匹配)或一个复杂的方法来计算这种偏移量(最好与 iptables 一起使用)u32匹配)nftables無法使用。

    以下是使用原始有效载荷用单个规则替换上述所有规则的等效方法。语法仅允许最大 128 位,但此处需要 19x8=152 位,因此必须将其拆分为两个原始有效载荷(128 位 + 24 位)。printfxxd并且cut也用于一些帮助:

    nft add table inet mytable
    nft add chain inet mytable output '{ type filter hook output priority 0; policy accept; }'
    nft add inet mytable output udp dport 53 \
        @th,160,128 0x$(printf '\3%s\11%s\3%s\0' www netfilter org | xxd -p | cut -c-32) \
        @th,288,24 0x$(printf '\3%s\11%s\3%s\0' www netfilter org | xxd -p | cut -c33-) \
        drop
    

    输出为printf '\3%s\11%s\3%s\0' www netfilter org | xxd -p

      03777777096e657466696c746572036f726700
    

    获取两个原始有效载荷:

    0x03777777096e657466696c746572036f
                                    0x726700
    
  • 可能有其他方法

    • iptables可以调用 eBPF 对象(无论如何,只有最近的内核允许(有限)循环来轻松尝试实现某些算法),nftables缺乏此功能。所以它再次带有标记和iptables

    • 这样的 eBPF 对象可能与...一起使用西地普或者但这可能在数据包路径中为时过早(例如:没有可用的状态 NAT),需要实际编程而不是管理。无论如何,如果必须使用以下方式处理决策,则需要通过标记进行通信:nftables

相关内容