Meters: Difference between revisions

From nftables wiki
Jump to navigation Jump to search
m (Sample meter is called ssh-meter (not metering))
 
(22 intermediate revisions by 5 users not shown)
Line 1: Line 1:
== Meters ==
== Dynamic set/map and stateful expressions ==


This feature used to be known as ''flow tables'' before nft v0.8.1.
If you specify the ''dynamic'' flag to your set/map declaration, you can add elements to your set/map from the packet path. You can also attach a ratelimit per byte/packet/connection, counter and quota to such elements.


Since Linux Kernel 4.3 and nft v0.8.1 nftables supports this feature.
Among other things, the combination of dynamic set/map and stateful expressions provide a lot more flexible replacement for the ''hashlimit'' and ''connlimit'' matches in iptables.
 
Meters provide a native replacement for the ''hashlimit'' match in iptables, however, meters are a lot more flexible since you can use any selector, one or many through [[concatenations]].


== Using meters ==
== Using meters ==


The following commands create a table named ''filter'', a chain named ''input'' which hooks incoming traffic and a rule that uses a meter:
The following example shows to how ratelimit inbound TCP connections to port 22 per source IP address:


<source lang="bash">
<source lang="bash">
% nft add table filter
table ip filter {
% nft add chain filter input {type filter hook input priority 0\;}
      set my_ssh_ratelimit {
% nft add rule filter input tcp dport 22 ct state new meter ssh-meter { ip saddr limit rate 10/second } accept
            type ipv4_addr
            timeout 60s
            flags dynamic
      }
 
      chain input {
            type filter hook input priority 0; policy drop;
 
            ct state new tcp dport 22 update @my_ssh_ratelimit { ip saddr limit rate 3/minute } accept
      }
}
</source>
</source>


In this example we create a rule to match ''new''  ''ssh'' (port 22) connections, which uses a meter named ''ssh-meter'' to limit the traffic rate to 10 packets per second for each source IP address. The available time units on limits are: ''second'', ''minute'', ''hour'', ''day'' and ''week''.
For each packet matching this rule, it adds an element to the set whose key is 'ip saddr' and it attaches a ratelimiter to such element. If the element already exists, the ratelimiter is applied and the timeout is refreshed to 60 seconds. After 60 seconds of no use, the element expires and the ratelimiter is released.
 
You can also use [[concatenations]] to ratelimit the inbound connections per IP source address and TCP destination port:


Note that meters must have a name, so you can list its content.
<source lang="bash">
table ip filter {
      set my_ssh_ratelimit {
            type ipv4_addr . inet_service
            timeout 60s
            flags dynamic
      }


You can also use [[concatenations]] to build selectors:
      chain input {
            type filter hook input priority 0; policy drop;


<source lang="bash">
            ct state new update @my_ssh_ratelimit { ip saddr . tcp dport limit rate 3/minute } accept
% nft add rule filter input meter cnt-meter { iif . ip saddr . tcp dport timeout 60s counter }
      }
}
</source>
</source>


This rule counts incoming packets based on the tuple ''(input interface index, IP source address, TCP destination port)'', the counters are dropped after 60 seconds without update.
== Doing connlimit with nft ==
 
== Listing meters ==


To list the content matched by the meter use:
Since 4.18, ''ct count'' allows you to count the number of existing connections based on connection tracking table, you can use it to limit the maximum number of established connections.


<source lang="bash">
<source lang="bash">
% nft list meter filter cnt-meter
table ip filter {
table ip filter {
        set my_connlimit {
meter cnt-meter {
                type ipv4_addr
type iface_index . ipv4_addr . inet_service
                size 65535
flags timeout
                flags dynamic
elements = { "wlan1" . 64.62.190.36 . 55000 expires 38s : counter packets 2 bytes 220, "wlan1" . 83.98.201.47 . 35460 expires 39s : counter packets 10 bytes 5988, "wlan1" . 172.217.7.142 . 43254 expires 46s : counter packets 1 bytes 98}
        }
}
}
        chain output {
                type filter hook output priority filter; policy accept;
                ct state new add @my_connlimit { ip saddr ct count over 20 } counter drop
        }
}
</source>
</source>
For each packet matching this rule, it adds an element to the set whose key is 'ip saddr' and it allows a maximum number of 20 established connections to such IP source address.
'''NOTE:''' This policy does not specifies a timeout to sets intentionally. The connection tracking table timers apply in this case. For the same reason, you cannot use the ''update'' set statement which allows to refresh the timeout of your set element. Therefore, the ''ct count'' statement can only be used with the ''add'' set statement. If you define a timeout to your set and use it with ''ct count'', you will hit an "Operation is not supported" error.


== Doing iptables hashlimit with nft ==
== Doing iptables hashlimit with nft ==


Meters replace iptables hashlimit in nft. You can use the tool '''iptables-translate''' to see how to translate hashlimit rules, currently available in the [https://git.netfilter.org/iptables/ iptables git tree] and expected in the next official release, current release is v1.6.1.
Meters replace iptables hashlimit in nft. From iptables v1.6.2 onward, you can use the tool '''iptables-translate''' to see how to translate hashlimit rules.


Almost all hashlimit options are available in nft, starting with --hashlimit-mode, it is replaced by the selector in a meter. All modes are available except no mode, a meter demands a selector, an iptables rule without hashlimit-mode isn't supported in nft. A simple rule translation is:
Almost all hashlimit options are available in nft, starting with --hashlimit-mode, it is replaced by the selector in a meter. All modes are available except no mode, a meter demands a selector, an iptables rule without hashlimit-mode isn't supported in nft. A simple rule translation is:

Latest revision as of 22:58, 15 August 2023

Dynamic set/map and stateful expressions

If you specify the dynamic flag to your set/map declaration, you can add elements to your set/map from the packet path. You can also attach a ratelimit per byte/packet/connection, counter and quota to such elements.

Among other things, the combination of dynamic set/map and stateful expressions provide a lot more flexible replacement for the hashlimit and connlimit matches in iptables.

Using meters

The following example shows to how ratelimit inbound TCP connections to port 22 per source IP address:

table ip filter {
      set my_ssh_ratelimit {
             type ipv4_addr
             timeout 60s
             flags dynamic
      }

      chain input {
             type filter hook input priority 0; policy drop;

             ct state new tcp dport 22 update @my_ssh_ratelimit { ip saddr limit rate 3/minute } accept
      }
}

For each packet matching this rule, it adds an element to the set whose key is 'ip saddr' and it attaches a ratelimiter to such element. If the element already exists, the ratelimiter is applied and the timeout is refreshed to 60 seconds. After 60 seconds of no use, the element expires and the ratelimiter is released.

You can also use concatenations to ratelimit the inbound connections per IP source address and TCP destination port:

table ip filter {
      set my_ssh_ratelimit {
             type ipv4_addr . inet_service
             timeout 60s
             flags dynamic
      }

      chain input {
             type filter hook input priority 0; policy drop;

             ct state new update @my_ssh_ratelimit { ip saddr . tcp dport limit rate 3/minute } accept
      }
}

Doing connlimit with nft

Since 4.18, ct count allows you to count the number of existing connections based on connection tracking table, you can use it to limit the maximum number of established connections.

 table ip filter {
        set my_connlimit {
                type ipv4_addr
                size 65535
                flags dynamic
        }
 
        chain output {
                type filter hook output priority filter; policy accept;
                ct state new add @my_connlimit { ip saddr ct count over 20 } counter drop
        }
 }

For each packet matching this rule, it adds an element to the set whose key is 'ip saddr' and it allows a maximum number of 20 established connections to such IP source address.

NOTE: This policy does not specifies a timeout to sets intentionally. The connection tracking table timers apply in this case. For the same reason, you cannot use the update set statement which allows to refresh the timeout of your set element. Therefore, the ct count statement can only be used with the add set statement. If you define a timeout to your set and use it with ct count, you will hit an "Operation is not supported" error.

Doing iptables hashlimit with nft

Meters replace iptables hashlimit in nft. From iptables v1.6.2 onward, you can use the tool iptables-translate to see how to translate hashlimit rules.

Almost all hashlimit options are available in nft, starting with --hashlimit-mode, it is replaced by the selector in a meter. All modes are available except no mode, a meter demands a selector, an iptables rule without hashlimit-mode isn't supported in nft. A simple rule translation is:

$ iptables-translate -A INPUT -m tcp -p tcp --dport 80 -m hashlimit --hashlimit-above 200/sec --hashlimit-mode srcip,dstport --hashlimit-name http1 -j DROP
nft add rule ip filter INPUT tcp dport 80 meter http1 { tcp dport . ip saddr limit rate over 200/second } counter drop

Notice that a meter is named, like hashlimit, and using multiple hashlimit-modes is similar to using a concatenation of selectors. Also, --hashlimit-above is translated to limit rate over, to simulate --hashlimit-upto just omit or replace over with until in the rule.

The options --hashlimit-burst and --hashlimit-htable-expire are translated to burst and timeout in a meter:

$ iptables-translate -A INPUT -m tcp -p tcp --dport 80 -m hashlimit --hashlimit-above 200kb/s --hashlimit-burst 1mb --hashlimit-mode srcip,dstport --hashlimit-name http2 --hashlimit-htable-expire 3000 -j DROP
nft add rule ip filter INPUT tcp dport 80 meter http2 { tcp dport . ip saddr timeout 3s limit rate over 200 kbytes/second burst 1 mbytes} counter drop

This rule shows how timeout and burst are used in a meter, also notice that meters, similarly to hashlimit, accepts limiting rates by bytes frequency instead of packets.

Another hashlimit option is to limit the traffic rate on subnets, of IP source or destination addresses, using the options --hashlimit-srcmask and --hashlimit-dstmask. This feature is available in nft by attaching a subnet mask to a meter selector, attach to ip saddr for source address and to ip daddr for destination adress:

$ iptables-translate -A INPUT -m tcp -p tcp --dport 80 -m hashlimit --hashlimit-upto 200 --hashlimit-mode srcip --hashlimit-name http3 --hashlimit-srcmask 24 -j DROP
nft add rule ip filter INPUT tcp dport 80 meter http3 { ip saddr and 255.255.255.0 limit rate 200/second } counter drop

This rule will limit packets rate, grouping subnets determined by the first 24 bits of the IP source address, from the incoming packets on port 80.

The remaining options, --hashlimit-htable-max, --hashlimit-htable-size and --hashlimit-htable-gcinterval don't apply to meters.