Psad detect scan from early blocked host + fail2ban problem

Hello good people, I have scan detection running with psad and it works by logging events to /var/log/psad.conf
I added another chain in the /usr/local/hestia/bin/v-add-firewall-chain file and it now looks like this:

#                       Action                             #

# Self heal iptables links

# Checking known chains
case $chain in
    SSH)        # Get ssh port by reading ssh config file.
                sshport=$(grep '^Port ' /etc/ssh/sshd_config | head -1 | cut -d ' ' -f 2)
                if [ -z "$sshport" ]; then
                protocol=TCP ;;
    FTP)        port=21; protocol=TCP  ;;
    MAIL)       port='25,465,995,993'; protocol=TCP  ;;
    DNS)        port=53; protocol=UDP  ;;
    WEB)        port='80,443'; protocol=TCP  ;;
    DB)         port='3306,5432'; protocol=TCP  ;;
    HESTIA)     port=$hestiaport; protocol=TCP  ;;
    PSAD)       port=''; protocol=ALL  ;;
    RECIDIVE)   port=''; protocol=ALL  ;;
    *)          check_args '2' "$#" 'CHAIN PORT' ;;

I created a very simple filter in /etc/fail2ban/filter.d/psad.conf:


failregex = .* psad: scan detected <HOST> -\> .*
            .* psad: scan detected .* scan\): <HOST> -\> .*

ignoreregex = .* icmp .*

and of course section in jail.local

enabled  = true
filter   = psad
action   = hestia[name=PSAD]
logpath  = /var/log/psad.log
findtime = 2419200
maxretry = 3

So after several times of scanning from “hostile” hosts, the IP is added to the fail2ban-recidive chain on both UDP, TCP and ICMP (I created a separate rule for adding icmp in /usr/local/hestia/bin/v-add-firewall-ban):

# Adding ip to banlist
if [ $chain == "RECIDIVE" ];then

   $iptables -w 15 -I fail2ban-$chain 1 -s $ip -j DROP 2>/dev/null
   $iptables -w 15 -A INPUT -s $ip -p ICMP -j DROP 2>/dev/null

   $iptables -w 15 -I fail2ban-$chain 1 -s $ip -j DROP 2>/dev/null

My problem is that even though the IP address is sitting correctly in the iptables table, psad still detects scans from this address and fail2ban tries to add it to the recidive table again. It looks like:

==> /var/log/psad.log <==
2024-06-06 08:15:17.3279 info psad: scan detected (Nmap -sT or -sS scan): -> tcp: [8702] flags: SYN tcp pkts: 1 DL: 2
2024-06-06 08:15:17.3279 info psad: scan detected (Nmap -sT or -sS scan): -> tcp: [8702] flags: SYN tcp pkts: 1 DL: 2

==> /var/log/fail2ban.log <==
2024-06-06 08:15:17,577 fail2ban.actions        [2042648]: NOTICE  [scan-psad] Ban
2024-06-06 08:15:18,275 fail2ban.actions        [2042648]: WARNING [recidive] already banned

# iptables -nL |grep -w
DROP       icmp --           <- chain INPUT
DROP       all  --           <- chain fail2ban-psad
DROP       all  --           <- chain fail2ban-recidive

What am I doing wrong, or what is iptables doing wrong, or what is psad doing wrong :slight_smile: that I have a very large number of “already banned” in the logs?
Please give me some tips.

Have you tried crowdsec? It does the same thing.

It will break when Hestia gets update … Becarefull with that

You don’t need to edit script v-add-firewall-chain to add PSAD chain.

v-add-firewall-chain PSAD 1:65535

Port can’t be blank, use 0 or 1:65535. For **

**, the same you should use ICMP,, TCP or UDP but not ALL (even if iptables understand it, Hestia won’t take care).

As fasr as I know that is the correct behaviour.

Could you please show the entire output of iptables rules?

iptables -S

Thanks, I know, that’s why I haven’t updated hestia for some time, it’s a simple server, with one domain and all what I need works properly.

Hello sahsanu, thanks for advice, I will test the changes you wrote about and see if the blocking still works well. iptables -S - maybe later because in my case there are several thousand entries, I don’t know how to attach a text file here, it would definitely be better.

Ok - first question - how to create a recidive chain that blocks TCP and UCP and ICMP at the same time? Let’s say some hosts are so aggressive that I want to completely cut them off from hitting the server.

I don’t need to view all the rules, if you are dropping thousands of ips leave only one, I only want to see the order of your rules.

Anyway, if you have thousand of rules, maybe you should create an ipset and block that ipset instead of creating one rule per blocked ip. Performance could be a nightmare with so many individual rules.

You can use an external service like pastebin, gist of Github, etc.

Here you are:
So, I don’t know ipset well, I would have to learn it, and I would like to stay with the fail2ban + hestia mechanisms because I like the way of collecting and controlling blocked hosts.

I don’t have time now to take a deep look (I’ll try to do it later) but the first thing I can say is that you should stop and disable ufw. Hestia and ufw creating and modifying iptables rules at the same time is not a good combination.

Ok, thank you for the advice, I’ve already tested it, but you have to manually add rules to block ports, because by default Hestia allows unnecessary ports.
With UFW:

21/tcp   open  ftp
22/tcp   open  ssh
25/tcp   open  smtp
53/tcp   open  domain
80/tcp   open  http
143/tcp  open  imap
443/tcp  open  https
465/tcp  open  smtps
993/tcp  open  imaps
995/tcp  open  pop3s
9090/tcp open  zeus-admin

Nmap done: 1 IP address (1 host up) scanned in 110.77 seconds

Without UFW:

21/tcp   open  ftp
22/tcp   open  ssh
25/tcp   open  smtp
53/tcp   open  domain
80/tcp   open  http
110/tcp  open  pop3
143/tcp  open  imap
443/tcp  open  https
465/tcp  open  smtps
587/tcp  open  submission
993/tcp  open  imaps
995/tcp  open  pop3s
4190/tcp open  sieve
6010/tcp open  x11
8080/tcp open  http-proxy
8443/tcp open  https-alt
9090/tcp open  zeus-admin

Nmap done: 1 IP address (1 host up) scanned in 17.66 seconds

Hestia only allows ports that are used by the installed services.

Also, the nmap has been issued on your own server because these ports are not open to external connections:

4190/tcp open  sieve
6010/tcp open  x11
8080/tcp open  http-proxy
8443/tcp open  https-alt

And I suppose this one is the port you are using to access to Hestia Control Panel:

9090/tcp open  zeus-admin

Yes, 9090 this is HCP. However, nmap was launched from an external machine, and I assure you that by default I have these ports exposed externally, even though I don’t want it.

$ telnet 8080
Connected to
Escape character is '^]'.

Ok, my question is related to the fact that the blocked IP address is in the iptables tables and yet PSAD detects scanning from this address. Let’s dig into this problem, please.

They are not in a default Hestia installation.

I don’t use PSAD but as far as I know, it relies on logs.

-A INPUT -m set ! --match-set NLOG src -m limit --limit 1/sec --limit-burst 3 -j LOG
-A INPUT -j fail2ban-PSAD

The first rule is logging INPUT access for ips not belonging to NLOG ipset and that rule will be processed before the one that will jump to fail2ban-PSAD chain and BLOCK the ip (if is already there of course) so, the ip could be blocked but still being logged and psad detecting it in the logs.

I added this rule because I had a lot of entries from one IP address (mine) in /var/log/kern.log and it looks like this:

ipset create NLOG hash:ip
ipset add NLOG 77.xx.xx.xx
iptables -w10 -I INPUT -m set ! --match-set NLOG src -m limit --limit 1/second --limit-burst 3 -j LOG

Are you suggesting that this rule should be moved below -A INPUT -j fail2ban-PSAD?

Yes, I’m

Ok, thank you very much for your time, I implemented your suggestions, and at the same time I changed the package logging file from kern.log to iptables.log using the appropriate prefix from the iptables rule. I also improved the psad configuration by disabling the creation of chains and entries in iptables and leaving it solely to fail2ban.
As for open ports - maybe it’s a problem with the older version of hestiacp, but I’ve made so many “improvements” in various places that I’m afraid to release the update and I don’t have that much time to fix it later.
If anything we wrote here helps, I will let you know after some time of observation.

1 Like

Hi. I have been observing the effects of the modification for a long time and I can say that now everything is fine.
However, I found cases like this:

2024-06-20 08:35:16,012 fail2ban.actions [375668]: NOTICE [dovecot] already banned
2024-06-20 08:35:17,635 fail2ban.actions [375668]: NOTICE [exim] already banned

which say that two independent filters matched the rule from the logs. To prevent this situation, I slightly modified the action file:

actionban = tail -1 /var/log/hestia/system.log|grep -q -w <ip> || /usr/local/hestia/bin/v-add-firewall-ban <ip> <name> 2>/dev/null

so if almost the ip address has been blocked and it has been logged from the system.log file, the next blocking attempt will be stopped. Let me know what you think about it, from my observations everything is working fine so far.


I see no problem when an ip has been already banned, I won’t be worried about that and I won’t modify actionbam but if you want to do it, maybe tail -1 is a bit short, I’ll give it -15 or -30.

Thank for reply :slight_smile:
Today I modified this line because a moment after unblocking the IP, an event qualifying for blocking occurred again. However, the block did not occur because the last line of the system.log contained this IP address due to unblocking. And fail2ban got dizzy :).

grep '' /var/log/fail2ban.log 
2024-06-26 11:42:24,015 fail2ban.actions        [3233945]: NOTICE  [sshd] Ban
2024-06-26 12:12:23,164 fail2ban.actions        [3233945]: NOTICE  [sshd] Unban
2024-06-26 12:12:34,544 fail2ban.actions        [3233945]: NOTICE  [sshd] Ban
2024-06-26 12:13:29,233 fail2ban.actions        [3233945]: NOTICE  [sshd] already banned
2024-06-26 12:14:24,686 fail2ban.actions        [3233945]: WARNING [sshd] already banned
2024-06-26 12:15:26,821 fail2ban.actions        [3233945]: WARNING [sshd] already banned
grep '' /var/log/hestia/system.log 
2024-06-26 11:42:24 v-add-firewall-ban  '' 'SSH'
2024-06-26 12:12:23 v-delete-firewall-ban  '' 'SSH'

Corrected line in action file:

actionban = tail -1 /var/log/hestia/system.log|grep -w <ip>|grep -q add || /usr/local/hestia/bin/v-add-firewall-ban <ip> <name> 2>/dev/null

And why is tail -1 - because of the desire to eliminate collisions with an event that almost happened. If I gave more than 1, it could cause the situation as above.

1 Like