Introduction
From the official documentation website, nftables is :
[…] the new packet classification framework that
intends toreplaces the existing {ip,ip6,arp,eb}_tables infrastructure.
I won’t be listing all the pros and cons of using nftables
over iptables
, but simply citing the dedicated section of the Netfilter Wikipedia page :
The main advantages over iptables are simplification of the Linux kernel ABI (Application Binary Interface, ed.), reduction of code duplication, improved error reporting, and more efficient execution, storage, and incremental changes of filtering rules.
Wow ! What an introduction.
As it should be considered as the-way-of-managing-Netfilter since 2016, I was pretty frustrated not to find any “hardening” guide for it on the Web, so here is one !
Note : I’ll be using the declarative nftables scripting format, much more clear IMHO.
Everything starts with a shebang
This will allow you to run a regular chmod +x
on your rules definition file, and if you’re editing it with Sublime Text, the Nftables syntax definition will be automatically set (that was the moment of self-promotion, which doesn’t happen very often).
Let’s clean up this mess
I don’t know what your current ruleset
looks like (and maybe you don’t know too ), so let’s clean it up in an nft
fashion :
Note : By not specifying any network family type, all existing tables will be removed.
A very old rule of thumb
“Anything that is not explicitly permitted is prohibited.”
— M. S.
With iptables
, you would have (and I hope you did) set DROP
policies on each default FILTER
chains with :
We will drop any thoughts we may have about that, and simply look at how we can reproduce the same behavior with nftables
:
Describing an inet
table allows us to handle any IPv4 (ip
) and IPv6 (ip6
) packets at the very same location (you know DRY and so on).
With each chain bound to its respective hook
, and policies set to drop
, we can be sure that our default skeleton will, at this step, reject any packet.
Note : If you (accidentally) forgot how Netfilter handles packet flow, here is a[n] (almost-complete) reminder.
Mitigate DDoS attacks and script kiddies exploration
Here, the table has been declared with a netdev
network family type. It means that any incoming packet from layer 2 would go through the created chain, as an ingress
hook has been set.
You may also have noticed the -500
priority. By setting it lower than NF_IP_PRI_CONNTRACK_DEFRAG
(= -400
), we are sure that our chain will be evaluated before any other one registered on the ingress
hook. This makes it the perfect place to set our DDoS counter-measures, as we would “spare” a few CPU cycles per packet.
About the rules themselves, there are two kind of statements (decisions) : those that are terminal, and those which are not. For instance, drop
is terminal (a verdict), whereas counter
is not.
Thus, we may specify counter drop
, to make Netfilter count the number of packets matching the rule, and drop them at the same time (very useful for debugging purposes).
No need to duplicate weird iptables
calls anymore (calls that were duplicating Netfilter registered rules by the way ).
Note on “Bogons” : If you got an IPv6 stack, you might be interested in the IPv6 Full Bogons list.
One more hardening rule with conntrack
A regular anti-DDoS rule is to block new packets that are not SYN
.
Why didn’t you add such a rule to the previous code snippet then ?
Well, in order to match “new” packets, we need the help of the conntrack
Netfilter module.
The problem : It’s not available within a chain registered with the ingress
hook, that’s why we gotta use it elsewhere.
Let’s then take the firstly encountered other “location” on the Netfilter flow : the PREROUTING
chain of the filter
table, at the mangle
(-150) priority.
The first rule would drop any packet flagged as invalid
by the conntrack module.
The second would do the same for any new
packet, presenting any other TCP flag beside SYN
.
Conclusion
Here is the final skeleton detailed above :
You “only” have to complete it with your own rules now
Note : If you are interested in a migration from
iptables
, you might wanna read this.
If you think that something is definitely missing (or wrong !), please feel free to leave a comment below, as usual
Sources
Acknowledgments
-
Thanks to Timo for their improvement of
conntrack
-based hardening rules -
Thanks to Thomas for digging up the MSS “off-by-one” error and fixing the TCP XMAS detection rule