milprog edited this page Sep 10, 2017 · 19 revisions

For using fail2ban together with FireHOL, if you have a recent version of fail2ban and ipset installed, modify the jail.local file as follows:

banaction = iptables-ipset-proto6-allports

fail2ban then creates and manages its own ipsets (named f2b-xxxx). Don't use ipset names within your own scripts starting with f2b- to avoid naming conflicts. This solution was tested with CentOS 7.3 and fail2ban 0.9.6 . To avoid problems with two independent processes (FireHOL and fail2ban) using the iptables command, a recent version of iptables (>= 1.4.20) with the -w switch should be used (stock CentOS 7 is ok, CentOS 6 unfortunately not). fail2ban already does this by default on CentOS 7, for FireHOL it might be necessary to add the following line to /etc/firehol/firehol-defaults.conf (adapt the iptables path according to your distro):

IPTABLES_CMD="/sbin/iptables -w"

To ensure that fail2ban reinserts its iptables rules after restarting FireHOL, add the following line to the end of your firehol.conf script:

postprocess -warn /bin/fail2ban-client reload || return 1

Another solution (original solution on this wiki page):

This Linux-based solution is tested under Ubuntu 16.04. In it, fail2ban's banning and unbanning actions tweak an ipset named "fail2ban" used by firehol as a blacklist.

(1) Ubuntu 16.04's version of firehol lacks the ipset facility that permits IP blacklist(s) to be updated in real time without restarting firehol. Therefore we installed version 3.1.1. We built it from source, but Debian has a package (this link is for the x86_64 platform) that works.

(2) We installed the Ubuntu 16.04 fail2ban package.

(3) We created a new fail2ban so-called "action" module, /etc/fail2ban/action.d/firehol.conf (shown directly below).
It tells fail2ban what to do in order to tweak the ipset called "fail2ban". (As you can see below, the ipset can be tweaked by calling a script which, on our machines, lives at /usr/local/ch-tools3/fail2banTweakFireholBlacklist.)

# Fail2Ban configuration file


before = iptables-common.conf


# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
actionstart = /usr/local/ch-tools3/fail2banTweakFireholBlacklist b
# this is a no-op

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
actionstop = /usr/local/ch-tools3/fail2banTweakFireholBlacklist e
# this is a no-op

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
actioncheck = /usr/local/ch-tools3/fail2banTweakFireholBlacklist c
# this is a no-op

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
actionban = /usr/local/ch-tools3/fail2banTweakFireholBlacklist i <ip>
# this adds <ip> to ipset "fail2ban"

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
actionunban = /usr/local/ch-tools3/fail2banTweakFireholBlacklist r <ip>
# this removes <ip> from ipset "fail2ban"


Below is the source code of the fail2banTweakFireholBlacklist script that is called by the above "action" module. (Note: Under Ubuntu, setuid scripts must be encapsulated in setuid C programs as shown below. We didn't test the script without the setuid feature, which we felt was needed because we are expecting to call the same script from within other tools, such as Apache 2.4, that, unlike fail2ban, are never run as root. If that's not a requirement for you, then you don't need a setuid script, and you can call ipset directly in the action module.)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main( int argc, char ** argv)
   int uid;
   char * blacklistFilePath = "/etc/firehol/blacklist";
   char * blacklistPreviousFilePath = "/etc/firehol/blacklist.previous";
   char bashScript[ 5000];
   char * executableFilePath;
   char * command;
   char * iP;

   uid = getuid();
   setuid( 0);

   executableFilePath = argv[ 0];
   if ( argc > 1) {
       command = argv[ 1];
   } else {
       command = "";
   if ( argc > 2) {
       iP = argv[ 2];
   } else {
       iP = "";
   sprintf( bashScript, "/bin/bash -c '#!/bin/bash \n\
executableFilePath=%s \n\
command=%s \n\
iP=%s \n\
blacklistFilePath=%s \n\
blacklistPreviousFilePath=%s \n\
executableFileName=`basename $executableFilePath` \n\
set -e \n\
Usage() \n\
{ \n\
    cat - << __EOF__ \n\
Usage: $executableFilePath <command> [<IP>] \n\
commands: \n\
b       Begin firehol involvement in fail2ban operation (actionstart) (no-op) \n\
e       End firehol involvement in fail2ban operation (actionstop) (no-op) \n\
c       Check (actioncheck) (no-op) \n\
i <IP>  Insert IP in ipset \"fail2ban\" \n\
r <IP>  Remove IP from ipset \"fail2ban\" \n\
    exit 1 \n\
} \n\
case $command in \n\
    b) \n\
        exit 0 ;; \n\
    e) \n\
        exit 0 ;; \n\
    c) \n\
        exit 0 ;; \n\
    i) \n\
        ipset add fail2ban \"${iP}\" ;; \n\
    r) \n\
        ipset del fail2ban \"${iP}\" ;; \n\
    *) \n\
        echo -n unrecognized command: ${command} \n\
        Usage;; \n\
esac \n\
exit 0 \n\
'", executableFilePath, command, iP, blacklistFilePath, blacklistPreviousFilePath);

   return system( bashScript) >> 8;

(4) We tweaked the contents of /etc/fail2ban/jail.conf and /etc/fail2ban/jail.local in several places so that fail2ban would use the above "firehol" action:

banaction = firehol
action = firehol


(5) We tweaked the contents of /etc/firehol/firehol.conf so that firehol creates the "fail2ban" ipset whenever it starts, and so that it uses that same ipset as a blacklist. Here is an example of such a configuration file:

version 6

ipv4 ipset create fail2ban hash:ip
blacklist4 full ipset:fail2ban

interface any world
    policy drop
    protection all

    server ssh accept

    client all accept

(6) When we tested this solution on a server under more or less constant attack, rebooting revealed a synchronization problem. Fail2ban's database of "found" and banned IPs, /var/lib/fail2ban/fail2ban.sqlite3, is persistent, while ipsets are ephemeral. The telltale symptom was that in /var/log/fail2ban.log, we saw IPs being encountered that fail2ban considered already banned.

Fail2ban was encountering these already-banned IPs because the ipset in which they had been originally entered had been replaced by an empty one at reboot time -- thus unbanning all IPs -- while fail2ban's persistent database continued to exhibit them as banned.

The problem is easily remedied by maintaining fail2ban's database in memory, changing:

dbfile = /var/lib/fail2ban/fail2ban.sqlite3


dbfile = :memory:

If reboots are infrequent, the loss of banned-IP state at reboot time probably doesn't make much difference.

FireHOL installation


Link Balancer - routing tables with inheritance, multiple balancing gateways, routing rules

FireHOL & iptables marks

FireHOL & ipsets

FireHOL & SYNPROXY (DDoS mitigation)

FireHOL with basic IDS - just with plain iptables and ipsets

Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.