PF Communication between fail2ban and pf fails

EDIT: the problem is solved

Hello,

i had used Debian at the last several years and i'm very new to FreeBSD.

I tryed to port my configuration for fail2ban from my Debian machines to FreeBSD (with the modification due the firewall has changed).

In my testing phase i have found out that the recognition works fine as under debian. My IP is under the fail2ban's internal banlist marked (`fail2ban-client status ssh` shows my IP as "currently banned").
The problem is, that i'm still not banned by pf. When i try to ban myself via `/sbin/pfctl -t fail2ban -T add <ip>` it is working fine - pf will add me to my fail2ban table (connections will be refused).
I dont understand why it won't work..

My /usr/local/etc/fail2ban/jail.local configuration is:
Code:
[DEFAULT]

ignoreip = 127.0.0.1/8

# if 10 failures per 6 hours then ban the ip for 24 hours - that seems legit for me, i am the only sysadmin who can access to this systems
# i have in emergency cases every time access to this machines via vnc over my hostsystem
bantime  = 86400
findtime = 21600
maxretry = 10

backend = auto
usedns = warn

#banaction = iptables-multiport # ported from my debian configuration - inactive
protocol = tcp
chain = INPUT


# ported from my debian configuration - inactive
#action_ = %(banaction)s[name=%(__name__)s, port="%(port)s",
#protocol="%(protocol)s", chain="%(chain)s"]
#action = %(action_)s


actionban=/sbin/pfctl -t fail2ban -T add <ip>
actionunban=/sbin/pfctl -t fail2ban -T delete <ip>


[ssh]

enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log

And my /etc/pf.conf is
Code:
# Bezeichnung vom Netzwerkinterface
ext_if="em0"

# erlaubt nur bestimmte Typen von ICMP requests
#icmp_types = "{echoreq, unreach}"
icmp_types = "echoreq"

# Blockiere alles was rein kommt
block in all

# gibt connection refused an den client zurueck anstelle ihn bis zum timeout (vom clientsystem festgelegt) warten zu lassen
block return

# aktiviert den IP spoofing Schutz fuer alle interfaces
block in quick from urpf-failed

# wendet Blockierungsmethoden an gegen IP spoofing fuers angegebene Netzwerkinterface oben
antispoof log for $ext_if


# erlaubt es, dass der server heraustelefonieren darf zb um sich updates zu holen; er darf egal mit welchem Proto hintelefonieren wohin er will
# CHANGEME wird spaeter weiter eingeschraenkt
pass out keep state

# so sieht generell eine Freigaberegel aus - hier fuer ssh
pass in quick on $ext_if inet proto tcp from any to $ext_if port 22

# icmp Freigabe eingehend
pass in quick on $ext_if inet proto icmp all icmp-type $icmp_types keep state



#testabteilung

table <blockedips> persist file "/etc/pf.blocked.ip.conf"
block in quick on $ext_if from <blockedips> to any

table <fail2ban> persist
block in quick on $ext_if from <fail2ban> to any

My /etc/rc.conf is:
Code:
hostname="censored"
keymap="german.iso.kbd"
ifconfig_em0="inet censored netmask 0xfffffff0"
defaultrouter="censored"
ntpd_enable="YES"
dumpdev="AUTO"
#sshd_enable=TRUE #temporary disabled until the fail2ban firewall problem is solved
pf_enable="YES"
fail2ban_enable=TRUE

I'm sorry for my bad english (and the german comments.. just ignore them!).. :)


Thanks in advance!
 
Last edited:
Set banaction to pf.

i have tried the sample configuration of /usr/local/etc/fail2ban/jail.local from
with the recommended banaction.

I had restartet the fail2ban service but i have still the same problem.
fail2ban says to me that i'm banned (via `fail2ban-client status sshd`) but `pfctl -t fail2ban -T show` shows me nothing and i'm still able to connect to the server.

My /usr/local/etc/fail2ban/action.d/pf.conf config is the following:
Code:
# Fail2Ban configuration file
#
# OpenBSD pf ban/unban
#
# Author: Nick Hilliard <nick@foobar.org>
# Modified by: Alexander Koeppe making PF work seamless and with IPv4 and IPv6
#
#

[Definition]

# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
# we don't enable PF automatically; to enable run pfctl -e
# or add `pf_enable="YES"` to /etc/rc.conf (tested on FreeBSD)
# also, these rulesets are loaded into (nested) anchors
# to enable them, add
#     anchor f2b {
#        anchor name1
#        anchor name2
#        ...
#     }
# to your main pf ruleset, where "namei" are the names of the jails
# which invoke this action
actionstart = echo "table <<tablename>-<name>> persist counters" | <pfctl> -f-
              echo "<block> proto <protocol> from <<tablename>-<name>> to <actiontype>" | <pfctl> -f-

# Option:  start_on_demand - to start action on demand
# Example: `action=pf[actionstart_on_demand=true]`
actionstart_on_demand = false

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
# we only disable PF rules we've installed prior
actionstop = <pfctl> -sr 2>/dev/null | grep -v <tablename>-<name> | <pfctl> -f-
             <pfctl> -t <tablename>-<name> -T flush
             <pfctl> -t <tablename>-<name> -T kill


# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = <pfctl> -sr | grep -q <tablename>-<name>


# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    <ip>  IP address
#          <failures>  number of failures
#          <time>  unix timestamp of the ban time
#
actionban = <pfctl> -t <tablename>-<name> -T add <ip>


# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    <ip>  IP address
#          <failures>  number of failures
#          <time>  unix timestamp of the ban time
# Values:  CMD
#
# note -r option used to remove matching rule
actionunban = <pfctl> -t <tablename>-<name> -T delete <ip>

# Option: pfctl
#
# Use anchor as jailname to manipulate affected rulesets only.
# If more parameter expected it can be extended with `pf[pfctl="<known/pfctl> ..."]`
#
#pfctl = pfctl -a f2b/<name>
pfctl = pfctl -a fail2ban

[Init]
# Option:  tablename
# Notes.:  The pf table name.
# Values:  [ STRING ]
#
#tablename = f2b
tablename = fail2ban

# Option: block
#
# The action you want pf to take.
# Probably, you want "block quick", but adjust as needed.
block = block quick

# Option:  protocol
# Notes.:  internally used by config reader for interpolations.
# Values:  [ tcp | udp | icmp | ipv6-icmp ] Default: tcp
#
protocol = tcp

# Option: actiontype
# Notes.: defines additions to the blocking rule
# Values: leave empty to block all attempts from the host
# Default: Value of the multiport
actiontype = <multiport>

# Option: allports
# Notes.: default addition to block all ports
# Usage.: use in jail config: "banaction = pf[actiontype=<allports>]"
allports = any

# Option: multiport
# Notes.: addition to block access only to specific ports
# Usage.: use in jail config: "banaction = pf[actiontype=<multiport>]"
multiport = any port {<port>}

For pfctl i had tried {"pfctl -a f2b/<name>" (default value! creepy but okay), "pfctl -a f2b", "pfctl -a fail2ban"} and for tablename {"f2b", "fail2ban"} - separately, one after another.


In my opinion are the following lines interesting. Are they correctly?
Code:
actionban = <pfctl> -t <tablename>-<name> -T add <ip>
actionunban = <pfctl> -t <tablename>-<name> -T delete <ip>
#pfctl = pfctl -a f2b/<name>
 
Hi Leonard,

I'm seeing exactly the same problem - would you mind telling how you solved the problem on your side? Maybe I'm having the same error.

Regards,
Tobias
 
For any future visitors to this page, I should add that there might be some slight changes in the latest fail2ban (0.10.x +). Details can be found on this page here: http://www.purplehat.org/?page_id=566 and there was also a discussion on git about the topic (scroll to the end if you don't want to read through the whole thing) which can be seen here: https://github.com/fail2ban/fail2ban/issues/1915

The crux of it is that in addition to setting banaction to pf, one needs to add
Code:
anchor "f2b/*"
at/near the top of the /etc/pf.conf file.

The following is copied from the aforementioned purplehat page to ensure that this answer is self-contained, and appropriate changes will need to be made for individual use-cases.

Very basic example of /etc/pf.conf:
Code:
# define macros for each network interface
ext_if = "rl0"

icmp_types = "echoreq"
allproto = "{ tcp, udp, ipv6, icmp, esp, ipencap }"
privnets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"

set loginterface $ext_if

scrub in on $ext_if no-df random-id

# Anchor for fail2ban
anchor "f2b/*"

Excerpt of /usr/local/etc/fail2ban/jail.local:
Code:
[DEFAULT]
banaction = pf[actiontype=<allports>]
banaction = pf[actiontype=<multiport>]
Example of a fail2ban jail:
Code:
[bsd-ssh-pf]
enabled = true
filter = bsd-sshd
logpath = /var/log/auth.log
findtime = 600
maxretry = 3
bantime  = 86400
 
Although there's nothing wrong with simply setting up an extra anchor and then let pf parse those rules it is usually safer to associate the anchor with a specific device. For example:

Code:
anchor "blacklistd/*" in on $ext_if
This makes sure that the rules within blacklistd are only used for incoming data on ext_if (where ext_if is obviously a macro pointing to my real NIC).
 
Although there's nothing wrong with simply setting up an extra anchor and then let pf parse those rules it is usually safer to associate the anchor with a specific device. For example:

Code:
anchor "blacklistd/*" in on $ext_if
This makes sure that the rules within blacklistd are only used for incoming data on ext_if (where ext_if is obviously a macro pointing to my real NIC).

ShelLuser Many thanks for your comment. Apologies if this seems like a dumb remark (I am not sure since I'm only just starting to figure this out), but I get the impression that the f2b anchor is now a hardcoded thing. The purplehat blog post I linked to also states "However, the latest 0.10.1 version is a completely different animal". And reading through the linked git issues thread I got the impression there was a somewhat more fundamental change - meaning that the old setup (which is very nicely detailed in the blogpost SirDice had linked to doesn't work without a slight modification).

When I check in the action.d/pf.conf file, I see that the table name is indeed hardcoded. May I request you to have a look at that file (lines 20, 22, and more importantly 88, 95), and confirm if my hypothesis is correct - that this particular (named) anchor must now be included in the /etc/pf.conf? I copy below the lines from action.d/pf.conf

Code:
 20 #     anchor "f2b/*"
 21 # or using jail names:
 22 #     anchor f2b {
 23 #        anchor name1
 ...
 88 pfctl = pfctl -a f2b/<name>
 ...
 95 tablename = f2b

PS: I am using fail2ban v0.10.3.fix1
 
Apologies if this seems like a dumb remark (I am not sure since I'm only just starting to figure this out), but I get the impression that the f2b anchor is now a hardcoded thing.
I can well imagine. Yeah, re-reading my message I can see how this could be a bit confusing, sorry about that. My example is mostly about the way to define an Anchor, but it should not be taken literally. So ignore the name, and just pay attention to the rest of the definition.

I don't use Fail2Ban myself (well, very sporadically) but mostly rely on blacklistd(5). This is an IDS which is comparable to Fail2Ban with 2 specific differences: it works in real-time and it's part of the FreeBSD base system (FreeBSD 11 and up).

So above I simply shared the snippet from my pf.conf, however I don't use Fail2Ban and I was too lazy to edit my paste ;)

Hope this can help clear things up a bit!
 
I can well imagine. Yeah, re-reading my message I can see how this could be a bit confusing, sorry about that. My example is mostly about the way to define an Anchor, but it should not be taken literally. So ignore the name, and just pay attention to the rest of the definition.

I'll preface this with the caveat that I use fail2ban in a few places and I loathe it. In the past I've had issues with their ssh matching rules failing with FreeBSD (ssh version or config differences between FreeBSD and $SOME_DISTRO), it can be a total memory hog, it's way over-engineered while also being under-engineered, etc. For example, another fun design choice is that the daemon will start and keep running on hitting a fatal error from pf - just why? Bail out if you can't manipulate the firewall rules. Anyhow, that last one is what brought me to this thread.

So if you've never used anchors before (I haven't, also see "over-engineering" above, the old table method was fine and worked for at least a decade), maybe you're reading this thread and wondering "what are anchors?" - I was. Basically anchors allow you to create something of a "sub-ruleset" in your ruleset which can be manipulated independently of the main pf ruleset. This is effectively giving fail2ban the power to add not just IPs to a table, but new rules to your pf config. Anchors can also nest, so you can have an Inception-esque sub-sub-ruleset. You can have tables inside your anchors as well.

The things I found I needed to address to make this work post-upgrade in pf.conf were:

- remove the "fail2ban" table from the config (as this might collide with the anchor rules and was no longer needed in any case)
- add the anchor as 'anchor "f2b/*"'
- remove the rules for the old fail2ban table (I had things like "block in quick from <fail2ban>")

To verify that fail2ban is adding the rule(s): "pfctl -a f2b/bsd-sshd-pf -s rules"
To verify that you have a table created and it has entries: "pfctl -a f2b/bsd-sshd-pf -t f2b-bsd-sshd-pf -T show"
To watch what fail2ban is doing, enable logging - it will log the pf commands it runs to alter the anchor rules. My initial problem was fail2ban trying to create rules in anchors that did not exist/were not permitted.

In short, you can run many pfctl commands on an anchor.

Don't ask me about how those table names were created, I started this post two months ago and just found it today, so I don't remember. :) I believe it coincides with the rules in jail.local. Same with the info below - it works, don't recall why.

I also believe I had to move my "jail.local" to "/usr/local/etc/fail2ban/jail.d/jail.local". My diffs indicate I changed the following in jail.local:

- ban action changed to "banaction = pf[actiontype=<allports>]" from "banaction = pf[actiontype=<multiport>]"
- I renamed their "sshd" action to "bsd-sshd-pf" to help me find where the anchors were created and to lock that in for any future updates that might touch "sshd"
- In my "bsd-sshd-pf" action, I changed the action from "action = pf" to "action = pf[actiontype=<allports>]"
 
Back
Top