#!/bin/bash Version=0.1.2 export PATH="/bin:/sbin/:/usr/bin:/usr/sbin" #Copyright 2001 William Stearns #Released under the GPL. #Format=ascii|html-pre-bare|html-pre-full-page #html-table-full-page|html-table-bare later #FIXME - Load settings from the command line or $QUERY_STRING #Hard code here for testing. Format=html-pre-full-page #FIXME - when no fields to submit, it appears QUERY_STRING is blank. lc () { echo "$*" | tr A-Z a-z } uc () { echo "$*" | tr a-z A-Z } #------------------------------------------------------------------------- # mask2cisco function, returns the cisco "reverse netmask" of the netmask parameter. #------------------------------------------------------------------------- #No external apps needed. mask2cisco () { #SUDO checked #This could be done in fewer lines by subtracting each octet from 255. #I'm trying to avoid forking as it hurts performance. case $1 in 32|255.255.255.255) echo 0.0.0.0 ;; 31|255.255.255.254) echo 0.0.0.1 ;; 30|255.255.255.252) echo 0.0.0.3 ;; 29|255.255.255.248) echo 0.0.0.7 ;; 28|255.255.255.240) echo 0.0.0.15 ;; 27|255.255.255.224) echo 0.0.0.31 ;; 26|255.255.255.192) echo 0.0.0.63 ;; 25|255.255.255.128) echo 0.0.0.127 ;; 24|255.255.255.0) echo 0.0.0.255 ;; 23|255.255.254.0) echo 0.0.1.255 ;; 22|255.255.252.0) echo 0.0.3.255 ;; 21|255.255.248.0) echo 0.0.7.255 ;; 20|255.255.240.0) echo 0.0.15.255 ;; 19|255.255.224.0) echo 0.0.31.255 ;; 18|255.255.192.0) echo 0.0.63.255 ;; 17|255.255.128.0) echo 0.0.127.255 ;; 16|255.255.0.0) echo 0.0.255.255 ;; 15|255.254.0.0) echo 0.1.255.255 ;; 14|255.252.0.0) echo 0.3.255.255 ;; 13|255.248.0.0) echo 0.7.255.255 ;; 12|255.240.0.0) echo 0.15.255.255 ;; 11|255.224.0.0) echo 0.31.255.255 ;; 10|255.192.0.0) echo 0.63.255.255 ;; 9|255.128.0.0) echo 0.127.255.255 ;; 8|255.0.0.0) echo 0.255.255.255 ;; 7|254.0.0.0) echo 1.255.255.255 ;; 6|252.0.0.0) echo 3.255.255.255 ;; 5|248.0.0.0) echo 7.255.255.255 ;; 4|240.0.0.0) echo 15.255.255.255 ;; 3|224.0.0.0) echo 31.255.255.255 ;; 2|192.0.0.0) echo 63.255.255.255 ;; 1|128.0.0.0) echo 127.255.255.255 ;; 0|0.0.0.0) echo 255.255.255.255 ;; *) echo UnknownNetmaskError ;; esac } #End of mask2cisco #------------------------------------------------------------------------- # mask2cidr function, returns the cidr equivalent of the netmask parameter. #------------------------------------------------------------------------- #No external apps needed. mask2cidr () { #SUDO checked case $1 in 32|255.255.255.255) echo 32 ;; 31|255.255.255.254) echo 31 ;; 30|255.255.255.252) echo 30 ;; 29|255.255.255.248) echo 29 ;; 28|255.255.255.240) echo 28 ;; 27|255.255.255.224) echo 27 ;; 26|255.255.255.192) echo 26 ;; 25|255.255.255.128) echo 25 ;; 24|255.255.255.0) echo 24 ;; 23|255.255.254.0) echo 23 ;; 22|255.255.252.0) echo 22 ;; 21|255.255.248.0) echo 21 ;; 20|255.255.240.0) echo 20 ;; 19|255.255.224.0) echo 19 ;; 18|255.255.192.0) echo 18 ;; 17|255.255.128.0) echo 17 ;; 16|255.255.0.0) echo 16 ;; 15|255.254.0.0) echo 15 ;; 14|255.252.0.0) echo 14 ;; 13|255.248.0.0) echo 13 ;; 12|255.240.0.0) echo 12 ;; 11|255.224.0.0) echo 11 ;; 10|255.192.0.0) echo 10 ;; 9|255.128.0.0) echo 9 ;; 8|255.0.0.0) echo 8 ;; 7|254.0.0.0) echo 7 ;; 6|252.0.0.0) echo 6 ;; 5|248.0.0.0) echo 5 ;; 4|240.0.0.0) echo 4 ;; 3|224.0.0.0) echo 3 ;; 2|192.0.0.0) echo 2 ;; 1|128.0.0.0) echo 1 ;; 0|0.0.0.0) echo 0 ;; *) echo UnknownNetmaskError ;; esac } #End of mask2cidr #------------------------------------------------------------------------- # port2ciscoport function, returns the individual port or range of # ports for the given port/port range and protocol parameters in cisco format. #------------------------------------------------------------------------- port2ciscoport () { #SUDO checked #Parameters: $1 is the port number, $2 is the protocol PCPRETVAL="" case "$1/$2" in 0:1023/*) PCPRETVAL=" lt 1024" ;; 1024:65535/*) PCPRETVAL=" gt 1023" ;; #FIXME - this does not drop the protocol, I think. *:*/*) PCPRETVAL=" range ${1%%:*} ${1##*:}" ;; 179/tcp|bgp/tcp) PCPRETVAL=" eq bgp" ;; 19/tcp|chargen/tcp|ttyst/tcp|source/tcp) PCPRETVAL=" eq chargen" ;; 13/tcp|daytime/tcp) PCPRETVAL=" eq daytime" ;; 9/tcp|discard/tcp|sink/tcp|null/tcp) PCPRETVAL=" eq discard" ;; 53/tcp|domain/tcp|dns/tcp) PCPRETVAL=" eq domain" ;; 7/tcp|echo/tcp) PCPRETVAL=" eq echo" ;; 79/tcp|finger/tcp) PCPRETVAL=" eq finger" ;; 21/tcp|ftp/tcp) PCPRETVAL=" eq ftp" ;; 20/tcp|ftp-data/tcp) PCPRETVAL=" eq ftp-data" ;; 70/tcp|gopher/tcp) PCPRETVAL=" eq gopher" ;; 101/tcp|hostname/tcp|hostnames/tcp) PCPRETVAL=" eq hostname" ;; 194/tcp|irc/tcp) PCPRETVAL=" eq irc" ;; 543/tcp|klogin/tcp) PCPRETVAL=" eq klogin" ;; 544/tcp|kshell/tcp|krcmd/tcp) PCPRETVAL=" eq kshell" ;; 515/tcp|lpd/tcp|printer/tcp|spooler/tcp) PCPRETVAL=" eq lpd" ;; 109/tcp|pop-2/tcp|pop2/tcp|postoffice/tcp) PCPRETVAL=" eq pop2" ;; 110/tcp|pop-3/tcp|pop3/tcp) PCPRETVAL=" eq pop3" ;; 25/tcp|smtp/tcp) PCPRETVAL=" eq smtp" ;; 111/tcp|sunrpc/tcp|portmapper/tcp) PCPRETVAL=" eq sunrpc" ;; #I think the following was a mistake. Cisco's docs show a TCP syslog - I dont think there is one. syslog/tcp) PCPRETVAL=" eq syslog" ;; 65/tcp|tacacs-ds/tcp) PCPRETVAL=" eq tacacs-ds" ;; 517/tcp|talk/tcp) PCPRETVAL=" eq talk" ;; 23/tcp|telnet/tcp) PCPRETVAL=" eq telnet" ;; 37/tcp|time/tcp|timserver/tcp) PCPRETVAL=" eq time" ;; 540/tcp|uucp/tcp|uucpd/tcp) PCPRETVAL=" eq uucp" ;; 43/tcp|whois/tcp|nicname/tcp) PCPRETVAL=" eq whois" ;; 80/tcp|www/tcp|http/tcp) PCPRETVAL=" eq www" ;; 512/udp|biff/udp|comsat/udp) PCPRETVAL=" eq biff" ;; 68/udp|bootpc/udp) PCPRETVAL=" eq bootpc" ;; 67/udp|bootps/udp) PCPRETVAL=" eq bootps" ;; 9/udp|discard/udp|sink/udp|null/udp) PCPRETVAL=" eq discard" ;; 53/udp|dns/udp|domain/udp) PCPRETVAL=" eq dns" ;; 90/udp|dnsix/udp) PCPRETVAL=" eq dnsix" ;; 7/udp|echo/udp) PCPRETVAL=" eq echo" ;; 434/udp|mobile-ip/udp|mobileip-agent/udp) PCPRETVAL=" eq mobile-ip" ;; 42/udp|nameserver/udp|name/udp) PCPRETVAL=" eq nameserver" ;; 138/udp|netbios-dgm/udp) PCPRETVAL=" eq netbios-dgm" ;; 137/udp|netbios-ns/udp) PCPRETVAL=" eq netbios-ns" ;; 123/udp|ntp/udp) PCPRETVAL=" eq ntp" ;; 520/udp|rip/udp|route/udp|router/udp|routed/udp) PCPRETVAL=" eq rip" ;; 161/udp|snmp/udp) PCPRETVAL=" eq snmp" ;; 162/udp|snmptrap/udp|snmp-trap/udp) PCPRETVAL=" eq snmptrap" ;; 111/udp|sunrpc/udp|portmapper/udp) PCPRETVAL=" eq sunrpc" ;; 514/udp|syslog/udp) PCPRETVAL=" eq syslog" ;; 65/udp|tacacs-ds/udp) PCPRETVAL=" eq tacacs-ds" ;; 517/udp|talk/udp) PCPRETVAL=" eq talk" ;; 69/udp|tftp/udp) PCPRETVAL=" eq tftp" ;; 37/udp|time/udp) PCPRETVAL=" eq time" ;; 513/udp|who/udp|whod/udp) PCPRETVAL=" eq who" ;; 177/udp|xdmcp/udp) PCPRETVAL=" eq xdmcp" ;; *) PCPRETVAL=" eq $1" ;; esac echo "$PCPRETVAL" } #End of port2ciscoport ClearOptions () { unset SourceAddress SourceNetmask SourcePort DestinationAddress DestinationNetmask DestinationPort \ Protocol Description RuleType } ParseOption () { ONEVAL=`echo ${1##*=} | sed -e 's/\+/ /g'` #Finally replace any html-encoded embedded spaces in Description case $1 in SourceAddress=*) SourceAddress="$ONEVAL" ;; SourceNetmask=*) SourceNetmask="$ONEVAL" ;; SourcePort=*) SourcePort="$ONEVAL" ;; DestinationAddress=*) DestinationAddress="$ONEVAL" ;; DestinationNetmask=*) DestinationNetmask="$ONEVAL" ;; DestinationPort=*) DestinationPort="$ONEVAL" ;; Protocol=*) Protocol="$ONEVAL" ;; Description=*) Description="$ONEVAL" ;; RuleType=*) RuleType="$ONEVAL" ;; esac } GenericHeader () { case $Format in html-pre-full-page) cat < $Description Firewall blocking rules EOTEXT ;; esac case $Format in html-pre-*) echo '
'
		;;
	esac
}

GenericFooter () {
	case $Format in
	html-pre-*)
		echo '
' ;; esac case $Format in html-pre-full-page) cat <Please enter the IP and/or port(s) you wish to block. Any of the following may be left blank; blank addresses will be treated as "any address", blank ports will be treated as "any port" and blank netmasks will be treated as "single host".

Source Address
Examples: somehost, somehost.somedomain.com, 1.2.3.4
Source Netmask
Examples: 255.128.0.0, 255.255.255.0, 8, 24 .
Source Port
Examples: 12, 1024:65535
Destination Address
(Same format as Source Address)
Destination Netmask
(Same format as Source Netmask)
Destination Port
(Same format as Source Port)
Protocol tcp udp
Description
(short alphanumeric description)
Rule type desired all iptables ipchains ipfwadm ios ipfilter snort

Created by the blockrules $Version program. See http://www.stearns.org for more information about this tool and updated versions.

EOTEXT #method=get places params on the url, method=post places them on stdin ;; esac } readlog () { if read DestinationPort ; then return 0 #True else return 1 #False fi } showrule () { #SourceAddress SourceNetmask SourcePort DestinationAddress DestinationNetmask DestinationPort Protocol if [ -n "$SourcePort$DestinationPort" ] && [ -z "$Protocol" ]; then Protocol="tcp" echo '#TCP protocol assumed' fi if [ -z "$SourceAddress" ] && [ -n "$SourceNetmask" ]; then echo '#Source Netmask specified without Source Address, Netmask cleared.' SourceNetmask='' fi if [ -z "$DestinationAddress" ] && [ -n "$DestinationNetmask" ]; then echo '#Destination Netmask specified without Destination Address, Netmask cleared.' DestinationNetmask='' fi if [ -z "$RuleType" ]; then RuleType="all" fi if [ "$RuleType" = "all" ] || [ "$RuleType" = "iptables" ]; then echo echo '# Iptables' #Takes /n or /255.255... Params="" if [ -n "$Protocol" ]; then Params="$Params -p `lc $Protocol`" ; fi if [ -n "$SourceAddress" ]; then Params="$Params -s $SourceAddress" if [ -n "$SourceNetmask" ]; then Params="$Params/$SourceNetmask" fi fi if [ -n "$SourcePort" ]; then Params="$Params --sport $SourcePort" ; fi if [ -n "$DestinationAddress" ]; then Params="$Params -d $DestinationAddress" if [ -n "$DestinationNetmask" ]; then Params="$Params/$DestinationNetmask" fi fi if [ -n "$DestinationPort" ]; then Params="$Params --dport $DestinationPort" ; fi echo 'iptables -A INPUT' $Params '-j LOG --log-level info #' $Description echo 'iptables -A INPUT' $Params '-j DROP #' $Description echo 'iptables -A FORWARD' $Params '-j LOG --log-level info #' $Description echo 'iptables -A FORWARD' $Params '-j DROP #' $Description fi if [ "$RuleType" = "all" ] || [ "$RuleType" = "ipchains" ]; then echo echo '# Ipchains' #Takes /n or /255.255... Params="" if [ -n "$Protocol" ]; then Params="$Params -p `lc $Protocol`" ; fi if [ -n "$SourceAddress$SourcePort" ]; then Params="$Params -s" if [ -n "$SourceAddress" ]; then Params="$Params $SourceAddress" if [ -n "$SourceNetmask" ]; then Params="$Params/$SourceNetmask" fi else Params="$Params 0/0" fi if [ -n "$SourcePort" ]; then Params="$Params $SourcePort" fi fi if [ -n "$DestinationAddress$DestinationPort" ]; then Params="$Params -d" if [ -n "$DestinationAddress" ]; then Params="$Params $DestinationAddress" if [ -n "$DestinationNetmask" ]; then Params="$Params/$DestinationNetmask" fi else Params="$Params 0/0" fi if [ -n "$DestinationPort" ]; then Params="$Params $DestinationPort" fi fi echo 'ipchains -A input' $Params '-l -j DENY #' $Description fi if [ "$RuleType" = "all" ] || [ "$RuleType" = "ipfwadm" ]; then #Sample: /sbin/ipfwadm -a accept -W lo -I -P tcp -S localhost/32 1024:65535 -D localhost/32 auth echo echo '# Ipfwadm' #Takes /n or /255.255... Params="" if [ -n "$Protocol" ]; then Params="$Params -P `lc $Protocol`" ; fi if [ -n "$SourceAddress$SourcePort" ]; then Params="$Params -S" if [ -n "$SourceAddress" ]; then Params="$Params $SourceAddress" if [ -n "$SourceNetmask" ]; then Params="$Params/$SourceNetmask" fi else Params="$Params 0/0" fi if [ -n "$SourcePort" ]; then Params="$Params $SourcePort" fi fi if [ -n "$DestinationAddress$DestinationPort" ]; then Params="$Params -D" if [ -n "$DestinationAddress" ]; then Params="$Params $DestinationAddress" if [ -n "$DestinationNetmask" ]; then Params="$Params/$DestinationNetmask" fi else Params="$Params 0/0" fi if [ -n "$DestinationPort" ]; then Params="$Params $DestinationPort" fi fi echo 'ipfwadm -a deny -I' $Params '-o #' $Description fi if [ "$RuleType" = "all" ] || [ "$RuleType" = "ios" ]; then echo echo '! Cisco IOS' if [ -n "$Description" ]; then echo '!' "$Description" fi Params="" if [ -n "$Protocol" ]; then Params="$Params `lc $Protocol`" fi if [ -n "$SourceAddress" ]; then if [ -n "$SourceNetmask" ]; then Params="$Params $SourceAddress `mask2cisco $SourceNetmask`" else Params="$Params host $SourceAddress" fi else Params="$Params any" fi if [ -n "$SourcePort" ]; then Params="$Params $(port2ciscoport $(lc $SourcePort) $(lc $Protocol))" fi if [ -n "$DestinationAddress" ]; then if [ -n "$DestinationNetmask" ]; then Params="$Params $DestinationAddress `mask2cisco $DestinationNetmask`" else Params="$Params host $DestinationAddress" fi else Params="$Params any" fi if [ -n "$DestinationPort" ]; then Params="$Params $(port2ciscoport $(lc $DestinationPort) $(lc $Protocol))" fi echo 'Access-list 101 deny' $Params 'log' fi if [ "$RuleType" = "all" ] || [ "$RuleType" = "ipfilter" ]; then echo echo '# ipfilter' #takes /n or /255.255.. Params="" if [ -n "$Protocol" ]; then Params="$Params proto $Protocol" ; fi if [ -n "$SourceAddress" ]; then Params="$Params from $SourceAddress" if [ -n "$SourceNetmask" ]; then Params="$Params/$SourceNetmask" fi else Params="$Params from any" fi if [ -n "$SourcePort" ]; then Params="$Params port = $SourcePort" ; fi if [ -n "$DestinationAddress" ]; then Params="$Params to $DestinationAddress" if [ -n "$DestinationNetmask" ]; then Params="$Params/$DestinationNetmask" fi else Params="$Params to any" fi if [ -n "$DestinationPort" ]; then Params="$Params port = $DestinationPort" ; fi echo 'block in log' $Params '#' $Description #"block in log quick" not needed; the quick keyword reverses the processing order. fi if [ "$RuleType" = "all" ] || [ "$RuleType" = "snort" ]; then #Sample: alert TCP $EXTERNAL any -> $INTERNAL 617 (msg: "IDS261/dos-arkiea-backup"; flags: AP; dsize: >1445;) echo echo '# Snort IDS' #takes /n only Params="" if [ -n "$Protocol" ]; then Params="$Params `uc $Protocol`" ; fi #FIXME - $EXTERNAL vs. source address. #FIXME - numeric IP's only if [ -n "$SourceAddress" ]; then Params="$Params $SourceAddress" if [ -n "$SourceNetmask" ]; then Params="$Params/`mask2cidr $SourceNetmask`" fi else Params="$Params any" fi if [ -n "$SourcePort" ]; then Params="$Params $SourcePort" else Params="$Params any" fi case $Format in html-*) Params="$Params ->" ;; *) Params="$Params ->" ;; esac #FIXME - $INTERNAL vs. dest address #FIXME - numeric IP's only if [ -n "$DestinationAddress" ]; then Params="$Params $DestinationAddress" if [ -n "$DestinationNetmask" ]; then Params="$Params/`mask2cidr $DestinationNetmask`" fi else Params="$Params any" fi if [ -n "$DestinationPort" ]; then Params="$Params $DestinationPort" else Params="$Params any" fi if [ -n "$Description" ]; then echo 'alert' $Params "(msg: \"$Description\")" else echo 'alert' $Params fi fi #if [ "$RuleType" = "all" ] || [ "$RuleType" = "" ]; then # echo # echo '# Template' # Params="" # if [ -n "$Protocol" ]; then Params="$Params $Protocol" ; fi # if [ -n "$SourceAddress" ]; then # Params="$Params $SourceAddress" # if [ -n "$SourceNetmask" ]; then # Params="$Params/$SourceNetmask" # fi # fi # if [ -n "$SourcePort" ]; then Params="$Params $SourcePort" ; fi # if [ -n "$DestinationAddress" ]; then # Params="$Params $DestinationAddress" # if [ -n "$DestinationNetmask" ]; then # Params="$Params/$DestinationNetmask" # fi # fi # if [ -n "$DestinationPort" ]; then Params="$Params $DestinationPort" ; fi # if [ -n "$Description" ]; then Params="$Params #$Description" ; fi # echo ZZZZ $Params #fi } #Parse html form submission and command line params, if any. if [ -n "$QUERY_STRING" ]; then #Leave +'s as is/are for the moment QUERY_STRING=`echo "$QUERY_STRING" | sed -e 's/%3A/:/g' -e 's/[^A-Za-z0-9\-\.\+=&:]//g' -e 's/&/ /g'` for ONEFIELD in $QUERY_STRING $* ; do ParseOption "$ONEFIELD" done elif [ -n "$SERVER_PROTOCOL" ]; then #FIXME - use CONTENT_LENGTH to make sure we got it all. read ALLOPTIONS for ONEFIELD in `echo "$ALLOPTIONS" | sed -e 's/%3A/:/g' -e 's/[^A-Za-z0-9\-\.\+=&:]//g' -e 's/&/ /g'` ; do ParseOption "$ONEFIELD" done fi #Sanity checks on variables case $Format in ascii|html-pre-bare|html-pre-full-page) : ;; *) if [ -n "$SERVER_PROTOCOL" ]; then Format=html-pre-full-page else Format=ascii fi ;; esac GenericHeader if [ -n "$SourceAddress$SourcePort$DestinationAddress$DestinationPort$Protocol" ]; then showrule else while readlog ; do showrule done fi GenericFooter