当前位置: 首页 > 工具软件 > Nftables > 使用案例 >

nftables基础与实践

艾谦
2023-12-01

翻译nftables的文档man nft - mankier.com ,加上实际的操作实践,满足基本的需求。

最后更新时间:2021/7/13


1. 简介

nft是一个命令行工具,用于在Linux内核的nftables框架中设置、维护和检查包过滤和分类规则。Linux 内核子系统称为 nf_tables,"nf"代表 Netfilter。

2. 地址簇

ipIPv4 地址簇
ip6IPv6 地址簇
inetInternet (IPv4/IPv6) 地址簇
arpARP 地址簇,处理 IPv4 ARP 数据包
bridge网桥地址簇,处理通过网桥设备的数据包
netdevNetdev 地址簇,处理来自入口的数据包

如果指定的标识符没有地址族,则默认使用ip簇;

IPv4/IPv6/Inet 地址簇的hooks

Hook描述
prerouting所有进入系统的数据包都由prerouting钩子处理。它在路由过程之前调用,用于早期过滤或更改影响路由的数据包属性。
input传送到本地系统的数据包由input钩子处理。
forward转发到不同主机的数据包由forward钩子处理。
output本地进程发送的数据包由output钩子处理。
postrouting所有离开系统的数据包都由 postrouting 钩子处理。
ingress所有进入系统的数据包都由这个钩子处理。它在第 3 层协议处理程序之前调用,因此在prerouting钩子之前调用,并且可用于过滤和监管。Ingress 仅适用于 Inet 系列(自 Linux 内核 5.10 起)。

其他地址簇不记录了。

3. 规则集ruleset

ruleset关键词被用来标识被放置在内核中的整套表、链、规则的集合。操作命令有list和flush,具体如下:

# 查询所有规则
nft list ruleset -a
# 按照地址簇查询——只查询inet地址簇的规则集
nft list ruleset inet -a

# 清空规则集【危险操作】
【nft flush ruleset】
# 按地址簇清空规则
【nft flush ruleset arp】
【nft flush ruleset ip】
【nft flush ruleset ip6】
【nft flush ruleset bridge】
【nft flush ruleset inet】
【nft flush ruleset netdev】

4. 表table

  • table是链、集合和有状态对象的容器。
    通过地址簇与命名区分。地址簇是ip ip6 inet arp bridge netdev六个其中之一,若未指定,默认为ip地址簇。inet是dummy虚拟的簇,代表IPv4/IPv6的混合hybrid。
  • 元表达式nfproto关键字可用来测试 正在处理的包属于哪个地址簇上下文(ipv4 或 ipv6)
  • add和create的唯一的区别是若表已经存在,前者不会报错,后者会报错Error: Could not process rule: File exists;因为add命令可以修改表的状态。

具体操作如下:

# 以交互模式启动nft 后面就不用一直输入nft命令,当远程服务器有堡垒机的root用户限制时候,可以更为方便的使用
nft --interactive
nft --i


# 创建表 不指定协议簇 默认ip协议
nft add|create table [地址簇] [表名]
nft create table nat
nft add table nat
# 查看运行结果 nft list ruleset
table ip nat {
}

# 增加链prerouting postrouting
nft -- add chain nat prerouting { type nat hook prerouting priority -100 \; }
nft add chain nat postrouting { type nat hook postrouting priority 100 \; }
## 即使您没有向prerouting链添加规则,nftables框架也要求此链与传入的数据包回复匹配。
## 请注意,您必须将--选项传递给nft命令,以避免shell将负优先级值解析为nft命令的选项
# 查看运行结果 nft list ruleset
table ip nat {
	chain prerouting {
		type nat hook prerouting priority -100; policy accept;
	}

	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
	}
}

# 增加规则
# 源IP是10.11.0.0/16的伪装成wg0网卡的流量
nft add rule nat postrouting ip saddr 10.121.0.0/16 oifname wg0 counter masquerade
# 从tun0网卡进来的流量伪装成wg0网卡的流量
nft add rule nat postrouting iifname tun0 oifname wg0 counter masquerade
# 查看运行结果 nft list ruleset
table ip nat {
	chain prerouting {
		type nat hook prerouting priority -100; policy accept;
	}

	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
		ip saddr 10.121.0.0/16 oifname "wg0" counter packets 0 bytes 0 masquerade
		iifname "tun0" oifname "wg0" counter packets 0 bytes 0 masquerade
	}
}

nft add rule filter input tcp dport 22 accept

# 向链中增加一个计数器
nft add rule nat postrouting counter
# 查看运行结果 nft list ruleset
table ip nat {
	chain prerouting {
		type nat hook prerouting priority -100; policy accept;
	}

	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
		ip saddr 10.121.0.0/16 oifname "wg0" counter packets 0 bytes 0 masquerade
		iifname "tun0" oifname "wg0" counter packets 0 bytes 0 masquerade
		counter packets 0 bytes 0
	}
}
# 暂时禁用表,规则会失效
nft add table nat { flags dormant\; }
# 查看运行结果 nft list ruleset
table ip nat {
	flags dormant

	chain prerouting {
		type nat hook prerouting priority -100; policy accept;
	}

	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
		ip saddr 10.121.0.0/16 oifname "wg0" counter packets 0 bytes 0 masquerade
		iifname "tun0" oifname "wg0" counter packets 0 bytes 0 masquerade
		counter packets 0 bytes 0
	}
}
# 激活表
nft add table nat
# 查看运行结果 nft list ruleset
# 发现flags dormant消失了

# 为了测试表的删除需要新建表test
nft add table inet mytable
# 此时再用nft list ruleset查看就太多了
# 查询所有表
nft list tables
# 结果是两行table ip nat和table inet test
# 查询指定指定表 地址簇为inet表名为test
nft list table inet mytable
# 命令后加-a用于显示句柄handles 后面加-nn用于不解析ip地址和端口

# 为了测试清空 需要给表test增加链和规则
nft add chain inet mytable mychain { type filter hook input priority 100\; }  # 添加新的基础链:获取输入数据包
nft add rule inet mytable mychain counter  # 给链增加计数器
# 查询结果 nft list table inet mytable
table inet mytable {
	chain mychain {
		type filter hook input priority 100; policy accept;
		counter packets 60 bytes 13792
	}
}
# 查询结果 nft list table inet mytable -a 可以查询规则的句柄
table inet mytable {
	chain mychain {
		type filter hook input priority 100; policy accept;
		counter packets 201 bytes 25718 # handle 2
	}
}
# 清空表test 不会删除基础链
nft flush table inet mytable
# 删除表
nft delete table inet mytable

5. 链chain

链是规则的容器。

  • 有两种形式——基础链和常规链。基础链是来自网络堆栈的数据包的入口点,常规链可用作跳转目标并用于更好的组织规则。
  • 指定钩子和优先级值后,该链将被创建为基础链并链接到到网络堆栈。
  • 若基础链的类型填写了不匹配的钩子,会报错Error: Could not process rule: Operation not supported
# 新增
nft add chain [地址簇] [表名] [链名] { type [类型] hook [钩子] priority [优先级值]\; }
nft add chain inet mytable mychain { type filter hook input priority 100\; }  # 添加新的基础链:获取输入
nft add chain inet mytable forward { type nat hook postrouting priority 150\; }  # 添加新的基础链:转发给其他主机
# 查询结果 nft list table inet mytable -a
table inet mytable {
	chain mychain {
		type filter hook input priority 100; policy accept;
	}

	chain postrouting {
		type nat hook postrouting priority 150; policy accept;
	}
}

# 修改链 rename
nft rename chain [表地址簇] [表名] [旧链名] [新链名]
nft rename chain inet mytable mychain mychain1

# 新增规则
nft add rule mytable postrouting iifname tun0 oifname wg0 counter masquerade
会报错Error: NAT is only supported for IPv4/IPv6
nft add rule nat postrouting iifname tun0 oifname wg0 counter masquerade
nat表是ip地址簇的,就可以增加这个规则
# 新增常规链
nft add rule nat postrouting iifname tun0 oifname wg0 counter masquerade

支持的链类型

类型协议簇钩子描述
filterallall使用的标准链类型
natip, ip6, inetprerouting, input, output, postrouting这种类型的链根据 conntrack 条目执行本地地址转换。 只有连接的第一个数据包实际遍历此链 - 它的规则通常定义创建的 conntrack 条目的详细信息(例如 NAT 语句)。
routeip, ip6output如果数据包已经穿过这种类型的链并即将被接受,并且 IP 标头的相关部分已更改,则会执行新的路由查找。 这允许例如 在 nftables 中实现策略路由选择器。

除了上面说明的特殊情况,还有三个值得注意的怪癖:

  • netdev簇仅支持一种组合:即filter类型和ingress钩子。基本链还需要存在设备参数,因为他们仅存在于每个传入接口。
  • arp簇仅支持filter类型链的input和output钩子。
  • inet簇还支持ingress钩子,在与netdev链input钩子相同的位置过滤 IPv4 和 IPv6 数据包。这个inet hook允许你在preroutinginputforwardoutputpostrouting和这个ingress hook之间共享集合和映射。

priority参数接收有符号整数值或标准优先级名称,指定有相同钩子值得链的遍历顺序。该顺序是升序的,低值比高值对应的链优先级更高。

标准优先级值可以替换为易于记忆的名称。 并非所有名称在每个钩子的每个系列中都有意义(请参阅下面的兼容性矩阵),但它们的数值仍可用于确定链的优先级。

这些名称和值是根据 xtables 在注册其默认链时使用的优先级来定义和提供的。

大多数地址簇使用相同的值,但bridge使用与其他地址簇不同的值。 请参阅以下描述值和兼容性的表格。

  1. 标准优先级名称、地址簇和钩子兼容性矩阵:
名称地址簇钩子
raw-300ip, ip6, inetall
mangle-150ip, ip6, inetall
dstnat-100ip, ip6, inetprerouting
filter0ip, ip6, inet, arp, netdevall
security50ip, ip6, inetall
srcnat100ip, ip6, inetpostrouting
  1. bridge地址簇系列的标准优先级名称和钩子兼容性
名称钩子
dstnat-300prerouting
filter-200all
out100output
srcnat300postrouting

使用这些标准名称也可以实现基本算术表达式(加法和减法)以简化相对优先级,例如 mangle - 5 代表 -155。 值也将像这样打印,直到值与标准值相差不超过 10。

基础链还允许设置链的策略,即在包含的规则中没有明确接受或拒绝的数据包会发生什么。 支持的策略值是接受(这是默认值)或丢弃。

6. 规则rule

规则被添加到指定表指定链中,由表达式和语句组成。操作有add insert replace delete,add和insert命令可支持用句柄handle或index(以0开始)新增规则

在内部,规则位置总是由handle标识,index的转换发生在用户空间。如果在翻译完成后发生并发规则集更改,这有两个潜在影响: 如果在引用的规则之前插入或删除规则,则有效规则index可能会更改。如果引用的规则被删除,则该命令将被内核拒绝,就像给出了无效句柄一样。

注释是单个单词或双引号括起来的多单词字符串,可用于对实际规则注释。注意:如果使用bash添加规则要对双引号进行转义。

# 创建规则—— add 将规则添加到链的末尾,insert 则将规则添加到链的开头。
nft insert rule nat postrouting oif eth0 snat to 1.2.3.5
# 将规则添加到链中指定位置有两种方法——利用handle或index,推荐handle,因为链中有其他规则增加到index之前,则index会发生变化
# add配handle,添加到对应handle后面; insert加handle添加到对应handle之前;
# nft add rule [表名] [链名] handle 9 [规则]
# nft insert rule [表名] [链名] handle 9 [规则]
# 可以在创建规则时就获取到规则的句柄值,只需要在创建规则时同时加上参数 --echo 和 --handle
nft add rule nat postrouting handle 9 oif eth0 snat to 1.2.3.7
nft insert rule nat postrouting handle 9 oif eth0 snat to 1.2.3.6
nft list table  nat -a
table ip nat {
	chain prerouting {
		type nat hook prerouting priority -100; policy accept;
	}

	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
		oif "eth0" snat to 1.2.3.5 # handle 10
		ip saddr 10.121.0.0/16 oifname "wg0" counter packets 0 bytes 0 masquerade # handle 3
		iifname "tun0" oifname "wg0" counter packets 0 bytes 0 masquerade # handle 4
		counter packets 3172 bytes 214592 # handle 5
		ip saddr 10.121.0.3 iifname "tun0" oifname "eth0" counter packets 0 bytes 0 masquerade # handle 6
		oif "eth0" snat to 1.2.3.6 # handle 12
		oif "eth0" snat to 1.2.3.4 # handle 9
	}
}

# 删除规则
nft delete rule nat postrouting handle 9
# 更新规则
nft replace rule nat postrouting handle 12 oif eth0 snat to 1.2.3.7
# 查询结果 nft list table  nat -a
table ip nat {
	chain prerouting {
		type nat hook prerouting priority -100; policy accept;
	}

	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
		oif "eth0" snat to 1.2.3.5 # handle 10
		ip saddr 10.121.0.0/16 oifname "wg0" counter packets 0 bytes 0 masquerade # handle 3
		iifname "tun0" oifname "wg0" counter packets 0 bytes 0 masquerade # handle 4
		counter packets 3172 bytes 214592 # handle 5
		ip saddr 10.121.0.3 iifname "tun0" oifname "eth0" counter packets 0 bytes 0 masquerade # handle 6
		oif "eth0" snat to 1.2.3.7 # handle 12
	}
}

# 查询指定表nat的指定链postrouting
nft list chain nat postrouting -a
table ip nat {
	chain postrouting {
		type nat hook postrouting priority 100; policy accept;
		oif "eth0" snat to 1.2.3.5 # handle 10
		ip saddr 10.121.0.0/16 oifname "wg0" counter packets 0 bytes 0 masquerade # handle 3
		iifname "tun0" oifname "wg0" counter packets 0 bytes 0 masquerade # handle 4
		counter packets 3172 bytes 214592 # handle 5
		ip saddr 10.121.0.3 iifname "tun0" oifname "eth0" counter packets 0 bytes 0 masquerade # handle 6
		oif "eth0" snat to 1.2.3.7 # handle 12
	}
}

7. 集合set

  1. 匿名集合

匿名集是没有特定名称的集。集合成员用花括号括起来,在创建使用集合的规则时用逗号分隔元素。一旦删除该规则,该集合也将被删除。它们无法更新,即一旦声明了匿名集,就不能再更改它,除非通过删除/更改使用匿名集的规则。

# 创建表filter
nft add table filter
# 创建表filter的链input
nft add chain filter input
# 用匿名集合创建规则 此处实际上匹配了四条规则
nft add rule filter input ip saddr { 10.0.0.0/8, 192.168.0.0/16 } tcp dport { 22, 443 } accept
table ip filter {
	chain input {
		ip saddr { 10.0.0.0/8, 192.168.0.0/16 } tcp dport { ssh, https } accept
	}
}

  1. 命名集合

命名集是需要先定义才能在规则中引用的集。与匿名集合不同,元素可以随时添加到命名集合或从命名集合中删除。使用集合名称前缀的@ 从规则中引用集合。

# 先定义命名集合
nft add set filter allowed_hosts { type ipv4_addr \; }
nft list sets
nft list filter allowed_hosts
table ip nat {
}
table inet mytable {
}
table ip filter {
	set allowed_hosts {
		type ipv4_addr
	}
}
# 集合添加元素
nft add element filter allowed_hosts { 192.168.1.2, 192.168.1.3 }
nft list set filter allowed_hosts
table ip filter {
	set allowed_hosts {
		type ipv4_addr
		elements = { 192.168.1.2, 192.168.1.3 }
	}
}
# 删除集合元素
nft delete element filter allowed_hosts { 192.168.1.2 }

# 用命名集合创建规则
nft add set filter allowed_ports { type inet_service \; }
nft add element filter allowed_ports { 80, 443, 8000 }
# 查看
nft list set filter allowed_ports
table ip filter {
	set allowed_ports {
		type inet_service
		elements = { http, https, 8000 }
	}
}
nft list set filter allowed_ports -nn
table ip filter {
	set allowed_ports {
		type inet_service
		elements = { 80, 443, 8000 }
	}
}
# 使用命名集合
nft add rule filter input ip saddr @allowed_hosts tcp dport @allowed_ports accept
# 查询 nft list chain filter input
table ip filter {
	chain input {
		ip saddr { 10.0.0.0/8, 192.168.0.0/16 } tcp dport { ssh, https } accept
		ip saddr @allowed_hosts tcp dport @allowed_ports accept
	}
}


设置规格

关键词描述类型
type集合所有元素的数据类型字符串: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark
typeof集合元素的数据类型派生数据类型的表达式
flags设置标志字符串: constant, dynamic, interval, timeout
timeout元素停留在集合中的时间,如果从数据包路径(规则集)中添加集合,则是必需的字符串, decimal followed by unit. Units are: d, h, m, s
gc-interval垃圾收集间隔,仅在 timeout 或 flag timeout 处于活动状态时可用字符串, decimal followed by unit. Units are: d, h, m, s
elements集合包含的元素set data type
size集合中元素的最大数量,如果从数据包路径(规则集)中添加集合,则为强制性unsigned integer (64 bit)
policy制定政策字符串: performance [default], memory
auto-merge相邻/重叠集合元素的自动合并(仅适用于区间集合)

8. 字典map

使用不同类型的数据并将匹配条件映射到某一个规则上面,并且由于是哈希映射的方式,可以完美的避免链式规则跳转的性能开销。

设置规格

关键词描述类型
type集合所有元素的数据类型字符串: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark
typeof集合元素的数据类型派生数据类型的表达式
flags设置标志字符串: constant, dynamic, interval, timeout
elements集合包含的元素set data type
size集合中元素的最大数量,如果从数据包路径(规则集)中添加集合,则为强制性unsigned integer (64 bit)
policy制定政策字符串: performance [default], memory

匿名字典

# 创建一个表
nft create table ip mytable
# 创建三个个链
nft create chain ip mytable tcpchain
nft create chain ip mytable udpchain
nft create chain ip mytable filterchain
# 地址簇为ip的表mytable的filterchain链增加一条规则——从逻辑上将对 TCP 和 UDP 数据包的处理规则拆分开来
nft add rule ip mytable filterchain meta l4proto vmap { tcp : jump tcpchain, udp : jump udpchain }
# 查看 nft list chain ip mytable filterchain
table ip mytable {
	chain filterchain {
		meta l4proto vmap { tcp : jump tcpchain, udp : jump udpchain }
	}
}

命名字典

# 创建
nft add map ip mytable myvmap { type ipv4_addr : verdict \; }
# 添加元素
nft add element ip mytable myvmap { 192.168.0.10 : accept, 192.168.0.11 : drop }
# 添加规则
nft add rule ip mytable filterchain ip saddr vmap @myvmap
# 查看 nft list table  mytable
table ip mytable {
	map myvmap {
		type ipv4_addr : verdict
		elements = { 192.168.0.10 : accept, 192.168.0.11 : drop }
	}

	chain tcpchain {
	}

	chain udpchain {
	}

	chain filterchain {
		meta l4proto vmap { tcp : jump tcpchain, udp : jump udpchain }
		ip saddr vmap @myvmap
	}
}

9. 元素

语法规则

{add | create | delete | get } element [family] table set { ELEMENT[, ...] }
ELEMENT := key_expression OPTIONS [: value_expression]
OPTIONS := [timeout TIMESPEC] [expires TIMESPEC] [comment string]
TIMESPEC := [numd][numh][numm][num[s]]

元素相关命令允许更改命名集合和命名字典的内容。

get命令可以检查一个元素是否包含在一个集合中。

选项描述
timeout带有标志超时的集合/映射的超时值
expires给定元素到期之前的时间,仅对规则集复制有用
comment每个元素的注释字段
# 创建表
nft create table filter
# 用命名集合创建规则
nft add set filter allowed_ports { type inet_service \; }
nft add element filter allowed_ports { 80, 443, 8000 }
# 查看
nft list set filter allowed_ports
# 删除
nft delete element ip filter allowed_ports {8000}
# 判断某元素是否在集合中【此条未测试通过】
nft get inet_service filter allowed_ports { 8000 }

10. 备份|恢复

# 备份
nft list ruleset >> backup.nft
# 恢复(原子性)
nft -f backup.nft

11. 流表flowtable

flowtable允许在软件中加速数据包转发。其条目通过一个元组表示,元组由输入接口、原地址、目的地址、端口和3/4层协议组成。

12. 有状态对象【重要】

基础语法

{add | delete | list | reset} type [family] table object
delete type [family] table handle handle
list counters [family]
list quotas [family]

有状态对象是附加到表的并由唯一名称标识。它们将规则中的状态信息分组,以在规则中引用它们,使用关键字“类型名称”,例如“计数器名称”。

  1. CT Helper

    • 基础语法ct helper helper { type type protocol protocol ; [l3proto family ;] }

    • ct helper用于定义连接跟踪助手,可以将其与ct helper set语句结合使用。typeprotocol是强制性的,l3proto 默认派生自表簇,即在 inet 表中,内核将尝试加载 ipv4 和 ipv6 助手后端,如果内核支持它们。

  2. CT Timeout

    • 基础语法ct timeout name { protocol protocol ; policy = { state: value [, ...] } ; [l3proto family ;] }

    • ct timeout用于更新连接跟踪超时值。超时策略由ct timeout set语句指定。protocolpolicy是强制性的,l3proto 默认派生自表族。

    • conntrack 超时规格

      关键词描述类型
      protocol字符串(例:ip)
      state字符串(例:“established”)
      value无符号整数
      l3proto地址簇(例:ip)
    • 定义和分配ct timeout策略

      table ip filter {
              ct timeout customtimeout {
                      protocol tcp;
                      l3proto ip
                      policy = { established: 120, close: 20 }
              }
      
              chain output {
                      type filter hook output priority filter; policy accept;
                      ct timeout set "customtimeout"
              }
      }
      
    • 测试和更新超时策略

      yum install conntrack安装

      conntrack-tools的使用手册

      关于conntrack的一篇文章

      # 命令 显示流事件
      conntrack -E
      # 结果 前两个值为 协议 剩余秒数
      [NEW] icmp     1 30 src=10.121.6.6 dst=192.168.5.71 type=8 code=0 id=1 [UNREPLIED] src=192.168.5.71 dst=192.168.5.119 type=0 code=0 id=1
      [UPDATE] icmp     1 30 src=10.121.6.6 dst=192.168.5.71 type=8 code=0 id=1 src=192.168.5.71 dst=192.168.5.119 type=0 code=0 id=1
      
      # 晒选条件为tcp协议22端口 mark是更新标记
      conntrack -U -p tcp --dport 22 --mark 10
      # 结果 可以看到10.121.6.6访问了192.168.5.71的22端口、58.40.70.86访问了192.168.5.119的22端口
      tcp      6 431971 ESTABLISHED src=10.121.6.6 dst=192.168.5.71 sport=6401 dport=22 src=192.168.5.71 dst=192.168.5.119 sport=22 dport=6401 [ASSURED] mark=10 use=2
      tcp      6 79 TIME_WAIT src=10.121.6.6 dst=192.168.5.71 sport=9890 dport=22 src=192.168.5.71 dst=192.168.5.119 sport=22 dport=9890 [ASSURED] mark=10 use=2
      tcp      6 299 ESTABLISHED src=58.40.70.86 dst=192.168.5.119 sport=2526 dport=22 src=192.168.5.119 dst=58.40.70.86 sport=22 dport=2526 [ASSURED] mark=10 use=2
      tcp      6 431943 ESTABLISHED src=58.40.70.86 dst=192.168.5.119 sport=2528 dport=22 src=192.168.5.119 dst=58.40.70.86 sport=22 dport=2528 [ASSURED] mark=10 use=2
      
  3. CT Expectation

    • 基础语法ct expectation name { protocol protocol ; dport dport ; timeout timeout ; size size ; [*l3proto family ;] }

    • ct expectation 用于创建连接期望。期望是用ct expectation set语句分配的。protocol, dport, timeoutsize是强制性的,l3proto 默认源于表簇。

    • conntrack 期望规格

      关键词描述类型
      protocol期望对象的第四层协议字符串(例:ip)
      dport期望连接的目的端口无符号整数
      timeout期望的超时值无符号整数
      size期望的大小值无符号整数
      l3proto期望对象的第3层协议地址簇(例:ip)
    • 定义和分配ct expectation策略

      table ip filter {
              ct expectation expect {
                      protocol udp
                      dport 9876
                      timeout 2m
                      size 8
                      l3proto ip
              }
      
              chain input {
                      type filter hook input priority filter; policy accept;
                      ct expectation set "expect"
              }
      }
      
  4. Counter

    • 基础语法counter [packets bytes]

    • counter 规格

      关键词描述类型
      packets数据包的初始计数无符号整数 (64 bit)
      bytes初始字节数无符号整数 (64 bit)
  5. Quota

    • 基础语法quota [over | until] [used]

    • counter 规格

      关键词描述类型
      quota配额限制,用作配额名称两个参数,无符号整数 (64 bit)和字符串,bytes, kbytes, mbytes 需要在这些参数前写上 “over” 和"until"
      used已用配额的初始值两个参数,无符号整数 (64 bit)和字符串,bytes, kbytes, mbytes

13. 表达式Expression

表达式表示值,可以是网络地址、端口号等常量,也可以是在规则集评估期间从数据包中收集的数据。可以使用二进制、逻辑、关系和其他类型的表达式组合表达式以形成复杂或关系(匹配)表达式。它们还用作某些类型操作的参数,例如 NAT、数据包标记等。每个表达式都有一个数据类型,它决定了符号值的大小、解析和表示以及与其他表达式的类型兼容性。

# 描述命令
describe expression | data type

nft describe tcp flags

14. 数据类型

14种,暂时留空

15. 主要表达式

  1. 元表达式
meta {length | nfproto | l4proto | protocol | priority}
[meta] {mark | iif | iifname | iiftype | oif | oifname | oiftype | skuid | skgid | nftrace | rtclassid | ibrname | obrname | pkttype | cpu | iifgroup | oifgroup | cgroup | random | ipsec | iifkind | oifkind | time | hour | day }

元表达式类型

KeywordDescriptionType
length数据包的长度(以字节为单位)整数(32-bit)
nfproto真正的钩子协议族,仅在 inet 表中有用整数(32 bit)
l4proto4层协议,跳过 ipv6 扩展标头整数(8 bit)
protocolEtherType 协议值ether_type
priorityTC 报文优先级tc_handle
mark报文标记mark
iif输入接口索引iface_index
iifname输入接口名称ifname
iiftype输入接口类型iface_type
oif输出接口索引iface_index
oifname输出接口名称ifname
oiftype输出接口硬件类型iface_type
sdif从机输入接口索引iface_index
sdifname从设备接口名称ifname
skuid与原始套接字关联的 UIDuid
skgid与原始套接字关联的 GIDgid
rtclassid路由领域realm
ibrname输入桥接口名称ifname
obrname输出桥接口名称ifname
pkttypepacket typepkt_type
cpu处理数据包的 CPU 编号整数(32 bit)
iifgroup传入设备组devgroup
oifgroup传出设备组devgroup
cgroup控制组标识id整数(32 bit)
random伪随机数整数(32 bit)
ipsec若数据包是 ipsec 加密的,则为 true布尔值(1 bit)
iifkind输入接口种类
oifkind输出接口种类
time接收包的绝对时间整数(32 bit) 或 字符串
day星期几整数(8 bit) 或 字符串
hour一天中的第几小时字符串

元表达式特定类型

类型描述
iface_index接口索引(32 位数字) 可以用数字指定,也可以指定为现有接口的名称。
ifname接口名称(16 字节字符串) 不一定存在。
iface_type接口类型(16 位数字)
uid用户 ID(32 位数字) 可以用数字或用户名指定。
gid组 ID(32 位数字) 可以用数字或组名指定。
realm路由领域(32 位数字)。可以用数字指定或作为 /etc/iproute2/rt_realms 中定义的符号名称指定。
devgroup_type设备组(32 位数字)。可以用数字指定,也可以指定为 /etc/iproute2/group 中定义的符号名称。
pkt_type数据包类型:主机(寻址到本地主机)、广播(对所有)、多播(对组)、其他(寻址到另一台主机)。
ifkindI接口种类(16 字节字符串)。有关列表,请参阅ip-link(8)中的TYPES 。
timeISO 格式的整数或日期。例如:“2019-06-06 17:00”。小时和秒是可选的,如果需要可以省略。如果省略,则假定为午夜。以下三个等效:“2019-06-06”、“2019-06-06 00:00”和“2019-06-06 00:00:00”。当给出一个整数时,它被假定为一个 UNIX 时间戳。
day一周中的某一天(“Monday”、“Tuesday”等),或者 0 到 6 之间的整数。字符串不区分大小写匹配,并且不需要完全匹配(例如,“Mon”将匹配“Monday” )。当给出整数时,0 是星期日,6 是星期六。
hour以 24 小时格式表示小时的字符串。可以选择指定秒数。例如,17:00 和 17:00:00 是等价的。
# 使用元表达式
# 合格的元表达式
filter output meta oif eth0
filter forward meta iifkind { "tun", "veth" }

# 【不合格的元表达式】
filter output oif eth0

# 传入的数据包经过 ipsec 处理
raw prerouting meta ipsec exists accept
  1. 套接字表达式

  2. Osf表达式

  3. 路由表达式

  4. Numgen表达式

  5. 哈希表达式

16. 有效载荷表达式

留空待写

17. 语句

  1. Nat语句

语法规则

snat [[ip | ip6] to] ADDR_SPEC [:PORT_SPEC] [FLAGS]
dnat [[ip | ip6] to] ADDR_SPEC [:PORT_SPEC] [FLAGS]
masquerade [to :PORT_SPEC] [FLAGS]
redirect [to :PORT_SPEC] [FLAGS]

ADDR_SPEC := address | address - address
PORT_SPEC := port | port - port

FLAGS  := FLAG [, FLAGS]
FLAG  := persistent | random | fully-random

nat 语句仅对 nat 链类型有效。

待补充

18. 参考文档

  1. nftables用户手册 man nft - mankier.com
  2. golang库-nftableslib——lib文档
  3. nftables官方文档 nftables HOWTO documentation page——HowTo中文翻译
  4. 疑难问题解决和 FAQ
  5. 其他前辈的文章1
  6. 基佬杨写的教程
  7. 第七章是nftables入门 Red Hat Enterprise Linux 8 安全网络-配置安全网络和网络通信
  8. nftables家族介绍
  9. 官方故障排除文档
  10. 剖析语法文档——nftables相比iptables到底改变了什么
  11. ebpf防火墙GUI版本——ebpfsnitch
 类似资料: