fail2ban
fail2ban copied to clipboard
Support to ban subnets
Hello,
in which case does fail2ban support to ban subnets. I used the instruction from http://cup.wpcoder.de/fail2ban-ip-blacklist/ and entered the subnet instead of the single IP, but fail2ban seems not to handle them at all.
Kind regards, K1LLUM1N471
I'm not sure where on that page it refers to subnets being blacklisted (ignoring /32 as a subnet). Generally only one IP fails to authenticate and subsequently gets blacklisted by fail2ban. Do you have a specific use case you are attempting to achieve? How would the subnet be determined from a single IP failing to log in?
There is no specific use case, just a server in a sensitive area of research and development, which has to be secured. The main reason is, to block iterated unauthorised access from foreign countries e.g. China, USA). The determination of the associating subnet is currently done by hand (Google + Subnet calculator).
Kind regards, K1LLUM1N471
Am 28.01.2015 um 01:27 schrieb Lee Clemens:
I'm not sure where on that page it refers to subnets being blacklisted (ignoring /32 as a subnet). Generally only one IP fails to authenticate and subsequently gets blacklisted by fail2ban. Do you have a specific use case you are attempting to achieve? How would the subnet be determined from a single IP failing to log in?
— Reply to this email directly or view it on GitHub https://github.com/fail2ban/fail2ban/issues/927#issuecomment-71758441.
@K1LLUM1N471 I have a branch doing that, at the moment written relative #716 (as part of increment feature - ban-time-incr within factor plugin for observer). It can be easy configured in [jail]
resp. [default]
or as include in it, here is an example:
...
# If geo feature enabled (dictionaries "geo.country" or "geo.region" are specified):
# - for each failure this factor appears like a simple "divider" for "maxretry" (inside of "findtime" interval);
# - for time of each ban it is a simple multiplier coefficient besides "bantime.factor" ("jail.Factor"),
# to change default behavior use "ban.Factor" in expression "bantime.formula".
# The larger value of factor leads to faster ban (few failures) and longest time of ban by increase.
# "geo.country" - dictionary to define factor by country of IP address (country:factor pair)
# (using of this method needs a Country, Region, or City database)
#geo.country =
geo.country = default:10
DE:1 RU:2
...
Example above means - the factor for each country is 10, however for DE it is 1 and RU it is 2.
This feature is configurable to use geoip
databases or cymru-like dns resolvers...
I will commit it this or next week and let know if as far as.
@K1LLUM1N471 Can you help me understand "block iterated unauthorised access". Do you mean if an IP from RU gets banned, all IP space from RU gets banned? Or if one IP gets banned, for fail2ban to ban the entire subnet it is a member of (as allocated by the RIR)?
@sebres Thanks for info. How reliable is the identification of a IP this way?
@leeclemens I guess it is the second case. When one IP got banned, all the other IPs from this subnet got banned, too.
For this reason I would prefer to set manually the array of IPs or subnets by the use of a blacklist, which is interpreted by Fail2Ban. For example: "subnet.blacklist" > "198.27.100.224/29" or "ip.blacklist" > "198.27.100.224 - 198.27.100.231"
Ban array of IPs by subnet or by defined array
Kind regards, K1LLU1N471
@K1LLUM1N471
How reliable is the identification of a IP this way?
Good question, I would say how outdated the geoip database is. This applies of course to cymru-like services also.
But this impacts failures/bans only, so if IP makes no failures - it country will not be taken into account.
After putting this into service I have decreased a value of banTime
to 1m
(because initial value, will be incremented + factored), to prevent a banning for long time for first failures from "foreign" countries.
I +1 this request. I found that some China subnets work together for ssh-bruteforce : when one IP is banned an other one (very close to the 1st one) continues few minutes after. To handle this I created an ad hoc script that takes IP to ban and check in a subnet list (from a file) and returns a subnet ban to iptables (i.e. X.Y.Z.W/24 rather than just X.Y.Z.W). And of course the same for deban. But it would be better if this can be handled directly from fail2ban, because with my approach it don't consider several attempts from different IPs (in the subnet) as counting for the subnet ban: one IP must trigger the ban.
Regards,
Hexasoft
You can try replacing <ip>
in your action(s) with this:whois <ip> | grep route: | awk '{print $2}'
. It will ban the whole subnet according to the whois data, not only /24 which may be not enough.
As I had the same concern as you seem to have, I tried myself at making a special subnet banning system using fail2ban, called fail2ban-subnets, that you can find here. It's a simple python script that you can configure quite easily and that will use the fail2ban.log file to identify subnets and log the ones that have a consequent (configurable) number of bans and IPs involved. It only supports banning up to /24 subnets currently as I didn't want to make it find too big subnets if there's innocent IPs in that range. I plan however on making that configurable too in the future if some people would need it. I'm using it on a few servers currently and it works like a charm! Hope this helps.
I see reference by sebres using geoip to modify behaviour based on country of origin. Is this a concept that will be added to fail2ban soon?
> # If geo feature enabled (dictionaries "geo.country" or "geo.region" are specified):
> # - for each failure this factor appears like a simple "divider" for "maxretry" (inside of "findtime" interval);
> # - for time of each ban it is a simple multiplier coefficient besides "bantime.factor" ("jail.Factor"),
> # to change default behavior use "ban.Factor" in expression "bantime.formula".
>
> # The larger value of factor leads to faster ban (few failures) and longest time of ban by increase.
>
> # "geo.country" - dictionary to define factor by country of IP address (country:factor pair)
> # (using of this method needs a Country, Region, or City database)
> #geo.country =
> geo.country = default:10
> DE:1 RU:2
What i do every few months and that i'd like to be upstream is permaban full subnets after too many recidives.
It goes like ban an ip for a few minutes, unban it do this a few times you hit a recidive rule and get banned for a day a few dozen ip from the same subnet hit the recidive rule during a month, permaban the subnet ... no issues so far
it takes like 4_5_20 = 400 attempts before getting a permaban (didnt checked my exacts rules) Seems fair to me; it takes a lot of attempts during an extended period of time to get permabaned Any legitimate admin/user would notice an issue beforehand and the attempts would stop.
It works because these guys use whole ip ranges, are very persistant and switch to another ip of their subnet once they are hit by a recidive rule.
tbh 99 of the ips are from china, it s just that i thought it was too discrimnatory to geoban china
iptables-save | grep fail2ban |grep '/32' | wc -l 206 iptables-save | grep fail2ban |grep '/24' | wc -l 217 iptables-save | grep fail2ban |grep '/16' | wc -l 21
I ban /16 if there s too much /24 banned as reported by a whois
Using @justabaka Idea, this works for me:
actionban = whois <ip> | grep route: | awk '{print $2}' | xargs -n1 -I{} iptables -I fail2ban-<name> 1 -s {} -j <blocktype>
actionunban = whois <ip> | grep route: | awk '{print $2}' | xargs -n1 -I{} iptables -D fail2ban-<name> 1 -s {} -j <blocktype>
@rodrigorojasmoraleda: this solution is really interesting, but unfortunately not generic enough.
Indeed, in my experience, I've seen that each whois server replies with its own format. The string "route:" does not necessarily appear in the answer. Thus many IP will get through your fail2ban.
For instance, using the 3 last IP addresses that attacked my companies' servers:
$ whois 14.119.66.49 | grep -F 'route:'
$ whois 139.227.188.103 | grep -F 'route:'
$ whois 138.219.29.18 | grep -F 'route:'
I've seen whois answers with "CIDR" or "inetnum" or "route", and generally they do not use the / notation, but an ip range :{
I'm sure it's possible to write a rule to manage all possible cases, but it would require to know them all. Also since the rule would be complicated, it would probably be better to wrap it inside a module/plug-in.
When I use :
actionunban = whois
2017-06-09 17:37:01,323 fail2ban.action [26026]: ERROR whois 159.226.71.236 | grep route: | awk '{print $2}' | xargs -n1 -I{} iptables -w -D f2b-sshd 1 -s {} -j REJECT --reject-with icmp-port-unreachable -- stderr: b"iptables v1.6.0: Illegal option `-s' with this command\n\nTry \`iptables -h' or 'iptables --help' for more information.\n"
So removed 1 then it is ok. (Can anyone give some comment for this?)
Also found that results of whois use different format & keyword by each hosting carrier such as route/CIDR/inetnum IPv4 etc. So wrote below script to handle this - referred several web pages(CIDR regex etc.)
#!/bin/bash
debug=0
checkCIDR="^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$"
checkIP="^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
function debugEcho()
{
if [ $debug == 1 ] ; then
echo "$*" 1>&2
fi
}
function findCIDR()
{
if [ ! -z "$1" ]; then
cidrData="$1"
if [[ ! "$cidrData" =~ $checkCIDR ]]; then
debugEcho "Try xx.xx/xx type"
cidrData=`echo $1 | sed -E 's/^([0-9]{1,3}\.[0-9]{1,3})(\/([0-9]|[1-2][0-9]|3[0-2]))/\1.0.0\2/'`
if [[ ! "$cidrData" =~ $checkCIDR ]] ; then
debugEcho "$cidrData is not CIDR"
debugEcho "Try xx.xx.xx/xx type"
cidrData=`echo $1 | sed -E 's/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(\/([0-9]|[1-2][0-9]|3[0-2]))/\1.0\2/'`
if [[ ! "$cidrData" =~ $checkCIDR ]] ; then
debugEcho "$cidrData is not CIDR"
cidrData=""
else
debugEcho "$cidrData is CIDR"
fi
else
debugEcho "$cidrData is CIDR"
fi
else
debugEcho "$cidrData is CIDR"
fi
else
cidrData=""
fi
echo $cidrData
}
function findRange()
{
localSubnet=""
rangeData="$*"
debugEcho "rangeData : $rangeData"
# Check Range or not
IP_1=`echo $rangeData | awk '{print $1}'`
IP_2=`echo $rangeData | awk '{print $3}'`
debugEcho "IP_1 : $IP_1"
debugEcho "IP_2 : $IP_2"
if [[ "$IP_1" =~ $checkIP && "$IP_2" =~ $checkIP ]]; then
localSubnet=`ipcalc $rangeData | grep -m 1 -v deaggregate | awk '{print $1}'`
if [[ ! "$localSubnet" =~ $checkCIDR ]]; then
debugEcho "$localSubnet is not CIDR"
localSubnet=""
else
debugEcho "$localSubnet is CIDR"
fi
else
debugEcho "Invald Range"
fi
echo $localSubnet
}
function getSubnet()
{
IP="$1"
debugEcho "Input : $IP"
debugEcho "Try Keyword : route"
whoisResult=$(whois $IP)
Subnet=`echo "$whoisResult" | grep -m 1 route: | awk '{print $2}'`
if [ -z "$Subnet" ]; then
debugEcho "Keyword route result for $IP is null"
debugEcho "Try Keyword : CIDR"
Subnet=`echo "$whoisResult" | grep -m 1 CIDR | awk '{print $2}'`
debugEcho "CIDR result is $Subnet"
Subnet=$(findCIDR $Subnet)
fi
if [ -z "$Subnet" ]; then
debugEcho "Keyword CIDR is null"
debugEcho "Try Keyword : inetnum"
NetRange=`echo "$whoisResult" | grep -m 1 inetnum: | awk '{print $2 " - " $4}'`
if [ ! -z "$NetRange" ]; then
Subnet=$(findRange $NetRange)
if [ -z "$Subnet" ]; then
# inetnum result is not Range, check whether CIDR or not
debugEcho "Check CIDR of inetnum ($NetRange)"
Subnet=`echo $NetRange | awk '{print $1}'`
Subnet=$(findCIDR $Subnet);
fi
else
debugEcho "Keyword inetnum result for $IP is null."
fi
fi
if [ -z "$Subnet" ]; then
debugEcho "Try Keyword : IPv4"
NetRange=`echo "$whoisResult" | grep -m 1 "IPv4 Address" | awk '{print $4 " - " $6}'`
debugEcho "Result of IPv4 is $NetRange"
if [ ! -z "$NetRange" ]; then
Subnet=$(findRange $NetRange)
else
debugEcho "Result of IPv4 for $IP is null try NetRange"
Subnet=""
fi
fi
if [ -z "$Subnet" ]; then
debugEcho "Try Keyword : NetRange"
NetRange=`echo "$whoisResult" | grep NetRange | awk '{print $2 " - " $4}'`
Subnet=$(findRange $NetRange)
if [ -z $Subnet ]; then
Subnet=`echo $Netrange | awk '{print $1}'`
Subnet=$(findCIDR $Subnet)
fi
fi
if [ -z "$Subnet" ]; then
debugEcho "Couldn't find Subnet, Use IP instead"
Subnet=$IP
fi
echo $Subnet
}
if [ ! -z "$1" ]; then
if [ -f "$1" ]; then
while read -r line
do
result=$(getSubnet $line)
debugEcho $line : $result
echo $result
done < $1
else
if [[ "$1" =~ $checkIP ]]; then
result=$(getSubnet $1)
debugEcho "$1 : $result"
echo $result
else
debugEcho "Invalid IP : $1"
echo INVALID
fi
fi
fi
iptable-allports.conf & iptable-multiport.conf
actionban = f2b.getSubnet.sh <ip> | xargs -n1 -I{} <iptables> -I f2b-<name> 1 -s {} -j <blocktype>
actionunban = f2b.getSubnet.sh <ip> | xargs -n1 -I{} <iptables> -D f2b-<name> -s {} -j <blocktype>
will be better if those are included in the module/plug-in.
Right now (Fail2Ban v0.9.6) we have
[jno@git fail2ban]$ sudo fail2ban-client -vvv set sshd banip 61.177.0.0/16
INFO Loading configs for fail2ban under /etc/fail2ban
DEBUG Reading configs for fail2ban under /etc/fail2ban
DEBUG Reading config files: /etc/fail2ban/fail2ban.conf
INFO Loading files: ['/etc/fail2ban/fail2ban.conf']
Level 7 Reading file: /etc/fail2ban/fail2ban.conf
INFO Loading files: ['/etc/fail2ban/fail2ban.conf']
Level 7 Shared file: /etc/fail2ban/fail2ban.conf
INFO Using socket file /var/run/fail2ban/fail2ban.sock
DEBUG OK : '61.177.0.0/16'
DEBUG Beautify '61.177.0.0/16' with ['set', 'sshd', 'banip', '61.177.0.0/16']
61.177.0.0/16
It could get into the database:
[jno@git fail2ban]$ echo 'select distinct ip from bans;' | sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 | grep 61.177
61.177.0.0/16
61.177.172.19
61.177.172.34
And finally:
[jno@git fail2ban]$ sudo iptables-save | grep 61.177
-A f2b-sshd -s 61.177.0.0/16 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 61.177.172.34/32 -j REJECT --reject-with icmp-port-unreachable
So, should it be closed now?
My point of view on the original issue and need for this, and maybe that can help decide if you can close it.
Some hackers have controls of /24 and /16. The pattern is that if fail2ban bans an ip, their tools will understand this, and switch to another ip try to continue to connect. In these cases, fail2ban is of little uses because it ban individual ip. So what is needed is to ban the whole block to stop it.
Personally one thing i would like to see before the issue is closed is more integration. Like what has been done for recidive (no need to fiddle yourself in the logs, you can just enable recidive in fail2ban conf).
Maybe allow to enable actions/detection to manage things as subnet. Like If the subnet hit 50 failed attempts or as already been banned 50 times, ban subnet?
Good idea. But one have to decide on the source for that "subnets". Whois on various servers? RA.net? Looking glasses? How long should the found values be cached? Should the whole "criminal" AS be banned (route to null would be fine here) along with its IPs?
My process is manual. But what about toreit script to manage subnets?
Also maybe with an automated process, it s not necessary to handle anything else than /24 range as x.x.x.0-255 which are 90% of these ban anyway. As fail2ban would handle the ban in realtime and not every few months like me.
I permaban after about 400 attempts. If the process was automated maybe fail2ban could ban faster; unban after 1week or 1month then reban if needed to avoid to keep a very long list.
FYI,
During 10 days, I got results using my script above.
fail2ban-client status sshd & recidive
Status for the jail: sshd
|- Filter
| |- Currently failed: 22
| |- Total failed: 419
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 12
|- Total banned: 57
`- Banned IP list: 181.21.52.102 45.55.207.181 91.134.133.251 81.228.144.32 195.14.163.214 171.244.18.196 188.22.239.233 216.243.62.206 74.74.132.156 186.62.15.142 201.254.78.45 190.48.114.151
Status for the jail: recidive
|- Filter
| |- Currently failed: 42
| |- Total failed: 113
| `- File list: /var/log/fail2ban.log
`- Actions
|- Currently banned: 27
|- Total banned: 27
`- Banned IP list: 103.89.88.182 104.131.50.215 111.40.166.130 113.252.218.224 115.195.119.3 117.0.12.108 121.150.125.212 125.227.128.173 171.49.178.208 182.100.67.120 186.121.240.62 189.44.10.114 198.0.148.211 2.177.129.3 209.93.132.216 211.44.43.165 212.83.142.251 45.243.21.106 61.177.21.226 64.179.211.161 81.137.204.43 86.104.15.15 93.149.10.162 93.187.16.70 94.233.189.208 103.68.42.168 103.79.141.150
iptables -L -n
Chain f2b-recidive (1 references)
target prot opt source destination
REJECT all -- 103.79.140.0/22 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 103.68.40.0/22 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 94.233.184.0/21 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 93.187.16.0/21 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 93.149.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 86.104.15.0/24 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 81.128.0.0/12 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 64.179.208.0/20 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 61.177.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 45.240.0.0/13 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 212.83.128.0/19 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 211.44.0.0/17 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 209.93.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 2.177.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 198.0.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 189.44.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 186.121.192.0/18 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 182.96.0.0/12 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 171.49.160.0/19 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 125.224.0.0/13 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 121.128.0.0/11 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 117.0.0.0/13 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 115.194.0.0/15 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 113.252.0.0/14 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 111.0.0.0/10 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 104.131.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 103.89.88.0/22 0.0.0.0/0 reject-with icmp-port-unreachable
RETURN all -- 0.0.0.0/0 0.0.0.0/0
Chain f2b-sshd (1 references)
target prot opt source destination
REJECT all -- 190.48.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 201.254.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 186.60.0.0/14 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 74.64.0.0/12 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 216.243.0.0/18 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 188.20.0.0/14 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 171.224.0.0/11 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 195.14.160.0/19 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 81.224.0.0/12 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 91.134.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 45.55.0.0/16 0.0.0.0/0 reject-with icmp-port-unreachable
REJECT all -- 181.20.0.0/14 0.0.0.0/0 reject-with icmp-port-unreachable
RETURN all -- 0.0.0.0/0 0.0.0.0/0
As I see the conversation is still running here, just a following comment to my previous one https://github.com/fail2ban/fail2ban/issues/927#issuecomment-127075107 to say that I'm still using my fail2ban-subnets tool on a few servers and that it still work to protect them. I am also still actively supporting it to improve it as needed.
I agree with XaF, I'm also still actively supporting an improvement of the subnet banning feature.
What I would see as important features:
-
easy ban by geoip Indeed, China is the source of 99% of attacks on my companies' server and we don't do business with china, so being able to simply bann china as a whole woulb be great.
-
easy ban of the whole subnet of the originating IP. But this would not act by blindly, by banning /xx , rather "intelligently", using the "whois" solution, but taking into account that different whois servers reply in different manners ("route:"/"CDIR:"/"inetnum:"/... , followed with either an IP-range or a subnet "shortcut")
Please do support ban by network number. Many attackers change the IP address to circunvent fail2ban, with IP address within a range.
Reading over this I don't think I saw this suggested -- would it make more sense rather than banning a /24 when a particular /32 within the /24 hits a threshold to instead keep track of the entire /24 and when the aggregate /24 hits the threshold, ban the /24?
In a sense you would be treating the /24 as a single IP.
I support @rrauenza's suggestion as an option alongside single-IP banning -- what would be REALLY great is an option to track failures on a given /24 subnet (or, even better, the entire CIDR determined from whois
) so that it can track attackers who are using subnets to evade single-IP-based tracking. @XaF's and @toreit's scripts require the IPs to already have been banned, but many modern distributed botnets push an attack through a given IP only once every few hours, or maybe days, so single IPs may never get banned. But tracking failures per subnet would help to combat this.
So, for example, one could have:
findtime_perIP = 600 ; 10 minutes
maxretry_perIP = 3
findtime_perSubnet = 604800 ; 1 week
maxretry_perSubnet = 30
so that a given IP is banned for 3 failures in 10 minutes, but an entire subnet is banned for 30 failures (from that subnet) in 1 week even if no single IP within that subnet ever met the perIP ban criteria. This can help to combat these "slow burn" distributed botnets that use multiple IPs per subnet.
I wouldn't recommend JUST tracking the subnet because you don't want to ban an entire subnet when only one IP has failed... but tracking both single-IP and subnet, with different findtime/maxretry for each, allows knocking out single-IP attacks on a short-term basis while simultaneously handling subnet attacks longer-term.
Is there any solution for #2627 and https://github.com/fail2ban/fail2ban/issues/927#issuecomment-479216812 I am a little confused because it seems that there are two things mixed in this old tread: Banning a complete subnet when a some IPs of the class C net are already banned, and findig and recognicing a spamming subnet when the spammer is using one ip less than f.e three times in during the find time.
You have surely noticed that this is still open?
In fact there is a couple of approaches that could help to "solve" (well rather implement) that, but still nothing to "automatically recognize a subnet and ban it" or "let automatically grow a subnet starting from single IP". So the answer to your question is rather - No.
If you want to do banning of subnet per default (every ban of single IP causes a ban of some predefined subnet), you can either try to use an action that support subnet banning or even extend some fail2ban's action by yourself or write your own action.
Simplest local config for such action (here iptables-multiport.local
) may look like:
[Definition]
actionban = <iptables> -I f2b-<name> 1 -s <ip>/24 -j <blocktype>
actionunban = <iptables> -D f2b-<name> -s <ip>/24 -j <blocktype>
But it'd look differently for different actions (we have no common tag or parameter in actions for subnet at the moment).
Pull request #2560 solves only part of this. so only for the case if the filter could capture a subnet, and an action would support the same notation for the subnet (e. g. if filter captures 192.0.2.1/24
as failure-ID, the action should be able to ban the subnet using this 192.0.2.1/24
notation).
As for #2627 - it was closed as duplicate of this.
there are two things mixed in this old tread findig and recognicing a spamming subnet
This issue has nothing with "spamming subnet". Fail2ban is able to recognize every kind of failures (spamming inclusive) if some filter allow that, but the main word of this issue is "subnet" (not the "spamming", what does not matter at all).
What you're noticed as a mix - is one of many prerequirements that would help to implement this enhancement.
Thanks for your answer. as a quick and dirty apporach i created a batch script to build a logfile to find subnet spammers. Those Ips do not hit any other jail mostly because of spamming/attacing from a subnet. Maybe there will be some false positive, but still not - all of them are subnet attacs/spammer If I run the script the new IPs will be recogniced (and banned) (the script could be called in a cronjob)
#!/bin/bash
# first initialize
# mkdir /var/log/fail2ban.subnets
# touch /var/log/fail2ban.subnets/fail2ban.sub.log
# touch /var/log/fail2ban.subnets/fail2ban.processed.log
# touch /var/log/fail2ban.subnets/fail2ban.sub.log.diff
rm /var/log/fail2ban.subnets/fail2ban.sub.log.diff
touch /var/log/fail2ban.subnets/fail2ban.sub.log.diff
diff /var/log/fail2ban.log /var/log/fail2ban.subnets/fail2ban.processed.log >> /var/log/fail2ban.subnets/fail2ban.sub.log.diff
filename='/var/log/fail2ban.subnets/fail2ban.sub.log.diff'
n=1
while read ip; do
# reading each line
# ip=$1
# 2020-02-11 09:57:26,961 fail2ban.actions [24467]: NOTICE [courier-auth] Unban 119.167.182.138
# search for 4th dot and cut
baseip=`echo $ip | cut -d"." -f1-4`
sub="Found"
if [[ "$baseip" == *"$sub"* ]]; then
echo $baseip".0" >> /var/log/fail2ban.subnets/fail2ban.sub.log
fi
done < $filename
cp /var/log/fail2ban.log /var/log/fail2ban.subnets/fail2ban.processed.log
Jail .local:
banaction_subnets = iptables-subnets
....
[subnets]
maxretry = 50
enabled = true
logpath = /var/log/fail2ban.subnets/fail2ban.sub.log
banaction = %(banaction_subnets)s
#for testing
bantime = 180 ;
#live
#bantime = 604800 ; 1 week
findtime = 86400 ; 1 day
I used for banaction_subnets.conf the iptables-allports.conf genommen and changed
actionban = <iptables> -I f2b-<name> 1 -s <ip>/24 -j <blocktype>
actionunban = <iptables> -D f2b-<name> -s <ip>/24 -j <blocktype>
Finding the ips is working but they are banned als single ip xxx.yyy.zzz.0 Thats the point where i am looking for the error since a a couple of hours now
they are banned als single ip xxx.yyy.zzz.0
Hmm... possibly you just misinterpret the output of iptables. Here is a test dropping some test subnet:
$ sudo iptables -w -I INPUT 1 -s 192.0.2.123/24 -j DROP
$ sudo iptables -nL INPUT | grep 192.0.2
DROP all -- 192.0.2.0/24 0.0.0.0/0
$ sudo iptables -w -D INPUT -s 192.0.2.123/24 -j DROP
So if you mean this automatic wrapping of 192.0.2.123/24
to 192.0.2.0/24
- this is pretty correct, because the CIDR that corresponding the mask /24
implies removing of last 8 bits from the address (32 bits - 24 bits) - they are simply irrelevant by this mask.
Please take a look at wikipedia CIDR-de (or CIDR-en)
Otherwise I would like to see your excerpt (output of iptables), what you exactly meant.
thank you for your help, there is something what I do not understand
doing the banning wiht
$ fail2ban-client status subnets
Status for the jail: subnets
|- Filter
| |- Currently failed: 805
| |- Total failed: 1961
| `- File list: /var/log/fail2ban.subnets/fail2ban.sub.log
`- Actions
|- Currently banned: 5
|- Total banned: 5
`- Banned IP list: 134.73.51.0 217.112.142.0 78.128.113.0 193.56.28.0
$ iptables -nL INPUT | grep 134.73.51
No entry for 134.73.51
doing:
fail2ban-client set subnets banip 134.73.51.0/24
$ fail2ban-client status subnets
Status for the jail: subnets
|- Filter
| |- Currently failed: 805
| |- Total failed: 1995
| `- File list: /var/log/fail2ban.subnets/fail2ban.sub.log
`- Actions
|- Currently banned: 6
|- Total banned: 6
`- Banned IP list: 134.73.51.0/24 134.73.51.0 217.112.142.0 78.128.113.0 193.56.28.0
$ iptables -nL INPUT | grep 134.73.51
No entry for 134.73.51Chain INPUT (policy ACCEPT))
$ iptables -nL INPUT
target prot opt source destination
f2b-subnets tcp -- 0.0.0.0/0 0.0.0.0/0
f2b-recidive tcp -- 0.0.0.0/0 0.0.0.0/0
f2b-mysqld-auth tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 3306
and maybe it is a good idea to add in recidive.conf
_jailnameignore = subnets
ignoreregex = ^(%(__prefix_line)s| %(_daemon)s%(__pid_re)s?:\s+)NOTICE\s+\[(?!%(_jailnameignore)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
but the subnets jail is definitvely working
$ iptables -nL INPUT | grep 134.73.51
No entry for 134.73.51Chain INPUT (policy ACCEPT))
of course there is no entry, your chain (where fail2ban would add it) is called f2b-subnets
, so take a look in:
iptables -nL f2b-subnets | grep 134.73.51