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>