CentOS 8 has been released and you still can’t use nftables?

If you didn’t live in the last century and are working in cloud computing or related fields, you may have heard that CentOS 8 has recently been officially released. CentOS is fully compliant with Red Hat’s redistribution policy and is committed to being fully functional compatible with upstream products. CentOS 8 is the same as RedHat Enterprise Linux 8. It is based on Fedora 28 and kernel 4.18. The major network change is that the NFtables framework replaces the Iptables framework as the default network packet filtering tool. ** If you haven’t heard of nftables, now is the time to learn about it.

Nftables is a NetFilter project designed to replace the existing {IP, IP6, ARP, EB}tables framework by providing {IP, IP6}tables with a new packet filtering framework,a new user-space utility (NFT), and a compatibility layer. It uses existing hooks, link tracking systems, user-space queuing components, and the NetFilter logging subsystem.

Nftables consists of three main components: kernel implementation, LibnL NetLink communication, and nfTables user space. The kernel provides a NetLink configuration interface and run-time rule set evaluation, libnL contains basic functions to communicate with the kernel, and the user space can interact with the user through NFT.

This article mainly introduces the use of the user space command line tool NFT.

1. nftables VS iptables

Nftables, like iptables, consists of tables, chains, and rules. Tables contain chains, chains contain rules, and rules are real actions. Compared to iptables, nftables has the following major changes:

  • iptablesThe layout of rules is based on contiguous chunks of memory, that is, array layout; whilenftablesThe rules use a chain layout. It’s the difference between an array and a linked list, as if Kubernetes users should be excited about this, right?
  • iptablesMost of the work is done in kernel mode, so if you want to add new features, you have to recompile the kernel. whilenftablesMost of the work is done in user mode, and it’s easy to add new features without changing the kernel.
  • iptablesThere are built-in links, even if you only need one, the others will follow; whilenftablesThere is no built-in chain, you can register on demand. Due to theiptablesA packet counter is built in, so even if these built-in chains are empty, there is a performance penalty.
  • To simplify theIPv4/IPv6Double stack management
  • Native support for collections, dictionaries, and maps

Going back to nftables, let’s see what the default rule set is:

$ nft list ruleset
Copy the code

There is no built-in link (if you turn off firewalld service).

2. Create the tables

Each table of NFTables has only one address cluster and applies only to packets from that cluster. A table can specify one of five clusters:

Nftables cluster Iptables command line tool
ip iptables
ip6 ip6tables
inet The iptables and ip6tables
arp arptables
bridge ebtables

Inet applies to both IPv4 and IPv6 packets. That is, IP and IP6 clusters are unified, making it easier to define rules. The inet cluster is used in the following examples.

Create a new table:

$ nft add table inet my_table
Copy the code

List all the rules:

$ nft list ruleset
table inet my_table {
}
Copy the code

Now that there are no rules in the table, you need to create a chain to hold the rules.

3. Create a chain

Chains are used to hold rules, and like tables, chains need to be created explicitly because NFTables does not have a built-in chain. There are two types of chains:

  • Regular chains: You do not need to specify hook types and priorities, but can be used to jump and logically classify rules.
  • Base chain: The entry point of the packet, which needs to specify hook type and priority.

Create a regular chain:

$ nft add chain inet my_table my_utility_chain
Copy the code

Create a basic chain:

$ nft add chain inet my_table my_filter_chain { type filter hook input priority 0 \; }
Copy the code
  • The backslash (\) to escape so that the shell does not interpret the semicolon as the end of a command.
  • priorityInteger values, which can be negative, are used. Chains with smaller values are treated 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 {typefilter hook input priority 0; policy accept; }}Copy the code

4. Create rules

Once you have tables and chains, you can create rules, which consist of statements or expressions, contained in chains. Add a rule to allow SSH login:

$ nft add rule inet my_table my_filter_chain tcp dport ssh accept
Copy the code

Add means to add the rule to the end of the chain, and if you want to add the rule to the beginning of the chain, use INSERT.

$ nft insert rule inet my_table my_filter_chain tcp dport http accept
Copy the code

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
        }
}
Copy the code

Note that the HTTP rule comes ahead of the SSH rule because of the previous use of INSERT.

Rules can also be inserted at the specified location in the chain in 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 index value 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 {
             typefilter 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
     }
}
Copy the code

Index is similar to the -i option of Iptables, with two caveats: the index value starts at 0; Index must point to an existing rule, such as NFT insert rule… Index 0 is illegal.

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 with the –handle argument.

$ 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}}Copy the code

In NFTables, the handle value is fixed until the rule is deleted, which provides a stable index for the rule. The index value is mutable and can change whenever a new rule is inserted. It is generally recommended to use Handle to insert new rules.

You can also get the rule handle value when you create the rule by adding –echo and –handle at the same time.

$ 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
Copy the code

5. Delete the rule

A single rule can only be deleted by 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}}Copy the code

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}}Copy the code

6. List the rules

The previous examples listed all the rules, but we can also list some of the rules based on our own requirements. Such as:

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
        }
}
Copy the code

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"}}Copy the code

Collection of 7.

Nftables’ syntactically native support set can be used to match multiple IP addresses, port numbers, network cards, or any other criteria.

Anonymous collection

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 rules allow traffic from hosts whose source IP addresses range from 10.10.10.123 to 10.10.10.231.

$NFT add rule inet my_table my_filter_chain IP saddr {10.10.10.123, Accept $NFT list ruleset table inet my_table {chain my_filter_chain {typefilter hook input priority 0; policy accept; SSH Accept IP saddr {10.10.10.123, 10.10.10.231} Accept}}Copy the code

The disadvantage of anonymous collections is that if you need to modify the collection, you have to replace the rules. A named collection is recommended if you need to modify the collection frequently later.

The rules added in the previous example can also be simplified by collections:

$ nft add rule inet my_table my_filter_chain tcp dport { http, nfs, ssh } accept
Copy the code

Iptables can use collections with the help of ipsets, whereas NFTables natively supports collections, so you don’t need ipsets.

Named collections

Nftables also supports named collections, which can be modified. To create a collection, you need to specify the type of its elements. Currently, the data types supported are:

  • ipv4_addr: the IPv4 address
  • ipv6_addr: IPv6 address
  • ether_addr: Ethernet address
  • inet_proto: Network protocol
  • inet_service: Network service
  • mark: Tag type

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
        }
}
Copy the code

To reference the collection when adding rules, use the @ symbol to follow the name of the collection. The following rule adds IP addresses from the collection 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 {
                typefilter 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}}Copy the code

Add an element to a collection:

$NFT add element inet my_table my_set {10.10.10.22, 10.10.10.33} $NFT listset inet my_table my_set
table inet my_table {
        set my_set {
                typeIpv4_addr Elements = {10.10.10.22, 10.10.10.33}}}Copy the code

An error is reported if you add an interval to the collection:

$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} ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^Copy the code

To use an interval in a collection, you need to add a flag interval, because the kernel must confirm in advance what data type the collection stores in order to use the appropriate data structure.

Support interval

Create a named collection that supports an interval:

$ nft add set inet my_table my_range_set { typeipv4_addr \; Flags interval $NFT add element inet my_table my_range_set {10.20.20.0/24} $NFT listset inet my_table my_range_set
table inet my_table {
        set my_range_set {
                typeIpv4_addr Flags Interval Elements = {10.20.20.0/24}}}Copy the code

The subnet mask representation is implicitly translated to the IP address range. You can also use the range 10.20.20.0-10.20.20.255 to get the same effect.

Different types of cascades

Named collections also support cascading of elements of different types, separated by the cascading operator. For example, the following rule can match an IP address, protocol, and port number 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
        }
}
Copy the code

Add an element to a collection:

$NFT add element inet my_table my_concat_set {10.30.30.30.tcp. Telnet}Copy the code

The collection of cascading types referenced in the rule is the same as before, but you need to indicate where each element in the collection corresponds to in the rule.

$ nft add rule inet my_table my_filter_chain ip saddr . meta l4proto . tcp dport @my_concat_set accept
Copy the code

This means that nftables will allow packets to pass if the source IP address, protocol type, and destination port match 10.30.30.30, TCP, or Telnet.

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} AcceptCopy the code

Now you can see the power of the NFTables collection.

Nftables sets of cascading types are similar to aggregation types of IPsets, such as hash: IP,port.

A dictionary 8.

Dictionaries are an advanced feature of NFTables that can take different types of data and map matching criteria to a single rule, and because they are hash mapped, they perfectly avoid the performance overhead of chained rule jumps.

For example, to logically separate the processing rules for TCP and UDP packets, you can use a dictionary so that you can implement the requirements in a single rule.

$ 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 { ... Udp dport {10.30.30.30.udp.bootps} Accept meta l4proto vmap {TCP: jump my_tcp_chain, udp : jump my_udp_chain } } }Copy the code

As with collections, in addition to anonymous dictionaries, you can create named dictionaries:

$ nft add map inet my_table my_vmap { type inet_proto : verdict \; }
Copy the code

Add elements to a dictionary:

$NFT add element inet my_table my_vmap {192.168.0.10: drop, 192.168.0.11: accept}Copy the code

We can then reference elements from the dictionary in our rules:

$ nft add rule inet my_table my_filter_chain ip saddr vmap @my_vmap
Copy the code

9. Tables and namespaces

In NFTables, each table is a separate namespace, which means that chains, collections, dictionaries, and so on in different tables can all have the same name. Such as:

$ 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 {
    }
}
Copy the code

With this feature, different applications can manage the rules in their own tables without affecting each other, something that cannot be done with Iptables.

Since each table is treated as an independent firewall, a packet must be allowed by the rules in all tables. Even if Table_One allows the packet to pass, the packet may still be rejected by Table_two. To solve this problem, nftables introduces priority, where chains with a higher priority value have a lower priority, so chains with a lower priority value are executed before chains with a higher priority value. If two chains have the same priority, they enter a state of contention.

10. Backup and restoration

The rules in all of the above examples are temporary. To make them permanent, you can back them up and load the restore automatically after a restart, which is how the systemd service for NFtables works.

Backup rules:

$ nft list ruleset > /root/nftables.conf
Copy the code

Load recovery:

$ nft -f /root/nftables.conf
Copy the code

In CentOS 8 nftables. Service rules are stored in the/etc/nftables. Conf, which include some other examples of rules, usually in the/etc/sysconfig/nftables conf file, But it’s commented out by default.

11. A summary

Hopefully, this article has given you an idea of what nftables can do and how to use it. Of course, this article has only covered a few superficial uses. For more advanced uses, check out the official nftables wiki or wait for my next article. With this knowledge in hand, you should be happy to implement intelligent shunt for Linux using NFtables, as described in this article: Linux Global Intelligent Shunt Solution.

Wechat official account

Scan the following QR code to follow the wechat public account, in the public account reply ◉ plus group ◉ to join our cloud native communication group, and Sun Hongliang, Zhang Curator, Yang Ming and other leaders to discuss cloud native technology