Howto block unwanted requests to your apache server with DD-WRT

Recently I made a mistake while configuring my Apache web server and the whole world found out that I have an open proxy (which I don't... at least not anymore). My apache was bombarded with proxy requests and I could barely load up any of my websites (this blog included) from both internal network as well as from outside. So, I started to search the web in hopes of finding people with similar problems and their solutions. Here is what I have found on this website:
Step 1: Make sure that your open proxy is turned off.
Place directives below to your httpd.conf file:

ProxyRequests off
<Proxy *>
        AddDefaultCharset off
        Order deny,allow
        Deny from all
</Proxy>

Step 2: Create a default virtual host that would catch all unwanted requests
Add the following VirtualHost definition to your default site

<VirtualHost *:80>
	ServerName default.only
 
	ErrorDocument 403 "403"
 
	<Location />
		Order allow,deny
		Deny from all
	</Location>
 
	LogLevel crit
	LogFormat "%h %>s" minimal
	CustomLog /var/log/apache2/ips.log minimal
</VirtualHost>

Above VirtualHost will catch all requests that do not match any of your other VirtualHosts and serve 'Access Forbidden' error. It will also log all IPs that were caught by this VirtualHost and output results to /var/log/apache2/ips.log in a form of: XXX.XXX.XXX.XXX 403

Step 3: Create a script that will read logged IPs and add a firewall rule to block it from accessing your server.

#!/bin/bash
 
HTTP_CONF_DIR="/etc/apache2/"
LOG_DIR="/var/log/apache2"
HOSTS_DENY="${HTTP_CONF_DIR}/hosts.deny"
LOG_FILE="${LOG_DIR}/ips.log"
TMP_IPTABLES_DENY=`mktemp /tmp/iptables.drop.XXXXXXXX`
TMP_IPTABLES_NEW=`mktemp /tmp/iptables.drop.XXXXXXXX`
TMPFILES="$TMP_IPTABLES_DENY $TMP_IPTABLES_NEW"
# Defaults to 127.0.0.1 if the file doesn't exist or is empty.
IGNORED_HOSTS=`if [ -s ${HTTP_CONF_DIR}/httpblock.ignored ]; then cat ${HTTP_CONF_DIR}/httpblock.ignored; else echo 127.0.0.1; fi`
function dropForbidden() {
  cat $LOG_FILE | grep -vF "$IGNORED_HOSTS" | awk '$2 == 403 || $2 == 400 { print $1 }' | sort | uniq >> $TMP_IPTABLES_NEW
  iptables -L -n | grep DROP | awk '{print $4}' | sort | uniq >> $TMP_IPTABLES_DENY
  FORBIDDEN=`cat $TMP_IPTABLES_NEW | grep -vF --file="$TMP_IPTABLES_DENY"`
  for ip in $FORBIDDEN
  do
   iptables -I INPUT -s $ip -j DROP
  done
}
dropForbidden
rm -f $TMPFILES

The script above is going to scan list of blocked IPs that were logged by Apache, filter out duplicate IPs, filter out previously added IPs and add remaining IPs to your firewall.

Step 4: Create a cron job that will run this script every so often to assure that your firewall is up to date

Step 5: Every now and then, clear out your iptables entrees
This will assure that your tables are always current and don't have any IPs that are no longer a threat to you. If you do not remote your cron job, your iptables will get re-populated with latest offenders.

This approach works great if you want your server to block everything. In my case, however, I wanted my DD-WRT router to do all the heavy lifting and block my offenders before they get to my apache server.
In order to accomplish this task, I made the following modifications to the above-mentioned procedure:

Step 1: Follow step 1 above

Step 2: Follow step 2 above

Step 3: Create a smb mount on your web server and mount it in your DD-WRT

Step 4: Separate the script from Step 3 above into 2 scripts
The first script is going to be executed by the server, where apache resides, and its task will be to filter out IP addresses and save them to a text file, where DD-WRT can access them.
The second script is going to be reading that list and adding those IPs to its internal iptables database.
Here are my scripts:
Server script

#!/bin/sh
 
DDWRT_SHARE="/mnt/dd-wrt"
IPS_ALLOWED="${DDWRT_SHARE}/ips_allow"
IPS_DENIED="${DDWRT_SHARE}/ips_denied"
APACHE_LOG="/var/log/apache2/ips.log"
RES_FILE="${DDWRT_SHARE}/ips_toBlock"
cat /var/log/apache2/default.log | awk '$2 == 403 || $2 == 400  { print $1 }' | sort | uniq | grep -vF --file=${IPS_DENIED} | grep -vF --file=${IPS_ALLOWED} > ${RES_FILE}

DD-WRT script

#!/bin/sh
 
TMP_IPTABLES_NEW="/tmp/smbshare/ips_toBlock"
TMP_IPTABLES_DENY="/tmp/smbshare/ips_denied"
 
FORBIDDEN=`cat $TMP_IPTABLES_NEW`
count=0
for ip in $FORBIDDEN
do
  if [ $count -gt 50 ]
  then
    break
  fi
 
  iptables -I FORWARD -s $ip -j DROP
  count=`expr $count + 1`
done
 
iptables -L FORWARD -n | grep DROP | awk '{print $4}' | sort | uniq > $TMP_IPTABLES_DENY

NOTE: The reason for the loop of 50 is because my routere was overwhelmed and rebooted in the middle of the process. Chunks of 50 additions at a time seemed like a good choice.

Step 4: Setup cron jobs
Add a cron job on a server to update IPs using server script every few mins
Add a cron job on DD-WRT to add new IPs to its internal iptables database

I hope this will help you as much as it helped me!

Comments