firewalld
The proposed way to ban IPs using firewalld uses one reaction
zone.
The IPs are banned on all ports, meaning banned IPs won't be able to connect on any service.
Start/Stop
We first need to create this zone on startup.
{
start: [
// create the new zone
['firewall-cmd', '--permanent', '--new-zone', 'reaction'],
// set its target to DROP
['firewall-cmd', '--permanent', '--set-target', 'DROP', '--zone', 'reaction'],
// reload firewalld to be able to use the new zone
['firewall-cmd', '--reload'],
],
}
We want reaction
to remove it when quitting:
{
stop: [
// remove the zone
['firewall-cmd', '--permanent', '--delete-zone', 'reaction'],
// reload firewalld
['firewall-cmd', '--reload'],
],
}
Ban/Unban
Now we can ban an IP with this command:
{
cmd: ['firewall-cmd', '--zone', 'reaction', '--add-source', '<ip>'],
}
And unban the IP with this command:
{
cmd: ['firewall-cmd', '--zone', 'reaction', '--remove-source', '<ip>']
}
A good practice is to wrap the actions in a function with parameters:
local banFor(time) = {
ban: {
cmd: ['firewall-cmd', '--zone', 'reaction', '--add-source', '<ip>'],
},
unban: {
cmd: ['firewall-cmd', '--zone', 'reaction', '--remove-source', '<ip>']
after: time,
},
};
See how to merge different actions in JSONnet FAQ
Real-world example
local banFor(time) = {
ban: {
cmd: ['firewall-cmd', '--zone', 'reaction', '--add-source', '<ip>'],
},
unban: {
after: time,
cmd: ['firewall-cmd', '--zone', 'reaction', '--remove-source', '<ip>']
},
};
{
patterns: {
// IPs can be IPv4 or IPv6
// ip46tables (C program also in this repo) handles running the good commands
ip: {
regex: '...', // See patterns.md
},
},
start: [
['firewall-cmd', '--permanent', '--new-zone', 'reaction'],
['firewall-cmd', '--permanent', '--set-target', 'DROP', '--zone', 'reaction'],
['firewall-cmd', '--reload'],
],
stop: [
['firewall-cmd', '--permanent', '--delete-zone', 'reaction'],
['firewall-cmd', '--reload'],
],
streams: {
// Ban hosts failing to connect via ssh
ssh: {
cmd: ['journalctl', '-fn0', '-u', 'sshd.service'],
filters: {
failedlogin: {
regex: [
@'authentication failure;.*rhost=<ip>',
@'Connection reset by authenticating user .* <ip>',
@'Failed password for .* from <ip>',
],
retry: 3,
retryperiod: '6h',
actions: banFor('48h'),
},
},
},
},
}