If you have not lived in the last century and are a brick mover in cloud computing or related fields, then you should have heard that the official version of CentOS 8 has been released recently, and CentOS fully complies with the reissue of Red Hat Policy, and strive to be fully functionally compatible with upstream products. The main changes of CentOS 8 are the same as RedHat Enterprise Linux 8. It is based on Fedora 28 and kernel version 4.18. The main network change is to use **nftables** framework instead of * *iptables** The framework is used as the default network packet filtering tool. **If you haven't heard of nftables, now is the time to learn.
nftables is a netfilter project, which aims to replace the existing {ip,ip6,arp,eb}tables framework and provide a new packet filtering framework for {ip,ip6}tables and a new user space utility (nft ) And a compatibility layer. It uses existing hooks, link tracking system, user space queuing component and netfilter logging subsystem.
nftables is mainly composed of three components: kernel implementation, libnl netlink communication and nftables user space. The kernel provides a netlink configuration interface and runtime rule set evaluation, libnl contains basic functions for communicating with the kernel, and the user space can interact with users through nft.
This article mainly introduces the usage of user space command line tool nft.
1.
nftables VS iptables
Like iptables, nftables consists of a table, a chain, and a rule. The table contains the chain, the chain contains the rules, and the rule is the real action. Compared with iptables, nftables mainly has the following changes:
The layout of iptables rules is based on continuous large blocks of memory, that is, array layout; while the rules of nftables adopt chain layout. In fact, it is the difference between arrays and linked lists. It seems that Kubernetes users should be very excited about this? Most of the work of iptables is done in the kernel mode. If you want to add new functions, you can only recompile the kernel; while most of the work of nftables is done in the user mode. It is easy to add new functions and does not need to change the kernel. iptables has a built-in chain, even if you only need one chain, the other chains will be registered as well; while there is no built-in chain in nftables, you can register on demand. Since iptables has a built-in packet counter, even if these built-in chains are empty, it will cause performance loss.IPv4/IPv6 dual stack managementBack to nftables, let's take a look at the default rule set:
$ nft list ruleset
Nothing, there really is no built-in chain (if you turn off the firewalld service).
2.
Create table
Each table of nftables has only one address cluster, and it is only applicable to data packets of that cluster. The table can specify one of five clusters:
| nftables cluster | iptables command line tool |
|---|---|
| ip | iptables |
| ip6 | ip6tables |
| inet | iptables and ip6tables |
| arp | arptables |
| bridge | ebtables |
inet is applicable to both IPv4 and IPv6 packets, that is, the ip and ip6 clusters are unified, which makes it easier to define rules. The following examples will all use inet clusters.
First create a new table:
$ nft add table inet my_table
List all the rules:
$ nft list ruleset
table inet my_table {}
Now there are no rules in the table. You need to create a chain to save the rules.
3.
Create chain
Chains are used to store rules. Like tables, chains need to be created explicitly because nftables has no built-in chain. There are two types of chains:
Create a regular chain:
$ nft add chain inet my_table my_utility_chain
Create a basic chain:
$ nft add chain inet my_table my_filter_chain { type filter hook input priority 0 \;}
\) is used to escape, so the shell does not interpret the semicolon as the end of the command. priority uses an integer value, which can be a negative number, and the chain with a smaller value is processed first.List all the rules in the chain:
$ nft list chain inet my_table my_utility_chain
table inet my_table {
chain my_utility_chain {}}
$ nft list chain inet my_table my_filter_chain
table inet my_table {
chain my_filter_chain {
type filter hook input priority 0; policy accept;}}
4.
Create rule
Once you have the table and chain, you can create rules, which are composed of statements or expressions and are included in the chain. Add a rule below to allow SSH login:
$ nft add rule inet my_table my_filter_chain tcp dport ssh accept
add means to add the rule to the end of the chain. If you want to add the rule to the beginning of the chain, you can use insert.
$ nft insert rule inet my_table my_filter_chain tcp dport http accept
List all rules:
$ nft list ruleset
table inet my_table {
chain my_filter_chain {
type filter hook input priority 0; policy accept;
tcp dport http accept
tcp dport ssh accept
}}
Note that http rules come before ssh rules because insert was used before.
You can also insert the rule into the specified position of the chain, there are two ways:
1、 Use index to specify the index of the rule. add means that the new rule is added after the rule at the index position, and inser means that the new rule is added before the rule at the index position. The value of index increases from 0.
$ nft insert rule inet my_table my_filter_chain index 1 tcp dport nfs accept
$ nft list ruleset
table inet my_table {
chain my_filter_chain {
type filter hook input priority 0; policy accept;
tcp dport http accept
tcp dport nfs accept
tcp dport ssh accept
}}
$ nft add rule inet my_table my_filter_chain index 0 tcp dport 1234 accept
$ nft list ruleset
table inet my_table {
chain my_filter_chain {
type filter hook input priority 0; policy accept;
tcp dport http accept
tcp dport 1234 accept
tcp dport nfs accept
tcp dport ssh accept
}}
index is similar to the -I option of iptables, but there are two points to note: one is that the value of index starts from 0; the other is that index must point to an existing rule, such as nft insert rule… index 0 Unlawful.
2、 Use handle to specify the handle of the rule. add means that the new rule is added after the rule at the index position, and inser means that the new rule is added before the rule at the index position. The value of handle can be obtained by parameter --handle.
$ nft --handle list ruleset
table inet my_table { # handle 10
chain my_filter_chain { # handle 2
type filter hook input priority 0; policy accept;
tcp dport http accept # handle 4
tcp dport 1234 accept # handle 6
tcp dport nfs accept # handle 5
tcp dport ssh accept # handle 3}}
$ nft add rule inet my_table my_filter_chain handle 4 tcp dport 1234 accept
$ nft insert rule inet my_table my_filter_chain handle 5 tcp dport nfs accept
$ nft --handle list ruleset
table inet my_table { # handle 10
chain my_filter_chain { # handle 2
type filter hook input priority 0; policy accept;
tcp dport http accept # handle 4
tcp dport 2345 accept # handle 8
tcp dport 1234 accept # handle 6
tcp dport 3456 accept # handle 9
tcp dport nfs accept # handle 5
tcp dport ssh accept # handle 3}}
In nftables, the handle value is fixed, unless the rule is deleted, which provides a stable index for the rule. The value of index is variable, as long as there are new rules inserted, it may change. It is generally recommended to use handle to insert new rules.
You can also get the handle value of the rule when you create the rule. You only need to add the parameters --echo and --handle at the same time when creating the rule.
$ nft --echo --handle add rule inet my_table my_filter_chain udp dport 3333 accept
add rule inet my_table my_filter_chain udp dport 3333 accept # handle 10
5.
Delete rule
A single rule can only be deleted through its handle. First, you need to find the rule handle you want to delete:
$ nft --handle list ruleset
table inet my_table { # handle 10
chain my_filter_chain { # handle 2
type filter hook input priority 0; policy accept;
tcp dport http accept # handle 4
tcp dport 2345 accept # handle 8
tcp dport 1234 accept # handle 6
tcp dport 3456 accept # handle 9
tcp dport nfs accept # handle 5
tcp dport ssh accept # handle 3
udp dport 3333 accept # handle 10}}
Then use the handle value to delete the rule:
$ nft delete rule inet my_table my_filter_chain handle 8
$ nft --handle list ruleset
table inet my_table { # handle 10
chain my_filter_chain { # handle 2
type filter hook input priority 0; policy accept;
tcp dport http accept # handle 4
tcp dport 1234 accept # handle 6
tcp dport 3456 accept # handle 9
tcp dport nfs accept # handle 5
tcp dport ssh accept # handle 3
udp dport 3333 accept # handle 10}}
6.
List rules
The previous examples list all the rules, and we can also list part of the rules according to our needs. E.g:
List all rules in a table:
$ nft list table inet my_table
table inet my_table {
chain my_filter_chain {
type filter hook input priority 0; policy accept;
tcp dport http accept
tcp dport 1234 accept
tcp dport 3456 accept
tcp dport nfs accept
tcp dport ssh accept
udp dport 3333 accept
}}
List all the rules in a chain:
$ nft list chain inet my_table my_other_chain
table inet my_table {
chain my_other_chain {
udp dport 12345 log prefix "UDP-12345"}}
7.
set
The syntax of nftables natively supports collections, which can be used to match multiple IP addresses, port numbers, network cards or any other conditions.
Collections are divided into anonymous collections and named collections. Anonymous collections are more suitable for rules that do not need to be changed in the future.
For example, the following rule allows traffic from hosts whose source IP is in the range of 10.10.10.123 ~ 10.10.10.231.
$ nft add rule inet my_table my_filter_chain ip saddr {10.10.10.123,10.10.10.231} accept
$ nft list ruleset
table inet my_table {
chain my_filter_chain {
type filter hook input priority 0; policy accept;
tcp dport http accept
tcp dport nfs accept
tcp dport ssh accept
ip saddr {10.10.10.123,10.10.10.231} accept
}}
The disadvantage of anonymous collections is that if you need to modify the collection, you have to replace the rules. If you need to modify the collection frequently later, it is recommended to use a named collection.
The rules added in the previous example can also be simplified by sets:
$ nft add rule inet my_table my_filter_chain tcp dport { http, nfs, ssh } accept
iptables can use
ipsetto use collections, and nftables natively supports collections, so there is no need to resort toipset.
nftables also supports named collections, and named collections can be modified. To create a collection, you need to specify the type of its elements. The currently supported data types are:
ipv4_addr: IPv4 address ipv6_addr: IPv6 address ether_addr: Ethernet address inet_proto: network protocol inet_service: network service mark: mark typeFirst create an empty named collection:
$ nft add set inet my_table my_set { type ipv4_addr \;}
$ nft list sets
table inet my_table {set my_set {
type ipv4_addr
}}
To refer to the collection when adding rules, you can use the @ symbol to keep up with the name of the collection. The following rule means adding the IP addresses in the set my_set to the blacklist.
$ nft insert rule inet my_table my_filter_chain ip saddr @my_set drop
$ nft list chain inet my_table my_filter_chain
table inet my_table {
chain my_filter_chain {
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
}}
Add elements to the collection:
$ nft add element inet my_table my_set {10.10.10.22,10.10.10.33}
$ nft list set inet my_table my_set
table inet my_table {set my_set {
type ipv4_addr
elements ={10.10.10.22,10.10.10.33}}}
If you add an interval to the collection, an error will be reported:
$ nft add element inet my_table my_set {10.20.20.0-10.20.20.255}
Error: Set member cannot be range, missing interval flag on declaration
add element inet my_table my_set {10.20.20.0-10.20.20.255}^^^^^^^^^^^^^^^^^^^^^^^
If you want to use the interval in the collection, you need to add a flag interval, because the kernel must confirm the type of data stored in the collection in advance in order to adopt the appropriate data structure.
Create a named collection of support intervals:
$ nft add set inet my_table my_range_set { type ipv4_addr \; flags interval
$ nft add element inet my_table my_range_set {10.20.20.0/24}
$ nft list set inet my_table my_range_set
table inet my_table {set my_range_set {
type ipv4_addr
flags interval
elements ={10.20.20.0/24}}}
The subnet mask notation will be implicitly converted to the range of the IP address. You can also directly use the range
10.20.20.0-10.20.20.255to get the same effect.
Named collections also support the cascade of different types of elements, separated by the cascade operator .. For example, the following rules can match IP addresses, protocols, and port numbers all at once.
$ nft add set inet my_table my_concat_set { type ipv4_addr . inet_proto . inet_service \;}
$ nft list set inet my_table my_concat_set
table inet my_table {set my_concat_set {
type ipv4_addr . inet_proto . inet_service
}}
Add elements to the collection:
$ nft add element inet my_table my_concat_set {10.30.30.30. tcp . telnet }
The set of cascading types referenced in the rule is the same as before, but it is necessary to indicate which position in the rule each element in the set corresponds to.
$ nft add rule inet my_table my_filter_chain ip saddr . meta l4proto . tcp dport @my_concat_set accept
This means that if the source IP, protocol type, and destination port of the packet match 10.30.30.30, tcp, telnet, nftables will allow the packet to pass.
Anonymous collections can also use cascading elements, for example:
$ nft add rule inet my_table my_filter_chain ip saddr . meta l4proto . udp dport {10.30.30.30. udp . bootps } accept
Now you should be able to appreciate the power of the nftables collection.
The collection of nftables cascade types is similar to the aggregation type of ipset, such as
hash:ip,port.
8.
dictionary
Dictionary is an advanced feature of nftables. It can use different types of data and map matching conditions to a certain rule, and because it is a hash mapping method, it can perfectly avoid the performance overhead of chain rule jumps.
For example, in order to logically separate the processing rules for TCP and UDP data packets, a dictionary can be used to achieve the above requirements.
$ nft add chain inet my_table my_tcp_chain
$ nft add chain inet my_table my_udp_chain
$ nft add rule inet my_table my_filter_chain meta l4proto vmap { tcp : jump my_tcp_chain, udp : jump my_udp_chain }
$ nft list chain inet my_table my_filter_chain
table inet my_table {
chain my_filter_chain {...
meta nfproto ipv4 ip saddr . meta l4proto . udp dport {10.30.30.30. udp . bootps } accept
meta l4proto vmap { tcp : jump my_tcp_chain, udp : jump my_udp_chain }}}
Like collections, in addition to anonymous dictionaries, you can also create named dictionaries:
$ nft add map inet my_table my_vmap { type inet_proto : verdict \;}
Add elements to the dictionary:
$ nft add element inet my_table my_vmap {192.168.0.10: drop,192.168.0.11: accept }
The elements in the dictionary can be referenced in the rules later:
$ nft add rule inet my_table my_filter_chain ip saddr vmap @my_vmap
9.
Tables and namespaces
In nftables, each table is an independent namespace, which means that chains, sets, dictionaries, etc. in different tables can all have the same name. E.g:
$ nft add table inet table_one
$ nft add chain inet table_one my_chain
$ nft add table inet table_two
$ nft add chain inet table_two my_chain
$ nft list ruleset
...
table inet table_one {
chain my_chain {}}
table inet table_two {
chain my_chain {}}
With this feature, different applications can manage the rules in their own tables without affecting each other, which cannot be achieved with iptables.
Of course, this feature is also flawed. Since each table is regarded as an independent firewall, a certain data packet must be released by the rules in all tables before it is truly released. Even if the table_one allows the data packet to pass, the Data packets may still be rejected by table_two. To solve this problem, nftables introduces priority. The higher the value of priority, the lower the priority, so the chain with the lower value of priority will be executed before the chain with the higher value of priority. If the two chains have the same priority, they will enter a competitive state.
10.
Backup and restore
The rules in all the above examples are temporary. To take effect permanently, we can back up the rules and automatically load and restore them after restarting. In fact, the systemd service of nftables works like this.
Backup rules:
$ nft list ruleset >/root/nftables.conf
Load recovery:
$ nft -f /root/nftables.conf
In CentOS 8, the rules of nftables.service are stored in /etc/nftables.conf, which includes some other example rules, generally located in the file /etc/sysconfig/nftables.conf, but by default Will be commented out.
11.
to sum up
I hope that through the explanation of this article, you can understand the function and usage of nftables. Of course, this article only involves some simple usage. For more advanced usage, please check the official wiki of nftables, or wait for my next article. I believe that with the knowledge of this article, you should be able to happily use nftables to implement Linux intelligent distribution. For details, scan the QR code below and refer to this article: Linux Global Intelligent Distribution Scheme.
Recommended Posts