#!/bin/bash
#
#   Start/stop firewall
#
#   interfarce
#   firewall [start|stop|...] interface ip_number 
#        e.g. firewall start pppo 62.4.175.82 
#
#     interface and ip_number are only used by start
#			
# if you need complete logging of denied packets
#FULL_DENIED_LOG="-l"
FULL_DENIED_LOG=""
# even more logging
#FULL_LOG="-l"
FULL_LOG=""

logger -p daemon.info "firewall: $0 $*"

function start_firewall {
  # reset all
  ipchains -F
  ipchains -X

  # by default deny all incoming and forwarding traffic
  ipchains -P input  DENY
  ipchains -P output  DENY
  ipchains -P forward  DENY

  # accept some outgoing traffic
  # (we need to specify outgoing traffic first, because in some rules,
  #  DNS lookups are needed and these are resolved externally ;-)

  # nothing destined for myself should go out
#  ipchains -A output -d $myhost -l -j DENY

  # all outgoing traffic originating from me is valid
  # except for netbios services and portmapper
  ipchains -A output -i $INTERFACE -p udp -s $myhost 137:139 -j REJECT -l
  ipchains -A output -i $INTERFACE -p tcp -s $myhost 137:139 -j REJECT -l
  ipchains -A output -i $INTERFACE -p udp -s $myhost 111 -j REJECT -l
  ipchains -A output -i $INTERFACE -p tcp -s $myhost 111 -j REJECT -l
  ipchains -A output -i $INTERFACE -s $myhost -j ACCEPT

  # loopback => OK
  ipchains -A output -i lo -j ACCEPT

  # vmware => OK
#  ipchains -A output -i vmnet+ -j ACCEPT

  # Catch all other traffic and log it
  ipchains -A output  -i $INTERFACE -j DENY -l

  # accept/deny specific incoming traffic

  # somebody else is spoofing my IP-address => get lost
  ipchains -A input  -i $INTERFACE -s $myhost -j DENY -l
  # somebody else is using unroutable adresses => get lost
  # you should comment out unroutable adresses used in your organisation
  #  e.g. KULeuven uses 10.0.0.0 internally
  ipchains -A input  -i $INTERFACE -b -s 10.0.0.0/8 -j DENY -l
  ipchains -A input  -i $INTERFACE -b -s 172.16.0.0/12 -j DENY -l
  ipchains -A input  -i $INTERFACE -b -s 192.168.0.0/16 -j DENY -l
  # somebody else is using the loopback interface 127.0.0.0 => get lost
  ipchains -A input  -i $INTERFACE -b -s 127.0.0.0/8 -j DENY -l
  # refuse malformed broadcast packets
  ipchains -A input  -i $INTERFACE -b -s 255.255.255.255 -j DENY -l

  # ICMP (ping, traceroute) => OK
  ipchains -A input -i $INTERFACE -p icmp -d $myhost -j ACCEPT

  # Bootp (dhcp) => OK if coming from/going to designated bootp ports
  ipchains -A input  -i $INTERFACE -p udp -s 0/0 bootps -d $myhost bootpc -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 0/0 bootps -d $myhost bootpc -j ACCEPT

  # ftp for testing
  # ipchains -A input -p tcp -d $myhost 21 -j REJECT -l

  # SSH ...
  # if established connection (ACK bit is set) => OK
  ipchains -A input -i $INTERFACE -p tcp -s 0/0 ssh -d $myhost ! -y -j ACCEPT
  # if from DeptCW => OK
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.39.0/31 -d $myhost ssh -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.40.0/24 -d $myhost ssh -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.41.0/24 -d $myhost ssh -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.42.0/24 -d $myhost ssh -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.43.0/24 -d $myhost ssh -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.44.0/24 -d $myhost ssh -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.45.0/24 -d $myhost ssh -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.46.0/24 -d $myhost ssh -j ACCEPT

  # NTP => OK
  ipchains -A input -i $INTERFACE -p udp -s 134.58.0.0/16 ntp -d $myhost -j ACCEPT

  # DNS ...
  # udp => OK
  # if from cs.kuleuven.ac.be and kulnet
  ipchains -A input -i $INTERFACE -p udp -s 134.58.126.3/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p udp -s 134.58.127.1/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.39.0/31 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p udp -s 134.58.40.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p udp -s 134.58.41.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p udp -s 134.58.42.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p udp -s 134.58.43.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p udp -s 134.58.45.0/24 domain -d $myhost -j ACCEPT
  # from skynet.be
  ipchains -A input -i $INTERFACE -p udp -s 195.238.2.21 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p udp -s 195.238.2.22 domain -d $myhost -j ACCEPT
  # tcp => OK (if answer is large, tcp is used)
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.126.3/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.127.1/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.39.0/31 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.40.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.41.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.42.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.43.0/24 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 134.58.45.0/24 domain -d $myhost -j ACCEPT
  # from skynet.be
  ipchains -A input -i $INTERFACE -p tcp -s 195.238.2.21 domain -d $myhost -j ACCEPT
  ipchains -A input -i $INTERFACE -p tcp -s 195.238.2.22 domain -d $myhost -j ACCEPT
  # if you run a nameserver locally
#  ipchains -A input -i $INTERFACE -p udp -d $myhost domain -j ACCEPT
#  ipchains -A input -i $INTERFACE -p tcp -d $myhost domain -j ACCEPT

  # Identd => OK
  ipchains -A input -i $INTERFACE -p tcp -s 0/0 -d $myhost auth -j ACCEPT

  # all other tcp connections only if established connection
  # (ACK bit is set)
  # this rule covers POP/IMAP/passive FTP/SMTP ...
  ipchains -A input -p tcp -d $myhost ! -y -j ACCEPT

  # RealAudio only on specified port
  ipchains -A input -i $INTERFACE -p udp -s 0/0 -d $myhost 7070 -j ACCEPT

  # loopback => OK
  ipchains -A input -i lo -j ACCEPT

  # vmware => OK
  ipchains -A input -i vmnet1 -j ACCEPT

  # don't log anything sent to (global) broadcast
  ipchains -A input -d 255.255.255.255 -j DENY $FULL_DENIED_LOG

  if [ ! -z "$mybrdcst" ] 
    then
      # don't log anything sent to broadcast and Windows ports
      # There are just too many stupid Windows machines looking for each other
      # Only log if they are not directed to (network) broadcast
      ipchains -A input -i $INTERFACE -p udp -d $mybrdcst 137:139 -j DENY
  fi
  # allow fragments  and log to debug
  ipchains -A input -i $INTERFACE -p tcp -f -d $myhost -j ACCEPT $FULL_LOG

  # Catch all other traffic and log it
  ipchains -A input -i $INTERFACE -j DENY -l
}

function stop_firewall {
  # reset all
  ipchains -F
  ipchains -X

  # by default accept all incoming and forwarding traffic
  ipchains -P input ACCEPT
  ipchains -P output ACCEPT
  ipchains -P forward ACCEPT
}

function print_rules {
  ipchains -L -n
}

function print_accounting {
  ipchains -L -nv
}

function reset_accounting {
  ipchains -Z
}

function log_accounting {
  ipchains -L -Z -nvx
}

# main routine

# how long does testing last
WAIT=60

case "$1" in
start)
	INTERFACE=$2
	IP=$3

	trap 'rm /tmp/firewall.$$' 0 1 2 3 4 5 6 7 8 15

	ifconfig $INTERFACE >/tmp/firewall.$$ 2>&1

	TEST_INTERFACE=` grep "error fetching interface information" /tmp/firewall.$$ `
	if [ -z "$TEST_INTERFACE" ]
  	then
# 	  who am i ?
   	  myhost="`ifconfig $INTERFACE | grep 'inet addr:' | sed 's/.*inet addr:\([0-9\.]*\).*/\1/'`"
#   beware ppp interface donot have a broadcast address
   	  mybrdcst="`ifconfig $INTERFACE | grep 'Bcast:' | sed 's/.*Bcast:\([0-9\.]*\).*/\1/'`"
	  else
  	  exit 1
	fi

# some sanity checking

	if [ "$IP" = "$myhost" ] 
	  then
	    logger -p daemon.info "firewall: $0 $INTERFACE $IP $1"
	  else
	    logger -i -p daemon.notice "firewall: error real ip $myhost $0 $INTERFACE $IP $1"
	    exit 2
	fi
        start_firewall
        ;;
stop)
        stop_firewall
        ;;
test)
        start_firewall
        echo "**** THE FIREWALL WILL BE DISABLED AGAIN IN $WAIT SECONDS ****"
        ( sleep $WAIT; $0 $INTERFACE $IP stop ) &
        ;;
rules)
        print_rules
        ;;
status)
        print_accounting
        ;;
reset)
        reset_accounting
        ;;
log)
        log_accounting
        ;;
*)
        echo
        echo "Usage: $0 INTERFACE IP {start|stop|test|rules|status|reset|log}"
        echo
        echo "  start:   Enable the firewall"
        echo "  stop:    Disable the firewall"
        echo "  test:    Test the firewall : it will automatically be disabled"
        echo "           after $WAIT seconds"
        echo "  rules:   Print the firewall rules"
        echo "  status:  Print the accounting information"
        echo "  reset:   Reset the accounting counters"
        echo "  log:     Print and then reset the accounting information"
        echo "           Is to be called from crontab"
        echo
        exit 1
        ;;
esac

