PF PF counters: How do I reset them selectively?

I'm hoping someone can help me do what I'm trying to do.

We're talking about the PF firewall.

My goal is to automatically expire table entries, unless they come back before they expire.
An example to clarify:

IP address X is caught executing a bruteforce attack on my SSH port, so I add it to table block22.
I have a cronjob that runs every hour, and expires all entries in table block22 that are older than 24 hours.
However, if IP address X returns within those 24 hours, I want it's timer to be reset, so that it remains quarantined for another 24 hours counting from the last bruteforce attempt.

This way, IP addresses that 'better their lives' are silently removed from the block22 table, while IP addresses that insist on retrying remain there indefinitely.

I was hoping I could do this with the -T zero argument to pfctl in an hourly cronjob. I hoped this would only reset the counters that were not zero, so that the reset time of well-behaving IP addresses would eventually reach 24 hours, and they could be removed from the table.

Code:
pfctl -t block22 -T zero

But unfortunately this resets the statistics for all IP addresses in the table, and not only for those that are non-zero. So no IP address ever expires.

Does anybody have a setup that does roughly what I need?
I would appreciate hearing about it.

Thanks,
Rob
 
I think the -T expire pfctl(8) option does exactly what you want.
Delete addresses which had their statistics cleared
more than number seconds ago. For entries which
have never had their statistics cleared, number
refers to the time they were added to the table.
I presume an addresses' statistics will be reset if it tries to connect again inside the expire period.
 
Hi Jose,

Thanks for that, but unfortunately no.

Addresses only have their statistics cleared explicitly. Which kind of makes sense, because otherwise you would not be able to see how often an IP address tries to connect (if each connection resets the counter, the count is always 1 until it expires, and it becomes 0).
So, to clear the statistics I have to use -T zero. But this clears the statistics for all IP addresses in the table.
And I can't find a command to clear the statistic for a single IP address (or subnet) in a table, without touching the statistics for the other IP addresses in the table.
 
Well, I guess I could script a wrapper around blacklistd/fail2ban/sshguard... (In the mixed Windows/Linux/*BSD environment where I worked some years ago, the goto-phrase was "Ask Rob to write a script around it.").
But I can't imagine this functionality doesn't exist in PF.

The function of a firewall is to keep wrong-doers out, so I can't imagine that I have to resort to work-arounds to keep wrong-doers out.
And besides, if I use a -T delete followed by a -T add, there will always be a gap where malicious connections are allowed.
 
Hi VladiBG.

You're clearly a person of few words... :)
I use fail2ban. I'm sure I could write some scrips around this, but that would be no different from writing some script around PF itself.
I'm looking for some very simple functionality that I can't imagine not existing in PF itself.

But thanks anyway. If no other solutions exist, my solution will indeed be to write a wrapper around blacklistd (I'm planning to replace fail2ban with blacklistd, which is another story).
 
Good, now check the fail2ban manual and read about:
bantime
findtime
maxretry

Edit:
If you still use password auth for SSH it's better to switch to ed25519
 
Good, now check the fail2ban manual and read about:
bantime
findtime
maxretry

Edit:
If you still use password auth for SSH it's better to switch to ed25519
I switched to pubkey authentication 10-15 years ago, and never looked back.

I know these fail2ban parameters exist, but they do not do what I'm looking for.

I know that I can ban an IP address for X time, if it was found to bruteforce my server Y times in Z minutes.

But what I'm looking for, is banning an IP address for a fairly short period X, but restart the count for that period X if this same IP address retries to bruteforce my server within that period X. This way, IP addresses that 'accidentally' bruteforce my server once are released quickly, while repeated offenders remain blocked indefinitely.

This is quite different from blocking an IP address for a longer period, and then re-blocking that IP address if it retries to bruteforce my server.

To name a few differences, if I find what I'm looking for:
  • my initial blocking periods can be way shorter (in my experience, connection attempts for bruteforce attacks are never further apart than 5 minutes, so I can reduce the initial blocking period to <= 10 minutes)
  • following an IP address through my logs will become easier
  • PF and fail2ban will use less resources, because instead of unblocking and re-blocking IP addresses, these IP addresses will just remain blocked
 
For my setup i'm allowing SSH only for specific IP ranges. When i need to connect outside those ranges i'm using VPN.
 
Well, I guess I could script a wrapper around blacklistd/fail2ban/sshguard... (In the mixed Windows/Linux/*BSD environment where I worked some years ago, the goto-phrase was "Ask Rob to write a script around it.").
But I can't imagine this functionality doesn't exist in PF.

The function of a firewall is to keep wrong-doers out, so I can't imagine that I have to resort to work-arounds to keep wrong-doers out.
And besides, if I use a -T delete followed by a -T add, there will always be a gap where malicious connections are allowed.
Yes, but you're getting into tiny percentages here. If you really can't allow any access even for a few fractions of a second to certain services, I wonder about those services.
If you want something really bulletproof like that, you're going to have to roll up your sleeves and extend pf tables to use an RDMS-based back end, or add two-stage commits to the current tables implementation.
 
Well, no matter how you look at it, such a script would feel like a workaround.
And since PF can keep per-IP address statistics, and PF has the functionality to reset statistics, I can't imagine that there is no way to reset the statistics for a single IP address.
 
Well, no matter how you look at it, such a script would feel like a workaround.
And since PF can keep per-IP address statistics, and PF has the functionality to reset statistics, I can't imagine that there is no way to reset the statistics for a single IP address.
Doesn't feel like a workaround at all to me. Fact is, there are hundreds of thousands of machines on the Internet constantly probing all public IPs for vulnerabilities. Those machines and their IPs come and go constantly many times per second. Starting from that assumption, you cannot let your defenses down even for fractions of a second. This is a hard and fast requirement of the first line of defense.

Banning IPs temporarily is a second line of defense at best. It's useless if the first line isn't solid. It doesn't make sense to add tricky two-stage commit logic to it with its high probability of introducing subtle locking bugs.

It's indeed likely that Pf already has all the data and functionality needed to implement this, and it probably just hasn't been added to pftctl. This is probably because no one has needed it badly enough. You know the rest about rolling up your sleeves if you are the person who needs this badly enough.
 
Back
Top