阻止过时的 TCP 选项

阻止过时的 TCP 选项

在 Linux 上,我想删除所有包含过时 tcp 选项的数据包。我所说的过时选项是指所有 tcp 选项类型编号大于 8 的选项。我如何使用 来做到这一点nftables

例如,如果有一种方法可以检查 tcp 数据包是否具有 nftables 中给定数字类型的选项,那就可行。如果 nftables 不支持此功能,我可以使用tc或其他标准 Linux 实用程序来执行此操作吗?

答案1

里面有很多关键词nftables只是代表一个常数。这就是 tcp 选项的情况(更新: 但只是从那时起nftables0.9.8)。

以下是 tcp 选项的摘录:

扩展头表达式

扩展标头表达式是指来自可变大小协议标头的数据,例如 IPv6 扩展标头和 TCP 选项。

[...]

TCP选项

{停产|努普 |最大分段|窗口|解雇允许|麻袋|麻袋0 |麻袋1 |麻袋2 |麻袋3 |时间戳} tcp_option_field

TCP 选项

关键词 描述 TCP 选项字段
停产 选项列表结束 种类
努普 1 字节 TCP 无操作选项 种类
最大分段 TCP 最大段大小 种类、长度、尺寸
窗户 TCP 窗口缩放 种类、长度、数量
[...]
时间戳 TCP 时间戳 种类、长度、tsval、tsecr

[...]

布尔规范

以下表达式支持布尔比较:

表达 行为
谎言 检查路由是否存在。
扩展 检查 IPv6 扩展标头是否存在。
TCP选项 检查 TCP 选项标头是否存在。

[...]

# match if TCP timestamp option is present
filter input tcp option timestamp exists

这里eol代表0,nop代表1,...timestamp代表8,等等。

更新:从0.9.8版本开始可以指定任意数值而不是关键字:

  • 添加原始 tcp 选项匹配支持

    ... TCP 选项@42,16,4

    您可以在其中指定@kind、offset、length

  • 允许检查是否存在任何 tcp 选项

    ... TCP 选项 42 存在

所以有了这样的规则:

nft add table t
nft add chain t c '{ type filter hook input priority 0; policy accept; }'
nft add rule t c tcp option 8 exists drop
nft add rule t c tcp option 9 exists drop
nft add rule t c tcp option 10 exists drop
[...]
nft add rule t c tcp option 254 exists drop

可以过滤值为 8(包含在后面显示 8 的意思timestamp)或以上(选项值位于 8 位字段上)的所有规则。

已知值(仅此处timestamp)与关键字一起显示,否则它们保留为数字:

# nft -a --debug=netlink list ruleset
ip t c 2
  [ exthdr load tcpopt 1b @ 8 + 0 present => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ immediate reg 0 drop ]

ip t c 3 2
  [ exthdr load tcpopt 1b @ 9 + 0 present => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ immediate reg 0 drop ]

ip t c 4 3
  [ exthdr load tcpopt 1b @ 10 + 0 present => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ immediate reg 0 drop ]

ip t c 5 4
  [ exthdr load tcpopt 1b @ 254 + 0 present => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ immediate reg 0 drop ]

table ip t { # handle 21
    chain c { # handle 1
        type filter hook input priority filter; policy accept;
        tcp option timestamp exists drop # handle 2
        tcp option 9 exists drop # handle 3
        tcp option 10 exists drop # handle 4
        tcp option 254 exists drop # handle 5
    }
}

我没有找到一种方法将其分解为集合或映射,也没有与选项值进行比较,这会简化这一点,因为整体tcp option foo必须在语法中使用,而不仅仅是tcp option,据我所知,这会导致无用特点如下:

  • 检查选项时间戳是否意味着种类8其 kind 值为... 8。(如果存在则始终为 true,因此相当于tcp option timestamp exists):

    nft add rule t c tcp option timestamp kind == 8
    
  • 或检查选项时间戳是否意味着种类8kind 值大于 8(始终为 false):

    nft add rule t c 'tcp option timestamp kind > 8'
    

考虑到一个TCP选项是选项列表的一部分,我可以理解实现并不那么容易,因为它必须循环遍历所有现有选项才能选择一个。当两个可以匹配时会选择哪个?


注意:8 以上的几个选项值得保留。例如TCP 选项种类 30是用来多点TCP最近被添加到主流 Linux 中,而 tcp 选项种类 6(回显)和 7(回显回复)已过时。

相关内容