iptables
The proposed way to ban IPs using iptables uses one reaction
chain.
The IPs are banned on all ports, meaning banned IPs won't be able to connect on any service.
We use the ip46tables
binary included alongside reaction
, which permits to support both IPv4 and IPv6.
Start/Stop
We first need to create this chain on startup, and add it at the beginning of the INPUT
iptables chain.
Docker & LXD users will need to add this rule to the FORWARD
chain as well.
{
start: [
// create the `N`ew chain
['ip46tables', '-w', '-N', 'reaction'],
// `I`nsert the chain at the beginning of INPUT & FORWARD
['ip46tables', '-w', '-I', 'INPUT', '-p', 'all', '-j', 'reaction'],
['ip46tables', '-w', '-I', 'FORWARD', '-p', 'all', '-j', 'reaction'],
],
}
We want reaction
to remove it when quitting:
{
stop: [
// `D`elete it from INPUT & FORWARD
['ip46tables', '-w', '-D', 'INPUT', '-p', 'all', '-j', 'reaction'],
['ip46tables', '-w', '-D', 'FORWARD', '-p', 'all', '-j', 'reaction'],
// `F`lush it (delete all the items in the chain)
['ip46tables', '-w', '-F', 'reaction'],
// Remove it completely
['ip46tables', '-w', '-X', 'reaction'],
],
}
Ban/Unban
Now we can ban an IP with this command:
{
cmd: ['ip46tables', '-w', '-A', 'reaction', '-s', '<ip>', '-j', 'DROP']
// or
cmd: [ 'sh', '-c', 'ip46tables -w -A reaction -s <ip> -j DROP']
}
And unban the IP with this command:
{
cmd: ['ip46tables', '-w', '-D', 'reaction', '-s', '<ip>', '-j', 'DROP']
// or
cmd: [ 'sh', '-c', 'ip46tables -w -D reaction -s <ip> -j DROP']
}
A good practice is to wrap the actions in a function with parameters:
local banFor(time) = {
ban: {
cmd: ['ip46tables', '-w', '-A', 'reaction', '-s', '<ip>', '-j', 'DROP'],
},
unban: {
cmd: ['ip46tables', '-w', '-D', 'reaction', '-s', '<ip>', '-j', 'DROP'],
after: time,
},
};
See how to merge different actions in JSONnet FAQ
Real-world example
local banFor(time) = {
ban: {
cmd: ['ip46tables', '-w', '-A', 'reaction', '-s', '<ip>', '-j', 'DROP'],
},
unban: {
after: time,
cmd: ['ip46tables', '-w', '-D', 'reaction', '-s', '<ip>', '-j', 'DROP'],
},
};
{
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: [
['ip46tables', '-w', '-N', 'reaction'],
['ip46tables', '-w', '-I', 'INPUT', '-p', 'all', '-j', 'reaction'],
['ip46tables', '-w', '-I', 'FORWARD', '-p', 'all', '-j', 'reaction'],
],
stop: [
['ip46tables', '-w', '-D', 'INPUT', '-p', 'all', '-j', 'reaction'],
['ip46tables', '-w', '-D', 'FORWARD', '-p', 'all', '-j', 'reaction'],
['ip46tables', '-w', '-F', 'reaction'],
['ip46tables', '-w', '-X', 'reaction'],
],
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'),
},
},
},
},
}