#!/bin/sh 

# Run pre script
if [ -f /etc/ipkungfu/pre.conf ] ; then
 source /etc/ipkungfu/pre.conf
fi

IPKF_VERSION="0.5.1"
IPKUNGFU="$0"

# Get the main configuration directives
source /etc/ipkungfu/ipkungfu.conf

# Get PATH
if [ -z "`grep ^PATH /etc/ipkungfu/ipkungfu.conf`" ] ; then
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin
fi

# Detect EXT_NET if not specified
if [ -z "$EXT_NET" ] ; then
 EXT_NET=`route -n | grep ^0.0.0.0 | awk '{print $8}'`
fi

# Detect INT_NET if not defined
if [ -z "$INT_NET" ] ; then
 INT_NET=`echo $(ls /proc/sys/net/ipv4/conf | egrep -v "^lo$|^all$|^default$|$EXT_NET" | cut -d/ -f1)`
fi
if [ -z "$INT_NET" ] ; then
 INT_NET="lo"
fi

# Reasonable guess for LOCAL_NET if not defined
if [ -z "$LOCAL_NET" ] ; then
 LOCAL_NET="192.168.0.0/255.255.0.0 10.0.0.0/255.0.0.0"
fi

# Find iptables if necessary
if [ -z "$IPTABLES" ] ; then
 IPTABLES=`which iptables`
fi

# Find modprobe if necessary
if [ -z "$MODPROBE" ] ; then
 MODPROBE=`which modprobe`
fi

# Enable internet connection sharing by default
if [ "$MASQ_LOCAL_NET" != "0" -a "$GATEWAY" != "0" ] ; then
 if [ "$INT_NET" != "lo" ] ; then
  MASQ_LOCAL_NET="1"
  IP_FORWARD="1"
 else
  MASQ_LOCAL_NET="0"
  IP_FORWARD="0"
 fi
fi

# Play nice by default
if [ "$BLOCK_PINGS" != "1" ] ; then
 BLOCK_PINGS="0"
fi

# Drop naughty packets by default
if [ -z "$SUSPECT" ] ; then
 SUSPECT="DROP"
fi
if [ -z "$KNOWN_BAD" ] ; then
 KNOWN_BAD="DROP"
fi
if [ -z "$PORT_SCAN" ] ; then
 PORT_SCAN="DROP"
fi

# Save rules by defalt
if [ "$SAVE_RULES" != "0" ] ; then
 SAVE_RULES="1"
fi

# Don't get IP of EXT_NET if no method for doing so is specified
if [ -z "$GET_IP" ] ; then
 GET_IP="NONE"
fi

if [ "$DONT_DROP_IDENTD" != "1" ] ; then
 DONT_DROP_IDENTD="0"
fi

# Drop requests from private IPs on EXT_NET
if [ "$INT_NET" = "lo" ] ; then
 DISALLOW_PRIVATE="0"
fi
if [ "$DISALLOW_PRIVATE" != "0" ] ; then
 DISALLOW_PRIVATE="1"
fi

# Enumerate internal interfaces
intniccount=0
for i in $INT_NET; do
 INT_DEV[$intniccount]=$i
 let "intniccount = $inttniccount + 1"
done
let "intniccount = $intniccount - 1"
INT_NET=${INT_DEV[0]}   # For backward compatibility

INIT=0

function conntrack_modules {
 # Check for ip_conntrack_irc module and load if possible
 if [ -f /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/ip_conntrack_irc* ] ; then
  if [ -z "`lsmod | grep ip_conntrack_irc`" ] ; then
   if [ $INIT != 1 ] ; then
    echo "Loading IRC connection tracking module..."
   fi
   $MODPROBE ip_conntrack_irc
  fi
 fi
 # Check for ip_nat_irc module and load if possible
 if [ -e /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/ip_nat_irc* ] ; then
  if [ -z "`lsmod | grep ip_nat_irc`" ] ; then
   if [ $INIT != 1 ] ; then
    echo "Loading IRC NAT module..."
   fi
   $MODPROBE ip_nat_irc
  fi
 fi 
 # Check for ip_conntrack_ftp module and load if possible
 if [ -e /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/ip_conntrack_ftp* ] ; then
  if [ -z "`lsmod | grep ip_conntrack_ftp`" ] ; then
   if [ $INIT != 1 ] ; then
    echo "Loading FTP CONNTRACK module..."
   fi
   $MODPROBE ip_conntrack_ftp
  fi
 fi
 # Check for ip_nat_ftp module and load if possible
 if [ -e /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/ip_nat_ftp* ] ; then
  if [ -z "`lsmod | grep ip_nat_ftp`" ] ; then
   if [ $INIT != 1 ] ; then
    echo "Loading FTP NAT module..."
   fi
   $MODPROBE ip_nat_irc
  fi
 fi
}

function check_network {
 # Checks config options that involve a host/mask 
 FAILURE=""
 HOST=`echo "$NET/" | cut -d/ -f1`
 MASK=`echo "$NET/" | cut -d/ -f2`	# Optional: Netfilter assumes /32 if not defined.
 if (( `echo "$NET/" | cut -d/ -f3 | grep -c "."` )); then
  FAILURE="Syntax error"
  return 1
 fi
 if [ -z "$HOST" ]; then
  FAILURE="Syntax error"
  return 1
 fi
 for OCTET in 1 2 3 4; do
  OCTET=`echo "$HOST." | cut -d. -f$OCTET --output-delimiter=" "`
  if [ -z "$OCTET" ] || (( `echo "$OCTET" | grep -c "[^[:digit:]]"` )) || [ "$OCTET" -lt "0" ] || [ "$OCTET" -gt "255" ]; then
   FAILURE="Network addresses must be in dotted decimal format"
   return 1
  fi
 done
 if (( `echo "$HOST." | cut -d. -f5 | grep -c "."` )); then
  FAILURE="Network address must be in dotted decimal format"
  return 1
 fi
 if [ -n "$MASK" ]; then
  if [ ! -z `echo $MASK | grep .` ] ; then
   for OCTET in 1 2 3 4; do
    OCTET=`echo "$MASK." | cut -d. -f$OCTET --output-delimiter=" "`
    if [ -z "$OCTET" ] || (( `echo "$OCTET" | grep -c "[^[:digit:]]"` )) || [ "$OCTET" -lt "0" ] || [ "$OCTET" -gt "255" ] ; then
     FAILURE="Netmask must be 0-32 or in dotted decimal format"
     return 1
    fi
   done
   return 0
  fi
  if (( `echo "$MASK" | grep -c "[^[:digit:]]"` )) || [ "$MASK" -lt "0" ] || [ "$MASK" -gt "32" ] ; then
   FAILURE="Network mask must be between '/0' (0.0.0.0) and '/32' (255.255.255.255) inclusive"
   return 1
  fi
 else
  if (( `echo "$NET" | grep -c "/"` )); then
   FAILURE="Mask expected but not found"
   return 1
  fi
 fi
}

# Get IP of external device
if [ "$GET_IP" != "NONE" -a "$GET_IP" != "None" -a "$GET_IP" != "none" -a ! -z "$GET_IP" ] ; then
 if [ "$GET_IP" == "AUTO" -o "$GET_IP" == "Auto" -o "$GET_IP" == "auto" ] ; then
  inEXT_IP="-d `ifconfig $EXT_NET | grep 'inet addr' | cut -d: -f2 | cut -d ' ' -f1`"
  outEXT_IP="-s `ifconfig $EXT_NET | grep 'inet addr' | cut -d: -f2 | cut -d ' ' -f1`"
  if [ -z "$1" ] ; then
   echo "Using external IP address `echo $inEXT_IP | cut -d ' ' -f2`"
  fi
 fi		
else
 check_network $GET_IP
 if [ "$?" == "0" ] ; then
  inEXT_IP="-d $GET_IP"
  outEXT_IP="-s $GET_IP"
 else
  inEXT_IP=""
  outEXT_IP=""
 fi
fi

function DelTestChain {
 # Delete test chain
 $IPTABLES -F SYSTEST
 $IPTABLES -X SYSTEST
}

function iptFlush {
 # Gets rid of all rules and custom chains
 if [ $INIT != 1 ] ; then
  echo "Clearing old chains and tables..."
 fi
 cat /proc/net/ip_tables_names | while read table; do
  $IPTABLES -t $table -L -n | while read c chain rest; do
   if test "X$c" = "XChain" ; then
    $IPTABLES -t $table -F $chain
   fi
  done
  $IPTABLES -t $table -X
 done
 $IPTABLES -Z
 $IPTABLES -t nat -Z
 $IPTABLES -t mangle -Z
}

function fwdPorts {
 # Port Forwarding
 FWT=`grep : /etc/ipkungfu/vhosts.conf | cut -d \# -f 1`
 for NET in ${LOCAL_NET[@]}; do
  $IPTABLES -t nat -A PREROUTING -s $NET -d ! $NET -j RETURN
 done
 for i in $FWT; do
  # Set up the variables - this gets pretty convoluted
  HPD=":"
  HPDa=":"
  ALLOWED=`echo $i | cut -d ':' -f 1 | sed s/\!/\!\ /`
  VHOST=`echo $i | cut -d ':' -f 2`
  ORIGINAL_PORT=`echo $i | cut -d ':' -f 3 | sed s/-/:/`
  VHOST_PORT=`echo $i | cut -d ':' -f 4`
  VHOST_PORTb=`echo $i | cut -d ':' -f 4 | sed s/-/:/`
  if [ ! -z `echo $VHOST_PORT | grep \-` ] ; then
   VHOST_PORTa=""
   HPDa=""
  else
   VHOST_PORTa=$VHOST_PORT
   HPDa=":"
  fi
  if [ -z "$VHOST_PORTa" -a -z "$ORIGINAL_PORT" ] ; then
   HPDa=""
  fi
  if [ ! -z "$ORIGINAL_PORT" ] ; then
   ORIGINAL_PORT="--dport $ORIGINAL_PORT"
  fi
  if [ ! -z "$VHOST_PORTb" ] ; then
   VHOST_PORTb="--dport $VHOST_PORTb"
  fi
  PROTO=`echo $i | cut -d ':' -f 5`;
  if [ -z "$PROTO" -o "$PROTO" == "any" -o "$PROTO" == "both" -o "$PROTO" == "ANY" -o "$PROTO" == "BOTH" ] ; then
   PROTO="tcp udp"
  fi
  for PCOL in $PROTO; do
   # This is the really important line
   $IPTABLES -t nat -A PREROUTING -p $PCOL $ORIGINAL_PORT -s $ALLOWED $inEXT_IP -j DNAT --to-destination $VHOST$HPDa$VHOST_PORTa
  done
  if [ -z "$inEXT_IP" ] ; then
   for INT_NET in "${INT_DEV[@]}"; do
    for PCOL in $PROTO; do
     # Do it differently if we don't know the external ip address
     $IPTABLES -t nat -A PREROUTING -p $PCOL $ORIGINAL_PORT -s $ALLOWED -i $INT_NET -j DNAT --to-destination $VHOST$HPDa$VHOST_PORTa
    done
   done
  fi
  for INT_NET in "${INT_DEV[@]}"; do
   LOCAL_IP=`ifconfig $INT_NET | grep 'inet addr' | cut -d: -f2 | cut -d' ' -f1`
   for NET in ${LOCAL_NET[@]}; do
    for PCOL in $PROTO; do
     # This is what allows it to work on the local network
     $IPTABLES -t nat -A POSTROUTING -p $PCOL $VHOST_PORTb -s $NET -d $VHOST -j SNAT --to-source $LOCAL_IP
    done
   done
  done
  if [ $INIT != 1 ] ; then
   for PCOL in $PROTO; do
    echo -n "VHost: $VHOST"
    echo -n ", $PCOL"
    if [ ! -z "$ORIGINAL_PORT" ] ; then
     echo -n -e "/\033[40m\033[1;32m`echo $ORIGINAL_PORT | cut -d' ' -f2`\033[0m"
    fi
    echo -n " to $PCOL"
    if [ ! -z "$ORIGINAL_PORT" ] ; then
     echo -n -e "/\033[40m\033[1;32m$VHOST_PORT\033[0m"
    fi
    echo ", from $ALLOWED"
   done
  fi
 done
}
										  
function rdrPorts {
 # Port Redirecting
 RPT=`grep : /etc/ipkungfu/redirect.conf | cut -d \# -f 1`
 for i in $RPT; do
  PROTO=`echo $i | cut -d ':' -f 1`
  ORIGINAL_PORT=`echo $i | cut -d ':' -f 2`
  NEWPORT=`echo $i | cut -d ':' -f 3`
  DIRECTION=`echo $i | cut -d ':' -f 4`
  if [ $INIT != 1 ] ; then
   echo -e "Redirecting \033[40m\033[1;32m${ORIGINAL_PORT}/$PROTO\033[0m to \033[40m\033[1;32m${NEWPORT}\033[0m"
  fi
  if [ -z "$DIRECTION" ] ; then
   $IPTABLES -t nat -A PREROUTING -p $PROTO --dport $ORIGINAL_PORT -j REDIRECT --to-ports $NEWPORT
  else
   if [ "$DIRECTION" == "internal" -o "$DIRECTION" == "INTERNAL" -o "$DIRECTION" == "int" -o "$DIRECTION" == "INT" ] ; then
    for INT_NET in "${INT_DEV[@]}"; do
     $IPTABLES -t nat -A PREROUTING -p $PROTO --dport $ORIGINAL_PORT -i $INT_NET -j REDIRECT --to-ports $NEWPORT
    done
   else
    $IPTABLES -t nat -A PREROUTING -p $PROTO --dport $ORIGINAL_PORT -i $EXT_NET -j REDIRECT --to-ports $NEWPORT
   fi
  fi
 done
}

function manage_forward {
 for rule in `grep ':' /etc/ipkungfu/forward.conf | grep -v ^\#`; do
  FWD_SRC=`echo $rule | cut -d: -f1`
  FWD_DST=`echo $rule | cut -d: -f2`
  FWD_PORT=`echo $rule | cut -d: -f3`
  FWD_PROTO=`echo $rule | cut -d: -f4`
  FWD_TARGET=`echo $rule | cut -d: -f5`
  FWD_PREFIX=`echo $rule | cut -d: -f6`
  COMMAND="$IPTABLES -A FORWARD"
  if [ ! -z "$FWD_SRC" ] ; then
   COMMAND="$COMMAND -s $FWD_SRC"
  fi
  if [ ! -z "$FWD_DST" ] ; then
   COMMAND="$COMMAND -d $FWD_DST"
  fi
  if [ ! -z "$FWD_PROTO" ] ; then
   COMMAND="$COMMAND -p $FWD_PROTO"
   if [ ! -z "$FWD_PORT" ] ; then
    COMMAND="$COMMAND --dport $FWD_PORT"
   fi
  fi
  if [ "$FWD_TARGET" != "LOG" -a "$FWD_TARGET" != "Log" -a "$FWD_TARGET" != "log" ] ; then
   COMMAND="$COMMAND -j $FWD_TARGET"
  else
   COMMAND="$COMMAND $LOG_CMD"
   if [ ! -z "$FWD_PREFIX" ] ; then
    COMMAND="$COMMAND \"$FWD_PREFIX\""
   fi
  fi
  $COMMAND
 done
}

function ipMasq {
 # Masquerading
 if [ "$MASQ_LOCAL_NET" = "1" ]; then
  for NET in ${LOCAL_NET[@]}; do
   $IPTABLES -t nat -A POSTROUTING -o $EXT_NET -s $NET -j MASQUERADE
  done
 fi
}

# Usage Statement
USEAGE="USEAGE: ipkungfu [option] \n\t[-c or --check]   Check to see if ipkungfu is loaded & mode if any\n\t[-d or --disable] Disable the firewall & set default poilicy to ACCEPT\n\t{--quiet]   Run with no standard output\n\t[-h or --help]    Display this help message and exit\n\t[-l or --list] Displays the iptables rule sets.\n\t[--panic] Shut down all internal and external access\n\t[-t or --test] Test the firewall configuration\n\t[-f or --flush] Flush all rules\n\t[-v or --version] Display the version of ipkungfu and exit\n\t[--show-vars] Show main configuration options, whether specified or detected\n\t[--failsafe] If ipkungfu fails, disable the firewall to prevent loss of remote access"

# Set up logging
source /etc/ipkungfu/log.conf
if [ "$LOG_FACILITY" == "ulog" -o "$LOG_FACILITY" == "ULOG" -o "$LOG_FACILITY" == "ulogd" -o "$LOG_FACILITY" == "ULOGD" ] ; then
 LOG_CMD="-m limit --limit ${LOG_FLOOD} -j ULOG --ulog-prefix"
 TEST_FOR_LOG_SUPPORT=0
else
 LOG_CMD="-m limit --limit ${LOG_FLOOD} -j LOG --log-prefix"
 TEST_FOR_LOG_SUPPORT=1
fi

# Get command line option
if [ $# -ne 0 ] ; then
 if [ $# -gt 1 ] ; then
  echo -e "Please select one option only or none\n"
  echo -e $USEAGE"\n"
  exit 1
 fi
 case "$1" in
  "--version")
   echo -e "\033[40m\033[1;31mipkungfu-$IPKF_VERSION\033[0m"
   exit 0
   ;;
  "-v") 
   echo -e "\033[40m\033[1;31mipkungfu-$IPKF_VERSION\033[0m"
   exit 0
   ;;
  "--show-vars")
  echo "IPTABLES=$IPTABLES"
  echo "MODPROBE=$MODPROBE"
  echo "EXT_NET=$EXT_NET"
  echo "INT_NET=$INT_NET"
  echo "LOCAL_NET=$LOCAL_NET"
  echo "MASQ_LOCAL_NET=$MASQ_LOCAL_NET"
  echo "IP_FORWARD=$IP_FORWARD"
  echo "ALLOWED_TCP_IN=$ALLOWED_TCP_IN"
  echo "ALLOWED_UDP_IN=$ALLOWED_UDP_IN"
  echo "FORBIDDEN_PORTS=$FORBIDDEN_PORTS"
  echo "BLOCK_PINGS=$BLOCK_PINGS"
  echo "PING_FLOOD=$PING_FLOOD"
  echo "SUSPECT=$SUSPECT"
  echo "KNOWN_BAD=$KNOWN_BAD"
  echo "PORT_SCAN=$PORT_SCAN"
  echo "GET_IP=$GET_IP"
  echo "DONT_DROP_IDENTD=$DONT_DROP_IDENTD"
  echo "DISALLOW_PRIVATE=$DISALLOW_PRIVATE"
  echo "WAIT_SECONDS=$WAIT_SECONDS"
  echo "LOG_FACILITY=$LOG_FACILITY"
  echo "GATEWAY=$GATEWAY"
  exit 0
  ;;
  "--list") 
   $IPTABLES -L -v 
   exit 0
   ;;
  "-l")
   $IPTABLES -L -v
   exit 0
   ;;
  "-t")
   ;;
  "--test")
   ;;
  "--disable")
   echo -n "Stopping ipkungfu:                                              "
   INIT=1
   iptFlush
   $IPTABLES -P INPUT ACCEPT
   $IPTABLES -P OUTPUT ACCEPT
   $IPTABLES -P FORWARD ACCEPT
   echo "$IP_FORWARD" > /proc/sys/net/ipv4/ip_forward
   rdrPorts
   fwdPorts
   ipMasq
   $IPTABLES -A INPUT -i $INT_NET -s 0.0.0.1 -j LOG --log-prefix "IPKungFu ($1)" 
   echo -e "[  \033[40m\033[1;32mOK\033[0m  ]"
   echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all
   exit 0
   ;;
  "-d")
   echo -n "Stopping ipkungfu:                                              "
   INIT=1
   iptFlush
   $IPTABLES -P INPUT ACCEPT
   $IPTABLES -P OUTPUT ACCEPT
   $IPTABLES -P FORWARD ACCEPT
   echo "$IP_FORWARD" > /proc/sys/net/ipv4/ip_forward
   rdrPorts
   fwdPorts
   ipMasq
   $IPTABLES -A INPUT -i $INT_NET -s 0.0.0.1 -j LOG --log-prefix "IPKungFu ($1)"
   echo -e "[  \033[40m\033[1;32mOK\033[0m  ]"
   echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all
   exit 0
   ;;
  "-c")
   if [ -z "`${IPTABLES}-save | grep IPKungFu`" ] ; then
    echo "IPKungFu does NOT appear to be loaded."
   else
    echo -n "IPKungFu is loaded "
    if [ -z "`${IPTABLES}-save | grep IPKungFu | cut -d '(' -f 2 | cut -d ')' -f 1`" ] ; then
     echo ""
    else
     echo -n "with option "
     echo "`${IPTABLES}-save | grep IPKungFu | cut -d '(' -f 2 | cut -d ')' -f 1`"
    fi
   fi
   exit 0
   ;;
  "--check")
   if [ -z "`${IPTABLES}-save | grep IPKungFu`" ] ; then
    echo "IPKungFu does NOT appear to be loaded."
   else
    echo -n "IPKungFu version $IPKF_VERSION is loaded "
    if [ -z "`${IPTABLES}-save | grep IPKungFu | cut -d '(' -f 2 | cut -d ')' -f 1`" ] ; then
     echo ""
    else
     echo -n "with option "
     echo "`${IPTABLES}-save | grep IPKungFu | cut -d '(' -f 2 | cut -d ')' -f 1`"
    fi
   fi
   exit 0
   ;;
  "--panic")
   iptFlush
   $IPTABLES -P INPUT DROP
   $IPTABLES -P OUTPUT DROP
   $IPTABLES -P FORWARD DROP
   echo "0" > /proc/sys/net/ipv4/ip_forward
   echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
   echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
   ;;
  "--init")
   INIT=1
   if [ ! -z "$WAIT_SECONDS" ] ; then
    sleep $WAIT_SECONDS
   fi
   ;;
  "--quiet")
   INIT=1
   ;;
   "-h")
   echo -e $USEAGE"\n"
   exit 0
   ;;
   "--help")
   echo -e $USEAGE"\n"
   exit 0
   ;;
   "--flush")
   echo "Flushing ALL chains and rules..."
   iptFlush
   echo "Done"
   exit 0
   ;;
   "-f")
   echo "Flushing ALL chains and rules..."
   iptFlush
   echo "Done"
   exit 0
   ;;
  *) 
   echo -e "ipkungfu: unknown option: $1\n" 
   echo -e $USEAGE"\n"
   exit 1
   ;;
 esac
fi

#### Configuration Sanity Checks ###############################

if [ ! -e /etc/ipkungfu/ipkungfu.conf ] ; then
 # Make sure it's installed
 echo "/etc/ipkungfu/ipkungfu.conf not found."
 echo "ipkungfu must be installed before it can be executed."
 echo "Please run ./install"
 exit 1
fi

source /etc/ipkungfu/advanced.conf

if [ $INIT != 1 ] ; then
 echo "Checking configuration..."
fi

if [ "$UID" != "0" ]; then
 echo -e "\033[40m\033[1;31mERROR: Root check FAILED (you MUST be root to use this script)! Quitting...\033[0m"
 exit 1
fi

# It's hard to run an iptables script without iptables...
if [ ! -x $IPTABLES ]; then
 echo -e "\033[40m\033[1;31mERROR: Binary \"$IPTABLES\" does not exist or is not executable!\033[0m"
 echo "Please, make sure that IPTABLES is (properly) installed."
 exit 3
fi

# Make sure ipchains isn't loaded, as this causes problems
rmmod ipchains > /dev/null 2>&1

for NET in $LOCAL_NET; do
 check_network $NET
 if [ "$?" != "0" ] ; then
  echo "There is a problem with LOCAL_NET in /etc/ipkungfu/ipkungfu.conf:"
  echo "$FAILURE"
  echo "You have $NET"
  exit 1
 fi
done

if [ "$SUSPECT" != "DROP" -a "$SUSPECT" != "REJECT" -a "$SUSPECT" != "MIRROR" -a "$SUSPECT" != "RETURN" ] ; then
 echo "Configuration error:"
 echo "In /etc/ipkungfu/ipkungfu.conf, SUSPECT must be one of"
 echo "DROP, REJECT, or MIRROR (case sensitive)."
 echo "You have $SUSPECT."
 exit 1
fi

if [ "$KNOWN_BAD" != "DROP" -a "$KNOWN_BAD" != "REJECT" -a "$KNOWN_BAD" != "MIRROR" -a "$KNOWN_BAD" != "RETURN" ] ; then
 echo "Configuration error:"
 echo "In /etc/ipkungfu/ipkungfu.conf, KNOWN_BAD must be one of"
 echo "DROP, REJECT, or MIRROR (case sensitive)."
 echo "You have $KNOWN_BAD."
 exit 1
fi

if [ "$PORT_SCAN" != "DROP" -a "$PORT_SCAN" != "REJECT" -a "$PORT_SCAN" != "MIRROR" -a "$PORT_SCAN" != "TARPIT" -a "$PORT_SCAN" != "RETURN" ] ; then
 echo "Configuration error:"
 echo "In /etc/ipkungfu/ipkungfu.conf, PORT_SCAN must be one of"
 echo "DROP, REJECT, RETURN, or MIRROR (case sensitive)."
 echo "You have $PORT_SCAN."
 exit 1
fi

GOODHOSTS=`grep . /etc/ipkungfu/accept_hosts.conf | grep : | cut -d \# -f1`
for HOST in $GOODHOSTS; do
 PROTO=`echo $HOST | cut -d: -f3`
 if [ "$PROTO" != "tcp" -a "$PROTO" != "TCP" -a "$PROTO" != "udp" -a "$PROTO" != "UDP" -a ! -z "$PROTO" ] ; then
  echo "There is a problem in /etc/ipkungfu/accept_hosts:"
  echo "Format is host[:port:protocol]"
  echo "You have $HOST"
  exit 1
 fi
done

BADHOSTS=`grep . /etc/ipkungfu/deny_hosts.conf | grep : | cut -d \# -f1`
for HOST in $BADHOSTS; do
 PROTO=`echo $HOST | cut -d: -f3`
 if [ "$PROTO" != "tcp" -a "$PROTO" != "TCP" -a "$PROTO" != "udp" -a "$PROTO" != "UDP" -a ! -z "$PROTO" ] ; then
  echo "There is a problem in /etc/ipkungfu/deny_hosts:"
  echo "Format is host[:port:protocol]"
  echo "You have $HOST"
  exit 1
 fi
done

LFNUM=`echo $LOG_FLOOD | cut -d / -f1`
LFINT=`echo $LOG_FLOOD | cut -d / -f2`
if [ -z `echo "$LFNUM" | grep -c "[^[:digit:]]"` ] ; then
 echo "There is a problem in /etc/ipkungfu/log.conf:"
 echo "LOG_FLOOD must be in the format number/interval"
 echo "where interval is one of s,m,h, or d, or second,"
 echo "minute, hour, or day."
 echo "You have $LOG_FLOOD"
 exit 1
fi

if [ "$LFINT" != "s" -a "$LFINT" != "m" -a "$LFINT" != "h" -a "$LFINT" != "d" \
 -a "$LFINT" != "second" -a "$LFINT" != "minute" -a "$LFINT" != "hour" -a "$LFINT" != "day" ] ; then
 echo "There is a problem in /etc/ipkungfu/log.conf:"
 echo "LOG_FLOOD must be in the format number/interval"
 echo "where interval is one of s,m,h, or d, or second,"
 echo "minute, hour, or day."
 echo "You have $LOG_FLOOD"
 exit 1
fi

conntrack_modules

# Create a test chain to work with for system ablilities testing
$IPTABLES -N SYSTEST
if [ "$?" != "0" ] ; then 
 echo
 echo "ipkungfu can't create new chains or the script was interrupted previously!"
 echo "Flushing iptables rulesets..."
 $IPTABLES -F
 echo "Clearing old chains and tables..."
 cat /proc/net/ip_tables_names | while read table; do
  $IPTABLES -t $table -L -n | while read c chain rest; do
   if test "X$c" = "XChain" ; then
    $IPTABLES -t $table -F $chain
   fi
  done
  $IPTABLES -t $table -X
 done
 if [ "$1" == "--failsafe" -o "$FAILSAFE" == "1" ] ; then
  echo ""
  echo -e "     \033[40m\033[1;32m***********\033[0m"
  echo -e "     \033[40m\033[1;32m* WARNING *\033[0m"
  echo -e "     \033[40m\033[1;32m***********\033[0m"
  echo ""
  echo "ipkungfu has failed - setting policies to ACCEPT"
  $IPTABLES -P INPUT ACCEPT
  $IPTABLES -P OUTPUT ACCEPT
  $IPTABLES -P FORWARD ACCEPT
  echo "Done.  Please check your config and try again."
  exit 1
 fi
fi

# Test for valid vhosts config
FWT=`grep : /etc/ipkungfu/vhosts.conf | cut -d \# -f 1`
for i in $FWT; do
 HPD=":"
 HPDa=":"
 ALLOWED=`echo $i | cut -d ':' -f 1 | sed s/\!/\!\ /`
 VHOST=`echo $i | cut -d ':' -f 2`
 OPORT=`echo $i | cut -d ':' -f 3 | sed s/-/:/`
 VPORT=`echo $i | cut -d ':' -f 4`
 VPORTb=`echo $i | cut -d ':' -f 4 | sed s/-/:/`
 if [ ! -z `echo $VHOST_PORT | grep \-` ] ; then
  VPORTa=""
  HPDa=""
 else
  VPORTa=$VPORT
  HPDa=":"
 fi
 PROTO=`echo $i | cut -d ':' -f 5`;
 if [ -z "$PROTO" -o "$PROTO" == "any" -o "$PROTO" == "both" -o "$PROTO" == "ANY" -o "$PROTO" == "BOTH" ] ; then
  PROTO="tcp"
 fi
 if [ ! -z "$OPORT" ] ; then
  OPORT="--dport $OPORT"
 fi
 $IPTABLES -A SYSTEST -p $PROTO $OPORT -s $ALLOWED -d 0.0.0.1 -j ACCEPT > /dev/null 2>&1
 if [ "$?" != "0" ] ; then
  echo "There is a problem in /etc/ipkungfu/vhosts.conf:"
  echo "Format is allowedhost:virtualhostIP:originalport:destinationport:protocol"
  echo "You have $i"
  exit 1
 fi
done

function redirect_error {
 echo "There is a problem in /etc/ipkungfu/redirect.conf:"
 echo "Format is protocol:originalport:newport"
 echo "You have $ITEM"
 exit 1
}

# Test validity of redirect.conf
RPT=`grep : /etc/ipkungfu/redirect.conf | cut -d \# -f 1`
for ITEM in $RPT; do
 PROTO=`echo $ITEM | cut -d: -f1`
 OPORT=`echo $ITEM | cut -d: -f2`
 DPORT=`echo $ITEM | cut -d: -f3`
 if [ "$PROTO" != "tcp" -a "$PROTO" != "TCP" -a "$PROTO" != "udp" -a "$PROTO" != "UDP" -a ! -z "$PROTO" ] ; then
  redirect_error
 fi
 $IPTABLES -A SYSTEST -p tcp --dport $OPORT -j REJECT > /dev/null 2>&1
 if [ "$?" != "0" ] ; then
  redirect_error
 fi
 $IPTABLES -A SYSTEST -p tcp --dport $DPORT -j REJECT > /dev/null 2>&1
 if [ "$?" != "0" ] ; then
  redirect error
 fi
done

# Check for ULOG support
$IPTABLES -A SYSTEST -j ULOG > /dev/null 2>&1
if [ "$?" = "0" ] ; then 
 HAVE_ULOG="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mULOG\033[0m kernel support detected!"
 fi
else
 HAVE_ULOG="false" 
 if [ "$TEST_FOR_LOG_SUPPORT" == "0" ] ; then
  echo "ULOG support not detected!  Edit /etc/ipkungfu/log.conf accordingly."
  echo "Aborting."
  exit 3
 fi
fi

# Check for string matching support
$IPTABLES -A SYSTEST -m string --string "test" > /dev/null 2>&1
if [ "$?" = "0" ] ; then
 HAVE_STRING="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mString matching\033[0m support detected!"
 fi
else
 HAVE_STRING="false"
fi

# Check for TTL support
$IPTABLES -t mangle -A SYSTEST -j TTL --ttl-set 80 > /dev/null 2>&1
if [ "$?" = "0" ] ; then 
 HAVE_TTL="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mTTL\033[0m support detected!"
 fi
else
 HAVE_TTL="false"
fi

# Check for unclean support
$IPTABLES -A SYSTEST -m unclean > /dev/null 2>&1
if [ "$?" = "0" ] ; then
 HAVE_UNCLEAN="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mUnclean\033[0m support detected!"
 fi
else
 HAVE_UNCLEAN="false"
fi

# Check for nth support
$IPTABLES -A SYSTEST -m nth > /dev/null 2>&1
if [ "$?" = "0" ] ; then
 HAVE_NTH="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mipt_nth\033[0m patch detected!"
 fi
else
 HAVE_NTH="false"
fi

# Check for 'recent' support
$IPTABLES -A SYSTEST -m recent --name test --set > /dev/null 2>&1
if [ "$?" = "0" ] ; then
 HAVE_RECENT="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mRECENT\033[0m support detected!"
 fi
else
 HAVE_RECENT="false"
fi

# Check for iplimit support
$IPTABLES -A SYSTEST -p tcp --dport 1234 -m iplimit --iplimit-above 2 > /dev/null 2>&1
if [ "$?" = "0" ] ; then
 HAVE_IPLIMIT="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34miplimit\033[0m support detected!"
 fi
else
 HAVE_IPLIMIT="false"
fi

#Check for psd support
$IPTABLES -A SYSTEST -m psd > /dev/null 2>&1
if [ "$?" = "0" ] ; then
 HAVE_PSD="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mAdvanced Portscan Detection\033[0m support detected!"
 fi
else
 HAVE_PSD="false"
fi

# Check for Time support
$IPTABLES -A SYSTEST -m time --timestart 8:00 --timestop 8:01 --days Mon > /dev/null 2>&1
if [ "$?" = "0" ] ; then
 HAVE_TIME="true"
 if [ $INIT != 1 ] ; then
  echo -e " \033[40m\033[1;34mTime\033[0m matching support detected!"
 fi
else
 HAVE_TIME="false"
fi
   
# Check for LOG support
$IPTABLES -A SYSTEST -j LOG > /dev/null 2>&1
if [ "$?" != "0" ] ; then 
 if [ "$TEST_FOR_LOG_SUPPORT" == "1" ] ; then
  echo "Your kernel lacks LOG support required by this script. Aborting."
  exit 3
 fi
fi

# Check for stateful matching
$IPTABLES -A SYSTEST -m state --state ESTABLISHED -j ACCEPT > /dev/null 2>&1
if [ "$?" != "0" ] ; then 
 echo "Your kernel lacks stateful matching, this would break this script. Aborting."
 exit 3
fi

# Check for the limit match
$IPTABLES -A SYSTEST -m limit -j ACCEPT > /dev/null 2>&1
if [ "$?" != "0" ] ; then
 echo "Support not found for limiting needed by this script. Aborting."
 exit 3
fi

DelTestChain

# Configuration test
if [ "$1" = "--test" -o "$1" = "-t" ] ; then
 echo "Your external interface is: $EXT_NET"
 for INT_NET in "${INT_DEV[@]}"; do
  echo "Your internal interface is: $INT_NET"
 done
 echo -n "You "
 if [ $IP_FORWARD != 1 ] ; then
  echo -n "do NOT "
 fi
 echo "want IP forwarding"
 echo -n "You "
 if [ $MASQ_LOCAL_NET != 1 ] ; then
  echo -n "do NOT "
 fi
 echo "want IP masquerading"
 for NET in ${LOCAL_NET[@]}; do
  echo "Your local subnet is $NET"
 done
 echo "The following tcp ports will be open: $ALLOWED_TCP_IN"
 echo "The following udp ports will be open: $ALLOWED_UDP_IN"
 exit 0
fi

logger -p info "Activating ipkungfu"

echo "$IP_FORWARD" > /proc/sys/net/ipv4/ip_forward
echo "$LOG_MARTIANS" > /proc/sys/net/ipv4/conf/all/log_martians
echo "$BLOCK_PINGS" > /proc/sys/net/ipv4/icmp_echo_ignore_all

if [ ! -z $ICMP_ECHO_IGNORE_BROADCASTS ] ; then
 # Smurf-proofing
 echo "$ICMP_ECHO_IGNORE_BROADCASTS" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
else
 echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
fi

# Disable ICMP redirect acceptance. ICMP redirects can be used to 
# alter your routing tables, possibly to a bad end.
echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects

# Enable bad error message protection.
echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

# Helps slow down DoS attacks
echo "$FIN_TIMEOUT" > /proc/sys/net/ipv4/tcp_fin_timeout
echo "$TCP_KEEPALIVE" > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo "$TCP_KEEPALIVE" > /proc/sys/net/ipv4/tcp_keepalive_time
echo "$TCP_WINDOW_SCALING" > /proc/sys/net/ipv4/tcp_window_scaling
echo "$TCP_SACK" > /proc/sys/net/ipv4/tcp_sack
echo "$MAX_SYN_BACKLOG" > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo "$SYN_COOKIES" > /proc/sys/net/ipv4/tcp_syncookies 2> /dev/null

# If enabled, prevents nmap from guessing your uptime
echo "$TCP_TIMESTAMPS" > /proc/sys/net/ipv4/tcp_timestamps

# ICMP Dead Error Messages protection
if [ -e /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses ]; then
 echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
fi

# LooseUDP patch is required by some internet-based games
if [ -e /proc/sys/net/ipv4/ip_masq_udp_dloose ]; then
 if [ "$LOOSE_UDP_PATCH" == "1" ]; then
  echo "1" > /proc/sys/net/ipv4/ip_masq_udp_dloose
 else
  echo "0" > /proc/sys/net/ipv4/ip_masq_udp_dloose
 fi
fi

# Reject source routing
if [ -e /proc/sys/net/ipv4/conf/all/accept_source_route ]; then
 for interface in /proc/sys/net/ipv4/conf/*/accept_source_route; do
  echo "0" > $interface
 done
fi

# Increase the default queuelength. (Kernel Default: 1024)
if [ -e /proc/sys/net/ipv4/ipv4/ip_queue_maxlen ]; then
 if [ ! -z $IP_QUEUE_MAXLEN ] ; then
  echo "$IP_QUEUE_MAXLEN" > /proc/sys/net/ipv4/ip_queue_maxlen
 else
  echo "2048" > /proc/sys/net/ipv4/ip_queue_maxlen
 fi
fi

# Prevent IP spoofs
for i in /proc/sys/net/ipv4/conf/* ; do
 echo 1 > $i/rp_filter
 echo "$LOG_MARTIANS" > $i/log_martians
done

iptFlush

TRUSTED_HOSTS=`grep . /etc/ipkungfu/accept_hosts.conf | cut -d \# -f 1`
BADGUY_HOSTS=`grep . /etc/ipkungfu/deny_hosts.conf | cut -d \# -f 1`
FORWARD_POLICY=`grep FORWARD_POLICY /etc/ipkungfu/forward.conf | grep -v ^\# | cut -d= -f2`

# Set default chain policies
$IPTABLES -P OUTPUT  ACCEPT
$IPTABLES -P INPUT   DROP
$IPTABLES -P FORWARD $FORWARD_POLICY

if [ $INIT != 1 ] ; then
 echo "Implementing custom rules..."
fi
source /etc/ipkungfu/custom.conf 

# Useless rule for checking that ipkungfu is loaded
$IPTABLES -A INPUT -i $INT_NET -s 0.0.0.1 -j LOG --log-prefix "IPKF IPKungFu ($1)"

if [ ! -z "$BADGUY_HOSTS" ] ; then
 if [ $INIT != 1 ] ; then
  echo "$KNOWN_BAD all traffic from the following hosts/nets:"
 fi
 for HOST in $BADGUY_HOSTS; do
  LINE=`echo $HOST | cut -d ':' -f 2,3 --output-delimiter=QWQ | grep QWQ`
  if [ ! -z "$LINE" ] ; then
   DHOST=`echo $HOST | cut -d ':' -f 1`
   PORT=`echo $HOST | cut -d ':' -f 2 | sed s/-/:/`
   PROTO=`echo $HOST | cut -d ':' -f 3`
   $IPTABLES -A INPUT -i $EXT_NET -s $DHOST -p $PROTO --dport $PORT -j $KNOWN_BAD
   $IPTABLES -A FORWARD -i $EXT_NET -s $DHOST -p $PROTO --dport $PORT -j $KNOWN_BAD
   if [ $INIT != 1 ] ; then
    echo -e " \033[40m\033[1;32m$DHOST:$PORT/$PROTO\033[0m"
   fi
  else
   $IPTABLES -A INPUT -s $HOST -i $EXT_NET -j $KNOWN_BAD
   if [ $INIT != 1 ] ; then
    echo -e " \033[40m\033[1;32m$HOST\033[0m"
   fi
  fi
 done
fi

rdrPorts
fwdPorts

if [ ! -z "$TRUSTED_HOSTS" ] ; then
 if [ $INIT != 1 ] ; then
  echo "ACCEPT all connections from the following hosts/nets:"
 fi
 for HOST in $TRUSTED_HOSTS; do
  LINE=`echo $HOST | cut -d ':' -f 2,3 --output-delimiter=QWQ | grep QWQ`
  if [ ! -z "$LINE" ] ; then
   THOST=`echo $HOST | cut -d ':' -f 1`
   PORT=`echo $HOST | cut -d ':' -f 2 | sed s/-/:/`
   PROTO=`echo $HOST | cut -d ':' -f 3`
   if [ "$LOG_EST_EXT" == "1" ] ; then
    $IPTABLES -A INPUT -s $THOST -p $PROTO --dport $PORT $LOG_CMD "IPKF New Connection: "
    $IPTABLES -A FORWARD -i $EXT_NET -s $THOST -p $PROTO --dport $PORT $LOG_CMD "IPKF New Connection: "
   fi
   $IPTABLES -A INPUT -s $THOST -p $PROTO --dport $PORT -j ACCEPT
   $IPTABLES -A FORWARD -i $EXT_NET -s $THOST -p $PROTO --dport $PORT -j ACCEPT
   if [ $INIT != 1 ] ; then
    echo -e " \033[40m\033[1;32m$THOST:$PORT/$PROTO\033[0m"
   fi
  else
   if [ "$LOG_EST_EXT" == "1" ] ; then
    $IPTABLES -A INPUT -s $HOST $LOG_CMD "IPKF New Connection: "
    $IPTABLES -A FORWARD -i $EXT_NET -s $HOST $LOG_CMD "IPKF New Connection: "
   fi
   $IPTABLES -A INPUT -s $HOST -j ACCEPT
   $IPTABLES -A FORWARD -i $EXT_NET -s $HOST -j ACCEPT
   if [ $INIT != 1 ] ; then
    echo -e " \033[40m\033[1;32m$HOST\033[0m"
   fi
  fi
 done
fi

#if [ ! -z "$IP_PERSONALITY" ] ; then
# echo "Spoofing operating system type to $IP_PERSONALITY"
# IPPPATH="/etc/ipkungfu/ipp"  
# IPPSTR="PERS --tweak dst --local --conf"
# $IPTABLES -t mangle -A OUTPUT -j $IPPSTR $IPPPATH/$IP_PERSONALITY.conf
# $IPTABLES -t mangle -I PREROUTING -j $IPPSTR $IPPPATH/$IP_PERSONALITY.conf
#fi

ipMasq

manage_forward

if [ "$HAVE_RECENT" = "true" ]; then
 $IPTABLES -A INPUT -m recent --name badguy --rcheck --seconds 120 -j $KNOWN_BAD
 $IPTABLES -A FORWARD -i $EXT_NET -m recent --name badguy --rcheck --seconds 120 -j $KNOWN_BAD
 for PORT in $FORBIDDEN_PORTS; do
  $IPTABLES -A INPUT -p tcp -i $EXT_NET --dport $PORT $LOG_CMD "IPKF BADGUY on port $PORT: "
  $IPTABLES -A FORWARD -p tcp -i $EXT_NET --dport $PORT $LOG_CMD "IPKF BADGUY on port $PORT: "
  $IPTABLES -A INPUT -p tcp -i $EXT_NET --dport $PORT -m recent --name badguy --set -j $KNOWN_BAD
  $IPTABLES -A FORWARD -p tcp -i $EXT_NET --dport $PORT -m recent --name badguy --set -j $KNOWN_BAD
 done
fi

#if [ "$HAVE_STRING" = "true" ]; then
# # Deal with HTTP packets matching evil strings
# if [ $INIT != 1 ] ; then
#  echo "Dealing with evil strings..."
# fi
# SI=1
# while [ "$SI" -lt "${#KILLSTRING[@]}" ]; do
#  $IPTABLES -A INPUT -p tcp --dport 80 -m string --string "${KILLSTRING[$SI]}" $LOG_CMD "IPKF ${KILLSTRING[$SI]}: "
#  $IPTABLES -A INPUT -j $KNOWN_BAD -p tcp --dport 80 -m string --string "${KILLSTRING[$SI]}: "
#  $IPTABLES -A FORWARD -i $EXT_NET -p tcp --dport 80 -m string --string "${KILLSTRING[$SI]}" $LOG_CMD "IPKF ${KILLSTRING[$SI]}: "
#  $IPTABLES -A FORWARD -i $EXT_NET -j $KNOWN_BAD -p tcp --dport 80 -m string --string "${KILLSTRING[$SI]}: "
#  let "SI = $SI + 1"
# done
#fi

# Attempt to detect port scans
if [ "$HAVE_PSD" = "true" ] ; then
 if [ "$LOG_PORT_SCANS" = "1" ] ; then
  $IPTABLES -A INPUT -i $EXT_NET -m psd --psd-delay-threshold 2000 $LOG_CMD "IPKF PORTSCAN: "
  $IPTABLES -A FORWARD -i $EXT_NET -m psd --psd-delay-threshold 2000 $LOG_CMD "IPKF PORTSCAN: "
 fi
 $IPTABLES -A INPUT -i $EXT_NET -m psd --psd-delay-threshold 2000 -j $PORT_SCAN
 $IPTABLES -A FORWARD -i $EXT_NET -m psd --psd-delay-threshold 2000 -j $PORT_SCAN
fi
if [ "$LOG_PORT_SCANS" = "1" ] ; then
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL ALL $LOG_CMD "IPKF flags ALL: "
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL NONE $LOG_CMD "IPKF flags NONE: "
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH $LOG_CMD "IPKF PORTSCAN (nmap XMAS): "
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL FIN $LOG_CMD "IPKF PORTSCAN (nmap FIN): "
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN $LOG_CMD "IPKF flags SYN,FIN: "
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST $LOG_CMD "IPKF flags SYN,RST: "
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG $LOG_CMD "IPKF SYN,RST,ACK,FIN,URG: "
 $IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE $LOG_CMD "IPKF PORTSCAN (nmap NULL): "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL ALL $LOG_CMD "IPKF flags ALL: "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL NONE $LOG_CMD "IPKF flags NONE: "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH $LOG_CMD "IPKF flags FIN,URG,PSH: "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN $LOG_CMD "IPKF PORTSCAN (nmap XMAS): "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN $LOG_CMD "IPKF flags SYN,FIN: "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST $LOG_CMD "IPKF flags SYN,RST: "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG $LOG_CMD "IPKF SYN,RST,ACK,FIN,URG: "
 $IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE $LOG_CMD "IPKF PORTSCAN (nmap NULL): "
fi
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL NONE -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL ALL -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL FIN -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL NONE -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL ALL -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN -j $PORT_SCAN

if [ "$BLOCK_PINGS" != "1" ] ; then
 $IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
fi

# Kill invalid packets (illegal combinations of flags)
if [ "$LOG_INVALID" = "1" ] ; then
 $IPTABLES -A INPUT -m state --state INVALID $LOG_CMD "IPKF Invalid TCP flag: "
 $IPTABLES -A FORWARD -m state -i $EXT_NET --state INVALID $LOG_CMD "IPKF Invalid TCP flag: "
fi
$IPTABLES -A FORWARD -m state  -i $EXT_NET --state INVALID -j $SUSPECT
$IPTABLES -A INPUT -m state --state INVALID -j $SUSPECT

# Kill and log fragments
if [ "$LOG_FRAGMENTS" == "1" ] ; then
 $IPTABLES -A INPUT -i $EXT_NET -f $LOG_CMD "IPKF Fragmented Packet: "
 $IPTABLES -A FORWARD -i $EXT_NET -f $LOG_CMD "IPKF Fragmented Packet: "
fi
$IPTABLES -A INPUT -i $EXT_NET -f -j $SUSPECT
$IPTABLES -A FORWARD -i $EXT_NET -f -j $SUSPECT

# Drop unclean
if [ "$DROP_UNCLEAN" == "1" ] ; then
 if [ "$HAVE_UNCLEAN" == "true" ] ; then
  $IPTABLES -A INPUT -i $EXT_NET -m unclean $LOG_CMD "IPKF Unclean: "
  $IPTABLES -A INPUT -i $EXT_NET -m unclean -j $SUSPECT
  $IPTABLES -A FORWARD -i $EXT_NET -m unclean $LOG_CMD "IPKF Unclean: "
  $IPTABLES -A FORWARD -i $EXT_NET -m unclean -j $SUSPECT
 fi
fi

# Block possibly dangerous ICMP timestamp requests
$IPTABLES -A INPUT -p icmp --icmp-type timestamp-request -i $EXT_NET $LOG_CMD "IPKF ICMP Timestamp: "
$IPTABLES -A FORWARD -p icmp --icmp-type timestamp-request -i $EXT_NET $LOG_CMD "IPKF ICMP Timestamp: "
$IPTABLES -A INPUT -p icmp --icmp-type timestamp-request -i $EXT_NET -j $SUSPECT
$IPTABLES -A FORWARD -p icmp --icmp-type timestamp-request -i $EXT_NET -j $SUSPECT

# Prevent SYN-floods
$IPTABLES -N syn-flood
$IPTABLES -A INPUT -i $EXT_NET -p tcp --syn -j syn-flood
$IPTABLES -A FORWARD -i $EXT_NET -p tcp --syn -j syn-flood
$IPTABLES -A syn-flood -m limit --limit $SYN_FLOOD/s --limit-burst $SYN_FLOOD_BURST -j RETURN
if [ "$LOG_DOS" = "1" ] ; then
 $IPTABLES -A syn-flood $LOG_CMD "IPKF SYN flood: "
fi
$IPTABLES -A syn-flood -j $SUSPECT

# This fixes DCC
$IPTABLES -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -I OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# Make sure NEW tcp connections are SYN packets
if [ "$LOG_INVALID" = "1" ] ; then
 $IPTABLES -A INPUT -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW $LOG_CMD "IPKF New Not SYN: "
 $IPTABLES -A FORWARD -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW $LOG_CMD "IPKF New Not SYN: "
fi
$IPTABLES -A INPUT -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j $SUSPECT
$IPTABLES -A FORWARD -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j $SUSPECT

# Drop these tcp ports without logging
PORTS=`echo "$DONT_LOG_TCP" | sed 's/\ /,/g' | sed s/-/:/`
if [ ! -z "$PORTS" ] ; then
 $IPTABLES -A INPUT -i $EXT_NET -p tcp -m multiport --destination-port $PORTS -j DROP
 $IPTABLES -A FORWARD -i $EXT_NET -p tcp -m multiport --destination-port $PORTS -j DROP
fi

# Drop these udp ports without logging
PORTS=`echo "$DONT_LOG_UDP" | sed 's/\ /,/g' | sed s/-/:/`
if [ ! -z "$PORTS" ] ; then
 $IPTABLES -A INPUT -i $EXT_NET -p udp -m multiport --destination-port $PORTS -j DROP
 $IPTABLES -A FORWARD -i $EXT_NET -p udp -m multiport --destination-port $PORTS -j DROP
fi

# Prevent Spoofs
if [ "$DISALLOW_PRIVATE" == "1" ] ; then
 $IPTABLES -A INPUT -s 10.0.0.0/255.0.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 172.16.0.0/255.240.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 192.168.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 127.0.0.0/255.255.255.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 169.254.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 192.0.2.0/255.255.255.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 198.18.0.0/255.254.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 255.255.255.255/255.255.255.255 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A FORWARD -s 10.0.0.0/255.0.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof"
 $IPTABLES -A FORWARD -s 172.16.0.0/255.240.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof"
 $IPTABLES -A FORWARD -s 192.168.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof"
 $IPTABLES -A FORWARD -s 127.0.0.0/255.255.255.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A FORWARD -s 169.254.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A FORWARD -s 192.0.2.0/255.255.255.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A FORWARD -s 198.18.0.0/255.254.0.0 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A FORWARD -s 255.255.255.255/255.255.255.255 -i $EXT_NET $LOG_CMD "IPKF Spoof: "
 $IPTABLES -A INPUT -s 10.0.0.0/255.0.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A INPUT -s 172.16.0.0/255.240.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A INPUT -s 192.168.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A INPUT -s 127.0.0.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A INPUT -s 169.254.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A INPUT -s 192.0.2.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A INPUT -s 198.18.0.0/255.254.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A INPUT -s 255.255.255.255/255.255.255.255 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 10.0.0.0/255.0.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 172.16.0.0/255.240.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 192.168.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 127.0.0.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 169.254.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 192.0.2.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 198.18.0.0/255.254.0.0 -i $EXT_NET -j $KNOWN_BAD
 $IPTABLES -A FORWARD -s 255.255.255.255/255.255.255.255 -i $EXT_NET -j $KNOWN_BAD
fi

# Allow tcp traffic according to ALLOWED_TCP_IN
if [ $INIT != 1 ] ; then
 if [ ! -z "$ALLOWED_TCP_IN" ] ; then
  echo "Allowing Incoming TCP Packets to the Following Ports..."
 fi
fi
SINGLE_PORTS="$(for i in $ALLOWED_TCP_IN; do echo $i | egrep -v -- ':|-';done)"
PORT_RANGES="$(for i in $ALLOWED_TCP_IN; do echo $i | egrep -- ':|-';done | sed s/-/:/g)"
if [ ! -z "$SINGLE_PORTS" ] ; then  
 if [ "$LOG_EST_EXT" == "1" ] ; then
  $IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW -m multiport --destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` $LOG_CMD "IPKF New Connection: "
 fi
 $IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW -m multiport --destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` -j ACCEPT
fi
if [ ! -z "$PORT_RANGES" ] ; then
 if [ "$LOG_EST_EXT" == "1" ] ; then
  for RANGE in $PORT_RANGES; do
   $IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW -p tcp --dport $RANGE $LOG_CMD "IPKF New Connection: "
  done
 fi
 for RANGE in $PORT_RANGES; do
  $IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW --dport $RANGE -j ACCEPT
 done
fi
if [ $INIT != 1 ] ; then
 for PORT in $SINGLE_PORTS; do
  service=`grep "\b$PORT/tcp" /etc/services | cut -f1`
  if [ -z "$service" ] ; then
   service="?"
  fi
   echo -e " \033[40m\033[1;32m$PORT\033[0m ($service)"
 done
 for RANGE in $PORT_RANGES; do
  echo -e " \033[40m\033[1;32m$RANGE\033[0m"
 done
fi

# Allow UDP traffic according to ALLOWED_UDP_IN
if [ $INIT != 1 ] ; then
 if [ ! -z "$ALLOWED_UDP_IN" ] ; then
  echo "Allowing Incoming UDP Packets to the Following Ports..."
 fi
fi
SINGLE_PORTS="$(for i in $ALLOWED_UDP_IN; do echo $i | egrep -v -- ':|-';done)"
PORT_RANGES="$(for i in $ALLOWED_UDP_IN; do echo $i | egrep -- ':|-';done | sed s/-/:/g)"
if [ ! -z "$SINGLE_PORTS" ] ; then
 if [ "$LOG_EST_EXT" == "1" ] ; then
  $IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW -m multiport --destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` $LOG_CMD "IPKF New Connection: "
 fi
 $IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW -m multiport --destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` -j ACCEPT
fi
if [ ! -z "$PORT_RANGES" ] ; then
 if [ "$LOG_EST_EXT" == "1" ] ; then
  for RANGE in $PORT_RANGES; do
   $IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW -p tcp --dport $RANGE $LOG_CMD "IPKF New Connection: "
  done
 fi
 for RANGE in $PORT_RANGES; do
  $IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW --dport $RANGE -j ACCEPT
 done
fi
if [ $INIT != 1 ] ; then
 for PORT in $SINGLE_PORTS; do
  service=`grep "\b$PORT/udp" /etc/services | cut -f1`
  if [ -z "$service" ] ; then
   service="?"
  fi
  echo -e " \033[40m\033[1;32m$PORT\033[0m ($service)"
 done
 for RANGE in $PORT_RANGES; do
  echo -e " \033[40m\033[1;32m$RANGE\033[0m"
 done
fi
					  

# Allow local traffic
$IPTABLES -A INPUT -i lo -m state --state NEW -j ACCEPT
for INT_NET in ${INT_DEV[@]}; do
 for NET in ${LOCAL_NET[@]}; do
  if [ "$LOG_EST_INT" == "1" ] ; then
   $IPTABLES -A INPUT -m state --state NEW -s $NET -i $INT_NET $LOG_CMD "IPKF New Connection: "
  fi
  $IPTABLES -A INPUT -m state --state NEW -s $NET -i $INT_NET -j ACCEPT
 done
done
$IPTABLES -A OUTPUT -m state --state NEW -j ACCEPT
 
if [ "$MASQ_LOCAL_NET" = "1" ] ; then
 # Set up masquerading for internet connection sharing
 for NET in ${LOCAL_NET[@]}; do
  for INT_NET in ${INT_DEV[@]}; do
   $IPTABLES -A FORWARD -m state --state NEW -s $NET -i $INT_NET -j ACCEPT
  done
 done
fi

if [ "$DONT_DROP_IDENTD" = "1" ] ; then
 # Gracefully close identd probes
 $IPTABLES -A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset
 $IPTABLES -A FORWARD -i $EXT_NET -p tcp --dport 113 -j REJECT --reject-with tcp-reset
fi

# Log new connections to the internal network from the internet.
# This shouldn't happen unless you have servers set up in
# vhosts.conf or you have one or more public IP addresses
# inside your LAN
if [ "$LOG_EST_EXT" == "1" ] ; then
 for NET in ${LOCAL_NET[@]}; do
  $IPTABLES -A FORWARD -d $NET -m state --state NEW -p tcp --tcp-flags SYN,RST,ACK SYN $LOG_CMD "IPKF New Connection: "
 done
fi

if [ "$LOG_EST_INT" == "1" ] ; then
 for NET in ${LOCAL_NET[@]}; do
  $IPTABLES -A FORWARD -s $NET -m state --state NEW -p tcp --tcp-flags SYN,RST,ACK SYN $LOG_CMD "IPKF New Connection: "
 done
fi

# Anything not caught by another rule gets caught here
if [ "$LOG_CATCH_ALL" = "1" ] ; then
 $IPTABLES -A INPUT -p ! icmp $LOG_CMD "IPKF INPUT Catch-all: "
# $IPTABLES -A OUTPUT $LOG_CMD "IPKF OUTPUT Catch-all: " 
fi
$IPTABLES -A INPUT -j $SUSPECT
#$IPTABLES -A OUTPUT -j $SUSPECT

if [ ! -z "$TTL" ] ; then
 # If so configured, try to foil attempts to determine
 # whether there is a NAT network
 if [ "$HAVE_TTL" = "true" ] ; then
  $IPTABLES -t mangle -I OUTPUT -j TTL --ttl-set $TTL
  $IPTABLES -t mangle -I FORWARD -o $EXT_NET -j TTL --ttl-set $TTL
 else
  echo -e "\033[40m\033[1;34mWarning:\033[0m TTL configured in advanced.conf but not supported by your kernel"
 fi
fi

# RFC 1060/1349 suggested TOS values
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 20 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 21 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 22 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 23 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 25 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p udp --dport 53 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 67 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 80 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 110 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 113 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 123 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 143 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 443 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 993 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 995 -j TOS --set-tos Maximize-Throughput
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 1080 -j TOS --set-tos Minimize-Delay
$IPTABLES -t mangle -A OUTPUT -p tcp --dport 6000:6063 -j TOS --set-tos Maximize-Throughput

# Run post script
if [ -f /etc/ipkungfu/post.conf ] ; then
 source /etc/ipkungfu/post.conf
fi
 
