nftables (简体中文)
nftables 是一个netfilter项目,旨在替换现有的{ip,ip6,arp,eb}tables框架,为{ip,ip6}tables提供一个新的包过滤框架、一个新的用户空间实用程序(nft)和一个兼容层。它使用现有的钩子、链接跟踪系统、用户空间排队组件和netfilter日志子系统。
它由三个主要组件组成:内核实现、libnl netlink通信和nftables用户空间前端。 内核提供了一个netlink配置接口以及运行时规则集评估,libnl包含了与内核通信的基本函数,nftables前端是用户通过nft交互。
您还可以访问nftables官方wiki页面获取更多信息。
安装
安装用户空间实用程序包nftables或者git版本nftables-gitAUR。
用法
nftables区分命令行输入的临时规则和从文件加载或保存到文件的永久规则。
默认配置文件是/etc/nftables.conf
,其中已经包含一个名为"inet filter"的简单ipv4/ipv6防火墙列表。
start/enable nftables.service
。
检查规则集:
# nft list ruleset
/etc/modules-load.d/nftables.conf
文件。可以用以下命令获取模块列表: $ lsmod | grep '^nf'否则,可能会出现错误:
Error: Could not process rule: No such file or directory
配置
nftables的用户空间实用程序nft评估大多数规则集并传递到内核。规则存储在链中,链存储在表中。以下部分说明如何创建和修改这些结构。
以下所有更改都是临时的。要永久更改,请见规则集保存到nftables.service
加载的/etc/nftables.conf
中:
# nft list ruleset > /etc/nftables.conf
-
nft list
不输出变量的定义,如果在/etc/nftables.conf
中有任何变量定义将会丢失。规则中使用的变量将替换为其变量值。 -
nft list ruleset
在nftables v0.7 (Scrooge McDuck)在同时使用ICMP和ICMPv6时有语法限制。如果导出用作新的规则集将会导致错误。有关信息和解决方案,请参阅 stackexchange post。
要从文件读取输入,请使用-f
参数:
# nft -f filename
注意,任何已加载的规则不会自动清空。
有关命令的完整列表,参见nft(8)。
表(Tables)
表包含#链[损坏的链接:无效的章节]。与iptables中的表不同,nftables中没有内置表。表的数量和名称由用户决定。但是,每个表只有一个地址簇,并且只适用于该簇的数据包。表可以指定五个簇中的一个:
nftables簇 | iptables实用程序 |
---|---|
ip | iptables |
ip6 | ip6tables |
inet | iptables和ip6tables |
arp | arptables |
bridge | ebtables |
ip
(即IPv4)是默认簇,如果未指定簇,则使用该簇。
要创建同时适用于IPv4和IPv6的规则,请使用inet
。inet
允许统一ip
和ip6
簇,以便更容易地定义规则。
有关地址簇的完整描述,请参见nft(8)中的ADDRESS FAMILIES
章节。
在以下情况中,family
是可选的,如果未指定则设为ip
。
创建表
创建一个新的表:
# nft add table family table
列出表
列出所有表:
# nft list tables
列出表中的链和规则
列出指定表中的所有链和规则:
# nft list table family table
例如,要列出inet
簇中filter
表中的所有规则:
# nft list table inet filter
删除表
删除一个表:
# nft delete table family table
只能删除不包含链的表。
清空表
要清空一个表中的所有规则:
# nft flush table family table
链(Chains)
链的目的是保存#规则[损坏的链接:无效的章节]。与iptables中的链不同,nftables没有内置链。这意味着与iptables不同,如果链没有使用netfilter框架中的任何类型或钩子,则流经这些链的数据包不会被nftables触及。
链有两种类型。基本链是来自网络栈的数据包的入口点,其中指定了钩子值。常规链可以作为更好地处理的跳转目标。
在以下情况中,family
是可选的,如果未指定则设为ip
。
创建链
常规链
将名为chain
的常规链添加到名为table
的表中:
# nft add chain family table chain
例如,将名为tcpchain
的常规链添加到inet
簇中名为filter
的表中:
# nft add chain inet filter tcpchain
基本链
添加基本链,需要指定钩子和优先级值:
# nft add chain family table chain { type type hook hook priority priority \; }
type
可以是filter
、route
或者nat
。
IPv4/IPv6/Inet地址簇中,hook
可以是prerouting
、input
、forward
、output
或者postrouting
。其他地址簇中的钩子列表请参见nft(8)。
priority
采用整数值。数字较小的链优先处理,并且可以是负数。[3]
例如,添加筛选输入数据包的基本链:
# nft add chain inet filter input { type filter hook input priority 0\; }
将上面命令中的add
替换为create
则可以添加一个新的链,但如果链已经存在,则返回错误。
列出规则
列出一个链中的所有规则:
# nft list chain family table chain
例如,要列出inet
中filter
表的output
链中的所有规则:
# nft list chain inet filter output
编辑链
要编辑一个链,只需按名称调用并定义要更改的规则。
# nft chain family table chain { [ type type hook hook device device priority priority \; policy <policy> \; ] }
例如,将默认表中的input链策略从accept
更改为drop
:
# nft chain inet filter input { policy drop \; }
删除链
删除一个链:
# nft delete chain family table chain
要删除的链不能包含任何规则或者跳转目标。
清空链中的规则
清空一个链的规则:
# nft flush chain family table chain
规则(Rules)
规则由语句或表达式构成,包含在链中。
添加规则
将一条规则添加到链中:
# nft add rule family table chain handle handle statement
规则添加到handle
处,这是可选的。如果不指定,则规则添加到链的末尾。
将规则插入到指定位置:
# nft insert rule family table chain handle handle statement
如果未指定handle
,则规则插入到链的开头。
表达式
通常情况下,statement
包含一些要匹配的表达式,然后是判断语句。结论语句包括accept
、drop
、queue
、continue
、return
、jump chain
和goto chain
。也可能是其他陈述。有关信息信息,请参阅nft(8)。
nftables中有多种可用的表达式,并且在大多数情况下,与iptables的对应项一致。最明显的区别是没有一般或隐式匹配。一般匹配是始终可用的匹配,如--protocol
或--source
。隐式匹配是用于特定协议的匹配,如TCP数据包的--sport
。
以下是可用匹配的部分列表:
- meta (元属性,如接口)
- icmp (ICMP协议)
- icmpv6 (ICMPv6协议)
- ip (IP协议)
- ip6 (IPv6协议)
- tcp (TCP协议)
- udp (UDP协议)
- sctp (SCTP协议)
- ct (链接跟踪)
以下是匹配参数的部分列表(完整列表请参见nft(8)):
meta: oif <output interface INDEX> iif <input interface INDEX> oifname <output interface NAME> iifname <input interface NAME> (oif 和 iif 接受字符串参数并转换为接口索引) (oifname 和 iifname 更具动态性,但因字符串匹配速度更慢) icmp: type <icmp type> icmpv6: type <icmpv6 type> ip: protocol <protocol> daddr <destination address> saddr <source address> ip6: daddr <destination address> saddr <source address> tcp: dport <destination port> sport <source port> udp: dport <destination port> sport <source port> sctp: dport <destination port> sport <source port> ct: state <new | established | related | invalid>
删除
单个规则只能通过其句柄删除。使用nft --handle list
命令确定规则的句柄。请注意,--handle
开关告诉nft
输出句柄列表。
下面命令确定一个规则的句柄,然后删除。--number
参数用于查看数字输出,如未解析的IP地址。
# nft --handle --numeric list chain inet filter input
table ip fltrTable { chain input { type filter hook input priority 0; ip saddr 127.0.0.1 accept # handle 10 } }
# nft delete rule inet fltrTable input handle 10
可以用nft flush table
命令清空表中的所有的链。可以用nft flush chain
或者nft delete rule
命令清空单个链。
# nft flush table foo # nft flush chain foo bar # nft delete rule ip6 foo bar
第一个命令清空foo
表中的所有链。第二个命令清空ip foo
表中的bar
链。第三个命令删除ip6 foo
表bar
两种的所有规则。
自动重载
清空当前规则集:
# echo "flush ruleset" > /tmp/nftables
导出当前规则集:
# nft list ruleset >> /tmp/nftables
可以直接修改/tmp/nftables文件,使更改生效则运行:
# nft -f /tmp/nftables
配置示例
工作站
/etc/nftables.conf
flush ruleset table inet filter { chain input { type filter hook input priority 0; # accept any localhost traffic iif lo accept # accept traffic originated from us ct state established,related accept # accept ICMP & IGMP ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept ip protocol igmp accept # activate the following line to accept common local services #tcp dport { 22, 80, 443 } ct state new accept # count and drop any other traffic counter drop } }
简单的IPv4/IPv6防火墙
firewall.rules
# A simple firewall flush ruleset table inet filter { chain input { type filter hook input priority 0; policy drop; # established/related connections ct state established,related accept # invalid connections ct state invalid drop # loopback interface iif lo accept # ICMP & IGMP ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept ip protocol igmp accept # SSH (port 22) tcp dport ssh accept # HTTP (ports 80 & 443) tcp dport { http, https } accept } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } }
IPv4/IPv6防火墙限流
firewall.2.rules
table inet filter { chain input { type filter hook input priority 0; policy drop; ct state invalid drop iif lo accept # no ping floods: ip protocol icmp icmp type echo-request limit rate over 10/second burst 4 packets drop ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 10/second burst 4 packets drop ct state established,related accept # ICMP & IGMP ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept ip protocol igmp accept # avoid brute force on ssh: tcp dport ssh ct state new limit rate 15/minute accept } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } }
跳转
在配置文件中使用跳转时,必须确保已经定义目标链。否则会引起错误Error: Could not process rule: No such file or directory
。
jump.rules
table inet filter { chain web { tcp dport http accept tcp dport 8080 accept } chain input { type filter hook input priority 0; ip saddr 10.0.2.0/24 jump web drop } }
不同接口采用不同规则
如果设备有多个网络接口,并且需要对不同接口采用不同的规则,则可能需要使用“调度”筛选链,然后使用特定接口筛选链。例如,假设设备用作家庭路由器,你需要在LAN(接口enp3s0)运行一个web服务器,但不用于internet(接口enp2s0),可以考虑以下的结构:
table inet filter { chain input { # this chain serves as a dispatcher type filter hook input priority 0; iif lo accept # always accept loopback iifname enp2s0 jump input_enp2s0 iifname enp3s0 jump input_enp3s0 reject with icmp type port-unreachable # refuse traffic from all other interfaces } chain input_enp2s0 { # rules applicable to public interface interface ct state {established,related} accept ct state invalid drop udp dport bootpc accept tcp dport bootpc accept reject with icmp type port-unreachable # all other traffic } chain input_enp3s0 { ct state {established,related} accept ct state invalid drop udp dport bootpc accept tcp dport bootpc accept tcp port http accept tcp port https accept reject with icmp type port-unreachable # all other traffic } chain ouput { # we let everything out type filter hook output priority 0; accept } }
或者,可以只选择一个iifname
语句,如单个上游接口,并将其他接口的默认规则放在一起,而不是为每个接口进行调度。
Masquerading
nftables有一个特殊的关键字masquerade
"where the source address is automagically set to the address of the output interface(源地址自动设置为出口地址)" ([http://wiki.nftables.org/wiki-ip地址改变时更新规则。[失效链接 2020-08-04 ⓘ]
使用方法:
- 确保在内核中启用Masquerading(默认内核已启用),否则在内核配置过程中设置
CONFIG_NFT_MASQ=m
-
masquerade
关键字只能用于nat
类型的链,而nat
链又不能在inet
簇的表中。要用ip
和/或ip6
簇的表。 - masquerading是一中源NAT,只能工作于输出路径。
具有两个接口的计算机的示例:LAN连接到nsp3s0
,internet连接到enp2s0
:
table ip nat { chain prerouting { type nat hook prerouting priority 0; } chain postrouting { type nat hook postrouting priority 100; oifname "enp0s2" masquerade } }
提示和技巧
简单可用的防火墙
详细信息参见 Simple stateful firewall 。
单一计算机
清空当前规则集:
# nft flush ruleset
添加一个表:
# nft add table inet filter
添加input、forward和output三个基本链。input和forward的默认策略是drop。output的默认策略是accept。
# nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; } # nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; } # nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
添加两个与TCP和UDP关联的常规链:
# nft add chain inet filter TCP # nft add chain inet filter UDP
related和established的流量会accept:
# nft add rule inet filter input ct state related,established accept
loopback接口的流量会accept:
# nft add rule inet filter input iif lo accept
无效的流量会drop:
# nft add rule inet filter input ct state invalid drop
新的echo请求(ping)会accept:
# nft add rule inet filter input ip protocol icmp icmp type echo-request ct state new accept
新的UDP流量跳转到UDP链:
# nft add rule inet filter input ip protocol udp ct state new jump UDP
新的TCP流量跳转到TCP链:
# nft add rule inet filter input ip protocol tcp tcp flags \& \(fin\|syn\|rst\|ack\) == syn ct state new jump TCP
未由其他规则处理的所有通信会reject:
# nft add rule inet filter input ip protocol udp reject # nft add rule inet filter input ip protocol tcp reject with tcp reset # nft add rule inet filter input counter reject with icmp type prot-unreachable
此时,应决定对传入连接打开哪些端口,这些由TCP和UDP链处理。例如,要打开web服务器的连接端口,添加:
# nft add rule inet filter TCP tcp dport 80 accept
要打开web服务器HTTPS连接端口443:
# nft add rule inet filter TCP tcp dport 443 accept
允许SSH连接端口22:
# nft add rule inet filter TCP tcp dport 22 accept
允许传入DNS请求:
# nft add rule inet filter TCP tcp dport 53 accept # nft add rule inet filter UDP udp dport 53 accept
确保更改是永久的。
防止暴力攻击
Sshguard是可以检测暴力攻击的程序,并根据临时黑名单IP地址修改防火墙。有关如何与nftables一起使用的问题,请参阅Sshguard#nftables。