Nftables是个嘛
简单来说,他是一个数据包分类框架,nftables的推出,直接能够取代 {ip,ip6,arp,eb}_tables四种框架,也就是nftables直接实现了四合一的功能
当然,他也对上述四个框架做了一定程度上的兼容,能让你在nftables内核上运行iptables(也就是nft
可以利用内核提供的表达式去模拟旧的 iptables
命令)
nftables的特点
与iptables之间的差异:
iptables
规则的布局是基于连续的大块内存的,即数组式布局;而nftables
的规则采用链式布局。其实就是数组和链表的区别iptables
大部分工作在内核态完成,如果要添加新功能,只能重新编译内核;而nftables
的大部分工作是在用户态完成的,添加新功能很 easy,不需要改内核。iptables
有内置的链,即使你只需要一条链,其他的链也会跟着注册;而nftables
不存在内置的链,你可以按需注册。由于iptables
内置了一个数据包计数器,所以即使这些内置的链是空的,也会带来性能损耗。- 简化了
IPv4/IPv6
双栈管理 - 原生支持集合、字典和映射
优势功能:
改进性能
支持查询表
nftables
拥有一些高级的类似编程语言的能力,例如:定义变量和包含外部文件,即拥有使用额外脚本的能力。nftables
也可以用于多种地址簇的过滤和处理- 不同于
iptables
,nftables
并不包含任何的内置表,需要哪些表并在这些表中添加什么处理规则一切由管理员决定 - 表包含规则链,规则链包含规则
事务型规则更新
所有规则自动应用
组件组成:
内核的实现 提供了 netlink 接口并 运行时规则集评估
libnl netlink通信 与内核通信的基本函数
nftables 用户空间 新引入的命令行工具
nft
和用户进行交互
优点:
更新速度快:
nftables
使用原子的快速操作来更新规则集合内核更新少:
使用
iptables
时,每一个匹配或投递都需要内核模块的支持。因此,如果你忘记一些东西或者要添加新的功能时都需要重新编译内核。而在nftables
中就不存在这种情况了, 因为在nftables
中,大部分工作是在用户态完成的,内核只知道一些基本指令(过滤是用伪状态机实现的)。例如,icmpv6
支持是通过nft
工具的一个简单的补丁实现的,而在iptables
中这种类型的更改需要内核和iptables
都升级才可以。
nftables 使用
基础操作
首先,我们需要明确一点:nftables实际上也是由tables,chain和rule组成,tables包含chain,chain包含rule,其中rule是真正的动作。
因此,开始使用时我们未尝不可先从添加一个表开始:
表:
介绍
首先,nftables并没有内置表,因此我们可以自由决定表的数量和名称
其次,我们可以自由决定表的地址簇,当然,每个表只有一个地址簇,其中ip(也就是ipv4)是默认簇
其中我们知道
inet
不能用于nat
类型,只能用于filter
的链
Nftables 表 是 Nftables 的一种容器,存放 chain 链
Nftables 表 无法修改名称,仅存在 flag 可能会有更新。
Nftables 表 需要定义 数据包 的 family 地址簇 类型,用以限定引用范围
Nftables 表 对 规则顺序 没有影响,仅限定了 规则 的使用区域与地址簇类别
Nftables 表 可以使用 标志位 flag 暂时禁用所有规则,且仅有 dormant 唯一标志 {flags dormant;}
Nftables 表 所使用的 地址簇****family 一共有六大类
主四类为 ip / ip6 / bridge / arp,分别对应 IPV4 / IPV6 / L2 / ARP 专项
第五类为 ip&ip6 双栈使用的 inet , 不能搭配 nat 类型链,只能搭配 filter 类型链,且网络层流量会自动匹配对应协议栈规则
第六类为 netdev ,优先级顺序最高,通常用于代码开发和排障测试使用。
Nftables 表的配置需要参考如下
可选项 [
可选项 [
具体操作:
创建表
1
nft add|create table [<family>] <name> [{ flags flags ; }]
列出表:
1
2
3
4
5
6
7
8列出所有表
nft list tables [<family>]
列出指定族的所有表
nft list tables [<family>] <name> [-n] [-a]
列出表中的所有规则:
nft list table [<family>] <name>如:列出 inet 簇中 mytable 表中的所有规则
nft list table inet mytable删除一个表:
1
nft delete table [<family>] <name>
只能删除不包含链的表
清空表中的链与规则:
1
nft flush table [<family>] <name>
链
介绍:
链是用来保存规则的,由于nftables不配置内置链,因此我们需要显式创建链
链内部规则按顺序从上到下执行
链分为两种类型:
- 常规链:主要用来做跳转, 不需要指定钩子的类型和优先级,支持所有簇,主要以调度其他链和跳转为主
- 基本链:来自网络栈数据包的入口点,需要指定钩子类型和优先级,支持
ip
和ip6
簇,管理流经网络协议栈(TCP/IP)的数据包
基本链的类型:
filter
:过滤数据包route
:对数据包进行重路由nat
:对 数据流 进行 网络地址转换(数据流仅第一个包会因为钩子进入本链,之后即使有钩子也会绕过)配置特点:
Nftables 链 需要指定 类型 type 配置 流量应当以何种方式被控制(基础链强制)
Nftables 链 需要调用 钩子 hook 抓取网络数据包 才会对数据进行处理(基础链强制)
Nftables 链 需要调用 优先级 priority 管理链的优先级顺序(基础链强制)nftables依然使用
netfiler
的五个钩子 然而nftables在钩子上相较于iptables 的不同在于 他新增了
ingress
钩子各个钩子的作用:
prerouting
:刚到达并未被nftables
的其他部分所路由或处理的数据包(在这条钩子捕获 刚刚进入内核网络接口的数据包。)。input
:已经被接收并且已经经过prerouting
钩子的传入数据包(捕获 打算进入本机的本地进程之前的数据包)。forward
:如果数据报将被发送到另一个设备,它将会通过forward
钩子(捕获 那些通过并不进入主机的所有数据包)。output
:从本地传出的数据包(捕获 打算离开本机的本地进程产出的数据包)。postrouting
:仅仅在离开系统之前,可以对数据包进行进一步处理(捕获 刚刚进入内核网络接口的数据包)ingress
:在prerouting之前处理(捕获 网卡驱动 向 内核网络接口 传递的数据包。)
不同簇之间对于钩子的适用范围不同
ip
、ip6
和inet
簇支持的钩子有:prerouting
、input
、forward
、output
、postrouting
。arp
簇支持的钩子有:input
、output
netdev
地址簇表 可以使用 INGRESS 钩子类型
nftables链的优先级:
Nftables 基础链 优先级 priority 通过 顺序排列 进而 按顺序执行不同 钩子 hook,优先级小数值优先
优先级采用整数值表现,数字越小处理优先级越高:
见:
- NF_IP_PRI_CONNTRACK_DEFRAG (-400)
- NF_IP_PRI_RAW (-300)
- NF_IP_PRI_SELINUX_FIRST (-225)
- NF_IP_PRI_CONNTRACK (-200)
- NF_IP_PRI_MANGLE (-150)
- NF_IP_PRI_NAT_DST (-100)
- NF_IP_PRI_FILTER (0)
- NF_IP_PRI_SECURITY (50)
- NF_IP_PRI_NAT_SRC (100)
- NF_IP_PRI_SELINUX_LAST (225)
- NF_IP_PRI_CONNTRACK_HELPER (300)
特殊 1:当存在两个拥有 相同钩子 但 钩子优先级不同 的 A/B 基础链 (A<B),会先执行 A 链 然后 执行 B 链
特殊 2:但当上方情况为 A 链 执行 Drop 时,此时数据包 Drop 行为会立即生效,并终止继续执行链有几个常见策略:
- accept(常用)
- drop (常用)
- queue
- continue
- return
基本语法
创建常规链:
1
2
3
4nft create chain [<family>] <table> <name>
如:
nft add chain inet mytable tcpchain创建一个基本链,必须指定钩子和优先级,基本链的类型可以是
filter
,route
或者nat
。1
2
3
4
5nft (add | create) chain [<family>] <table> <name> [ { type <type> hook <hook> [device <device>] priority <priority> \; [policy <policy> \;] } ]
例:添加一个筛选输入数据包的基本链
nft add chain inet mytable input { type filter hook input priority 0\; }命令中的反斜线
(\)
用来转义,这样Shell
就不会将分号解释为命令的结尾。列出链的所有规则:
1
nft list chain [<family>] <table> <name>
编辑链
要编辑一个链,只需按名称调用并重新定义要更改的规则即可。
1 | 将input链的策略更改成drop |
清空/删除链:
1
nft (delete | flush) chain [<family>] <table> <name>
要删除的链中不能包含任何规则或者跳转目标。
规则
基本操作
nftables 的规则包含在链中,创建nftables规则的基本语法有:
将规则添加到链尾:
1
nft add rule [<family>] <table> <chain> <matches> <statements>
将规则添加到链头:
1
nft insert rule [<family>] <table> <chain> [position <position>] <matches> <statements>
指定位置增加规则
1
2
3
4
5
6可以通过index/handle来指定增加规则的位置
例子:
在 input 链中已有规则中的第二条规则前插入一条新的规则
nft insert rule inet mytable input index 1 tcp dport nfs accept
在 input 链中已有规则中的第一条规则后插入一条新的规则
nft add rule inet mytable input index 0 tcp dport 1234 accept注意:
index
的值是从0
开始的,index
*必须指向一个已存在的规则的索引。
也可以使用handle来指定规则的句柄
通过handle来指定规则添加的位置
通过
handle
的值来指定规则添加的位置,必须先知道现有规则的句柄位置。你可以通过参数--handle
来获取当前规则的句柄位置。1
2nft --handle list ruleset
获取到当前规则的句柄位置后,我们就可以在指定句柄位置添加规则
在 nftables
中,句柄值是固定不变的,除非规则被删除。而 index
的值是可变的,只要有新规则插入,就 有可能发生变化。一般建议使用 handle
来插入新规则.
你也可以在创建规则时就获取到规则的句柄值,只需要在创建规则时同时加上参数 --echo
和 --handle
更改规则;
1
nft replace rule [<family>] <table> <chain> [handle <handle>] <matches> <statements>
删除规则:
1
nft delete rule [<family>] <table> <chain> [handle <handle>]
单个规则只能通过句柄值进行删除
matches 匹配
其中,matches为报文需要满足的条件:
目前有以下几种报文可以被识别:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22ip : ipv4 协议字段
ip6 : ipv6 协议字段
tcp : tcp 协议字段
udp : udp 协议字段
udplite : udp-lite 协议
sctp : sctp 协议
dccp
ah
esp
comp
icmp
icmpv6
ether : 以太头
dst
frag :
hbh
mh
rt
vlan : vlan
arp : arp协议
ct : 连接状态
meta : 报文的基本信息每种类型的报文可以检查多个字段,比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17ip dscp cs1
ip dscp != cs1
ip dscp 0x38
ip dscp != 0x20
ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21,
af22, af23, af31, af32, af33, af41, af42, af43, ef}
ip length 232
ip length != 233
ip length 333-435
ip length != 333-453
ip length { 333, 553, 673, 838}
ip6 flowlabel 22
ip6 flowlabel != 233
ip6 flowlabel { 33, 55, 67, 88 }
ip6 flowlabel { 33-55 }
具体有哪些match可以见:
https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Rules
https://www.mankier.com/8/nft#Expressions到https://www.mankier.com/8/nft#Payload_Expressions
statments 触发
statments作为保温匹配规则时触发的操作,有以下几种:
1 | Verdict statements : 动作 |
而Verdict Statements 是一系列报文匹配match时触发的操作:
accept:接受数据包并停止剩余规则评估。
drop:丢弃数据包并停止剩余规则评估。
queue:将数据包排队到用户空间并停止剩余规则评估。
continue:使用下一条规则继续进行规则评估。
return:从当前链返回并继续执行最后一条链的下一条规则。
jump < chain > :跳转到指定的规则链,当执行完成或者返回时,返回到调用的规则链。
goto < chain >:类似于跳转,发送到指定规则链但不返回。
rule中具体规则详见:https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes#Rules
statment详解见:https://www.mankier.com/8/nft#Statements
进阶
集合
nftables
的语法原生支持集合,可以用来匹配多个 IP
地址、端口号、网卡或其他任何条件。
匿名集合:
匿名集合适用于将来不需要更改的规则,但如果要修改集合规则,就得将原规则进行替换:
如:
1
2
3
4
5允许来自源 IP 处于 10.10.10.123 ~ 10.10.10.231 这个区间内的主机的流量。
nft add rule inet mytable input ip saddr { 10.10.10.123, 10.10.10.231 } accept
允许指定协义的流量通过
nft add rule inet mytable input tcp dport { http, nfs, ssh } accept命名集合:
nftables的命名集合是可以修改的。创建命名集合时需要指定其元素的类型,当前支持的数据类型有:
ipv4_addr
:IPv4
地址ipv6_addr
:IPv6
地址ether_addr
: 以太网(Ethernet)地址inet_proto
: 网络协议inet_service
: 网络服务mark
: 标记类型
例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31创建一个空的命名集合
nft add set inet mytable myset { type ipv4_addr \; }
nft list sets
table inet mytable {
set myset {
type ipv4_addr
}
}
之后向集合中添加一些元素
nft add element inet mytable myset { 10.10.10.22, 10.10.10.33 }
nft list set inet mytable myset
table inet mytable {
set myset {
type ipv4_addr
elements = { 10.10.10.22, 10.10.10.33 }
}
}
在添加规则时引用集合,你可以使用 @ 符号跟上集合的名字来引用命名集合
将来源为集合 myset 中的 IP 地址的请求阻止掉
nft insert rule inet mytable input ip saddr @myset drop
nft list chain inet mytable input
table inet mytable {
chain input {
type filter hook input priority 0; policy accept;
ip saddr @my_set drop
tcp dport http accept
tcp dport nfs accept
tcp dport ssh accept
ip saddr { 10.10.10.123, 10.10.10.231 } accept
}
}支持区间
如果想要在上述的集合钟使用区间,可以加一个
flag interval
例子:
1
2
3
4
5
6
7
8
9
10
11创建一个支持区间的命名集合
nft add set inet mytable my_rangeset { type ipv4_addr \; flags interval
nft add element inet mytable my_rangeset { 10.10.10.0/24 }# 使用了子网掩码来表示 IP 地址段,它会被隐式转换为 IP 地址的区间
nft list set inet mytable my_rangeset
table inet mytable {
set my_rangeset {
type ipv4_addr
flags interval
elements = { 10.10.10.0/24 }
}
}级联不同类型
集合支持不同类型的元素进行级联
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17nft add set inet mytable my_concatset { type ipv4_addr . inet_proto . inet_service \; }
不同类型的元素可以通过级联操作符 . 来分隔。
nft list set inet mytable my_concatset
table inet mytable {
set my_concatset {
type ipv4_addr . inet_proto . inet_service
}
}
向集合中添加元素
nft add element inet mytable my_concatset { 10.30.30.30 . tcp . telnet }
然后我们可以在级联类型中对集合进行引用
如果数据包的源 IP、协议类型、目标端口匹配 10.30.30.30、tcp、telnet 时,就会允许该数据包通过
nft add rule inet mytable input ip saddr . meta l4proto . tcp dport @my_concatset accept
当然,匿名集合也可以使用级联
nft add rule inet mytable input ip saddr . meta l4proto . udp dport { 10.30.30.30 . udp . bootps } accept
字典
字典支持在一条规则上面使用不同类型的数据
当然字典同集合一样,也分为命名字典和匿名字典
例:
1 | 创建命名字典 |
表和命名空间
在 nftables
中,每个表都是一个独立的命名空间,这就意味着不同的表中的链、集合、字典等名字可以相同。
如:
1 | nft add table inet table_one |
当然由于 nftables
将每个表都被视为独立的防火墙,一个数据包必须被所有表中的规则放行才能真正通过。如果,出现两条链的优先级相同,就会进入竞争状态。但我们可以通过nftables的优先级特性来讲这个问题解决
备份
通过 nftables
用户态工具 nft
直接在终端中加入的规则都是临时的。如果要想永久生效,我们可以将规则备份后并在开机自动加载时进行恢复。
备份规则:
$ nft list ruleset > /root/nftables.conf
恢复规则:
$ nft -f /root/nftables.conf
后记
大概的介绍了一下nftables的作用,感觉没啥要补充的了,接下来就要到实战了😋
后续:懒得整了,实战连接:
https://icloudnative.io/posts/use-nftables-as-firewall/
然后这byd写了我小一周,主要全在了解网络协议去了。唉,网络