PF DoS - How to extract IP addresses from Apache access.log?

I'm having an ongoing DoS to a certain directory on our Apache web server.

There are a few hundred requests at once, every one to five minutes, always to the same directory, always from the same IP addresses.

As a quick solution, I have removed that directory, making Apache generate a 404 response, and not overload the server.
Otherwise, the server is spiking in CPU, and sometimes dies due to memory issues.

I have both mod evasive and fail2ban installed, but I find them difficult to configure for this.

Is it possible to extract all the IP addresses from
httpd-access.log with awk, cat or grep?
This is how a request looks like:

Code:
123.123.123.123 - - [11/Oct/2025:07:49:48 +0200] 946 69303 "GET /wheels/cars?size=354%2C357%2C458%2C529%2C543 HTTP/1.1" 404 59341 "-" "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/3.1)" www.domain.xyz 443

I need to find a way to set at least two rules e.g status code 404 and target directory "/wheels/cars?size".
There are a lot of examples, but none with two rules.

Thanks,
 
Use fail2ban
failregex = ^<ADDR> \S+ \S+[^"]*"[A-Z]+ /%(baduri)s[^\"]*" 404\s

also you can rate limit the number of the connection per ip address

Code:
         block quick from <bad_hosts>
         pass in on    $ext_if    proto tcp to $webserver    port www keep state \
             (max-src-conn-rate    100/10,    overload <bad_hosts> flush global)
same goes for 443
 
Use fail2ban


also you can rate limit the number of the connection per ip address

Code:
         block quick from <bad_hosts>
         pass in on    $ext_if    proto tcp to $webserver    port www keep state \
             (max-src-conn-rate    100/10,    overload <bad_hosts> flush global)
same goes for 443
It seems to be a distributed attack, all the hundreds of requests have different IP addresses, so I think it would be easiest to block them manually for now.
But I need to look into the regex of fail2ban apache get dos filter - so thanks for the link.
 
awk '($11 == "404") {print $1}' /var/log/access.log|uniq -c |sort -n
this will have the ips with most failed tries at the bottom
if you don't care about this just pipe the awk command thru sort -u
 
Fantastic, thanks a lot!! 🙏

Would it be possible to also set the target directory "wheels/cars" as a string to search for?

Like:

Code:
awk '($11 == "404" && $8 like "/cars/wheels") {print $1}' /var/log/access.log|uniq -c |sort -n
 
Use fail2ban

Code:
block quick from <bad_hosts>
pass in on    $ext_if    proto tcp to $webserver    port www keep state \
(max-src-conn-rate    100/10,    overload <bad_hosts> flush global)

Do you know how I can add port 443 as well?

Would this be correct to add to PF?

Code:
table <bad_hosts> persistant
block quick from <bad_hosts>
pass in on $ext_if proto tcp to $webserver port {80,443} keep state \
(max-src-conn-rate 30/10, overload <bad_hosts> flush global)

And what is $webserver? Server IP address?

Thanks,
 
$webserver is the IP address of the WAN interface.
Table operation is "persist" check the pf.conf man page. You can also limit the number of connections per single IP address.
Check the STATEFUL TRACKING OPTIONS in pf.conf(5) man page for correct syntax.
 
Back
Top