block a whole IP range with fail2ban

Published on Author righter16 Comments

Updated on 08.09.16 for Debian Jessie

Fail2Ban is really cool. I use it to block ssh attacks.  But I wanted to block the whole IP range from the attacker.
Some guys don’t think this is a good idea. But in my oppinion it is. It depends on the service which you observer with fail2ban. In my case, I don’t see any problems to block the whole range for SSH. If you use it for protecting your mail server it is definitely not a good idea 🙂

First of all copy the original action to a new one:

cp /etc/fail2ban/action.d/iptables-multiport.conf /etc/fail2ban/action.d/iptables-multiport-range.conf

Create this File which gets the CIDR of the IP (I’ve edited this script, if no inetnum found use the single ip):
get_network

Make the file executable

chmod +x /etc/fail2ban/get_network.py

Change the un/ban actions in the script (Thanks to stephan for a modified version):

nano /etc/fail2ban/action.d/iptables-multiport-range.conf
 
actionban = /etc/fail2ban/get_network.py  | while read PREFIX; do iptables -C fail2ban- -s $PREFIX -j DROP >/dev/null || iptables -I fail2ban- 1 -s $PREFIX -j DROP; done
actionunban = /etc/fail2ban/get_network.py  | while read PREFIX; do iptables -D fail2ban- -s $PREFIX -j DROP; done

Change the banaction in jail.conf:

nano /etc/fail2ban/jail.conf
banaction = iptables-multiport-range

Restart fail2ban

/etc/init.d/fail2ban restart

Then you see the whole range will be blocked (in log file you still see the single ip)

2014-12-10 11:56:53,322 fail2ban.actions: WARNING [ssh] Ban 222.33.200.213
Chain fail2ban-sshx (1 references)
target     prot opt source               destination         
DROP       all  --  222.32.0.0/11        anywhere            
RETURN     all  --  anywhere             anywhere 

16 Responses to block a whole IP range with fail2ban

  1. Hallo,

    thanks for this guide, but it is not working for me, I’m using fail2ban v0.9.1.
    With the command: iptables –list-rules I’m checkiong the active bans:
    Normally it looks like this (with banaction = iptables-multioirt)
    All attackers are listed …
    -A f2b-ssh -s 117.21.174.111/32 -j REJECT –reject-with icmp-port-unreachable
    -A f2b-ssh -s 113.195.145.80/32 -j REJECT –reject-with icmp-port-unreachable

    With your guide I created the get_network.py and made it executble.
    I also copied the iptables-multiport to iptables-multiport-range and modified the ban and unban lines.
    After this I edited jail.conf and jail.local and changed the banaction to “iptables-multiport-range”

    But then iptables –list-rules only got the basic fail2ban stuff:
    -P INPUT ACCEPT
    -P FORWARD ACCEPT
    -P OUTPUT ACCEPT
    -N f2b-mysqld-auth
    -N f2b-postfix
    -N f2b-ssh
    -N f2b-ssh-ddos
    -A INPUT -p tcp -m multiport –dports 22 -j f2b-ssh-ddos
    -A INPUT -p tcp -m multiport –dports 22 -m set –match-set f2b-ssh-iptables-ipset4 src -j REJECT –reject-with icmp-port-unreachable
    -A INPUT -p tcp -m multiport –dports 22 -j f2b-ssh
    -A INPUT -p tcp -m multiport –dports 3306 -j f2b-mysqld-auth
    -A INPUT -p tcp -m multiport –dports 25,465,587 -j f2b-postfix
    -A f2b-mysqld-auth -j RETURN
    -A f2b-postfix -j RETURN
    -A f2b-ssh -j RETURN
    -A f2b-ssh-ddos -j RETURN

    and the fail2ban.log tells it is banning IPs and it does not, the attackers continue attacking according to auth.log.

    Where do I see the last part of your description?
    Chain fail2ban-sshx (1 references)
    target prot opt source destination
    DROP all — 222.32.0.0/11 anywhere
    RETURN all — anywhere anywhere

  2. Hallo,

    it’s me again, I recognized I’ve got to remove the spaces in the get_network.py file in front of the import commands.

    But there’s an additional issue I’m not able to fix:

    ./get_network.py 192.1.10.20
    Traceback (most recent call last):
    File “./get_network.py”, line 25, in
    data=re.search(‘^CIDR:s+(.*)$’,whois,re.MULTILINE).groups()[0]
    NameError: name ‘whois’ is not defined

  3. Hmmm damn i should repair my blog.
    the code sequence get defect on this page.
    i’ve uploaded the script now in a text file, please try that agin.

    cheers

  4. Hallo,

    thank you for the fix with the text file. Now it kind of works, but there is still something curios with the script:

    ./get_network.py 42.255.125.124
    42.248.0.0/13

    ./get_network.py 43.255.125.124
    Traceback (most recent call last):
    File “./get_network.py”, line 24, in
    data=re.search(‘^CIDR:s+(.*)$’,whois,re.MULTILINE).groups()[0]
    AttributeError: ‘NoneType’ object has no attribute ‘groups’

    ./get_network.py 44.255.125.124
    44.0.0.0/8

    ./get_network.py 45.255.125.124
    Traceback (most recent call last):
    File “./get_network.py”, line 24, in
    data=re.search(‘^CIDR:s+(.*)$’,whois,re.MULTILINE).groups()[0]
    AttributeError: ‘NoneType’ object has no attribute ‘groups’

    ./get_network.py 46.255.125.124
    46.255.125.0/24

    And in this case the second number value changes from 100 to 64:

    ./get_network.py 40.100.100.100
    40.64.0.0/10

    I’m not the great networking master, but all given IP addresses were valid, and in the last case the change of the numbers 100 to 64 should not appear I guess.

    I just did some pre tests with similar IPs which were already blocked by fail2ban.

    Just correct me if I’m wrong in this case.

    I’ll use this now and try it live.

    Thanks a lot for this tool I’ve been searching exactly for such a way to enhance fail2ban with ip range banning ability.

    Best regards Kitsab

  5. Hallo again,

    did a quick test with your enhancement applied.

    I just change jail.local and jail.conf (banaction) from iptables-multiport to iptables-multiport-range. The action.d/iptables-multiport-range.conf with the special ban/unban command is in place.

    Before restarting the fail2ban service i did iptables –list-rules and got about ~60 banned IPs

    After restarting fail2ban with the enhancement the same coammdn don’t gave me any blocked IPs just the basic fail2ban stuff.

    After changing banaction back to iptables-multiport and restarting the service again, the command gave me about 60 banned IPs again.

    Fail2ban log gives me:

    BAN:
    2015-04-13 21:52:59,750 fail2ban.actions [8307]: NOTICE [ssh] Ban 221.229.160.230
    2015-04-13 21:53:00,085 fail2ban.action [8307]: ERROR /etc/fail2ban/get_network.py 221.229.160.230 | while read PREFIX; do iptables -I fail2ban-ssh 1 -s $PREFIX -j DROP; done — stdout: ”
    2015-04-13 21:53:00,086 fail2ban.action [8307]: ERROR /etc/fail2ban/get_network.py 221.229.160.230 | while read PREFIX; do iptables -I fail2ban-ssh 1 -s $PREFIX -j DROP; done — stderr: ‘iptables: No chain/target/match by that name.n’
    2015-04-13 21:53:00,086 fail2ban.action [8307]: ERROR /etc/fail2ban/get_network.py 221.229.160.230 | while read PREFIX; do iptables -I fail2ban-ssh 1 -s $PREFIX -j DROP; done — returned 1
    2015-04-13 21:53:00,086 fail2ban.actions [8307]: ERROR Failed to execute ban jail ‘ssh’ action ‘iptables-multiport-range’ info ‘CallingMap({‘ipjailmatches’: <function at 0x7fb9eca02410>, ‘matches’: u’Apr 13 16:30:41 MediaCenter sshd[5407]: Failed password for root from 221.229.160.230 port 59838 ssh2nApr 13 16:30:43 MediaCenter sshd[5407]: Failed password for root from 221.229.160.230 port 59838 ssh2nApr 13 16:30:45 MediaCenter sshd[5407]: Failed password for root from 221.229.160.230 port 59838 ssh2′, ‘ip’: ‘221.229.160.230’, ‘ipmatches’: <function at 0x7fb9eca02500>, ‘ipfailures’: <function at 0x7fb9eca02488>, ‘time’: 1428954779.75006, ‘failures’: 3, ‘ipjailfailures’: <function at 0x7fb9eca02578>})’: Error banning 221.229.160.230

    UNBAN:
    2015-04-13 21:55:08,440 fail2ban.actions [8307]: NOTICE [ssh] Unban 218.87.111.108
    2015-04-13 21:55:08,759 fail2ban.action [8307]: ERROR /etc/fail2ban/get_network.py 218.87.111.108 | while read PREFIX; do iptables -D fail2ban-ssh -s $PREFIX -j DROP; done — stdout: ”
    2015-04-13 21:55:08,759 fail2ban.action [8307]: ERROR /etc/fail2ban/get_network.py 218.87.111.108 | while read PREFIX; do iptables -D fail2ban-ssh -s $PREFIX -j DROP; done — stderr: ‘iptables: Bad rule (does a matching rule exist in that chain?).n’
    2015-04-13 21:55:08,760 fail2ban.action [8307]: ERROR /etc/fail2ban/get_network.py 218.87.111.108 | while read PREFIX; do iptables -D fail2ban-ssh -s $PREFIX -j DROP; done — returned 1
    2015-04-13 21:55:08,760 fail2ban.actions [8307]: ERROR Failed to execute unban jail ‘ssh’ action ‘iptables-multiport-range’ info ‘{‘matches’: u’Apr 13 08:35:09 MediaCenter sshd[3499]: Failed password for root from 218.87.111.108 port 39186 ssh2Apr 13 08:35:12 MediaCenter sshd[3499]: Failed password for root from 218.87.111.108 port 39186 ssh2Apr 13 08:35:15 MediaCenter sshd[3499]: Failed password for root from 218.87.111.108 port 39186 ssh2′, ‘ip’: ‘218.87.111.108’, ‘time’: 1428954777.849713, ‘failures’: 3}’: Error unbanning 218.87.111.108

    Maybe the ban/unban action in /etc/fail2ban/action.d/iptables-multiport-range.conf is also scrambled by the blog format?

    actionban = /etc/fail2ban/get_network.py | while read PREFIX; do iptables -I fail2ban- 1 -s $PREFIX -j DROP; done
    actionunban = /etc/fail2ban/get_network.py | while read PREFIX; do iptables -D fail2ban- -s $PREFIX -j DROP; done

  6. Hallo,

    I found an very easy way to get the function banning ip ranges function finally working.

    Source: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=724274

    cp /etc/fail2ban/action.d/iptables-multpiport.conf /etc/fail2ban/action.d/iptables-multpiport24.conf

    nano /etc/fail2ban/action.d/iptables-multpiport24.conf

    modify the follwoing lines:
    actionban = iptables -I f2b- 1 -s -j
    to
    actionban = iptables -I f2b- 1 -s /24 -j

    and

    actionunban = iptables -D f2b- -s -j
    to
    actionunban = iptables -D f2b- -s /24 -j

    and finally modify jail.conf and/or jail.local – same modification in both files:
    banaction = iptables-multiport
    tio
    banaction = iptables-multiport24

    Best regards

    Kitsab

  7. Something did not work in copy paste or a blog issue.

    The lines modified in /etc/fail2ban/action.d/iptables-multirange24.conf should be like this:

    actionban = iptables -I f2b- 1 -s -j
    to
    actionban = iptables -I f2b- 1 -s /24 -j

    actionunban = iptables -D f2b- -s -j
    to
    actionunban = iptables -D f2b- -s /24 -j

    Hope the code is working this time

  8. Ok, the blog is damaging the code, please refer to the linked source last post.

    or replace the “)” and “(” with “>” and “<"

    actionban = iptables -D f2b-(name) -s (ip) -j (blocktype)
    to
    actionban = iptables -D f2b-(name) -s (ip)/24 -j (blocktype)

    actionunban = iptables -D f2b-(name) -s (ip) -j (blocktype)
    to
    actionunban = iptables -D f2b-(name) -s (ip)/24 -j (blocktype)

    Sorry for multiple posts.

    br Kitsab

  9. my 2 cents
    because it works out of logs, yo umay have been attaked by the same range.

    use this
    actionban = /etc/fail2ban/get_network.py | while read PREFIX; do iptables -n -L fail2ban- | grep -q “$PREFIX” || iptables -I fail2ban- 1 -s $PREFIX -j ; done

    this will prevent duplicated line in iptable
    sure this will trouble upon unban because you may unbal earlier, but on running tim ethis will be ok

  10. Thank you, this is brilliant solution but I noticed that iptables was occasionally returning error 200 due to list of networks not being enclosed in quotes. I updated ban/unban actions on my computer to:

    actionban = INET=`/etc/fail2ban/get_network.py (ip)` && iptables -I fail2ban-(name) 1 -s “${INET}” -j DROP
    actionunban = INET=`/etc/fail2ban/get_network.py (ip)` && iptables -D fail2ban-(name) -s “${INET}” -j DROP

    Note, parentheses above should be replaced with angle brackets

  11. you can prevent duplicate entries in iptables using:

    actionban = /etc/fail2ban/get_network.py | while read PREFIX; do iptables -C fail2ban- -s $PREFIX -j DROP >/dev/null || iptables -I fail2ban- 1 -s $PREFIX -j DROP; done

  12. My solution was to replace the action ban and unban by:

    actionban = whois | grep route: | awk ‘{print $2}’ | xargs -n1 -I{} iptables -I fail2ban- 1 -s {} -j

    actionunban = whois | grep route: | awk ‘{print $2}’ | xargs -n1 -I{} iptables -D fail2ban- 1 -s {} -j

    • consider that this blog the fields of “IP” and “NAME” and “BLOCKTYPE”

      actionban = whois “ipFIELD” | grep route: | awk ‘{print $2}’ | xargs -n1 -I{} iptables -I fail2ban-“nameFIELD” 1 -s {} -j “blocktypeFIELD”

      actionunban = whois “ipFIELD” | grep route: | awk ‘{print $2}’ | xargs -n1 -I{} iptables -D fail2ban-“nameFIELD” 1 -s {} -j “blocktypeFIELD”

  13. Hi.

    This is interesting, but what I’m searching it how to count the all the hit from the network (at least /24), not only to ban a network based on the on few hits from one IP (in fact it would be not good at all because of individual users having trouble with forgot passwords).

    For example:
    5 hits from 11.22.33.10
    5 hits from 11.22.33.15
    5 hits from 11.22.33.25
    5 hits from 11.22.33.100
    5 hits from 11.22.33.125
    5 hits from 11.22.33.200

    30 total hits would be enough to ban 111.22.33.0/24 but each 5 hits wouldn’t be enough for each individual because the limit is lower (limit seems to be taken in account by the attacker)

    Cheers.

Leave a Reply

Your email address will not be published. Required fields are marked *