Fail2Ban - how to prevent my ISP IP dynamic get banned?

I have just installed Fail2Ban.

I want to add my ISP IP to my ignore list but my IP is dynamic.

In the jail.conf file, I have like this:

[DEFAULT]

# "ignoreip" can be an IP address, a CIDR mask or a DNS host
ignoreip = 127.0.0.1
bantime  = 600
maxretry = 3

My DNS look something like this: 12-123-112-223.zone6.myISPName.co.uk

Is it possible to add DNS wild to the ignore list? eg, *.myISPName.co.uk


Solution 1:

fail2ban don't allow you to use wildcard addresses.
You have several possibilities :
1. use a dynamic DNS for the address you want to exclude
2. write an accept rule for iptable, executed prior to fail2ban rules
3. just configure fail2ban

How to configure fail2ban to ignore your address ?
Inside /etc/fail2ban/filter.d/ you have pre-made filters. Your rule(s) already use one of them (for example with filter = sshd use the sshd filter).
Just modify the filter(s) you want (or modify a copy) to add an "exclude" rule.
The exclude rules start with ignoreregex. They are written exactly as the "match" rules. Have a look at man fail2ban-regex.
For your example you can just add ignoreregex .myISPName.co.uk in the desired filter.
But this will also protect any attacker from the same ISP.

Solution 2:

My log file has only IP numbers (no domain names), so ignoreregex didn't work for me.

I'll post here what I did, in the case it is useful for someone trying to do something similar. This was done on Ubuntu 18.04, with Fail2Ban v0.10.2.

  1. Create a script that takes an IP number, do a reverse DNS lookup, and check if the hostname is in the allowed domain name. Put that script in /etc/fail2ban/filter.d/ignorecommands. I named that script ignorehost.
#!/usr/bin/env fail2ban-python
# Inspired by apache-fakegooglebot script
#
# Written in Python to reuse built-in Python batteries and not depend on
# presence of host and cut commands
#
import sys
import re
from fail2ban.server.ipdns import DNSUtils, IPAddr

ALLOWED_HOSTS = [
        ".phlapa.fios.verizon.net",
        ".nwrknj.fios.verizon.net",
        ".hsd1.de.comcast.net",
        ".hsd1.pa.comcast.net"]

def process_args(argv):
    if len(argv) != 2:
       raise ValueError("Please provide a single IP as an argument. Got: %s\n"
                        % (argv[1:]))
    ip = argv[1]

    if not IPAddr(ip).isValid:
       raise ValueError("Argument must be a single valid IP. Got: %s\n"
                        % ip)
    print("Ip received!")

    return ip

def is_allowed_host(ip):
    host = DNSUtils.ipToName(ip)
    if not host:
        return False
    else:
        m = re.match('.\S+(-\d+)(?P<domain>\.\S+)', host)
        domain = m.group('domain')
        if domain in ALLOWED_HOSTS:
           return True
        else:
           return False

if __name__ == '__main__': # pragma: no cover
    try:
      ret = is_allowed_host(process_args(sys.argv))
    except ValueError as e:
      sys.stderr.write(str(e))
      sys.exit(2)
    sys.exit(0 if ret else 1)
  1. Add this line to the desired jail(s), in /etc/fail2ban/jail.local:

ignorecommand = %(ignorecommands_dir)s/ignorehost <ip>

In my case, I put that line in the ssh and sshd jails:

[sshd]

ignorecommand = %(ignorecommands_dir)s/ignorehost <ip>

[ssh]

ignorecommand = %(ignorecommands_dir)s/ignorehost <ip>
  1. Reload fail2ban

systemctl reload fail2ban.service