Mod_qos Tailblock
Luke Hebert
- 3 minutes read - 474 wordsIf you are running Apache behind mod_qos and seeing a flood of “access denied” entries from a handful of IPs, you can turn that log data into an automatic blocklist with a short bash loop. The script below watches the error log, counts denials per IP, and rejects any address that crosses a threshold.
Continuous Monitor
This loop runs every 10 seconds, inspects the last 1,000 lines of the live error log, and blocks any IP with more than 10 denials that is not already in the bad_list file.
while true; do
tail -1000 /usr/local/apache/logs/error_log \
| grep "access denied" \
| cut -d= -f4 \
| sort \
| uniq -c \
| while read ct ip; do
if [[ $ct -gt 10 ]]; then
if [[ $(grep "$ip" bad_list | wc -l) -gt 0 ]]; then
echo "Blocked ${ip} already"
else
echo "Blocking ${ip}"
iptables -I INPUT -s "$ip" -j REJECT
echo "$ip" >> bad_list
fi
fi
done
sleep 10
doneOne-Time Check of an Archived Log
Use this variant when you want to audit a rotated log file (for example, after an incident) with a higher threshold of 20 denials.
zcat /usr/local/apache/logs/archive/error_log-11-2013.gz \
| tail -5000 \
| grep "access denied" \
| cut -d= -f4 \
| sort \
| uniq -c \
| while read ct ip; do
if [[ $ct -gt 20 ]]; then
if [[ $(grep "$ip" bad_list | wc -l) -gt 0 ]]; then
echo "Blocked ${ip} already"
else
echo "Blocking ${ip}"
iptables -I INPUT -s "$ip" -j REJECT
echo "$ip" >> bad_list
fi
fi
doneHow It Works
tailpulls the most recent log lines.grep "access denied"isolates mod_qos denial entries.cut -d= -f4extracts the client IP (the fourth=-delimited field).sort | uniq -cproduces a count per IP.- The
while readloop compares the count against the threshold. - If the IP is new,
iptables -I INPUT -s <ip> -j REJECTdrops traffic and the IP is appended tobad_listso it is not re-processed.
Notes
The bad_list file must exist in the working directory before you run the script. Create it with touch bad_list if it is missing.
This script inserts rules at the top of the INPUT chain (-I). If you run it repeatedly without checking, you can accumulate duplicate rules. The bad_list check mitigates this, but verify with iptables -L INPUT -n after a run.
Adjust the threshold (-gt 10 or -gt 20) to match your traffic profile. A value that is too low can block legitimate clients that trigger a burst of denials during a page load.
Unblocking an IP
To remove a block, delete the matching iptables rule and remove the IP from bad_list:
iptables -D INPUT -s <ip> -j REJECT
sed -i '/<ip>/d' bad_listReplace <ip> with the actual address.