nftables
⚠️ Warning: this plugin is beta. If if doesn't work, wait for the next release, that aims to fix those issues.
Permits to manipulate nftables ip sets much faster than with UNIX commands.
It's also more convenient to use. It easily permits to manage one ip set by Filter and thus avoid IP conflicts between filters.
The plugin will add an inet table named reaction to nftables, and remove it when quitting.
systemd options
This plugin requires the CAP_NET_ADMIN and the CAP_PERFMON capabilities to be able to talk to linux's netfilter subsystem.
{
plugins: {
nftables: {
path: '/usr/bin/reaction-plugin-nftables',
systemd_options: {
CapabilityBoundingSet: ['~CAP_NET_ADMIN', '~CAP_PERFMON'],
}
},
},
}plugins:
nftables:
path: /usr/bin/reaction-plugin-nftables
systemd_options:
CapabilityBoundingSet: ['~CAP_NET_ADMIN', '~CAP_PERFMON']Configuration
This plugin exposes only one action of type nftables.
{
ban: {
type: 'nftables',
options: {
set: 'reaction',
action: 'add',
},
},
unban: {
type: 'nftables',
options: {
set: 'reaction',
action: 'delete',
},
after: '6h',
},
}ban:
type: nftables
options:
set: reaction
action: add
unban:
type: nftables
options:
set: reaction
action: delete
after: 6hAction Options
Each action has 3 possible options:
set
Required. The name of the ip set that will be created.
action
Can be add (add the IP to the set) or delete (delete the IP from the set).
Defaults to add.
pattern
The name of the Pattern that holds the ip in this Filter.
It is most commonly ip, but can be set to any name, depending on your configuration.
{
patterns: {
ipv4: {
type: 'ipv4',
},
},
streams: {
s1: {
filters: {
f1: {
regex: ['^<ipv4> ...'],
actions: {
ban: {
type: 'nftables',
options: {
set: 'reaction',
pattern: 'ipv4',
}
}
}
}
}
}
}
}patterns:
ipv4:
type: 'ipv4'
streams:
s1:
filters:
f1:
regex: ['^<ipv4> ...']
actions:
ban:
type: 'nftables'
options:
set: 'reaction'
pattern: 'ipv4'Set Options
In addition to the previous options, 4 set-related options can be added.
They'll be merged between all actions of the same set.
Conflicting options for a same set in different actions will throw a configuration error.
version
One of ip, ipv4 or ipv6.
IP sets can only be of type ipv4 or ipv6.
- Specifying
ipv4will create an set capable of containing IPv4 addresses only. - Specifying
ipv6will create an set capable of containing IPv6 addresses only. - Specifying
ip(the default) will create two sets:- One IPv4 set, with name suffixed by
v4. - One IPv6 set, with name suffixed by
v6.
- One IPv4 set, with name suffixed by
The following example will create 4 sets:
- An IPv4 set named
a. - An IPv6 set named
b. - An IPv4 set named
cv4. - An IPv6 set named
cv6.
{
a1: {
ipv4only: true,
type: 'nftables',
options: {
set: 'a',
version: 'ipv4',
},
},
a2: {
ipv6only: true,
type: 'nftables',
options: {
set: 'b',
version: 'ipv6',
},
},
a3: {
type: 'nftables',
options: {
set: 'c',
version: 'ip',
},
},
}a1:
ipv4only: true
type: nftables
options:
set: a
version: ipv4
a2:
ipv6only: true
type: nftables
options:
set: b
version: ipv6
a3:
type: nftables
options:
set: c
version: ip
In summary:
- The version
ipis just a convenient shortcut for transparently handling both ipv4 and ipv6 and is the default. - If you need more control, or have an ipv4-only or ipv6-only server, you can set
versionto ipv4 or ipv6.
hooks
The nftables hooks where the set must be inserted.
Array of strings. Defaults to ["input", "forward"], but can be an array with any of those values:
ingresspreroutingforwardinputoutputpostroutingegress
See the nftables wiki for details about what those hooks mean.
Example:
{
type: 'nftables',
options: {
set: 'reaction',
// only in input, not in forward
hooks: ['input'],
}
}type: nftables
options:
set: reaction
# only in input, not in forward
hooks: ['input']target
The target associated with the match of an IP.
Defaults to drop, which means that associated packets are simply dropped.
But it can be any of those nftables statements:
acceptdropcontinuereturn
Example:
{
type: 'nftables',
options: {
set: 'reaction',
// user-defined chain
target: 'nixos-fw-log-refuse',
}
}type: 'nftables'
options:
set: 'reaction'
# user-defined chain
target: 'nixos-fw-log-refuse'timeout
Optional nftables timeout, letting linux/netfilter handle set removal instead of reaction.
If this is used instead of an after action, note that:
reaction showandreaction flushwon't work.- IPs won't be persisted to disk.
Same syntax as Action after.
Example:
{
type: 'nftables',
options: {
set: 'reaction',
action: 'add',
timeout: '1d',
}
}type: nftables
options:
set: reaction
action: add
timeout: 1d
We recommend using an after command like this instead:
{ type: 'nftables', options: { set: 'reaction', action: 'add', } }, { type: 'nftables', options: { set: 'reaction', action: 'delete', }, after: '1d', }
Full configuration example
{
plugins: {
nftables: {
path: '/usr/bin/reaction-plugin-nftables',
systemd_options: {
CapabilityBoundingSet: ['~CAP_NET_ADMIN', '~CAP_PERFMON'],
}
},
},
patterns: {
ip: {
type: 'ip',
},
},
streams: {
ssh: {
cmd: ['journalctl', '-n0', '-fu', 'sshd.service'],
filters: {
authfail: {
regex: [
'authentication failure;.*rhost=<ip>'
],
retry: 3,
retryperiod: '3h',
actions: {
ban: {
type: 'nftables',
options: {
set: 'ssh',
action: 'add',
},
},
unban: {
after: '24h',
type: 'nftables',
options: {
set: 'ssh',
action: 'delete',
},
},
},
},
},
},
nginx: {
cmd: ['tail', '-f', '/var/log/nginx/access.log'],
filters: {
directus: {
regex: [ @'^<ip> .* "POST /auth/login HTTP/..." 401', ],
retry: 6,
retryperiod: '4h',
actions: {
ban: {
type: 'nftables',
options: {
set: 'directus',
action: 'add',
},
},
unban: {
after: '4h',
type: 'nftables',
options: {
set: 'directus',
action: 'delete',
},
},
},
},
},
},
},
}
This will produce the following nftables config:
table inet reaction {
set directusv4 {
type ipv4_addr
flags interval
}
set directusv6 {
type ipv6_addr
flags interval
}
set sshv4 {
type ipv4_addr
flags interval
}
set sshv6 {
type ipv6_addr
flags interval
}
chain forward {
type filter hook forward priority filter; policy accept;
ip saddr @directusv4 drop
ip6 saddr @directusv6 drop
ip saddr @sshv4 drop
ip6 saddr @sshv6 drop
}
chain input {
type filter hook input priority filter; policy accept;
ip saddr @directusv4 drop
ip6 saddr @directusv6 drop
ip saddr @sshv4 drop
ip6 saddr @sshv6 drop
}
}