本文最后更新于:2023年12月5日 晚上
相关文档:
nftables 和 iptables 一样,依赖的底层机制都是 Netfilter,但是 nftables 各个方面都比 iptables 更优秀,未来一定会成为主流,所以有必要好好学习。
升级 nftables
CentOS8 自带的 nftables 版本是 0.9.3,而官网最新的版本是 0.9.6,所以需要先升级:
卸载系统自带的 nftables
去官网下载最新版本
安装
配置 systemctl
配置环境变量
nftables 和 iptables 的区别
- 1
- 2
- 3
- …
nf和 xt
nf是 netfilter 的缩写,nf_ 前缀的模块是 netfilter 的核心模块(以下称 nf 模块),nftables 之前,netfilter 提供了 iptables、ip6tables、arptables 等用户空间工具,xtables 就是这些工具的统称,缩写为 xt。可能是为了便于理解或者什么理由,专为 xtables 开发的模块以 xt前缀命名(以下称 xt 模块),当然,xtables 也可以调用 nf 模块。
安装 iptables 后,会生成/usr/lib64/xtables/目录,目录下就是各种 xt 模块。
xtables 既能调用 xt 模块,也能调用 nf 模块,为了方便我们把 xt 模块和 nf 模块统称为扩展。
现在,这些 xtables 工具被认为是过时的,推荐使用 nftables,nftables 是 xtables 的全面替代品,nftables 调用的都是 nf 模块,所以安装后自然也不会生成 /usr/lib64/xtables/目录。
因为并没有找到参考资料,以上都是个人理解和猜测,说的不一定准确。
表(Tables)
与 iptables 类似,在 nftables 中,表是链的容器,nftables 不包含任何的表和链,所以开始使用 nftables 时,首先需要添加至少一个表,然后向表里添加链,然后往链里添加规则。
地址簇与钩子函数
什么是地址族?
地址族:又叫地址簇,AF,Address;不要太纠结这个名称,可以认为就是 地址类型。
另外,还有协议族:又叫协议簇,PF,Protocol Family;协议族等价于地址族。
netfilter 中六个勾子函数(hook),前面 iptables 章节一节已经介绍过了,这里再说一遍,六个钩子函数是:
添加表
语法:
范例:
列出表
删除表
说明:内核 3.18 以前,需要先清空表中的内容,再删除表
清空表
链(Chains)
ntfables 没有内置的链,所有的链都需要手动创建,链有两种类型:基本类型和常规类型。
其中基本类型又分类三类:filter、nat、route
创建链
语法:
type:可以选择 filter、nat、route
hook:钩子函数,六个钩子函数,只能指定一个,不同的表 family 支持不同的钩子函数:
family |
hook |
ip、ip6、inet |
prerouting、input、forward、output、postrouting |
arp |
input、output |
bridge |
prerouting、input、forward、output、postrouting |
netdev |
ingress |
小总结:netdev 只支持 ingress + filter 一种组合;arp 支持 { input | output } + filter 两种组合
device:netdev 表只存在于每个传入接口,所以它需要指定 device 参数
priority:优先级,可以接受 整数值 或者 标准优先级名。整数值可以为负,数值越低优先级越高;有以下数值可以选择
- NF_IP_PRI_CONNTRACK_DEFRAG (-400): priority of defragmentation
- NF_IP_PRI_RAW (-300): traditional priority of the raw table placed before connection tracking operation
- NF_IP_PRI_SELINUX_FIRST (-225): SELinux operations
- NF_IP_PRI_CONNTRACK (-200): Connection tracking operations
- NF_IP_PRI_MANGLE (-150): mangle operation
- NF_IP_PRI_NAT_DST (-100): destination NAT
- NF_IP_PRI_FILTER (0): filtering operation, the filter table
- NF_IP_PRI_SECURITY (50): Place of security table where secmark can be set for example
- NF_IP_PRI_NAT_SRC (100): source NAT
- NF_IP_PRI_SELINUX_LAST (225): SELinux at packet exit
- NF_IP_PRI_CONNTRACK_HELPER (300): connection tracking at exit
policy:链的策略,支持的策略值是 accept、drop,默认是 accept
范例:
列出链
编辑链
把添加链语法的 add 或者 create 关键字去掉,就是编辑链的语法
范例:
删除链
要删除的链不能包含任何规则或者跳转目标。
范例:
清空链
范例:
iptables 和 nftables 的区别
参考博客:https://blog.csdn.net/dog250/article/details/41526421?locationNum=8
iptables
iptables 是由表、链、规则组成,其中规则又由 match、target 组成。
iptables 的规则是按照配置顺序顺序匹配的,在每一张表的每一个链上依次匹配每一条规则,在每一条规则依次匹配每一个 match,全部匹配的 match 执行该规则的 target,由 target 决定:
- 继续匹配下一条规则
- 对数据包做一些修改
- 跳转到其它的链(即开始从该链依次匹配该链上的每一条规则)
- 返回引发跳转的链(即继续匹配跳转前的链的下一条规则)
- 丢弃数据包
- 接收数据包(即不再继续往下匹配,直接返回)
- 记录日志
- …
整个 iptables 框架的执行流程如下:
可以发现,包过滤的流程最终要落实到规则匹配,而过滤的动作最终落实到了该规则的 target,前面的所有的 match 匹配返回结果就是 0 或者非 0 表示是否匹配,只有所有的 match 均匹配,才会执行 target。这也就导致了如果你想实现多个 target,就不得不写多条规则。
nftables
nftables 的规则去掉了“匹配所有的 match 之后执行一个 target”这样的限制,使一条规则真的成了“为一个数据包做一些事情”这样灵活的命令。我们来看一下 nftables 框架的执行流程:
可以看到,nftables 没有 match 和 target,而是将一条 rule 抽象成了若干条的表达式,即 expression,所谓的表达式就是一个主语加谓词的式子,它是“可执行”的,它可以“做任何事情”,而不仅仅是计算一个匹配结果。除此之外,nftables 内置了一组寄存器,其中之一是 verdict 寄存器,它指示了“下一步要怎么做”。每一条 expression 执行完了之后,会取出该寄存器,由该寄存器的值来采取下一步的行动。这个 verdict 寄存器替换了 iptables 中 target 返回值,这就可以在一条 rule 中采取多个动作,每条动作可以解析成一个 expression,只要每一个 expression 在执行后将 verdict 寄存器设置为 CONTINUE 即可。
除了执行流程的显著区别之外,nftables 最大的意义在于它对 expression 进行了抽象,nftables 的内核框架可以注册很多种的 expression,其中 expr 回调函数执行具体的 expression 表达式。
表达式 expression
规则由表达式组成,表达式有匹配表达式,和动作表达式两种,但官方文档不是这么划分的,而是分成表达式和语句,其实表达式就是匹配表达式,语句就是动作表达式,下文如果没有特别说明,采用的是官方的说法。
例如规则:
就是由ip sadd
、tcp dpor
两条表达式和accept
一条语句组成
每个表达式都有一个数据类型
describe
describe 命令可以显示表达式 或 数据类型的信息
语法:
范例:
数据类型分级别,全局数据类型是最低阶的,有 integer、string 两种,高阶的数据类型从低阶的派生而来,例如:bitmask 从 integer 派生而来,ct_state 从 bitmask 派生而来。
大部分数据类型固定长度,少部分不固定。
一些高阶的数据类型具有预定义的符号常量,例如:boolean 类型,固定 size 1bit,取值 0 或 1,预定义了 exists 和 missing 两个字符常量,会被自动替换为 1 和 0;
- integer:用于数值,可以指定为十进制、十六进制或八进制,没有固定大小
- string:用于字符串,以字母开头,此外,双引号内的任何内容都被认为是字符串
- bitmask:用于位掩码,基于 integer,至于什么是位掩码,自行百度或参考文章:什么是掩码 BitMask
- boolean:用于布尔值,固定 size 1bit
- inet_service:用于服务端口,固定 size 16bit
- ipv4_addr:用于 IPv4 地址,固定 size 32bit,预定义字符常量 localhost
- icmp_type:用于 ICMP 类型,固定 size 8bit,取值 0-18,预定义了 echo-reply、echo-request 等 19 个字符常量,会被自动替换为 0-18
- 链接跟踪
- …
expression
分为主表达式和有效负载表达式,不知道有什么区别,看起来好像在一条规则中,主表达式的位置在有效负载表达式的前面。
以下是对所有表达式做一个全面但简略的记录,详细信息参考:https://jlk.fjfi.cvut.cz/arch/manpages/man/nft.8
meta 表达式
meta 就是数据包的元数据,元表达式有限定和非限定两种,限定不能省略 meta 关键字,非限定则可以省略
范例:
socket 表达式
套接字表达式用于搜索已打开的 TCP/UDP 套接字,及其与数据包关联的属性
osf 表达式
被动操作系统指纹识别。此表达式将数据包中的某些数据(窗口大小、MSS、选项及其顺序、DF 等)与 SYN 位集进行比较
- ttl:对包进行 TTL 检查以确定操作系统
- version:对包进行 OS 版本检查
- name:要匹配的操作系统签名的名称。所有的签名都可以在 pf.os 文件中找到。对表达式无法检测到的操作系统签名使用“unknown”
fib 表达式
routing 表达式
路由表达式指的是与数据包关联的路由数据
ipsec 表达式
numgen 表达式
hash 表达式
使用一个哈希函数来生成一个数字。可用的函数是 jhash(Jenkins 散列)和 symhash(对称散列)。
jhash 和 symhash 的典型用例是负载均衡
以太网报头表达式
VLAN 头表达式
ARP 头表达式
IPV4 头表达
ICMP 头表达式
IGMP 头表达式
IPV6 报头表达式
ICMPV6 头表达
TCP 报头表达式
UDP 报头表达式
UDP-LITE 头表达
SCTP 头表达式
DCCP 头表达式
验证标题表达
加密的安全有效负载头表达式
IPCOMP 头表达式
原始载荷表达式
扩展头表达式
CONNTRACK 表达式
添加规则
语法:
- handle:规则句柄,句柄是不变的,除非规则被删除,这就为规则提供了稳定的索引。add 添加规则到句柄规则后面,insert 添加规则到句柄规则的前面。如果省略,add 默认添加规则到链末尾,insert 默认添加规则到链的开头
- expression:负责匹配数据包
- statement:负责对匹配的数据包做后续处理
- comment:备注
expressions
expr 回调函数每处理完一条表达式,就修改 verdict 寄存器的值为 CONTINUE,继续处理下一条。
上文 expression 章节中的表达式总结的很全面,下面对常用的表达式做详细的说明:
IP
上图是 IPv4 报头图,除了最后的可选字段,其他每个字段 matches 都可以匹配,下面挑常用的介绍,后面的 ip6、tcp、udp 等等,也都是只介绍常用的,这点就不再赘述:
Ip6
Tcp
sport
dport :Destination port
flags :TCP flags
Udp
- sport
- dport :Destination port
Udplite
Sctp
Dccp
Ah
Esp
Comp
Icmp
type <type>:ICMP packet type,也可以写数值,例如icmp type echo-reply
等价于icmp type 0
code <code>:ICMP packet code
mtu :ICMP packet mtu,最大传输单元
gateway :ICMP packet gateway
Icmpv6
Ether
Dst
Frag
Hbh
Mh
Rt
Vlan
Arp
Ct 是 Conntrack 的缩写,链接跟踪
state : State of the connection,这个匹配条件的作用和 iptables 的 state 模块一样
direction : Direction of the packet relative to the connection,数据包相对于链接的方向
status :Status of the connection
mark [set]:Mark of the connection
expiration: Connection expiration time,连接过期时间
helper ““:Helper associated with the connection
[original|reply] bytes
[original|reply] packets :
[original | reply] saddr
[original | reply] daddr
[original | reply] l3proto
[original | reply] protocol
[original | reply] proto-dst
[original | reply] proto-src
匹配(某些情况下可以 设置)数据包的元信息,虽然我现在也不知道元信息是什么?
不能省略 meta 关键字
- length – packet lenght
- protocol – packet protocol (as in skb->protocol)
- nfproto – netfilter packet protocol family (like ipv4, ipv6, etc..).
- l4proto – layer 4 protocol (tcp, udp, etc..)
- priority – packet priority, tc handle. Can be set.
- random – match against a single/simple random number
- secmark – packet secmark. Can be set.
- ibrvproto – match the bridge protocol
- ibrpvid – match the bridge pvid
可以省略 meta 关键字
- mark – packet mark. Can be set.
- iif – input interface index
- iifname – input interface name
- iiftype – input interface type
- oif – output interface index
- oifname – output interface name
- oiftype – output interface type
- skuid – socket uid
- skgid – socket gid
- nftrace – nftrace debugging bit. Can be set.
- rtclassid – realm
- ibriport – input bridge port
- obriport – output bridge port
- ibridgename – input bridge name
- obridgename – output bridge name
- pkttype – packet type. Can be set.
- cpu – cpu number
- iifgroup – input interface group
- oifgroup – output interface group
- cgroup – cgroup number
- ipsec – ipsec (secpath) packet or not
- time – packet timestamp
- day – packet timestamp
- hour – packet timestamp
Matching packets by interface name 通过接口名称匹配数据包
Matching packets by packet mark 通过数据标记匹配数据包
Matching packets the socket UID 匹配套接字 UID 的数据包
Matching packet priority 匹配数据包的优先级
statements
语句,分为两种,终结和非终结,终结语句不会再继续处理后面的表达式和规则,防火墙完成本次任务,而非终结语句会继续处理后面的表达式或者规则。
- Verdict:重定向
- Log:记录日志并继续处理请求
- Reject:停止处理并拒绝请求
- Counter:计数
- Limit:如果达到了接收数据包的匹配限制,则根据规则处理数据包
- Nat:NAT,分为 snat 和 dnat
- Queuea:停止处理并发送数据包到用户空间程序
verdict
每条 verdict 语句都与 verdict 寄存器的预设值一一对应,只负责控制已匹配数据包的重定向,如果在决定数据包的去向之前有任何操作,交给其他类型的语句负责
expr 处理完 verdict 语句,会跳出当前表达式的循环(即上文 nftables 框架的执行流程中的循环 2)这样不管最终重定向到哪里,都会就此结束当前规则,所以 verdict 语句,要写在规则的最后。
- accept:终结语句,接受数据包
- drop:终结语句,接受数据包
- queue:将数据包排队到用户空间,queue 本身不是终结语句,但是需要搭配 accept 或者 drop 使用
- continue:跳过本条规则后面的表达式和语句,处理下一条规则
- return:
- 从一个 CHAIN 里可以 jump 到另一个 CHAIN, jump 到的那个 CHAIN 是子 CHAIN
- 从子 CHAIN return 后,回到触发 jump 的那条规则,从那条规则的下一条继续匹配
- 如果不是在子 CHAIN 里 return,而是在 main CHAIN,那么就以默认规则进行
- jump :跳转到指定的规则链,当执行完成或者返回时,返回到调用的规则链
- goto :类似于跳转,发送到指定规则链但不返回
with type
按照数据包的大小递增字节计数器以及包计数器的值
packets bytes
Limit
等同于 iptables 中的 limit 条件匹配模块
适用于 nat 链
dnat :Destination address translation,目标地址转换
snat :Source address translation 源地址转换
masquerade [] [to :]:Masquerade,特殊的 snat,可以把 MASQUERADE 理解为动态的、自动化的 SNAT,如果没有动态 SNAT 的需求,没有必要使 MASQUERADE,因为 SNAT 更加高效
num
tproxy
synproxy
flow
dup
fwd
set
范例
替换规则
指定 handle,替换规则
列出规则
删除规则
删除规则只能通过 handle 值,所以删除之前需要先查询规则的 handle 值
清空规则
数据报文分组、分类的数据结构
表与命名空间
在 nftables 中,每个表都是独立的命名空间,这就意味着不同的表中的链、集合、字典等名字可以相同。不同的应用就可以在相互不影响的情况下管理自己表中的规则,不过要注意,由于 nftables 将每个表都视为独立的防火墙,一个数据包必须被所有表中的规则放行才能真正通过,如果在一个 hook,出现两条优先级相同的链,就会进入竞争状态。
集合(sets)
集合可以用来匹配多个 IP
地址、端口号、网卡或其他任何条件。
相对 iptables
来说,nftables
原生支持集合,并不需要借助 ipset
来实现。
nftables
的集合分为匿名集合与命名集合。
集合中的元素可能是连续的,也可能是不连续的,连续的使用 - 划分范围,不连续的使用 , 分割
匿名集合
范例:
如果写在文件中,通过 -f 加载,可以使用 define 关键字定义,使用 $ 关键字调用,范例:
命名集合
新建命名集合
上文的 表达式 expression 章节介绍了 datatype 和 expression。集合中的 type 和 typeof 关键字功能类似,type 指定 datatype,typeof 指定 expression,推荐使用 typeof,更易读
type:指定集合中元素的类型,当前支持的数据类型有:
ipv4_addr : IPv4 地址
- ipv6_addr : IPv6 地址
- ether_addr : 以太网(Ethernet)地址
- inet_proto : 网络协议
- inet_service : 网络服务
- mark : 标记类型
typeof:typeof 关键字从 0.9.4 版本开始用有效,允许使用表达式(参考下文的表达式章节),让 nftables 解析基本类型
flags:标志
- constant:内容不可变
- interval:内容包含区间集
- timeout:可以给元素设置一个过期时间
timeout:设置元素的过期时间
gc-interval:
elements:给初始化的集合填充元素
size:限制集合中元素的数量
policy:集合策略
- performance [default]
- memory
auto-merge:相邻/重叠集元素自动合并(仅适用于区间集)
counter:给每个元素设置计数器
范例:
使用 @ 关键字调用命名集合
列出命名集合
映射(Maps)
映射的元素形式是 key-value,key 和 vaule 之间的映射关系取决于映射的 type 或者 typeof
配置文件中的语法格式:
映射用于 map 和 vmap 语句,当键值均为表达式时,用于 map,当值为 verdict 语句时,用于 vmap。
map 通常用于 nat 地址转换。
- type:指定 datatype,支持以下 datatype,注意 counter 和 quota 不能用于键
- ipv4_addr : IPv4 地址
- ipv6_addr : IPv6 地址
- ether_addr : 以太网(Ethernet)地址
- inet_proto : 网络协议
- inet_service : 网络服务
- mark : 标记类型
- counter:
- quota:
- typeof:指定 expression
- flags:标志
- elements:初始化映射中的元素
- size:限制映射中元素的数量
- policy:策略
- performance [default]
- memory
范例:
使用 @ 关键字调用映射
Concatenations
Metering
以前称之为 flow tables
Updating sets from the packet path
Math operations
Stateful objects
Flowtable (the fastpath network stack bypass)
脚本
可以将规则写在文件中,通过nft -f file
加载。推荐这种方式
练习
说明:以下练习 INPUT 和 OUTPUT 默认策略均为 DROP
1、限制本地主机的 web 服务器在周一不允许访问;新请求的速率不能超过 100 个每秒;web 服务器包含了 admin 字符串的页面不允许访问;web 服务器仅允许响应报文离开本机
2、在工作时间,即周一到周五的 8:30-18:00,开放本机的 ftp 服务给 172.16.0.0 网络中的主机访问;数据下载请求的次数每分钟不得超过 5 个
3、开放本机的 ssh 服务给 172.16.x.1-172.16.x.100 中的主机,x 为你的学号,新请求建立的速率一分钟不得超过 2 个;仅允许响应报文通过其服务端口离开本机
4、拒绝 TCP 标志位全部为 1 及全部为 0 的报文访问本机
5、允许本机 ping 别的主机;但不开放别的主机 ping 本机
6、判断下述规则的意义