Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Sep 2010 19:14:43 +1000 (EST)
From:      Ian Smith <smithi@nimnet.asn.au>
To:        Carmel <carmel_ny@hotmail.com>
Cc:        freebsd-questions@freebsd.org
Subject:   Re: IPFW firewall and TCP ports
Message-ID:  <20100930165112.D62022@sola.nimnet.asn.au>
In-Reply-To: <20100929205531.76F991065713@hub.freebsd.org>
References:  <20100929205531.76F991065713@hub.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
In freebsd-questions Digest, Vol 330, Issue 5, Message: 1
On Wed, 29 Sep 2010 08:16:47 -0400 Carmel <carmel_ny@hotmail.com> wrote:

 > While perusing my Apache httpd-error.log, I noticed a large number of
 > attempts to access my phpmyadmin directory, as well as a few less know
 > others. Most of these probes originated from China. Since I have no
 > legitimate business dealing with that region, I decided to create a
 > table in my IPFW firewall to block them. This is an example:
 > 
 > ## IPFW Firewall Rules
 > 
 > # Set rules command prefix
 > cmd="ipfw -q add"
 > 
 > # public interface name of NIC facing the public Internet
 > pif="nfe0"  
 > 
 > # Lets start by listing known bad IP addresses and blocking them. We
 > # will put them into a table for easier handling.
 > 
 > ipfw -q table 1 add 60.0.0.0/8
 > ipfw -q table 1 add 61.0.0.0/8

Firstly, 60/8 and 61/8 include a lot more of the Asia Pacific region 
than China, including _some_ of the blocks allocated to Australia, New 
Zealand, Japan and many others.  The days of associating /8 blocks with 
countries are long gone.  For some scientific (and policy) rationale of 
the increasingly fragmented nature of new allocations down to /22 (ie 64 
IP addresses) have a look at http://www.potaroo.net/tools/ipv4/

Secondly, there are _dozens_ more IP blocks including Chinese IP space.

Thirdly, the script posted below to deal specifically with the issue you 
mention has caught lots of addresses in many other regions including 
some based or hosted in the USA; the notion that denying China or Europe 
or for that matter North America access will solve any problem is passe.

But if you do want to go down that path, and have any concern to limit 
'collateral damage' from parts of the planet you've nothing particular 
against, at least try to find accurate and complete data.  This is not 
so easy, and needs to be updated frequently as IP4 address space nears 
exhaustion sometime before early 2012 (reference the link above).

For example, if you used http://www.blockacountry.com/ and selected 
Australia, you'd see some 60.* and 61.* blocks mentioned above, but you 
=won't= find 115.70/16 there, ie the address this mail comes from!  This
was a problem when first allocated last year, mostly by people using out 
of date IP blocklists that assumed we were in China .. see the problem?

But ignoring geopolitics or xenophobia and concentrating on technics ..

 > $cmd set 1 deny log all from table\(1\) to any in via $pif
 > 
 > The above is the first entry in my "rules" file. I know that IPFW is
 > working since I have blocked other ports for other services and it has
 > worked correctly.
 > 
 > The problem is that these IPs are not being blocked. I continue to see
 > them listed in the httpd-error.log. I have rebooted my machine and
 > therefore am quite certain that these rules are being loaded.

A simple 'ipfw show' will likely show that rule not there, possibly a 
preexisting 'flush' rule comes after it?  Or, are your other rules all 
in 'set 1'?  Is 'set 1' your current set?  The default is set 0.  If you 
are using multiple sets use ipfw(8)'s -S switch to show disabled rules.

 > The problem is that I probably do not understand how to properly block
 > an IP or range of IPs from accessing my web server correctly. I would
 > really appreciate any assistance.

Modulo a probable flush or set issue, your syntax is right, and tables 
are indeed the way to go; the larger the list, the faster tables work.

So here's my script for dealing with this specific issue; I got tired of 
seeing over 150 requests from each IP of what is clearly a distributed 
bot scanning for */scripts/setup.php and more lately *p=phpinfo(); This 
usually blocks the offending IP before its second request.  FWIW, the 
latest IP logged and blocked was from a hosting company in the US :)

I run eg '# /path/to/botwatch 50 &' to start with the recent log lines.
'# kill /var/run/botwatch.pid' stops it and both of its bg processes.

cheers, Ian

#!/bin/sh
# botwatch smithi 23/7/10: pesky distribot seeking */scripts/setup.php
# v0.7 4/9/10 extend for p=phpinfo() so any others

watchlog=/usr/var/log/httpd-access.log		# combined format:
eg='1.2.3.4 - - [22/Jul/2010:22:40:47 +1000] "GET /pma/scripts/setup.php'
table=1		# ipfw table denying any further access
sleep=10	# max delay before killing pipeline blocking on 'tail -f'
name=`basename $0`
log=/var/log/${name}.log
pid=/var/run/${name}.pid
actions='GET POST HEAD'
ournets='127.0.0 192.168.7 aa.bb.cc xxx.yy.zzz'	# our local IP net/s
blocklist='scripts/setup.php p=phpinfo();'

[ "$1" ] && lines=$1 && shift || lines=1
[ "$1" ] && echo "usage: $name [lines]" && exit 1
[ -s $pid ] && op=`cat $pid` && [ "`ps ax | grep -w $op | grep $name`" ] \
    && echo "`date` $name [$$] exit: [$op] still running" >>$log && exit 2
echo $$ >$pid
echo "`date` $name [$$]: begin lines=$lines" >>$log

tail -f -n$lines $watchlog | \
while read ip a b datime tz get url etc; do
    [ "$url" -a "${actions%${get#\"}*}" != "$actions" ] || continue
    [ "${ournets%${ip%.*}*}" = "$ournets" ] || continue	# don't block me/24
    for string in $blocklist; do
	if [ "${url%$string}" != $url ]; then
	    blocked=`ipfw table $table list | awk '{print $1}' | grep $ip`
	    if [ "$blocked" ]; then		# eg startup $lines > 1
		echo "`date` $blocked already blocked" >>$log
	    else
		ipfw table $table add $ip `date "+%s"` 2>/dev/null
		echo "`date` blocked $ip seeking $string" >>$log
	    fi
	fi
    done
done &			# ; bgpid=$!	# two-process pipeline in bg

quit=0; trap "quit=1" int quit term
while [ $quit -eq 0 ]; do sleep $sleep; done
trap - int quit term

# kill tail, first proc in pipeline; $bgpid is of last proc, no use here
tailpid=`ps ax | grep "[t]ail -f" | grep "$watchlog" | awk '{print $1}'`
[ "$tailpid" ] && kill -TERM $tailpid && sleep 1 \
    || echo "`date` exit tailpid='$tailpid' ?" >>$log
echo "`date` $name [$$]: end (terminated)" >>$log
rm $pid
exit 0



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100930165112.D62022>