Go to file
john 5981e82ae2 Edits. 2019-12-07 07:04:37 -05:00
Jmakefile Implemented ez_libpthread 2019-12-05 11:00:39 -05:00
LICENSE Initial commit 2019-11-22 22:38:11 -05:00
Makefile Improved installation 2019-12-06 08:50:17 -05:00
README.md Edits. 2019-12-07 07:04:37 -05:00
TODO.txt Useful improvements 2019-12-03 07:55:15 -05:00
addrRpt.c Implemented cached reporting 2019-12-02 21:56:55 -05:00
addrRpt.h Implemented cached reporting 2019-12-02 21:56:55 -05:00
ban2fail.c Changed address report format 2019-12-06 08:44:51 -05:00
ban2fail.cfg Cosmetic edits 2019-12-05 11:03:57 -05:00
ban2fail.h Moved setuid to a later point in execution. 2019-12-03 22:24:42 -05:00
ban2fail.service Improvements to scripts, add cron script for report 2019-11-27 20:25:03 -05:00
ban2fail.sh Added fsckdns program 2019-12-02 10:19:22 -05:00
cfgmap.c Remove commented code blocks, refactor 2019-12-05 09:42:29 -05:00
cfgmap.h Remove commented code blocks, refactor 2019-12-05 09:42:29 -05:00
cntry.c Added CIDR & ipv6 support 2019-11-23 21:22:37 -05:00
cntry.h Add files via upload 2019-11-22 22:40:23 -05:00
cron-rpt.sh Improved reporting 2019-12-06 11:40:48 -05:00
dynstack.c Implemented cached reporting 2019-12-02 21:56:55 -05:00
dynstack.h Implemented cached reporting 2019-12-02 21:56:55 -05:00
es.c Fixed thread cleanup bug, improved README 2019-12-05 14:50:01 -05:00
es.h Fixed comments 2019-12-04 11:40:09 -05:00
ez_es.c Changed address report format 2019-12-06 08:44:51 -05:00
ez_es.h Changed address report format 2019-12-06 08:44:51 -05:00
ez_libanl.c Changed address report format 2019-12-06 08:44:51 -05:00
ez_libanl.h Changed address report format 2019-12-06 08:44:51 -05:00
ez_libc.c Changed address report format 2019-12-06 08:44:51 -05:00
ez_libc.h Changed address report format 2019-12-06 08:44:51 -05:00
ez_libdb.c Changed address report format 2019-12-06 08:44:51 -05:00
ez_libdb.h Changed address report format 2019-12-06 08:44:51 -05:00
ez_libpthread.c Changed address report format 2019-12-06 08:44:51 -05:00
ez_libpthread.h Changed address report format 2019-12-06 08:44:51 -05:00
ez_libz.c Changed address report format 2019-12-06 08:44:51 -05:00
ez_libz.h Changed address report format 2019-12-06 08:44:51 -05:00
fsckdns.c Added fsckdns program 2019-12-02 10:19:22 -05:00
install.sh Improved installation 2019-12-06 08:50:17 -05:00
iptables.c Lots of new reporting features 2019-12-03 21:38:51 -05:00
iptables.h Fixed bug not accounting for unjustly blocked addr 2019-11-26 06:42:23 -05:00
logFile.c Lots of new reporting features 2019-12-03 21:38:51 -05:00
logFile.h Implemented cached reporting 2019-12-02 21:56:55 -05:00
logType.c Fixed omission in DNS reporting 2019-12-04 09:11:39 -05:00
logType.h Fixed omission in DNS reporting 2019-12-04 09:11:39 -05:00
map.c Implemented cached reporting 2019-12-02 21:56:55 -05:00
map.h Add files via upload 2019-11-22 22:40:23 -05:00
maxoff.c Added event server sources 2019-11-29 17:23:16 -05:00
maxoff.h Add files via upload 2019-11-22 22:40:23 -05:00
msgqueue.c Implemented ez_libpthread 2019-12-05 11:00:39 -05:00
msgqueue.h DNS working well now 2019-11-30 14:14:42 -05:00
obsvTpl.c Fixed minor reporting bug 2019-12-03 04:06:45 -05:00
obsvTpl.h Implemented cached reporting 2019-12-02 21:56:55 -05:00
offEntry.c Changed address report format 2019-12-06 08:44:51 -05:00
offEntry.h Lots of new reporting features 2019-12-03 21:38:51 -05:00
pdns.c Fixed thread cleanup bug, improved README 2019-12-05 14:50:01 -05:00
pdns.h addresses reporting of log lines 2019-12-01 22:29:32 -05:00
ptrvec.c Add files via upload 2019-11-22 22:40:23 -05:00
ptrvec.h addresses reporting of log lines 2019-12-01 22:29:32 -05:00
str.c Add files via upload 2019-11-22 22:40:23 -05:00
str.h Add files via upload 2019-11-22 22:40:23 -05:00
target.c Fixed omission in DNS reporting 2019-12-04 09:11:39 -05:00
target.h Lots of new reporting features 2019-12-03 21:38:51 -05:00
timestamp.c Fixed omission in DNS reporting 2019-12-04 09:11:39 -05:00
timestamp.h Fixed omission in DNS reporting 2019-12-04 09:11:39 -05:00
util.c Fixed omission in DNS reporting 2019-12-04 09:11:39 -05:00
util.h Improved reporting features 2019-12-01 13:04:41 -05:00

ban2fail

(C) 2019 John D. Robertson john@rrci.com

ban2fail is a simple and efficient tool to coordinate log file scanning, reporting, and iptables filtering. As the name implies, ban2fail was inspired by the popular fail2ban project (http://fail2ban.org). The main technical advantages ban2fail provides over fail2ban are:

  • All relevant logfiles on disk are scanned, not just the current log files.

  • A unique and transparent caching scheme is employed to make this process at least 100x as fast as doing the same thing with, say, grep.

  • Instantaneously and conveniently produces on command all offending logfile entries which exist somewhere in the logfile history for given address(es).

  • Easily handles hundreds of thousands of blocked IP addresses.

  • Directly calls iptables, and handles filtering rules in batches of 100 per call.

  • Provides integrated reporting with reverse and forward DNS information.

  • When reporting, DNS lookups are performed in parallel with 200 simultaneous lookups.

  • Written in pure C, with less than 15,000 lines of source code.

  • Efficient enough to run every 0.4 seconds without monopolizing a CPU core on a modest server.

ban2fail started with a few hours of frenzied C hacking after my mail server was exploited to deliver spam for others who had cracked a user's SMTP send password. After inspecting the log files I realized that crackers are now using widely distributed attacks, and that I would need an extremely efficient tool that could scan my entire log file history in a fraction of a second on my rather modest Linode virtual server to have a chance of stopping them. Here are the timing results for a typical scan on my server:

real    0m0.325s
user    0m0.186s
sys     0m0.150s

Currently I am running ban2fail from a systemd service file which triggers ban2fail whenever a watched log file is modified. This gives attackers at most a 0.4 second window to do their worst. I hope you find this code useful.

Configuration

ban2fail works from a configuration file found at "/etc/ban2fail/ban2fail.cfg". The overarching premise is that if any REGEX appearing in a LOGTYPE clause matches a line in an associated log file, then by default that IP will be blocked.

LOGTYPE auth {

   # Where to find the log files
   DIR= /var/log
   PREFIX= auth.log

   # How to read the timestamp
   TIMESTAMP auth_ts {
      # isolates the timestamp from a line matched by a TARGET
      REGEX= ^(.*) srv
      # Passed to strptime() to intrepret the timestamp string
      STRPTIME= %b %d %T
      # These stamps do not include the year, so it is implied.
      FLAGS= GUESS_YEAR
   }

   TARGET imap {
      # Pattern to search for, isolates the IP address
      REGEX= imapd.*Login failed.*\[([0-9.a-f:]+)\]$
      # Assign this as the severity of the offense.
      SEVERITY= 3
   }

   TARGET ssh {
      SEVERITY= 4
      REGEX= sshd.*Failed password.*from ([0-9.a-f:]+) port [0-9]+ ssh2$
      REGEX= sshd.*Invalid user.*from ([0-9.a-f:]+) port
   }

   TARGET negotiate_fail {
      SEVERITY= 2
      REGEX= Unable to negotiate with ([0-9.a-f:]+) port
   }

   TARGET dovecot {
      SEVERITY= 3
      REGEX= dovecot.*authentication failure.*rhost=([0-9.a-f:]+)
   }
}

Syntax in the config file is pretty much the same as the nftables syntax. All keywords must be in upper case. Any values in the key=value pairs have whitespace stripped from the beginning and end of the line. Since there is little escaping of characters going on, regular expressions are mostly WYSIWYG. If you have a hash symbol '#' or a double quote '"' in your pattern (which are special characters for the config file parser), you will need to escape them like so:

# Nov 27 02:03:03 srv named[764]: client @0x7fe6a0053420 1.192.90.183#27388 (www.ipplus360.com): query (cache) 'www.ipplus360.com/A/IN' denied
   REGEX= named.*client.* ([0-9.a-f:]+)\#.*denied$

Finding typos and so forth in the config file is easy; use the -v command flag to print all unrecognized content (besides comments).

ban2fail -v

The only way to alter the default blocking behavior is with a MAX_OFFENSES clause. This clause allows you specify how many offenses are tolerated before an IP is blocked. Offenses will naturally disappear as old logfiles are deleted by logrotate.

# Whitelist ourself
MAX_OFFENSES -1 {
# Put your server's IP addresses here
#   IP= 1.2.3.4
   IP= 127.0.0.1
#   IP= dead:beef::20::32a
   IP= ::1
}

# Allegedly legit servers
MAX_OFFENSES 50 {

# Google Ireland
   IP= 2a00:1450:4864:20::32a
   IP= 2a00:1450:4864:20::336

# Google EU
# Attempted to break in
#   IP= 35.205.240.168

# Google US
   IP= 09.85.216.42
# Attempted to break in
#   IP= 130.211.246.128
   IP= 209.85.166.194
   IP= 209.85.166.195
   IP= 209.85.208.67
   IP= 209.85.214.194
   IP= 209.85.215.173
   IP= 209.85.215.175
   IP= 209.85.215.193
   IP= 209.85.216.42
   IP= 2607:f8b0:4864:20::1034
   IP= 2607:f8b0:4864:20::a46

# Yahoo
   IP= 106.10.244.139

# Outlook
   IP= 40.92.4.30
   IP= 40.107.73.61
   IP= 40.107.74.48
   IP= 40.107.74.72 
   IP= 40.107.76.74
   IP= 40.107.79.52
   IP= 40.107.79.59
   IP= 40.107.80.40
   IP= 40.107.80.53
   IP= 40.107.80.78
   IP= 40.107.82.75
   IP= 52.101.129.30
   IP= 52.101.132.108
   IP= 52.101.136.79
   IP= 52.101.140.230
}

# "trusted" addresses
MAX_OFFENSES 200 {

# me from home
#   IP= 1.2.3.4/20

# Customer
#   IP= 5.6.7.8/24
}

If you recieve a complaint about an address unjustly getting blocked, place it in one of the MAX_OFFENSES blocks, and the IP will be unblocked the next time ban2fail runs in production mode.

Working with ban2fail

There are two primary modes in which ban2fail is used:

  • Production mode, where iptables rules are modified.

  • Testing mode, where modifications to blocking rules are merely indicated.

Production

In production mode it is expected that ban2fail is running non-interactively, and no output is printed unless addresses are (un)blocked. It is also possible to generate a listing of addresses, offense counts, and status with the -a command flag. Likewise, a listing of countries and offense counts is available with the -c flag. In order to get DNS information for the -a flag, follow with a plus for all DNS info -a+, or a minus for only legit (backward & forward match) info -a-. In the list, DNS issues are presented like so:

# DNS is good
0 Dec 06 08:31      1/0    offenses AR [BLK] 200.71.237.244     host244.200-71-237.telecom.net.ar

# Reverse lookup failed with DNS server
0 Dec 05 19:43      1/0    offenses GB [BLK] 185.217.230.146     SERVFAIL

# Reverse lookup is a non-existent domain
2 Dec 05 21:11      1/0    offenses US [BLK] 67.205.153.94       NXDOMAIN

# Forward lookup does not match reverse lookup
0 Dec 06 08:40      1/0    offenses LU [BLK] 92.38.132.54       ibocke43.monster !

# Forward DNS record does not exist
0 Dec 06 08:37      1/0    offenses US [BLK] 63.81.90.135       63-81-90-135.nca.lanset.com !!

# DNS is inconclusive due to lack of response from a DNS server
0 Dec 05 22:04      1/0    offenses RU [BLK] 77.221.144.107     news5.burningcoalsa.com ~

If you want to see the offending log lines for specific address(es), supply them on the command line like so:

john@srv:~$  ban2fail 68.183.105.52
====== Report for 68.183.105.52 ======
------- /var/log/auth.log -------------
Dec  5 17:50:47 srv sshd[22326]: Invalid user cron from 68.183.105.52 port 41874
Dec  5 17:50:48 srv sshd[22326]: Failed password for invalid user cron from 68.183.105.52 port 41874 ssh2

Testing

In test mode (-t flag) the presumption is that you are testing a modified configuration which is not yet in place, and that you don't want to disturb the production setup. This is how you might do that:

ban2fail -t myNew.cfg -a

No iptables rules will be modified. You will be shown in the listing which addresses would be (un)blocked if the contents of "myNew.cfg" was in place, and ban2fail was running in production mode.

When you are happy with the new configuration, copy it into place, and the the iptable rule changes will be realized the next time ban2fail runs in production mode.

Building the Project

I've tested ban2fail only on Debian Buster, but it should compile on just about any modern Linux distro. It uses the following libraries:

  • libcrypto from the libssl package, for md5 checksums

  • libGeoIP to identify the country of origin for IP addresses

  • libz to read compressed log files

  • libpthread for parallel DNS lookups (200 simultaneous)

  • libdb caching of offense location and size in log files

Build and install like so:

make release
make install

The make install target calls install.sh, which does a bunch of stuff including setting up and enabling a systemd service, so you might want have a look before pulling the trigger.

ban2fail.service points to ban2fail.sh, which can be tested from the command line for debugging. Remember to make sure the service is disabled:

systemctl stop ban2fail

In order to run ban2fail as non-root user, the user must belong to group 'adm'. This is so in order to run iptables, which is accomplished via setuid(0) at the appropriate time.