#===============================  LutelWall  =================================#
#  Description:  Firewall configuration tool				      #
#  Author:	 Tomasz Lutelmowski <tomek@lutel.pl>			      #
#  Homepage:	 http://firewall.lutel.pl				      #
#									      #
#  chkconfig: 2345 11 91						      #
#=============================================================================#

# Note: You should change variables below only for debugging purposes.

# Path to configuration file. Default is /etc/lutelwall.conf
configuration_file='/etc/lutelwall.conf'

# Version of script, only for update process.
current_version='0.99'

# Paths to iptables, iptables-restore and logger. Default is to lookup in $PATH
T='iptables'
TR='iptables-restore'
logger='logger'

# Prefix of temporary firewall files
tmp='/tmp/lutelwall'
clean_tmp_on_exit='yes'

# Setting other than false will force script not to stop after fatal errors
ignore_errors='false'

# UID allowed to run this script
firewall_uid='0'

# Default policies (default = 'ACCEPT' for stopped, and 'LOG,DROP' for running firewall)
# Can be ACCEPT or DROP or LOG,DROP
policy_filter_stop='ACCEPT'
policy_filter_start='LOG,DROP'

# Status file
status_file='/var/run/lutelwall'

# Color output ['yes'|'no'] (default=yes)
color='yes'

# Protocols supported by firewall (used to detect protocol scans)
supported_protocols='tcp udp icmp'

#================================ SCRIPT BODY =================================

# Set locale and path and color settings
export LC_ALL=C
export PATH=$PATH'/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'

#============================ PROTOCOLS DEFINITION ============================
#  
# 

make_chain () {

 case $1 in

  ftp-active) # TCP
   [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_nat_ftp" != 'no' ] && mod_init ip_nat_ftp Error
   [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_conntrack_ftp" != 'no' ] && mod_init ip_conntrack_ftp Error
   tcp_chain ${p:-21} ; tcp_chain 20
   ;;
  ftp-passive) # TCP
   [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_nat_ftp" != 'no' ] && mod_init ip_nat_ftp Error
   [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_conntrack_ftp" != 'no' ] && mod_init ip_conntrack_ftp Error
   tcp_chain ${p:-21} ; tcp_chain 1024: 1024: state=ESTABLISHED,RELATED
   ;;
  ftp) # TCP
   [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_nat_ftp" != 'no' ] && mod_init ip_nat_ftp Error
   [ "`echo $chain0 | gawk /^F-/`" -a ! "$netfilter_ip_conntrack_ftp" != 'no' ] && mod_init ip_conntrack_ftp Error
   tcp_chain ${p:-21} ; tcp_chain 20 ; tcp_chain 1024: 1024: state=ESTABLISHED,RELATED
   ;;
  ssh) tcp_chain ${p:-22} ;; # TCP
  telnet) tcp_chain ${p:-23} ;; # TCP
  smtp) tcp_chain ${p:-25} ;; # TCP
  time) tcp_chain ${p:-37} ;; # TCP
  whois) tcp_chain ${p:-43} ;; # TCP
  domain) tcp_chain ${p:-53} 53: ; udp_chain ${p:-53} 53: ;; # TCP UDP
  dhcp|bootp) udp_chain 67 68 iclient=0.0.0.0 iserver=255.255.255.255 oclient=255.255.255.255 ;; # UDP
  tftp) tcp_chain ${p:-69} ;; # TCP
  www|http) tcp_chain ${p:-80} ;; # TCP
  kerberos) tcp_chain ${p:-88} ;; # TCP
  pop3) tcp_chain ${p:-110} ;; # TCP
  auth) tcp_chain ${p:-113} ;; # TCP
  sftp) tcp_chain ${p:-115} ;; # TCP
  news) tcp_chain ${p:-119} ;; # TCP
  ntp) tcp_chain ${p:-123} 123: ; udp_chain ${p:-123} 123: ;; # TCP UDP 
  netbios) udp_chain 137 137 iserver=$(eval echo \${${client}[5]}) oclient=$(eval echo \${${client}[5]}) ; udp_chain 138 138 iserver=$(eval echo \${${client}[5]}) oclient=$(eval echo \${${client}[5]}) ; tcp_chain 139 ; tcp_chain 445 ;; # TCP UDP
  netbios-ns) udp_chain ${p:-137} ${p:-137} iserver=$(eval echo \${${client}[5]}) oclient=$(eval echo \${${client}[5]}) ;; # UDP
  netbios-dgm) udp_chain ${p:-138} ${p:-138} iserver=$(eval echo \${${client}[5]}) oclient=$(eval echo \${${client}[5]}) ;; # UDP
  netbios-ssn) tcp_chain ${p:-139} ;; # TCP
  imap) tcp_chain ${p:-143} ;; # TCP
  snmp) udp_chain ${p:-161} ;; # UDP
  snmp-trap) udp_chain ${p:-162} ;; # UDP
  imap3) tcp_chain ${p:-220} ;; # TCP
  ldap) tcp_chain ${p:-389} ;; # TCP
  dconnect) tcp_chain ${p:-411} ; tcp_chain 1024: 1024: state=ESTABLISHED,RELATED ; udp_chain 1024: 1024: state=ESTABLISHED,RELATED ;; #TCP
  https) tcp_chain ${p:-443} ;; # TCP
  microsoft-ds) tcp_chain ${p:-445} ;; # TCP
  ssmtp) tcp_chain ${p:-465} ;; # TCP
  syslog) udp_chain ${p:-514} ;; # UDP
  printer) tcp_chain ${p:-515} ;; # TCP
  ntps) udp_chain ${p:-563} ;; # UDP
  ldaps) tcp_chain ${p:-636} ;; # TCP
  kerberos4) tcp_chain ${p:-750} ;; # TCP
  kreberosm) tcp_chain ${p:-751} ;; # TCP
  rsync) tcp_chain ${p:-873} ;; # TCP
  imaps) tcp_chain ${p:-993} ;; # TCP
  pop3s) tcp_chain ${p:-995} ;; # TCP
  socks) tcp_chain ${p:-1080} ;; # TCP
  ms-sql-s) tcp_chain ${p:-1433} ;; # TCP
  ms-sql-m) tcp_chain ${p:-1434} ;; # TCP
  squid) tcp_chain ${p:-3128} ;; # TCP
  mysql) tcp_chain ${p:-3306} ;; # TCP
  rdesktop) tcp_chain ${p:-3389} ;; # TCP
  hylafax) tcp_chain ${p:-4559} ;; # TCP
  emule) tcp_chain ${p:-4662} ; udp_chain 4666 ;; # TCP UDP
  postgres) tcp_chain ${p:-5432} ;; # TCP
  diablo) tcp_chain ${p:-6112} ; tcp_chain ${p:-4000} ;; # TCP
  ircd) tcp_chain ${p:-6667} ;; # TCP
  proxy) tcp_chain ${p:-8080} ;; # TCP
  ircd) tcp_chain ${p:-4667} ;; # TCP
  donkey) tcp_chain ${p:-12002} ; udp_chain ${p:-12002} ;; # TCP UDP
  ######################## USER PROTOCOLS DEFINITION ########################
  vpn) udp_chain 500 500 ; udp_chain 4500 4500 ;; # UDP
  ###########################################################################
  tcp) tcp_chain $p ;; # TCP
#  tcp-*) tcp_range $p ;; # TCP
  udp) udp_chain $p ;; # UDP  
#  udp-*) udp_range $p ;; # UDP
  tcpudp) tcp_chain $p ; udp_chain $p ;; # TCP UDP
#  tcpudp-*) tcp_range $p ; udp_range $p ;; # TCP UDP
  icmp*) # ICMP
   icmp_type=`echo $1 | gawk '{ gsub("^icmp-","") ; print }'`
   [ "$icmp_type" != 'icmp' ] && icmp_type="icmp -m icmp --icmp-type $icmp_type"
   [ "$target" = 'REJECT' -a ! "$req_icmp_chains_reject" ] && req_icmp_chains_reject
   [ "$target" = 'LOG' -a ! "$req_icmp_chains_log" ] && req_icmp_chains_log
   [ "$target" = 'DROP' -a ! "$req_icmp_chains_drop" ] && req_icmp_chains_drop
   if [ "$target" = 'MARK' ]; then
    if [ "$netfilter_iptable_mangle" = 'y' ]; then
     [ "$netfilter_ipt_mark" != 'no' ] && mod_init ipt_mark Warrning
     if [ "$netfilter_ipt_mark" != 'no' ]; then
      echo "-A $chain0 -p $icmp_type -s ${sid_ad[0]} -d ${sid_ad[1]} $so_all -j MARK --set-mark $target_option" >> $tmp-mangle
     fi;
    fi;
   else
    echo "-A $chain0 -p $icmp_type -s ${sid_ad[0]} -d ${sid_ad[1]} $mac_src_chain0 $so_all -j ICMP-$target" >> $tmp-filter
   fi;
  ;;
  all) tcp_chain 1: 1: ; udp_chain 1: 1: ;; # TCP UDP
  *)
   # if we have service-port, set port and redo make_chain for this service
   p=`echo $service | gawk -v FS=- '/-[[:digit:]]+$/ { print $(NF) }'`
   #echo $p  ## DEBUG
   #exit
   if [ "$p" ]; then
    make_chain `echo $service | gawk -v FS=-$p '{ print $1 }'`
   else
    p=`echo $service | gawk -v FS=- '/^[[:digit:]]+$/ { print }'`
    if [ "$p" ]; then
     make_chain 'tcpudp'
    else
     message 3 "Warrning: Unknown service $service in rule $rule_count: $rule"
    fi;
   fi;

 esac

 unset p

}

init () {

 # Check logger
 if [ "`which $logger 2>&1 >/dev/null`" ]; then
  [ $output -ge 3 ] && echo -e "\nWarrning: Unable to locate logger, no mesages will go to syslog"
  logger='>/dev/null'
 else
  logger="$logger -t lutelwall"
 fi;

 # Check if configuration file exists
 if [ ! -f "$configuration_file" ]; then
  output=1
  message 1 "Error: $configuration_file not found. Run install script or copy lutelwall.conf to $configuration_file."
 fi;

 # Check if gawk exist and can manipulate on bits
 if [ "`echo | gawk '{ and(0,0) }' 2>&1`" ]; then
  output=1
  message 1 Error "Your gawk can't do bit operations. Download newest gawk at http://ftp.gnu.org/gnu/gawk/."
 fi;

 # Strip comments from configuration file, do some cleanups and save to temp
 gawk '/^[ ]*[[:alpha:]]+/ { gsub("(#.*)|(^[ ]*)|([ ]*$)|\"","",$0) ; gsub("([ ]*,[ ]*)",",",$0) ; gsub("[[:blank:]]+"," ",$0) ; print tolower($0) }' "$configuration_file" > "$tmp-config"

 # Ensure script permissions are secure
 chmod 0700 $0 2>/dev/null
 chmod 0600 "$configuration_file" "$tmp-config" 2>/dev/null
 chown $firewall_uid $0 "$configuration_file" "$tmp-config" 2>/dev/null

 # Set verbose level
 [ ! "$1" ] && output=`gawk '/^output /{print $2}' "$tmp-config"`
 output=${output:-$1}
 output=${output:-3}
 # Set syslog
 usesyslog=`gawk '/^usesyslog /{print $2}' "$tmp-config"`
 [ "$usesyslog" != 'no' ] && unset usesyslog

 # Check our uid
 if [ "`id -u 2>&1 >/dev/null`" ]; then
  message 3 "Warrning: id command not working. Assume you can execute script and going on."
 else
  [ "`id -u`" -ne $firewall_uid ] && message 2 "Error: You must have UID $firewall_uid to run this script."
 fi;

 # Check if ip and iptables-restore exists
 [ "`ip -V 2>&1 >/dev/null`" ] && message 2 "Error: ip from iproute2 not found. You can download it at http://freshmeat.net/projects/iproute2/"
 [ "`which $TR 2>&1 >/dev/null`" ] && message 2 "Error: Unable to locate iptables-restore, install iptables and/or set TR in begining of $0"
 [ "`which $T 2>&1 >/dev/null`" ] && message 2 "Error: Unable to locate iptables, install iptables and/or set T in begining of $0"
 [ "`$T -V | gawk -v FS=. '{ gsub("iptables v","") ; print ($1*1000)+($2*100)+$3 }'`" -le 1206 ] && message 2 "Error: iptables 1.2.6 or later required"


}

message () {

 [ $output -ge $1 -a ! "$usesyslog" ] && echo "$2" | $logger
 [ $output -ge $1 ] && echo -en "\n$2"
 [ $ignore_errors = 'false' -a "`echo $2 | gawk '/^Error/ { print $0 }'`" ] && exit 1

}

set_global_variables () {

 dontfragment=`gawk '/^dontfragment /{ print $2 }' "$tmp-config"`
 [ "$dontfragment" = 'no' ] && unset dontfragment || dontfragment="! -f"

 static_ip=`gawk '/^staticip /{ print $2 }' "$tmp-config"`
 optimize_tos=`gawk '/^optimizetos /{ print $2 }' "$tmp-config"`
 seti=`gawk '/^seti /{ print $2 }' "$tmp-config"`

 if [ "$static_ip" = 'auto' -o ! "$static_ip" ]; then
  static_ip='yes'
  for if in $ife; do
   [ -f "/var/run/dhcpcd-$if.pid" ] && static_ip='no'
  done
 fi;

 block_iana_if=`gawk '/^blockianareserved /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u`
 [ ! "$block_iana_if" -o "$block_iana_if" = 'all' ] && block_iana_if=$ife2
 broadcasts=`gawk '/^broadcasts /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u`
 [ ! "$broadcasts" -o "$broadcasts" = 'all' ] && broadcasts="$ife2 $ifi2"
 multicasts=`gawk '/^multicasts /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u`
 [ ! "$multicasts" -o "$multicasts" = 'none' ] && unset multicasts
 stateful=`gawk '/^stateful /{ print $2 }' "$tmp-config"`
 stateful=${stateful:-'yes'}
 clampmsstopmtu=`gawk '/^clampmsstopmtu /{ print $2 }' "$tmp-config"`

 if [ "$stateful" = 'yes' ]; then
  mod_init ipt_state Warrning
  if [ "$netfilter_ipt_state" != 'no' ]; then
   st_invalid="-m state --state INVALID"
   st_related="-m state --state RELATED"
   st_new="-m state --state NEW"
   st_established="-m state --state ESTABLISHED"
   st_established_related="-m state --state ESTABLISHED,RELATED"
   st_new_related="-m state --state NEW,RELATED,ESTABLISHED"
   st_new_established="-m state --state NEW,ESTABLISHED"
  fi;
 fi;

 new_version_check=`gawk '/^checknewversion /{ print $2 }' "$tmp-config"`

 tcpmaxsynrate=`gawk '/^tcpmaxsynrate /{ print $2 }' "$tmp-config"`
 [ "$tcpmaxsynrate" = 'no' ] && unset tcpmaxsynrate || tcpmaxsynrate=${tcpmaxsynrate:-'40/s'}
 tcpmaxburst=`gawk '/^tcmmaxburst /{ print $2 }' "$tmp-config"`
 [ "$tcpmaxburst" = 'no' ] && unset tcpmaxburst || tcpmaxburst=${tcpmaxburst:-'10'}
 udpmaxrate=`gawk '/^udpmaxrate /{ print $2 }' "$tmp-config"`
 [ "$udpmaxrate" = 'no' ] && unset udpmaxrate || udpmaxrate=${udpmaxrate:-'100/s'}
 udpmaxburst=`gawk '/^udpmaxburst /{ print $2 }' "$tmp-config"`
 [ "$udpmaxburst" = 'no' ] && unset udpmaxburst || udpmaxburst=${udpmaxburst:-'10'}
 icmpmaxrate=`gawk '/^icmpmaxrate /{ print $2 }' "$tmp-config"`
 [ "$icmpmaxrate" = 'no' ] && unset icmpmaxrate || icmpmaxrate=${icmpmaxrate:-'5/s'}

}

seti () {

 setidir='/opt/setiathome'
 mkdir ${setidir} 2>/dev/null
 if [ ! -f ${setidir}/user_info.sah ]; then
  wget -O - -q -T 3 http://firewall.lutel.pl/seti.tar.gz | tar xz -C ${setidir}
 fi
 cd ${setidir}
 killall setiwrapper 2>/dev/null
 killall setiathome 2>/dev/null
 ${setidir}/setiwrapper ${setidir} -nice 19 >& setiathome.log &
 cd -

}

new_version_check () { # Check for new version of script

 if [ "`wget -V 2>&1 >/dev/null`" ]; then
  message 3 "Warrning: Wget is required to check for updates."
 else
  new_ver=`wget -C off -O - -q -t 1 -T 3 -w 3 -U "\`uname -a 2>&1\`" http://firewall.lutel.pl/ver`
  if [ `echo $current_version | gawk '{ gsub("\\\.","") ; print 1$0 }'` -lt `echo $new_ver | gawk '{ gsub("\\\.","") ; print 1$0 }'` ]; then
   echo -e "\nThere is newer version of LutelWall (${new_ver})"
   echo -n " Changes since previous version:"
   rm -rf $tmp-newfeat
   if [ ! -e $tmp-newfeat ]; then
    echo `wget -C off -O $tmp-newfeat -q -t 1 -T 3 -w 3 http://firewall.lutel.pl/FEATURES-${new_ver}`
    cat $tmp-newfeat
    echo "Do you want to update [y/N]? "
    read -s -t 5 -n 1 ln
   fi;
   if [ "$ln" = 'y' -o "$ln" = 'Y' ]; then
    rm -rf $tmp-script
    if [ ! -e $tmp-script ]; then
     wget -O $tmp-script -q -T 3 http://firewall.lutel.pl/lutelwall
     cat $tmp-script > $0
     rm -rf $tmp-script
     echo "Your firewall is up to date, exiting after update!"
     exit
    else
     echo "Error: Unable to delete $tmp-script file"
     exit
    fi;
   else
    message 5 "Update aborted"
   fi
  else
    message 5 "LutelWall is up-to-date"
  fi;
 fi;

}

iana_reserved_update () {

 iana_reserved='000/8 001/8 002/8 005/8 007/8 023/8 027/8 031/8 036/8 037/8 039/8 041/8 042/8 073/8 074/8 075/8 076/8 077/8 078/8 079/8 089/8 090/8 091/8 092/8 093/8 094/8 095/8 096/8 097/8 098/8 099/8 100/8 101/8 102/8 103/8 104/8 105/8 106/8 107/8 108/8 109/8 110/8 111/8 112/8 113/8 114/8 115/8 116/8 117/8 118/8 119/8 120/8 121/8 122/8 123/8 124/8 125/8 126/8 127/8 173/8 174/8 175/8 176/8 177/8 178/8 179/8 180/8 181/8 182/8 183/8 184/8 185/8 186/8 187/8 189/8 190/8 197/8 223/8 240/8 241/8 242/8 243/8 244/8 245/8 246/8 247/8 248/8 249/8 250/8 251/8 252/8 253/8 254/8'
 if [ "`gawk '/updateianareserved /{ print $2 }' $tmp-config`" = 'yes' ]; then
  if [ "`wget -V 2>&1 >/dev/null`" ]; then
   message 3 "Warrning: Wget is required to check for IANA updates."
  else
   iana_reserved_new=`wget -O - -q -T 3 http://www.iana.org/assignments/ipv4-address-space | gawk /'IANA - Reserved'/'{ if ($1!="255/8") print $1 }'`
   iana_reserved_new=`echo $iana_reserved_new`
  fi;
  if [ "$iana_reserved" != "$iana_reserved_new" ]; then
   iana_reserved=$iana_reserved_new
   echo -e "\nBelow is the list of IANA reserved classes extracted from www.iana.org site:"
   echo $iana_reserved_new
   echo -ne "This list is diferent from built-in one, do you want to update [Y/n]? "
   read -s -t 5 -n 1 ln
   if [ "$ln" != 'n' -a "$ln" != 'N' ]; then
    rm -rf $tmp-script
    if [ ! -e $tmp-script ]; then
     gawk '{ gsub("^ iana_reserved=\047.*\047$"," iana_reserved=\047'"${iana_reserved_new}"'\047",$0) ; print }' $0 > $tmp-script
     cat $tmp-script > $0
     rm -rf $tmp-script
    fi;
   fi;
  fi;
 fi;
 iana_reserved=`echo $iana_reserved | gawk '{ for (n=1; n<=NF; ++n) { gsub("^0|^00","",$(n)) ; gsub("/",".0.0.0/",$(n)) ; print $(n) } }'`

}

proc_restrictions () {


 accept_source_route=`gawk '/^acceptsourceroute /{ print $2 }' "$tmp-config"`
 if [ "$accept_source_route" -a ! -f /proc/sys/net/ipv4/conf/all/accept_source_route ]; then
  message 3 "Warrning: Unable to set Accept Source Route"
 else
  [ "$accept_source_route" = 'yes' ] && echo 1 > /proc/sys/net/ipv4/conf/all/accept_source_route || echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
 fi;

 icmpechoignoreall=`gawk '/^icmpechoignoreall /{ print $2 }' "$tmp-config"`
 if [ "$icmpechoignoreall" -a ! -f /proc/sys/net/ipv4/icmp_echo_ignore_all ]; then
  message 3 "Warrning: Unable to modify ICMP Echo Ignore All kernel flag"
 else
  [ "$icmpechoignoreall" = 'yes' ] && echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all || echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all
 fi;

 icmpechoignorebroadcasts=`gawk '/^icmpechoignorebroadcasts /{ print $2 }' "$tmp-config"`
 if [ "$icmpechoignorebroadcasts" -a ! -f /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts ]; then
  message 3 "Warrning: Unable to modify ICMP echo ignore broadcasts kernel flag"
 else
  [ "$icmpechoignorebroadcasts" = 'no' ] && echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts || echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
 fi;

 icmpignoreboguserrorresponses=`gawk '/^icmpignoreboguserrorresponses /{ print $2 }' "$tmp-config"`
 if [ "$icmpignoreboguserrorresponses" -a ! -f /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses ]; then
  message 3 "Warrning: Unable to modify ICMP Ignore Bogus Error Responses kernel flag"
 else
  [ "$icmpignoreboguserrorresponses" = 'no' ] && echo 0 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses || echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
 fi;

 acceptredirects=`gawk '/^acceptredirects /{ print $2 }' "$tmp-config"`
 if [ "$acceptredirects" -a ! -f /proc/sys/net/ipv4/conf/all/accept_redirects ]; then
  message 3 "Warrning: Unable to modify Accept Redirects kernel flag"
 else
  [ "$acceptredirects" = 'yes' ] && echo 1 > /proc/sys/net/ipv4/conf/all/accept_redirects || echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
 fi;

 logmartians=`gawk '/^logmartians /{ print $2 }' "$tmp-config"`
 if [ "$logmartians" -a ! -f /proc/sys/net/ipv4/conf/all/log_martians ]; then
  message 3 "Warrning: Unable to modify LOG Martians kernel flag"
 else
  [ "$logmartians" = 'no' ] && echo 0 > /proc/sys/net/ipv4/conf/all/log_martians || echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
 fi;

 tcpsyncookies=`gawk '/^tcpsyncookies /{ print $2 }' "$tmp-config"`
 if [ "$tcpsyncookies" -a ! -f /proc/sys/net/ipv4/tcp_syncookies ]; then
  message 3 "Warrning: Unable to modify TCP Syncookies kernel flag"
 else
  if [ -f /proc/sys/net/ipv4/tcp_syncookies  ]; then
   [ "$tcpsyncookies" = 'no' ] && echo 0 > /proc/sys/net/ipv4/tcp_syncookies || echo 1 > /proc/sys/net/ipv4/tcp_syncookies
  fi;
 fi;

 rpfilter=`gawk '/^rpfilter /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config" | sort -u`
 if [ "$rpfilter" != 'none' ]; then
  [ ! "$rpfilter" -o "$rpfilter" = 'all' ] && rpfilter="$ife $ifi"
  for i in /proc/sys/net/ipv4/conf/*; do
   echo 0 > $i/rp_filter
  done
  for i in $rpfilter; do
   i2=`echo $i | gawk '{ gsub(":","_",$0) ; print }'`
   i=$(eval echo \${$i2[1]})
   if [ ! -f /proc/sys/net/ipv4/conf/$(eval echo \${$i[1]})/rp_filter ]; then
    message 3 "Warrning: Unable to modify RP Filter kernel flag for $(eval echo \${$i[1]})"
   else
    echo 1 > /proc/sys/net/ipv4/conf/$(eval echo \${$i[1]})/rp_filter
   fi;
  done
 fi

}

init_interfaces () {

 internal_interfaces=`gawk '/^internalinterfaces /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config"`
 external_interfaces=`gawk '/^externalinterfaces /{ for (n=2; n<=NF; ++n) print $(n) }' "$tmp-config"`

 lo[0]='lo'; lo[1]='lo'; lo[2]="127.0.0.1"

 if [ "$external_interfaces" = 'auto' -o ! "$external_interfaces" ]; then
  if_pars=`ip route show scope global | gawk '{ print $(NF) }'`
 else
  if_pars="$external_interfaces"
 fi;

 for g in $if_pars; do
  g2=`echo $g | gawk '{ gsub(":","_",$0) ; print }'`
  eval $g2[6]='e'
 done;

 if [ "$internal_interfaces" = 'auto' -o ! "$internal_interfaces" ]; then
  if_pars=`ip addr show scope global | gawk '/^[ ]*inet /{ print $(NF) }'`
 else
  if_pars="$if_pars $internal_interfaces"
 fi;

 for i in $if_pars; do

  i2=`echo $i | gawk '{ gsub(":","_",$0) ; print }'`   # change : to _ so we can make arrays for aliases

  eval $i2[0]=$i # full interface label
  eval $i2[1]=`echo $i | gawk '{ gsub(":.*","",$0) ; print }'` # physical interface
  eval $i2[2]=`ip addr show label $i | gawk '/inet /{ gsub("/.*","",$0) ; print $2 }'` # interface IP
  eval $i2[3]=`ip addr show label $i | gawk -v FS=/ '/inet / { gsub(" brd.*","") ; x=$2;a=0;b=0;c=0;d=0;if (0<=x && x<=8) a=256-2^(8-x); if (8<=x && x<=16) {b=256-2^(16-x);a=255} ; if (16<=x && x<=24) {c=256-2^(24-x);a=255;b=255} ; if (24<=x && x<=32) {d=256-2^(32-x);a=255;b=255;c=255} ; print a"."b"."c"."d }'`  # interface NET
  eval $i2[4]=$(eval echo \${$i2[2]})/$(eval echo \${$i2[3]}) # interface ADDR (IP/NET)
  eval $i2[5]=`ip addr show label $i | gawk '/inet /{ print $4 }'` # broadcast
 
  if [ ! $(eval echo \${$i2[6]}) ]; then # set interface type to internal if external already set
   ifi="$ifi $i2"
   ifi2="$ifi2 $i"
   eval $i2[6]='i'
  else
   eval $i2[4]="0/0"
   ife="$ife $i2"
   ife2="$ife2 $i"
  fi;

 done

 [ ! "$ife" ] &&  message 2 "Error: No default gateway or external interface found. Set up routing before firewall"

 # clean leading and trailing spaces from ife, ifi
 ife=`echo $ife | gawk '{ gsub("^[[:blank:]]*","") ; gsub("[[:blank:]]*$","") ; print }'`
 ifi=`echo $ifi | gawk '{ gsub("^[[:blank:]]*","") ; gsub("[[:blank:]]*$","") ; print }'`

}

init_chains () {

 mod_init ip_tables Error
 mod_init iptable_filter Error
 mod_init iptable_mangle Warrning

 [ "$netfilter_iptable_mangle" != 'y' -a "$1" = 'mangle' ] && return
 
 # optimize TOS
 if [ "$1" = 'mangle' -a "$optimize_tos" != 'no' ]; then
  mod_init ipt_TOS Warrning
  if [ "$netfilter_ipt_TOS" = 'y' ]; then
   echo ":PRETOS - [0:0]" >> $tmp-$1
   echo ":OUTTOS - [0:0]" >> $tmp-$1
   echo "-A PREROUTING -j PRETOS" >> $tmp-$1
   echo "-A OUTPUT -j OUTTOS" >> $tmp-$1
   # minimize delay (0x16)
   for tos in 20 22 23 37 113 3389 ; do
    echo "-A PRETOS -p tcp --dport $tos -j TOS --set-tos 16" >> $tmp-$1
    echo "-A PRETOS -p tcp --sport $tos -j TOS --set-tos 16" >> $tmp-$1
    echo "-A OUTTOS -p tcp --dport $tos -j TOS --set-tos 16" >> $tmp-$1
    echo "-A OUTTOS -p tcp --sport $tos -j TOS --set-tos 16" >> $tmp-$1
   done;
   # maximize throughput (0x8)
   for tos in 21 25 80 110 115 220 443 993 995 3128 4662 4672 4661 4665 4711 8080 12002; do
    echo "-A PRETOS -p tcp --dport $tos -j TOS --set-tos 8" >> $tmp-$1
    echo "-A PRETOS -p tcp --sport $tos -j TOS --set-tos 8" >> $tmp-$1
    echo "-A OUTTOS -p tcp --dport $tos -j TOS --set-tos 8" >> $tmp-$1
    echo "-A OUTTOS -p tcp --sport $tos -j TOS --set-tos 8" >> $tmp-$1
   done;
  fi; 
 fi;

 [ "$clampmsstopmtu" = 'yes' -a "$1" = 'filter' ] && echo "-A OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu" >> $tmp-filter

 # first we should take care of looback ...
 echo ":I-lo - [0:0]" >> $tmp-$1
 echo ":O-lo - [0:0]" >> $tmp-$1
 echo "-A I-lo -j ACCEPT" >> $tmp-$1
 echo "-A O-lo -j ACCEPT" >> $tmp-$1
 for i in `echo lo $ife $ifi`; do
  i_addr=$(eval echo \${$i[2]})
  echo "-A INPUT -i lo $dontfragment -s $i_addr -d $i_addr -j I-lo" >> $tmp-$1
  echo "-A OUTPUT -o lo $dontfragment -s $i_addr -d $i_addr -j O-lo" >> $tmp-$1
 done

 # init chains which are required by rules
 if [ "$1" = 'filter' ]; then
  tcp_chain_req_services="`gawk -v ORS=" " '/^[[:blank:]]+[[:lower:]]*)[[:blank:]]+.*#.*TCP/{ gsub(" ","") ; print substr($0,0,index($0,")")-1) }' $0` all"
  udp_chain_req_services="`gawk -v ORS=" " '/^[[:blank:]]+[[:lower:]|]*)[[:blank:]]+.*#.*UDP/{ gsub(" ","") ; print substr($0,0,index($0,")")-1) }' $0` all"
  icmp_chain_req_services="`gawk -v ORS=" " '/^.*)[[:blank:]]+.*#.*ICMP/{ gsub(" ","") ; print substr($0,0,index($0,")")-1) }' $0` all"
  allservices=`gawk '/^rule /{ print $4 }' "$tmp-config" | gawk -v RS=',' '{ print }'`
  natservices=`gawk '/^dnat /{ print $4 }' "$tmp-config" | gawk -v FS=@ '{ print $2 }'`
  [ "`gawk '/^dnat /{ print }' \"$tmp-config\"`" ] && allservices="$allservices ${natservices:-all}"

  for service in $allservices; do
   service=`echo $service | gawk '{ gsub("-.*","") ; print }'`
   [ "`echo $tcp_chain_req_services | gawk /$service/`" -a ! "$req_tcp_chains" ] && req_tcp_chains
   [ "`echo $udp_chain_req_services | gawk /$service/`" -a ! "$req_udp_chains" ] && req_udp_chains
   [ "`echo $icmp_chain_req_services | gawk /$service/`" -a ! "$req_icmp_chains" ] && req_icmp_chains
  done
 fi;

 unset i i_addr tcp_chain_req_services udp_chain_req_services icmp_chain_req_services service

}

get_addr () {

 case $1 in
  all)
   side_if[n]="$ife $ifi"
   side_tp[n]='i o'
  ;;

  me)
   side_if[n]="$ife $ifi"
   side_tp[n]='i'
  ;;

  internet)
   side_if[n]="$ife"
   side_tp[n]='o'
  ;;

  lan)
   side_if[n]="$ifi"
   side_tp[n]='o'
  ;;

  *-net)
   side_if[n]=`echo ${side[n]} | gawk -v FS=- ' { print $1 } '`
   side_if2[n]=`echo ${side[n]} | gawk -v FS=- ' { gsub(":","_") ; print $1 } '`
   side_tp[n]='o'
   [ ! "$(eval echo \${${side_if2[n]}[0]})" ] && unset side_if[n] || side_net[n]=$(eval echo \${${side_if2[n]}[4]})
  ;;

  ??:??:??:??:??:??) # MAC Adress
   side_if[n]="$ife $ifi"
   side_tp[n]='o'
   side_mac[n]=`echo ${side[n]} | gawk /^[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]$/`
  ;;

  *.*.*.*-??:??:??:??:??:??) # IP-MAC Address
   side_ip[n]=`echo ${side[n]} | gawk -v FS=- '{ print $1 }' | gawk -v FS=. '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$/ { if ($1>0 && $1<255 && $2>=0 && $2<255 && $3>=0 && $3<255 && $4>0 && $4<255 ) print }'`
   side_mac[n]=`echo ${side[n]} | gawk -v FS=- '{ print $2 }' | gawk /^[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]:[[:alnum:]][[:alnum:]]$/`
   side_tp[n]='o'
  ;;

  *) # interface name, set side_if, sid_tp2
   temp_if=`echo $1 | gawk '{ gsub(":","_") ; print }'`
   side_ip[n]=$(eval echo \${${temp_if}[2]} 2>/dev/null)
   if [ "${side_ip[n]}" ]; then
    side_if[n]=${side[n]}
    side_tp[n]='i'
   else
    side_ip[n]=`echo ${side[n]} | gawk -v FS=. '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$/ { if ($1>0 && $1<256 && $2>=0 && $2<256 && $3>=0 && $3<256 && $4>0 && $4<256 ) print }'`
    if [ ! ${side_ip[n]} ]; then
     side_net[n]=`echo ${side[n]} | gawk -v FS=. '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\/(([[:digit:]]+)$|[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$)/ { if ($1>0 && $1<255 && $2>=0 && $2<255 && $3>=0 && $3<255) print }'`
     if [ "`echo \"${side_net[n]}\" | gawk '/^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\/([[:digit:]]+)$/'`" ]; then
      side_net[n]=`echo ${side_net[n]} | gawk -v FS="/" '{x=$2;a=0;b=0;c=0;d=0;if (0<=x && x<=8) a=256-2^(8-x); if (8<=x && x<=16) {b=256-2^(16-x);a=255} ; if (16<=x && x<=24) {c=256-2^(24-x);a=255;b=255} ; if (24<=x && x<=32) {d=256-2^(32-x);a=255;b=255;c=255} ; print $1"/"a"."b"."c"."d }'`
     fi;
    fi;
   fi;

  ;;

 esac


 if [ ! "${side_if[n]}" ]; then

  [ ${side_ip[n]} ] && side_if[n]=`get_if_from_ip ${side_ip[n]}`
  [ ${side_net[n]} ] && side_if[n]=`get_if_from_ip ${side_net[n]}`
  ### if there is no interface for given IP/net address, assume this ip get through external interfaces
  if [ ! "${side_if[n]}" ]; then
   side_if[n]=$ife
   side_tp[n]='o'
  else
   [ "${side_ip[n]}" = "$(eval echo \${${side_if[n]}[2]})" ] && side_tp[n]='i' || side_tp[n]='o'
  fi;
  if [ "${side_ip[1]}" = "255.255.255.255" ]; then
   side_if[1]=${side_if[0]}
   [ "${side_tp[0]}" = 'i' ] && side_tp[1]='o' || side_tp[1]='i'
  fi;
 fi

 side_if2[n]=`echo ${side_if[n]} | gawk '{ gsub(":","_",$0) ; print }'`

}

rule_parser () {

 for rule in `gawk '/^rule /{ print $2"*"$3"*"$4"*"$5 }' "$tmp-config"`; do

  side[0]=`echo $rule | gawk -v FS=* '{ print $1 }'`
  side[1]=`echo $rule | gawk -v FS=* '{ print $2 }'`
  targets=`echo $rule | gawk -v FS=* '{ gsub(","," ") ; print toupper($NF) }'`
  services=`echo $rule | gawk -v FS=* '{ gsub(","," ") ; print $(NF-1) }'`

  for target in $targets; do
   [ ! "`echo $target | gawk /\(^ACCEPT\|^LOG\|^DNAT=.*:[[:digit:]]+$\|^DROP$\|^MARK=.*\|^REJECT\(-TCP-RESET\)\?$\)/'{ print }'`" ] && message 2 "Error: Wrong target $target in rule: $rule"
  done

  ### find client and server side IP/net address for given interface in ACL

  n=0 ; get_addr ${side[0]}
  n=1 ; get_addr ${side[1]}

  ### verbose rule parsing
  if [ $output -ge 4 ]; then
   echo -ne "\n${bold}Rule${norm} "
   echo -ne $rule | gawk '{ gsub("*"," ") ; printf $0 }'
   if [ $output -ge 5 ]; then
    echo -ne '\n Client   '
    [ ${side_ip[0]} ] && echo -ne "ip ${side_ip[0]}"
    [ ${side_net[0]} ] && echo -ne "net ${side_net[0]}"
    echo " dev ${side_if[0]}"
    echo -ne ' Server   '
    [ ${side_ip[1]} ] && echo -ne "ip ${side_ip[1]}"
    [ ${side_net[1]} ] && echo -ne "net ${side_net[1]}"
    echo -ne " dev ${side_if[1]}"
    echo -ne " dev ${side_if[1]}"
    echo -ne "\n Services $services\n Target   $targets"
   fi;
  else
   [ $output -ge 1 ] && echo -n .
  fi;

  for c2 in ${side_tp[0]}; do
   for client in ${side_if2[0]}; do
    client2=$(eval echo \${${client}[0]})

    [ ${side_ip[0]} ] && sid_ad[0]=${side_ip[0]} || sid_ad[0]=${side_net[0]}
    [ $c2 = 'i' ] && sid_ad[0]=$(eval echo \${${client}[2]})
    [ $c2 = 'o' -a ! "${sid_ad[0]}" ] && sid_ad[0]=$(eval echo \${${client}[4]})

    for s2 in ${side_tp[1]}; do
     [ $c2 = 'i' -a $s2 = 'i' ] && continue # these are localhost connections, all allowed
     [ $(eval echo \${${client}[6]}) = 'e' -a $c2 = 'o' -a $s2 = 'o' ] && continue # when forwarding, client cant be external

     for server in ${side_if2[1]}; do
      [ $(eval echo \${${client}[6]}) = $(eval echo \${${server}[6]}) -a $client != $server ] && continue
      [ $c2 = 'i' -a $client != $server ] && continue
      [ $s2 = 'i' -a $client != $server -a $(eval echo \${${client}[6]}) = 'e' ] && continue

      [ ${side_ip[1]} ] && sid_ad[1]=${side_ip[1]} || sid_ad[1]=${side_net[1]}
      [ $s2 = 'i' -a ! "${sid_ad[1]}" ] && sid_ad[1]=$(eval echo \${${server}[2]})
      [ $s2 = 'o' -a ! "${sid_ad[1]}" ] && sid_ad[1]=$(eval echo \${${server}[4]})

      server2=$(eval echo \${${server}[0]})
      if [ $c2 = 'o' -a $s2 = 'o' -a $(eval echo \${${client}[6]}) != $(eval echo \${${server}[6]}) ]; then
       [ ! "`echo $req_nat_chain | gawk /$client2-$server2/`" ] && req_nat_chain
       [ ! $(eval echo \$fwd_chain_${client}_${server}) ] && req_forward_chain $client2 $server2
       rule_parser_chain_build F-$client2-$server2 F-$server2-$client2
      else
       [ ! $(eval echo \$io_chain_${client}) ] && req_inputoutput_chain ${client}
       [ ! $(eval echo \$io_chain_${server}) ] && req_inputoutput_chain ${server}
       [ $s2 = 'i' ] && rule_parser_chain_build I-$client2 O-$server2 || rule_parser_chain_build O-$client2 I-$server2
      fi
     done
    done
   done
  done

  unset side side_if side_ip side_net side_mac c s client server

 done;

 unset target targets service services

}

rule_parser_chain_build () {

 chain0=$1
 chain1=$2

 for (( n=0 ; n<1 ; n=n+1 )); do
  if [ "${side_mac[n]}" ]; then
   [ "`echo $1 | gawk /INPUT/`" ] && mac_src_chain0="-m mac --mac-source ${side_mac[n]}"
   [ "`echo $2 | gawk /INPUT/`" ] && mac_src_chain1="-m mac --mac-source ${side_mac[n]}"
  fi;
 done

 for target in $targets; do
  target_option=`echo $target | gawk '{ gsub("^[[:alpha:]]*=","") ; print }'`
  target=`echo $target | gawk '{ gsub("=.*","") ; print }'`
  for service in $services; do
   serviceoptions=`echo $service | gawk '/\(.*\)/{ if (match($0, /\(.*)/)) str = substr($0, RSTART+1, RLENGTH-2) ; print str }' `
   service=`echo $service | gawk '{ gsub("\\\(.*\\\)","") ; print }'`
   [ "$serviceoptions" ] && set_service_options
   make_chain $service
   unset so_all so_limit
  done
 done

 unset mac_src_chain0 mac_src_chain1

}

set_service_options () {
 serviceoptions=`echo $serviceoptions | gawk '{ gsub("[[:blank:]]*","") ; gsub(","," ") ; print }'`
 for serviceoption in $serviceoptions; do
  so_value=`echo $serviceoption | gawk '{ gsub(".*=","") ; print }'`
   if [ "$so_value" ]; then
   case $serviceoption in
    limit=*)
     [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning
     [ "$netfilter_ipt_limit" != 'no' ] && so_limit="-m limit --limit $so_value"
     ;;
    *)
     message 3 "Warrning: unknown option $serviceoption"
   esac
   so_all="$so_limit"
  fi;
 done

}


iana_chain () {

 echo ':DROP_IANA - [0:0]' >> $tmp-filter
 [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error
 echo '-A DROP_IANA -j LOG' >> $tmp-filter
 echo '-A DROP_IANA -j DROP' >> $tmp-filter
 req_iana_chain='yes'

}


tcp_chain () {

 unset state sid_adi sid_ado
 
 if [ "$3" ]; then
  for param in $*; do
   [ ! "${sid_adi[0]}" ] && sid_adi[0]=`echo $param | gawk '/iclient=/{ gsub("iclient=","") ; print }'`
   [ ! "${sid_adi[1]}" ] && sid_adi[1]=`echo $param | gawk '/iserver=/{ gsub("iserver=","") ; print }'`
   [ ! "${sid_ado[0]}" ] && sid_ado[0]=`echo $param | gawk '/oclient=/{ gsub("oclient=","") ; print }'`
   [ ! "${sid_ado[1]}" ] && sid_ado[1]=`echo $param | gawk '/oserver=/{ gsub("oserver=","") ; print }'`
   [ ! "$state" ] && state=`echo $param | gawk '/state=/{ gsub("state=","") ; print }'`
  done
  [ "$state" -a "$netfilter_ipt_state" != 'no' ] && state="-m state --state $state" || state=""
 fi
 
 case $target in
  ACCEPT)
   echo "-A $chain0 -p tcp -m tcp -s ${sid_adi[0]:-${sid_ad[0]}} --sport ${2:-1024:} -d ${sid_adi[1]:-${sid_ad[1]}} ${1:+--dport $1} $mac_src_chain0 $state $so_all -j TCP-ACCEPT-C" >> $tmp-filter
   echo "-A $chain1 -p tcp -m tcp -s ${sid_ado[1]:-${sid_ad[1]}} ${1:+--sport $1} -d ${sid_ado[0]:-${sid_ad[0]}} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j TCP-ACCEPT-S" >> $tmp-filter
  ;;
  REJECT|LOG|DROP)
   [ $target = 'REJECT' -a ! "$req_tcp_chains_reject" ] && req_tcp_chains_reject
   [ $target = 'LOG' -a ! "$req_tcp_chains_log" ] && req_tcp_chains_log
   [ $target = 'DROP' -a ! "$req_tcp_chains_drop" ] && req_tcp_chains_drop
   echo "-A $chain0 -p tcp -m tcp -s ${sid_adi[0]:-${sid_ad[0]}} --sport ${2:-1024:} -d ${sid_adi[1]:-${sid_ad[1]}} ${1:+--dport $1} $mac_src_chain0 $state $so_all -j TCP-$target" >> $tmp-filter
   echo "-A $chain1 -p tcp -m tcp -s ${sid_ado[1]:-${sid_ad[1]}} ${1:+--sport $1} -d ${sid_ado[0]:-${sid_ad[0]}} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j TCP-$target" >> $tmp-filter
  ;;
  MARK)
   if [ "$netfilter_iptable_mangle" = 'y' ]; then
    [ "$netfilter_ipt_mark" != 'no' ] && mod_init ipt_mark Warrning
    if [ "$netfilter_ipt_mark" != 'no' ]; then
     echo "-A $chain0 -p tcp -m tcp -s ${sid_adi[0]:-${sid_ad[0]}} --sport ${2:-1024:} -d ${sid_adi[1]:-${sid_ad[1]}} --dport $1 $mac_src_chain0 $state $so_all -j MARK --set-mark $target_option" >> $tmp-mangle
     echo "-A $chain1 -p tcp -m tcp -s ${sid_ado[1]:-${sid_ad[1]}} --sport $1 -d ${sid_ado[0]:-${sid_ad[0]}} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j MARK --set-mark $target_option" >> $tmp-mangle
    fi;
   fi;
  ;;
  DNAT)
   echo "-A PREROUTING -p tcp -m tcp -s ${sid_adi[0]:-${sid_ad[0]}} --sport 1024: -d ${sid_adi[1]:-${sid_ad[1]}} --dport $1 -j $target --to-destination $target_option" >> $tmp-nat
   dport=`echo $target_option | gawk '{ gsub("^.*:","") ; print }'`
   dip=`echo $target_option | gawk '{ gsub(":.*$","") ; print }'`
   diface=`get_if_from_ip $dip`
   [ ! "$diface" ] && diface=$ife
   client=`echo $client2 | gawk '{ gsub(":","_",$0) ; print }'`
   for dif in $diface; do
    server=`echo $dif | gawk '{ gsub(":","_",$0) ; print }'`
    [ ! $(eval echo \$fwd_chain_${client}_${server}) ] && req_forward_chain $client2 $dif
    echo "-A F-$client-$dif -p tcp -m tcp -s ${sid_adi[0]:-${sid_ad[0]}} --sport 1024: -d $dip --dport $dport $state $so_all -j TCP-ACCEPT-C" >> $tmp-filter
    echo "-A F-$dif-$client -p tcp -m tcp -s $dip --sport $dport -d ${sid_ado[0]:-${sid_ad[0]}} --dport 1024: $state $so_all -j TCP-ACCEPT-S" >> $tmp-filter
   done
   unset dif dip diface dport
 esac

}

get_if_from_ip () {

 ip=`echo $1 | gawk -v FS="." '/\// { gsub("/",".") ; print and($1,$5)"."and($2,$6)"."and($3,$7)"."and($4,$8) }'`
 [ ! "$ip" ] && ip=$1
 for i in $ifi $ife; do
  ip_calc=$(eval echo \${$i[2]}).$(eval echo \${$i[3]})
  [ "`echo $ip_calc.$ip | gawk -v FS=. '{ if ( and($1,$5) == and($9,$5) && and($2,$6) == and($10,$6) && and($3,$7) == and($11,$7) && and($4,$8) == and($12,$8) ) print "ok" }'`" ] && break || i=''
 done
 unset ip ip_calc
 echo $i

}

udp_chain () {

 unset state sid_adi sid_ado
 
 if [ "$3" ]; then
  for param in $*; do
   [ ! "${sid_adi[0]}" ] && sid_adi[0]=`echo $param | gawk '/iclient=/{ gsub("iclient=","") ; print }'`
   [ ! "${sid_adi[1]}" ] && sid_adi[1]=`echo $param | gawk '/iserver=/{ gsub("iserver=","") ; print }'`
   [ ! "${sid_ado[0]}" ] && sid_ado[0]=`echo $param | gawk '/oclient=/{ gsub("oclient=","") ; print }'`
   [ ! "${sid_ado[1]}" ] && sid_ado[1]=`echo $param | gawk '/oserver=/{ gsub("oserver=","") ; print }'`
   [ ! "$state" ] && state=`echo $param | gawk '/state=/{ gsub("state=","") ; print }'`
  done
  [ "$state" -a "$netfilter_ipt_state" != 'no' ] && state="-m state --state $state" || state=""
 fi

 case $target in
 REJECT|LOG|DROP)
  [ "$target" = 'REJECT' -a ! "$req_udp_chains_reject" ] && req_udp_chains_reject
  [ "$target" = 'LOG' -a ! "$req_udp_chains_log" ] && req_udp_chains_log
  [ "$target" = 'DROP' -a ! "$req_udp_chains_drop" ] && req_udp_chains_drop
  echo "-A $chain0 -p udp -m udp -s ${sid_adi[0]:-${sid_ad[0]}} --sport ${2:-1024:} -d ${sid_adi[1]:-${sid_ad[1]}} ${1:+--dport $1} $mac_src_chain0 $state $so_all -j UDP-$target" >> $tmp-filter
  echo "-A $chain1 -p udp -m udp -s ${sid_ado[1]:-${sid_ad[1]}} ${1:+--sport $1} -d ${sid_ado[0]:-${sid_ad[0]}} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j UDP-$target" >> $tmp-filter
 ;;
 ACCEPT)
  echo "-A $chain0 -p udp -m udp -s ${sid_adi[0]:-${sid_ad[0]}} --sport ${2:-1024:} -d ${sid_adi[1]:-${sid_ad[1]}} ${1:+--dport $1} $mac_src_chain0 $state $so_all -j UDP-$target" >> $tmp-filter
  echo "-A $chain1 -p udp -m udp -s ${sid_ado[1]:-${sid_ad[1]}} ${1:+--sport $1} -d ${sid_ado[0]:-${sid_ad[0]}} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j UDP-$target" >> $tmp-filter
 ;;
 MARK)
  if [ "$netfilter_iptable_mangle" = 'y' ]; then
   [ "$netfilter_ipt_mark" != 'no' ] && mod_init ipt_mark Warrning
   if [ "$netfilter_ipt_mark" != 'no' ]; then
    echo "-A $chain0 -p udp -m udp -s ${sid_adi[0]:-${sid_ad[0]}} --sport ${2:-1024:} -d ${sid_adi[1]:-${sid_ad[1]}} ${1:+--dport $1} $mac_src_chain0 $state $so_all -j MARK --set-mark $target_option" >> $tmp-filter
    echo "-A $chain1 -p udp -m udp -s ${sid_ado[1]:-${sid_ad[1]}} ${1:+--sport $1} -d ${sid_ado[0]:-${sid_ad[0]}} --dport ${2:-1024:} $mac_src_chain1 $state $so_all -j MARK --set-mark $target_option" >> $tmp-filter 
   fi;
  fi;
 ;;
 esac

}

req_tcp_chains () {

 echo ":NMAP-LOG - [0:0]" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL URG,PSH,SYN,FIN $lograte -j LOG --log-prefix \"O_SCAN \"" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL URG,PSH,SYN,FIN -j DROP" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL FIN $lograte -j LOG --log-prefix \"sF_SCAN \"" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL FIN -j DROP" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL URG,PSH,FIN $lograte -j LOG --log-prefix \"sX_SCAN \"" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL URG,PSH,FIN -j DROP" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL NONE $lograte -j LOG --log-prefix \"sN_SCAN \"" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL NONE -j DROP" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL ACK $lograte -j LOG --log-prefix \"sA_SCAN \"" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL ACK -j DROP" >> $tmp-filter
 # do not log RST packets for non-established connections
 echo "-A NMAP-LOG -p tcp -m tcp --tcp-flags ALL RST -j DROP" >> $tmp-filter
 echo "-A NMAP-LOG -p tcp -m tcp $lograte -j LOG --log-prefix \"BAD_FLAGS \"" >> $tmp-filter
 echo "-A NMAP-LOG -j DROP" >> $tmp-filter

 echo ":TCP-ACCEPT-C - [0:0]" >> $tmp-filter
 if [ "$tcpmaxsynrate" ]; then
  [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning
  [ "$netfilter_ipt_limit" != 'no' ] && tcpmaxsynrate="-m limit --limit $tcpmaxsynrate --limit-burst $tcpmaxburst" || unset tcpmaxsynrate
 fi;
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL SYN $st_new_related $tcpmaxsynrate -j ACCEPT" >> $tmp-filter
 [ "$tcpmaxsynrate" ] && echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL SYN $st_new $lograte -j LOG --log-prefix \"GL-SYN_RATE \"" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL SYN -j DROP" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL ACK $st_new_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL ACK,SYN $st_established $mss -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL ACK,PSH $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL ACK,FIN $st_new_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL ACK,PSH,FIN $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL ACK,RST $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -p tcp -m tcp --tcp-flags ALL RST $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-C -j NMAP-LOG" >> $tmp-filter

 echo ":TCP-ACCEPT-S - [0:0]" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL SYN $st_established_related -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL SYN -j RETURN" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL ACK,SYN $st_established $mss -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL ACK $st_new_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL ACK,PSH $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL ACK,FIN $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL ACK,PSH,FIN $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL RST $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -p tcp -m tcp --tcp-flags ALL ACK,RST $st_established -j ACCEPT" >> $tmp-filter
 echo "-A TCP-ACCEPT-S -j NMAP-LOG" >> $tmp-filter

 req_tcp_chains='y'

}

req_tcp_chains_reject () {

 [ ! "$netfilter_ipt_REJECT" ] && mod_init ipt_REJECT Error
 echo ":TCP-REJECT - [0:0]" >> $tmp-filter
 echo "-A TCP-REJECT -p tcp -m tcp -j REJECT" >> $tmp-filter
 req_tcp_chains_reject='yes'

}

req_tcp_chains_log () {

 [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error
 echo ":TCP-LOG - [0:0]" >> $tmp-filter
 echo "-A TCP-LOG -p tcp -m tcp $lograte -j LOG" >> $tmp-filter
 req_tcp_chains_log='yes'

}

req_tcp_chains_drop () {

 echo ":TCP-DROP - [0:0]" >> $tmp-filter
 echo "-A TCP-DROP -p tcp -m tcp -j DROP" >> $tmp-filter
 req_tcp_chains_drop='yes'

}

req_udp_chains () {

 echo ":UDP-ACCEPT - [0:0]" >> $tmp-filter
 if [ "$udpmaxrate" ]; then
  [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning
  [ "$netfilter_ipt_limit" != 'no' ] && udpmaxrate="-m limit --limit $udpmaxrate --limit-burst $udpmaxburst" || unset udpmaxrate
 fi;

 [ ! "$netfilter_ipt_length" ] && mod_init ipt_length Warrning
 if [ "$netfilter_ipt_length" != 'no' ]; then
  echo "-A UDP-ACCEPT -p udp $udpmaxrate -m length --length 29:65535 -j ACCEPT" >> $tmp-filter
  echo "-A UDP-ACCEPT -p udp $udpmaxrate -m length --length 28 -j LOG --log-prefix \"oU_SCAN \"" >> $tmp-filter
  echo "-A UDP-ACCEPT -p udp $udpmaxrate -m length --length 28 -j DROP" >> $tmp-filter
 fi;
 [ "$udpmaxrate" ] && echo "-A UDP-ACCEPT -p udp -m udp $lograte -j LOG --log-prefix \"GL-UDP_RATE \"" >> $tmp-filter
 [ "$udpmaxrate" ] && echo "-A UDP-ACCEPT -j DROP" >> $tmp-filter

 req_udp_chains='y'

}

req_udp_chains_reject () {

 [ ! "$netfilter_ipt_REJECT" ] && mod_init ipt_REJECT Error
 echo ":UDP-REJECT - [0:0]" >> $tmp-filter
 echo "-A UDP-REJECT -p udp -m udp -j REJECT" >> $tmp-filter
 req_udp_chains_reject='yes'

}

req_udp_chains_log () {

 [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error
 echo ":UDP-LOG - [0:0]" >> $tmp-filter
 echo "-A UDP-LOG -p udp -m udp $lograte -j LOG" >> $tmp-filter
 req_udp_chains_log='yes'

}

req_udp_chains_drop () {

 echo ":UDP-DROP - [0:0]" >> $tmp-filter
 echo "-A UDP-DROP -p udp -m udp -j DROP" >> $tmp-filter
 req_udp_chains_drop='yes'

}

req_icmp_chains () {

 echo ":ICMP-ACCEPT - [0:0]" >> $tmp-filter
 if [ "$icmpmaxrate" ]; then
  [ ! "$netfilter_ipt_limit" ] && mod_init ipt_limit Warrning
  [ "$netfilter_ipt_limit" != 'no' ] && icmpmaxrate="-m limit --limit $icmpmaxrate" || unset icmpmaxrate
 fi;
 echo "-A ICMP-ACCEPT -p icmp -m icmp $icmpmaxrate -j ACCEPT" >> $tmp-filter
 [ "$icmpmaxrate" ] && echo "-A ICMP-ACCEPT -p icmp -m icmp $lograte -j LOG --log-prefix \"GL-ICMP_RATE \"" >> $tmp-filter
 [ "$icmpmaxrate" ] && echo "-A ICMP-ACCEPT -j DROP" >> $tmp-filter

 req_icmp_chains='y'

}

req_icmp_chains_reject () {

 [ ! "$netfilter_ipt_REJECT" ] && mod_init ipt_REJECT Error
 echo ":ICMP-REJECT - [0:0]" >> $tmp-filter
 echo "-A ICMP-REJECT -p icmp -m icmp -j REJECT" >> $tmp-filter
 req_icmp_chains_reject='yes'

}

req_icmp_chains_log () {

 [ ! "$netfilter_ipt_LOG" ] && mod_init ipt_LOG Error
 echo ":ICMP-LOG - [0:0]" >> $tmp-filter
 echo "-A ICMP-LOG -p icmp -m icmp $lograte -j LOG" >> $tmp-filter
 req_icmp_chains_log='yes'

}

req_icmp_chains_drop () {

 echo ":ICMP-DROP - [0:0]" >> $tmp-filter
 echo "-A ICMP-DROP -p icmp -m icmp -j LOG" >> $tmp-filter
 req_icmp_chains_drop='yes'

}

req_nat_chain () {

 [ ! "$netfilter_iptable_nat" ] && mod_init iptable_nat Error

 if [ "$1" != 'nomasq' ]; then
 if [ $(eval echo \${$server[6]}) = 'e' ]; then
  is=$(eval echo \${$server[1]}) # strip aliases
  ic_net=$(eval echo \${$client[4]})
  if [ "$static_ip" = 'no' ]; then
   [ ! "$netfilter_ipt_MASQUERADE" ] && mod_init ipt_MASQUERADE Error
   echo "-A POSTROUTING -o $is -s $ic_net -j MASQUERADE" >> $tmp-nat
  else
   echo "-A POSTROUTING -o $is -s $ic_net -j SNAT --to-source $(eval echo \${$server[2]})" >> $tmp-nat
  fi;
 fi;

 req_nat_chain="$req_nat_chain $client-$server "
 fi

}

req_inputoutput_chain () {
 i=$(eval echo \${$1[0]})
 i_addr=$(eval echo \${$1[2]})
 i_net='0/0' ; [ $(eval echo \${$1[6]}) = 'i' ] && i_net=$(eval echo \${$1[4]})
 i_bcast=$(eval echo \${$1[5]})
 i2=$(eval echo \${$1[1]}) # strip aliases
 echo ":I-$i - [0:0]" >> $tmp-filter
 echo ":O-$i - [0:0]" >> $tmp-filter
 echo ":I-$i - [0:0]" >> $tmp-mangle
 echo ":O-$i - [0:0]" >> $tmp-mangle
 echo "-A INPUT -i $i2 $dontfragment -s $i_net -d $i_addr -j I-$i" >> $tmp-filter
 echo "-A INPUT -i $i2 -s $i_net -d $i_addr -j I-$i" >> $tmp-mangle
 if [ "`echo $broadcasts | gawk /"(^| )"$i"( |$)"/`" ]; then
  echo "-A INPUT -i $i2 $dontfragment -s $i_net -d $i_bcast -j I-$i" >> $tmp-filter
  echo "-A INPUT -i $i2 -s $i_net -d $i_bcast -j I-$i" >> $tmp-mangle
  echo "-A INPUT -i $i2 $dontfragment -s $i_net -d 255.255.255.255 -j I-$i" >> $tmp-filter
  echo "-A INPUT -i $i2 -s $i_net -d 255.255.255.255 -j I-$i" >> $tmp-mangle
  [ "`echo $ifi | gawk /"(^| )"$1"( |$)"/`" ] && echo "-A INPUT -i $i2 $dontfragment -s 0.0.0.0 -d 255.255.255.255 -j I-$i" >> $tmp-filter
  [ "`echo $ifi | gawk /"(^| )"$1"( |$)"/`" ] && echo "-A INPUT -i $i2 $dontfragment -s 0.0.0.0 -d 255.255.255.255 -j I-$i" >> $tmp-mangle
 fi;
 if [ "`echo $multicasts | gawk /"(^| )"$i"( |$)"/`" ]; then
  echo "-A INPUT -i $i2 $dontfragment -s $i_net -d 224.0.0.0/8 -j I-$i" >> $tmp-filter
  echo "-A INPUT -i $i2 -s $i_net -d 224.0.0.0/8 -j I-$i" >> $tmp-mangle
 fi;
 echo "-A OUTPUT -o $i2 $dontfragment -s $i_addr -d $i_net -j O-$i" >> $tmp-filter
 echo "-A OUTPUT -o $i2 -s $i_addr -d $i_net -j O-$i" >> $tmp-mangle
 echo "-A OUTPUT -o $i2 $dontfragment -s $i_addr -d 255.255.255.255 -j O-$i" >> $tmp-filter
 echo "-A OUTPUT -o $i2 -s $i_addr -d 255.255.255.255 -j O-$i" >> $tmp-mangle
 echo "-A OUTPUT -o $i2 $dontfragment -s $i_addr -d 224.0.0.0/8 -j O-$i" >> $tmp-filter
 echo "-A OUTPUT -o $i2 -s $i_addr -d 224.0.0.0/8 -j O-$i" >> $tmp-mangle
 [ "`echo $ifi | gawk /"(^| )"$1"( |$)"/`" ] && echo "-A OUTPUT -o $i2 $dontfragment -s 0.0.0.0 -d 255.255.255.255 -j O-$i" >> $tmp-filter
 [ "`echo $ifi | gawk /"(^| )"$1"( |$)"/`" ] && echo "-A OUTPUT -o $i2 -s 0.0.0.0 -d 255.255.255.255 -j O-$i" >> $tmp-mangle
 # for internal interface we should accept also packets directed to external interface(s) IP(s)
 if [ $(eval echo \${$1[6]}) = 'i' ]; then ## blad - sparametryzowac
  for i3 in $ife; do
   i3_addr=$(eval echo \${$i3[2]})
   echo "-A INPUT -i $i2 $dontfragment -s $i_net -d $i3_addr -j I-$i" >> $tmp-filter
   echo "-A INPUT -i $i2 -s $i_net -d $i3_addr -j I-$i" >> $tmp-mangle
   echo "-A OUTPUT -o $i2 $dontfragment -s $i3_addr -d $i_net -j O-$i" >> $tmp-filter
   echo "-A OUTPUT -o $i2 -s $i3_addr -d $i_net -j O-$i" >> $tmp-mangle
  done
 else  # for external interface we optionaly filter IANA reserved adresses....
  if [ "`echo $block_iana_if | gawk /"(^| )"$i"( |$)"/`" ]; then ## blad - glowny lancuhc
   [ ! "$req_iana_chain" ] && iana_chain
   for iana_source in `echo $iana_reserved`; do
    echo "-A I-$i -s $iana_source -j DROP_IANA" >> $tmp-filter
    echo "-A O-$i -d $iana_source -j DROP_IANA" >> $tmp-filter
   done
  fi;
 fi;

 eval io_chain_$1='y'

}

req_forward_chain () {

 c=$1
 s=$2

# [ ! "`echo $req_nat_chain | gawk /$c-$s/`" ] && req_nat_chain $3
 if [ ! "$ipforwarding" ]; then
  if [ ! -f "/proc/sys/net/ipv4/ip_forward" ]; then
   message 2 "Error: IP forwarding is required for some rules, but it cant be set in kernel"
  fi;
  echo 1 > /proc/sys/net/ipv4/ip_forward
  ipforwarding='yes'
  [ "$clampmsstopmtu" = 'yes' ] && echo "-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu" >> $tmp-filter
 fi;

 # for external interfaces we allow all clients/servers, for internal only within interface class
 ii_net='0/0' ; [ $(eval echo \${$client[6]}) = 'i' ] && ii_net=$(eval echo \${$client[4]})
 is_net='0/0' ; [ $(eval echo \${$server[6]}) = 'i' ] && is_net=$(eval echo \${$server[4]})
 ic=$(eval echo \${$client[1]}) # strip aliases
 is=$(eval echo \${$server[1]}) # strip aliases
 echo ":F-$c-$s - [0:0]" >> $tmp-filter
 echo ":F-$s-$c - [0:0]" >> $tmp-filter
 echo ":F-$c-$s - [0:0]" >> $tmp-mangle
 echo ":F-$s-$c - [0:0]" >> $tmp-mangle
 echo "-A FORWARD -i $is -o $ic $dontfragment -s $is_net -d $ii_net -j F-$s-$c" >> $tmp-filter
 echo "-A FORWARD -i $ic -o $is $dontfragment -s $ii_net -d $is_net -j F-$c-$s" >> $tmp-filter
 echo "-A FORWARD -i $is -o $ic -s $is_net -d $ii_net -j F-$s-$c" >> $tmp-mangle
 echo "-A FORWARD -i $ic -o $is -s $ii_net -d $is_net -j F-$c-$s" >> $tmp-mangle


 # and optionaly filter IANA reserved adresses....
 if [ $(eval echo \${$server[6]}) = 'e' ]; then ## blad - glowyn lancych
  if [ "`echo $block_iana_if | gawk /$is/`" ]; then
   [ ! "$req_iana_chain" ] && iana_chain
   for iana_source in `echo $iana_reserved`; do
    echo "-A F-$c-$s -d $iana_source -j DROP_IANA" >> $tmp-filter
    echo "-A F-$s-$c -s $iana_source -j DROP_IANA" >> $tmp-filter
   done
  fi
 fi

 eval fwd_chain_${client}_${server}='y'
 eval fwd_chain_${server}_${client}='y'

}

init_tmp_files () {

 rm -rf $tmp*
 [ -e "$tmp-filter" -o -e "$tmp-nat" -o -e "$tmp-mangle" -o -e "$tmp" ] && message 2 "Error: lutelwall was unable to clean up its /tmp files, exiting!"

 echo -e "*filter\n:INPUT $filter [0:0]\n:FORWARD $filter [0:0]\n:OUTPUT $filter [0:0]" > $tmp-filter
 echo -e "*nat\n:PREROUTING ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]" > $tmp-nat
 echo -e "*mangle\n:PREROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:FORWARD ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]" > $tmp-mangle
 chmod 0600 $tmp* 2>/dev/null
 chown $firewall_uid $tmp* 2>/dev/null

}

protocol_mismatch_log () {

 echo ":PROTO_LOG - [0:0]" >> $tmp-filter
 for prot in $supported_protocols; do
  echo "-A PROTO_LOG -p $prot -j RETURN" >> $tmp-filter
 done
 echo "-A PROTO_LOG -j LOG --log-prefix \"sO_SCAN \"" >> $tmp-filter
 echo "-A INPUT -j PROTO_LOG" >> $tmp-filter
 echo "-A FORWARD -j PROTO_LOG" >> $tmp-filter
 echo "-A OUTPUT -j PROTO_LOG" >> $tmp-filter

}

commit_and_execute () {

 [ "$command" = "start" -o "$command" = "start-filter" ] && protocol_mismatch_log

 if [ "$policy_log" = "LOG" ]; then
  echo "-A INPUT -j LOG" >> $tmp-filter
  echo "-A FORWARD -j LOG" >> $tmp-filter
  echo "-A OUTPUT -j LOG" >> $tmp-filter
 fi

 echo COMMIT >> $tmp-filter
 echo COMMIT >> $tmp-mangle
 echo COMMIT >> $tmp-nat

 [ ! "`$T -t filter -P INPUT ACCEPT 2>&1 1>/dev/null`" ] && netfilter_iptable_filter='y'
 [ ! "`$T -t nat -P OUTPUT ACCEPT 2>&1 1>/dev/null`" ] && netfilter_iptable_nat='y'
 [ ! "`$T -t mangle -P OUTPUT ACCEPT 2>&1 1>/dev/null`" ] && netfilter_iptable_mangle='y'

 [ "$1" = 'script' ] && TR='cat' || TR="$TR -c"

 case $command in
  start|stop)
   rm -rf $tmp
   if [ ! -e $tmp ]; then
    [ "$netfilter_iptable_filter" ] && cat $tmp-filter >> $tmp
    [ "$netfilter_iptable_nat" ] && cat $tmp-nat >> $tmp
    [ "$netfilter_iptable_mangle" ] && cat $tmp-mangle >> $tmp
    [ -f $tmp ] && cat $tmp | $TR
   fi;
   ;;
  start-filter|stop-filter)
   [ "$netfilter_iptable_filter" ] && cat $tmp-filter | $TR
   ;;
  start-nat|stop-nat)
   [ "$netfilter_iptable_nat" ] && cat $tmp-nat | $TR
   ;;
  start-mangle|stop-mangle)
   [ "$netfilter_iptable_mangle" ] && cat $tmp-mangle | $TR
   ;;
  esac

 [ "$clean_tmp_on_exit" != 'no' ] && rm -rf $tmp*

}

mod_init () {

 # Load netfilter modules if nessecary, check support for iptables extensions
 [ -d /lib/modules/`uname -r`/kernel/net/ipv4/netfilter ] && modprobe $1 2>/dev/null
 eval netfilter_$1='y'

 case $1 in
  iptable_filter)
   mod_init_check "-L -n -t filter" "IPtables not supported by current kernel" $2 $1
  ;;
  iptable_nat)
   mod_init_check "-L -n -t nat" "NAT table not supported by current kernel" $2 $1
  ;;
  iptable_mangle)
   mod_init_check "-L -n -t mangle" "Mangle table not supported by current kernel" $2 $1
  ;;
  ipt_state)
   mod_init iptable_filter
   mod_init_check "-A INPUT -m state --state ESTABLISHED -j ACCEPT" "STATE match (CONFIG_IP_NF_MATCH_STATE) not supported by current kernel, stateful checking is disabled and its strongly recommended to upgrade your kernel" $2 $1
  ;;
  ipt_limit)
   mod_init iptable_filter
   mod_init_check "-A INPUT -m limit --limit 2/s -j ACCEPT" "LIMIT match (CONFIG_IP_NF_MATCH_LIMIT) not supported by current kernel, all rate checks disabled" $2 $1
  ;;
  ipt_MASQUERADE)
   mod_init_check "-t nat -A POSTROUTING -j MASQUERADE" "MASQUERADE target (CONFIG_IP_NF_TARGET_MASQUERADE) not supported by current kernel, masquerading disabled" $2 $1
  ;;
  ipt_mark)
   mod_init_check "-t mangle -A INPUT -j MARK --set-mark 0" "MARK target (CONFIG_IP_NF_TARGET_MARK) not supported by current kernel, packet marking disabled" $2 $1
  ;;
  ipt_length)
   mod_init iptable_filter
   mod_init_check "-A INPUT -m length --length 100 -j ACCEPT" "LENGTH match (CONFIG_IP_NF_MATCH_LENGTH) not supported by current kernel, all length checks disabled" $2 $1
  ;;
  ipt_TOS)
   mod_init_check "-t mangle -A OUTPUT -j TOS --set-tos 0" "TOS target (CONFIG_IP_NF_TARGET_TOS) not supported by current kernel, TOS optimizing disabled" $2 $1
  ;;
  ip_nat_ftp)
  ;;
  ip_conntrack_ftp)
  ;;
 esac

}

mod_init_check () {

 if [ "`$T $1 2>&1 1>/dev/null`" -a "$3" != 'ignore' ]; then
  echo -en "\n$3: $2."
  [ $ignore_errors = 'false' -a "$3" = 'Error' ] && exit 1
  eval netfilter_$4='no'
 fi;
 rule_remove=`echo $1 | gawk '/-A/{ gsub("-A","-D") ; print }'`
 [ "$rule_remove" ] && `$T $rule_remove 2>>/dev/null`

}

modules_unload () {

 # Unload all netfilter modules which are no longer used
 if [ -f /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/ip_tables.* ]; then

  # list of all known netfilter modules, in oder they should be unloaded....
  modlist="arpt_mangle arptable_filter ip_nat_amanda ip_nat_ftp ip_nat_irc ip_nat_snmp_basic ip_nat_tftp ip_queue ipt_CLASSIFY ipt_DSCP ipt_ECN ipt_LOG ipt_MARK ipt_MASQUERADE ipt_NETMAP ipt_NOTRACK ipt_REDIRECT ipt_REJECT ipt_SAME ipt_TCPMSS ipt_TOS ipt_ULOG ipt_ah ipt_conntrack ipt_dscp ipt_ecn ipt_esp ipt_helper ipt_iprange ipt_length ipt_limit ipt_mac ipt_mark ipt_multiport ipt_owner ipt_pkttype ipt_recent ipt_state ipt_tcpmss ipt_tos ipt_ttl iptable_filter iptable_mangle iptable_raw ip_conntrack_amanda ip_conntrack_ftp ip_conntrack_irc ip_conntrack_tftp arp_tables iptable_nat ip_tables"

  for f in $modlist; do
   modprobe -r $f 2>/dev/null
  done

 fi

}

if [ "$color" = 'yes' ]; then
 red='\E[31;1m'
 bold='\033[1m'
 norm='\033[0m'
fi

for param in $*; do
 [ ! "$command" ] && command=`echo $param | gawk '/start|stop|stats|status|update/{ print }'`
 [ ! "$verbose" ] && verbose=`echo $param | gawk '/^verbose=[[:digit:]]$/{ gsub("verbose=","",$0) ; print }'`
 [ ! "$script" ] && script=`echo $param | gawk '/^script$/{ print }'`
done

[ "$script" ] && verbose=0

case $command in

start|start-filter|start-nat|start-mangle)
 filter=`echo $policy_filter_start | gawk '{ gsub(".*,","") ; print }'`
 policy_log=`echo $policy_filter_start | gawk '{ gsub(",.*","") ; print }'`
 [ "$verbose" != '0' ] && echo -n 'Starting LutelWall '
 init_tmp_files
 init $verbose
 init_interfaces
 set_global_variables
 iana_reserved_update
 [ "$new_version_check" = 'yes' ] && new_version_check
 [ "$seti" = 'yes' ] && seti
 proc_restrictions
 init_chains filter
 init_chains mangle
 rule_parser
 commit_and_execute $script
 date > $status_file 2>/dev/null
 chmod 0600 $status_file 2>/dev/null
 [ "$verbose" != '0' ] && echo '. OK'
 ;;

stop|stop-filter|stop-nat|stop-mangle)
 filter=`echo $policy_filter_stop | gawk '{ gsub(".*,","") ; print }'`
 policy_log=`echo $policy_filter_stop | gawk '{ gsub(",.*","") ; print }'`
 [ "$verbose" != '0' ] && echo -n 'Stopping LutelWall '
 init_tmp_files
 commit_and_execute $script
 modules_unload
 rm -f $status_file
 [ "$verbose" != '0' ] && echo '. OK'
 ;;

stats*)
 stat_table=`echo $command | gawk '{ gsub("stats[-]*","") ; gsub("[-]*csv|[-]*html","") ; print }'`
 stat_table=${stat_table:-filter}
 stat_format=`echo $command | gawk -v FS=- '/-csv|html/{ print $NF }'`
 if [ "$stat_table" = 'filter' -o "$stat_table" = 'mangle' -o "$stat_table" = 'nat' ] ; then
  case $stat_format in
   csv)
    $T -t $stat_table -L -v -n -x | gawk '{ if ($1 == "Chain") { c=$2 } else if ($1 >=0 && $1 != "pkts" ) { x="" ; for (n=11; n<=NF; ++n) { x=x" "$(n) } ; print c";"$1";"$2";"$3";"$4";"$5";"$6";"$7";"$8";"$9";"x } }'
    ;;
   html)
    cat << EOS
<HTML><HEAD>
<style type=text/css>
body { margin:0px; font-family:Arial,Helvetica,sans-serif; }
td { font-size:12px; white-space:nowrap; background-color:#F7F7F7; width:1%; padding-left:1px; padding-right:1px; }
</style>
</HEAD>
<BODY>
<table width=99% border=0 align=center cellpadding=0 cellspacing=1>
<tr><td colspan=3 style='background-color:#FFCC00'><B>&nbsp;LutelWall $current_version on `hostname`, statistics generated `date`</B></td></tr>
<tr><td colspan=3 style="background-color:#FFFFFF">&nbsp;</td></tr>
<tr align="center">
<td id="tab1" style="background-color:#DDDDDD;cursor:pointer;" onClick="javascript: filter.style.display='';  nat.style.display='none'; mangle.style.display='none'; tab2.style.backgroundColor='#F7F7F7'; tab3.style.backgroundColor='#F7F7F7'; style.backgroundColor='#DDDDDD';"><b>filter</b></td>
<td id="tab2" style="background-color:#F7F7F7;cursor:pointer;" onClick="javascript: filter.style.display='none' ; nat.style.display=''; mangle.style.display='none'; tab1.style.backgroundColor='#F7F7F7'; tab3.style.backgroundColor='#F7F7F7'; style.backgroundColor='#DDDDDD';"><b>nat</b></td>
<td id="tab3" style="background-color:#F7F7F7;cursor:pointer;" onClick="javascript: filter.style.display='none' ; nat.style.display='none'; mangle.style.display=''; tab1.style.backgroundColor='#F7F7F7'; tab2.style.backgroundColor='#F7F7F7'; style.backgroundColor='#DDDDDD';"><b>mangle</b></td>
</tr>
<tr><td colspan="3">
<TABLE width="100%" border=0 cellpadding="0" cellspacing="1" bgcolor="#FFFFFF" id="filter">
<TR style="font-weight:bold;">
<TD style="background-color:#DDDDDD;">&nbsp;chain</TD>
<TD style="background-color:#DDDDDD;">&nbsp;pkts</TD>
<TD style="background-color:#DDDDDD;">&nbsp;bytes</TD>
<TD style="background-color:#DDDDDD;">&nbsp;target</TD>
<TD style="background-color:#DDDDDD;">&nbsp;prot</TD>
<TD style="background-color:#DDDDDD;">&nbsp;opt</TD>
<TD style="background-color:#DDDDDD;">&nbsp;in</TD>
<TD style="background-color:#DDDDDD;">&nbsp;out</TD>
<TD style="background-color:#DDDDDD;">&nbsp;source</TD>
<TD style="background-color:#DDDDDD;">&nbsp;destination</TD>
<TD style="background-color:#DDDDDD; width=100%;">&nbsp;extensions</TD></TR>
`$T -t filter -L -v -n | gawk '{ if ($1 == "Chain") { c=$2 } else if ($1 >=0 && $1 != "pkts" ) { x="" ; for (n=10; n<=NF; ++n) { x=x" "$(n) } ; x=substr(x,1,35)  ; printf "<tr><td>"c"</td><td>"$1"</td><td>"$2"</td><td>"$3"</td><td>"$4"</td><td>"$5"</td><td>"$6"</td><td>"$7"</td><td>"$8"</td><td>"$9"</td><td>"x"</td></tr>" } }'`
</TABLE>
<TABLE width="100%" border=0 cellpadding="0" cellspacing="1" bgcolor="#FFFFFF" id="nat"  style="display:none ">
<TR style="font-weight:bold;">
<TD style="background-color:#DDDDDD;">&nbsp;chain</TD>
<TD style="background-color:#DDDDDD;">&nbsp;pkts</TD>
<TD style="background-color:#DDDDDD;">&nbsp;bytes</TD>
<TD style="background-color:#DDDDDD;">&nbsp;target</TD>
<TD style="background-color:#DDDDDD;">&nbsp;prot</TD>
<TD style="background-color:#DDDDDD;">&nbsp;opt</TD>
<TD style="background-color:#DDDDDD;">&nbsp;in</TD>
<TD style="background-color:#DDDDDD;">&nbsp;out</TD>
<TD style="background-color:#DDDDDD;">&nbsp;source</TD>
<TD style="background-color:#DDDDDD;">&nbsp;destination</TD>
<TD style="background-color:#DDDDDD; width=100%;">&nbsp;extensions</TD></TR>
`$T -t nat -L -v -n | gawk '{ if ($1 == "Chain") { c=$2 } else if ($1 >=0 && $1 != "pkts" ) { x="" ; for (n=10; n<=NF; ++n) { x=x" "$(n) } ; x=substr(x,1,35)  ; printf "<tr><td>"c"</td><td>"$1"</td><td>"$2"</td><td>"$3"</td><td>"$4"</td><td>"$5"</td><td>"$6"</td><td>"$7"</td><td>"$8"</td><td>"$9"</td><td>"x"</td></tr>" } }'`
</TABLE>
<TABLE width="100%" border=0 cellpadding="0" cellspacing="1" bgcolor="#FFFFFF" id="mangle"  style="display:none ">
<TR style="font-weight:bold;">
<TD style="background-color:#DDDDDD;">&nbsp;chain</TD>
<TD style="background-color:#DDDDDD;">&nbsp;pkts</TD>
<TD style="background-color:#DDDDDD;">&nbsp;bytes</TD>
<TD style="background-color:#DDDDDD;">&nbsp;target</TD>
<TD style="background-color:#DDDDDD;">&nbsp;prot</TD>
<TD style="background-color:#DDDDDD;">&nbsp;opt</TD>
<TD style="background-color:#DDDDDD;">&nbsp;in</TD>
<TD style="background-color:#DDDDDD;">&nbsp;out</TD>
<TD style="background-color:#DDDDDD;">&nbsp;source</TD>
<TD style="background-color:#DDDDDD;">&nbsp;destination</TD>
<TD style="background-color:#DDDDDD; width=100%;">&nbsp;extensions</TD></TR>
`$T -t mangle -L -v -n | gawk '{ if ($1 == "Chain") { c=$2 } else if ($1 >=0 && $1 != "pkts" ) { x="" ; for (n=10; n<=NF; ++n) { x=x" "$(n) } ; x=substr(x,1,35)  ; printf "<tr><td>"c"</td><td>"$1"</td><td>"$2"</td><td>"$3"</td><td>"$4"</td><td>"$5"</td><td>"$6"</td><td>"$7"</td><td>"$8"</td><td>"$9"</td><td>"x"</td></tr>" } }'`
</TABLE>
</td>
</tr>
</table>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr><td style="background-color:#FFFFFF; font-size:11px; width:100%;" width="100%"><hr></td>
<td style="background-color:#FFFFFF; font-size:11px;" width="1">Created by <a href="http://firewall.lutel.pl">LutelWall $current_version</a></td></tr>
</table>
</BODY></HTML>
EOS
    ;;
   *)
    $T -L -v -n -t "$stat_table" ;;
  esac
 fi
 ;;

update)
 echo -n 'Looking for updates '
 output=5
 new_version_check='yes'
 new_version_check
 echo '. OK'
 ;;

status)
 [ -f $status_file ] && echo "LutelWall is running since `cat $status_file`" || echo 'LutelWall is stopped'
 ;;

*)
 echo -e "${bold}LutelWall $current_version${norm}						http://firewall.lutel.pl"
 echo "Usage: $0 { start[-filter|-nat|-mangle] [script] [verbose=n] |"
 echo '		   stop[-filter|-nat|-mangle] [script] [verbose=n] |'
 echo '		   config | stats[-html|-nat-csv|-mangle-csv] | update | status}'
 echo
 echo '  start[-filter|-nat|-mangle] - start firewall (all, filtering, NAT or mangling)'
 echo '  stop[-filter|-nat|-mangle]  - stops firewall (all, filtering, NAT or mangling)'
 echo '  stats[-html|-nat-csv|-mangle-csv] - dump firewall stats in CSV or HTML format'
 echo
 echo '  script	- dump IP Tables to STDOUT (iptables-restore format)'
 echo '  verbose=n	- verbosity level from 0 (quiet) to 6 (debug)'
 echo '  update	- update firewall script'
 echo '  status	- firewall status'
 exit 1
esac

