Lework Study hard, improve every day.

nftables简介

2020-02-05
lework
本文 11246 字,阅读全文约需 33 分钟

介绍

nftables 是一个netfilter项目,旨在替换现有的{ip,ip6,arp,eb}tables框架,为{ip,ip6}tables提供一个新的包过滤框架、一个新的用户空间实用程序(nft)和一个兼容层。它使用现有的钩子、链接跟踪系统、用户空间排队组件和netfilter日志子系统。

它由三个主要组件组成:内核实现、libnl netlink通信和nftables用户空间前端。 内核提供了一个netlink配置接口以及运行时规则集评估,libnl包含了与内核通信的基本函数,nftables前端是用户通过nft交互。

iptables的不足

iptables框架有一些局限性,无法轻松解决:

  • 避免代码重复和不一致:许多iptables扩展都是特定于协议的,因此没有统一的方式来匹配数据包字段,而是为它支持的每种协议都有一个扩展。这使代码库中的代码非常相似,可以执行类似的任务:有效负载匹配。

  • 通过增强的通用集和映射基础结构,可以更快地进行数据包分类。

  • 通过新的inet系列简化的双堆栈IPv4 / IPv6管理,使您可以注册可查看IPv4和IPv6流量的基链。

  • 更好的动态规则集更新支持。

  • 就像其他Linux网络和Netfilter子系统一样,为第三方应用程序提供Netlink API。

  • 解决语法不一致的问题,并提供更好,更紧凑的语法。

与iptables 不同点

  • nftables 在用户空间中运行,iptables 中的每个模块都运行在内核(空间)

从用户的角度来看,nftableiptables之间的主要区别是:

  • 语法iptables的命令行工具使用getopt_long() -基于解析器其中密钥总是由双减去,例如之前。–key或一个减号,例如 -p tcp。在这方面,nftables使用了更好的,更直观的和更紧凑的语法,该语法受tcpdump的启发。

  • 表和链是完全可配置的。在nftable中,表是没有特定语义的链的容器。请注意,iptables附带了具有预定义数量的基链的表,您可以通过全有或全无的方式获得它们。因此,即使您只需要其中之一,所有链都已注册。过去我们得到的报告是,即使您根本不添加任何规则,未使用的基础链也会损害性能。使用这种新方法,您可以根据设置注册所需的链。此外,您还可以按照需要使用链优先级为管道建模,并为表和链选择任何名称。

  • 不再区分匹配和目标。在nftables表达式是规则的基本构建块,因此,规则基本上是从左到右线性求值的表达式的组合:如果第一个表达式匹配,则对下一个表达式求值,依此类推,直到达到规则的最后一个表达式。表达式可以匹配某些特定的有效负载字段,数据包/流元数据和任何操作。

  • 可以在一个规则中指定多个操作。在iptables中,您只能指定一个目标。这是一个长期存在的局限性,用户可以通过跳到自定义链来解决,但代价是使规则集结构稍微复杂一些。

  • 每个链和规则没有内置计数器。在nftable中,这些是可选的,因此您可以按需启用计数器。

  • 更好地支持动态规则集更新。在nftables中,如果添加新规则,则剩余的现有规则将保持不变,因为规则集以链表形式表示,这与整体式blob表示相反,后者在执行规则集更新时内部状态信息的维护很复杂。

  • 简化的双堆栈IPv4 / IPv6管理,通过新的inet系列,可让您注册同时查看IPv4和IPv6流量的基链。 因此,您不再需要依赖脚本来复制规则集。

  • 通用集和映射基础结构。这个新的基础设施紧密地集成到nftables核心中,它允许高级配置,如字典、映射和间隔,以实现面向性能的包分类。最重要的是,您可以使用任何受支持的选择器来对流量进行分类。

  • 支持串连。从Linux内核4.1开始,您可以连接几个键并将它们与字典和映射结合起来。其思想是构建一个元组,对其值进行散列处理,以获得将在O(1)附近执行的操作。

  • 无需内核升级的新受支持协议。内核升级可能是一项耗时且艰巨的任务。特别是如果您必须在网络中维护多个防火墙。出于稳定性方面的考虑,发行商通常包括一些较旧的Linux内核版本。使用新的nftables虚拟机方法,您很可能不需要进行此类升级即可支持新协议。相对简单的nft用户空间软件更新应足以支持新协议。

安装

# debian
apt-get install nftables
apt-get purge iptables

用法

nftables区分命令行输入的临时规则和从文件加载或保存到文件的永久规则。 默认配置文件是/etc/nftables.conf,其中已经包含一个名为”inet filter”的简单ipv4/ipv6防火墙列表。

运行服务

systemctl enable nftables
systemctl start nftables

也就是重新加载下/etc/nftables.conf里的规则

检查规则集

# nft list ruleset

nftables相关模块

确保nftables的模块被加载,服务才能正常运行

# lsmod | grep '^nf'
nf_nat_masquerade_ipv4    13412  1 ipt_MASQUERADE
nf_conntrack_netlink    40449  0 
nfnetlink              14696  2 nf_conntrack_netlink
nf_conntrack_ipv4      15053  4 
nf_defrag_ipv4         12729  1 nf_conntrack_ipv4
nf_nat_ipv4            14115  1 iptable_nat
nf_nat                 26787  3 nf_nat_ipv4,xt_nat,nf_nat_masquerade_ipv4
nf_conntrack          133387  6 nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ipv4

配置

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

注意,任何已加载的规则不会自动清空。

表(Tables)

表包含#链。与iptables中的表不同,nftables中没有内置表。表的数量和名称由用户决定。但是,每个表只有一个地址簇,并且只适用于该簇的数据包。表可以指定五个簇中的一个:

nftables簇 iptables实用程序
ip iptables
ip6 ip6tables
inet iptables和ip6tables
arp arptables
bridge ebtables

ip(即IPv4)是默认簇,如果未指定簇,则使用该簇。

要创建同时适用于IPv4和IPv6的规则,请使用inetinet允许统一ipip6簇,以便更容易地定义规则。

注意: inet不能用于nat类型的链,只能用于filter类型的链。(source

有关地址簇的完整描述,请参见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可以是filterroute或者nat

IPv4/IPv6/Inet地址簇中,hook可以是preroutinginputforwardoutput或者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

例如,要列出inetfilter表的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)

规则由语句或表达式构成,包含在链中。

添加规则

提示: iptables-translate实用程序何以将iptables规则转换成nftables格式。

将一条规则添加到链中:

# nft add rule family table chain handle handle statement

规则添加到handle处,这是可选的。如果不指定,则规则添加到链的末尾。

将规则插入到指定位置:

# nft insert rule family table chain handle handle statement

如果未指定handle,则规则插入到链的开头。

表达式

通常情况下,statement包含一些要匹配的表达式,然后是判断语句。结论语句包括acceptdropqueuecontinuereturnjump chaingoto 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不使用/etc/services文件匹配端口号和名称,而是使用内置列表。要在命令行显示端口映射,请使用 nft describe tcp dport

删除

单个规则只能通过其句柄删除。使用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 foobar两种的所有规则。

自动重载

清空当前规则集:

# echo "flush ruleset" > /tmp/nftables 

导出当前规则集:

# nft list ruleset >> /tmp/nftables

可以直接修改/tmp/nftables文件,使更改生效则运行:

# nft -f /tmp/nftables

简单可用的防火墙

详细信息参见 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

确保更改是永久的。

~# nft list ruleset > /etc/nftables.conf

检查规则集

~# nft list ruleset
table inet filter {
	chain forward {
		type filter hook forward priority 0; policy drop;
	}

	chain TCP {
		tcp dport http accept
		tcp dport https accept
		tcp dport ssh accept
		tcp dport domain accept
	}

	chain UDP {
		udp dport domain accept
	}

	chain output {
		type filter hook output priority 0; policy accept;
	}

	chain input {
		type filter hook input priority 0; policy drop;
		ct state established,related accept
		iif "lo" accept
		ct state invalid drop
		ip protocol icmp icmp type echo-request ct state new accept
		ip protocol udp ct state new jump UDP
		ip protocol tcp tcp flags & (fin | syn | rst | ack) == syn ct state new jump TCP
		ip protocol udp reject
		ip protocol tcp reject with tcp reset
		meta nfproto ipv4 counter packets 0 bytes 0 reject with icmp type prot-unreachable
	}
}

从iptables迁移到nftables

翻译单个规则

~# iptables-translate -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
nft add rule ip filter INPUT tcp dport 22 ct state new counter accept

~# ip6tables-translate -A FORWARD -i eth0 -o eth3 -p udp -m multiport --dports 111,222 -j ACCEPT
nft add rule ip6 filter FORWARD iifname "eth0" oifname "eth3" meta l4proto udp udp dport { 111,222} counter accept

翻译规则集

~# iptables-save > iptables_save.txt
~# cat iptables_save.txt 
# Generated by xtables-save v1.8.2 on Wed Feb  5 12:05:26 2020
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
COMMIT
# Completed on Wed Feb  5 12:05:26 2020

~# iptables-restore-translate -f iptables_save.txt
# Translated by iptables-restore-translate v1.8.2 on Wed Feb  5 12:05:38 2020
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; policy accept; }
add chain ip filter FORWARD { type filter hook forward priority 0; policy accept; }
add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }
add rule ip filter INPUT tcp dport 22 ct state new counter accept
# Completed on Wed Feb  5 12:05:38 2020

应用规则

~# iptables-restore-translate -f iptables_save.txt > ruleset.nft
~# nft -f ruleset.nft
~# nft list ruleset
table ip filter {
	chain INPUT {
		type filter hook input priority 0; policy accept;
		meta l4proto tcp tcp dport 22 ct state new counter packets 0 bytes 0 accept
		tcp dport ssh ct state new counter packets 0 bytes 0 accept
	}

	chain FORWARD {
		type filter hook forward priority 0; policy accept;
	}

	chain OUTPUT {
		type filter hook output priority 0; policy accept;
	}
}

使用nf_tables compat后端

~# iptables-nft -A FORWARD -p icmp -j ACCEPT
~# iptables-nft-save
# Generated by xtables-save v1.8.2 on Wed Feb  5 12:12:04 2020
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A FORWARD -p icmp -j ACCEPT
COMMIT
# Completed on Wed Feb  5 12:12:04 2020
~# nft list ruleset
table ip filter {
	chain INPUT {
		type filter hook input priority 0; policy accept;
	}

	chain FORWARD {
		type filter hook forward priority 0; policy accept;
		meta l4proto icmp counter packets 0 bytes 0 accept
	}

	chain OUTPUT {
		type filter hook output priority 0; policy accept;
	}
}

使用iptables-nft加载iptable的规则集

~# iptables-save  > iptables.txt
~# iptables-nft-restore < iptables.txt

~# iptables-nft-save 
# Generated by xtables-save v1.8.2 on Wed Feb  5 12:14:45 2020
*filter
:INPUT ACCEPT [6:364]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [4:352]
-A FORWARD -p icmp -j ACCEPT
COMMIT
# Completed on Wed Feb  5 12:14:45 2020


~# nft list ruleset
table ip filter {
	chain INPUT {
		type filter hook input priority 0; policy accept;
	}

	chain FORWARD {
		type filter hook forward priority 0; policy accept;
		meta l4proto icmp counter packets 0 bytes 0 accept
	}

	chain OUTPUT {
		type filter hook output priority 0; policy accept;
	}
}

原文地址 https://lework.github.io/2020/02/05/nftables/

Similar Posts

Comments