#!/bin/sh
#avbf2_6 for Linux iptables with Kernel 2.6.x.x
#avoid brute force in AP Mode on an Asus WL500gPV1 or newer (gPV2,500W,RT-N16)
#This script works with iptables and xt_recent module, xt_connlimit and xt_multiport
#Script works with oleg/ily's firmware for Asus-Routers with Kernel => 2.6.22.19
#written by newbiefan at wl500g.info (for asus users)
#Please read the entire howto of this script in order to understand which ports are protected
#contact: hirau@gmx.at
#Licence of this script: GNU GPL2
#
#AVBF2_6 V1.01
#
#be aware: this is not a firewall!!


#Message for logfile
logger -t AVBF "IPTABLES Script started"

################################ A D J U S T ##########################################
#where are the modules located........
ipt=/usr/sbin/iptables  #path to iptables
mod_ipt1=/lib/modules/2.6.22.19/xt_recent.ko
mod_ipt2=/lib/modules/2.6.22.19/xt_connlimit.ko
mod_ipt3=/lib/modules/2.6.22.19/xt_multiport.ko
#mod_ipt4=/lib/modules/2.6.22.19/xt_string.ko
#mod_ipt5=/lib/modules/2.6.22.19/iptable_raw.ko

forwardport="22,23" #use forwarded ports (all honeyports, comma-separated)
ftp_ssh_ports="21,2222" #ports for ftp and ssh (comma-separated)
                   
conlimit=true #activate connectionlimit to maxconn per ip for port 80, set to true or false
maxconn=20 #set the max connections per ip for tcp, consider, MS-IE can have 8 connections at the same time
           #for instance when somebody open a gallery with many thumbnails, increase this value
           #each picture can open a new connection
ssh_hitcount=3 #how many new connections within block_time_ssh seconds to port 21&2222 are allowed
webhitcount=15 #how many new connections within block_time_http seconds to your webserver are allowed
               #when you run into problems with your webserver, set it to max 20, if more hitcounts are needed
               #you have to set it to more as 20, just google how to set iptables
block_time_ssh=360 #how long to block port 21&2222 when hitcount reached
block_time_http=10 #how long to block port 80 when hitcount reached
################## E N D   O F   A D J U S T M E N T ##################################

#use the newest file located at /opt/etc/hosts.deny
if [ -f /opt/etc/hosts.deny ] ; then
   denyhosts=/opt/etc/hosts.deny
 else
   denyhosts=/tmp/etc/hosts.deny
fi   
logger -t AVBF "Use file $denyhosts to ban ip's"

#check for module xt_recent
if [ -z "`lsmod | grep xt_recent`" ] ; then
  echo AVBF: "Module xt_recent not loaded, will do it now...."
  logger -t AVBF "Module xt_recent loaded"
  /sbin/insmod $mod_ipt1 ; sleep 1
 else 
  logger -t AVBF "Module xt_recent already loaded"
fi

#check for module xt_connlimit when conlimit is set to true
if $conlimit ; then
if [ -z "`lsmod | grep xt_connlimit`" ] ; then
  echo AVBF: "Module xt_connlimit not loaded, will do it now...."
  logger -t AVBF "Module xt_connlimit loaded"
  /sbin/insmod $mod_ipt2 ; sleep 1
 else
  logger -t AVBF "Module xt_connlimit already loaded"
fi
  logger -t AVBF "xt_connlimit allows max $maxconn connections from one IP/netmask 8"
fi

#check for module xt_multiport
if [ -z "`lsmod | grep xt_multiport`" ] ; then
  echo AVBF: "Module xt_multiport not loaded, will do it now...."
  logger -t AVBF "Module xt_multiport loaded"
  /sbin/insmod $mod_ipt3 ; sleep 1
 else 
  logger -t AVBF "Module xt_multiport already loaded"
fi

#check for module xt_string
#if [ -z "`lsmod | grep xt_string`" ] ; then
#  echo AVBF: "Module xt_string not loaded, will do it now...."
#  logger -t AVBF "Module xt_string loaded"
#  /sbin/insmod $mod_ipt4 ; sleep 1
# else 
#  logger -t AVBF "Module xt_string already loaded"
#fi

#check for module iptable_raw
#if [ -z "`lsmod | grep iptable_raw`" ] ; then
#  echo AVBF: "Module iptable_raw not loaded, will do it now...."
#  logger -t AVBF "Module iptable_raw loaded"
#  /sbin/insmod $mod_ipt5 ; sleep 1
# else 
#  logger -t AVBF "Module iptable_raw already loaded"
#fi

#emty all chains
$ipt -F
#and delete own chains
$ipt -X
sleep 1

###############we create own chains
#$ipt -N BLOCKIT
$ipt -N Banned
$ipt -N limitlog
$ipt -N webprotect
$ipt -N BRUTE
$ipt -N SCANNER
$ipt -N logdrop
$ipt -N logaccept
$ipt -N UDPCHECK
$ipt -N logonly
$ipt -N logintern

######################### FILTER INPUT CONNECTIONS ########################################

#just make sure, that ips from lan and localhost get never banned and/or firewalled (this is very important in case of AP mode)
#RFC 1918 and RFC 1122 (Private Class C Network and Loopback)
#$ipt -A INPUT -i br0 -s 192.168.0.0/16 -m conntrack --ctstate NEW -j logintern
$ipt -A INPUT -s 192.168.0.0/16 -j ACCEPT

#When you need telnet and/or ssh only (for tests)
#$ipt -A INPUT -p tcp -m tcp --dport 23 -s 192.168.0.0/16 -j ACCEPT
#$ipt -A INPUT -p tcp -m tcp --dport 22 -s 192.168.0.0/16 -d $asusip -j logaccept

#accept loopback interface
#$ipt -A INPUT -i br0 -s 127.0.0.1/32 -m conntrack --ctstate NEW -j logintern
$ipt -A INPUT -s 127.0.0.1/32 -j ACCEPT

#Stealth Scans, keine Flags gesetzt
$ipt -A INPUT -p tcp --tcp-flags ALL NONE -j REJECT --reject-with tcp-reset 

#check for bogus packets and invalid ip addresses (RFC1918)
$ipt -A INPUT -m conntrack --ctstate INVALID -j DROP #drop invalid packets
$ipt -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP 
$ipt -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
$ipt -A INPUT -s 169.254.0.0/16 -j DROP
$ipt -A INPUT -s 172.16.0.0/12 -j DROP
$ipt -A INPUT -s 192.0.2.0/24 -j DROP
$ipt -A INPUT -s 10.0.0.0/8 -j DROP

#Allow an established connection, independent of port
$ipt -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

#open torrent ports, and xml-rpc port 6800, 6801
$ipt -A INPUT -p tcp --destination-port 6800:6801 -j ACCEPT
$ipt -A INPUT -p tcp --destination-port 6881:6999 -j ACCEPT
$ipt -A INPUT -p udp --destination-port 6800:6801 -j ACCEPT
$ipt -A INPUT -p udp --destination-port 6881:6999 -j ACCEPT

#we block everything of hosts.deny list with netmask, syntax of list: "ip/netmask"
#this allows you to block completely bad networks/provider
if [ -e $denyhosts ] ; then
  for ipnm in `cat $denyhosts` ; do
      $ipt -A INPUT -s $ipnm -j Banned
  done
   logger -t AVBF "List with banned ip's loaded"
 else
   logger -t AVBF "No List with banned ip's available!"
fi

#The first rule is BLOCKIT, so everything has to go through this chain
#Use this chain, when you want to block at runtime IP's aso.
#Just add an IP and/or with netmask to blockit at runtime, particulary when adding an ip by script
#$ipt -A INPUT -j BLOCKIT

################################LIMITS AND GENERAL PROTECTION#######################################################
#With paranoia you can log everything, except your network and banned network 
#$ipt -A INPUT -j LOG --log-prefix "LOG ALL "

#We filter bad user-agents like ZmEu
#$ipt -A INPUT -p tcp -s 0.0.0.0/0 -m string --string --algo bm "cmd.exe" -j DROP
#$ipt -A INPUT -p tcp -s 0.0.0.0/0 -m string --string --algo bm "ZmEu" -j DROP
#$ipt -I INPUT 1 -m string --string "cmd.exe" -j DROP

$ipt -A INPUT -p icmp -j logdrop	#any kind of icmp is dropped

#And fragmented packets are logged and dropped
$ipt -A INPUT -f -m limit --limit $(( $maxconn/2 ))/min -j LOG --log-prefix "[FRAGMENTED ] " --log-level=info
$ipt -A INPUT -f -j DROP

#Block IP's from a portscan for a complete day
#Forwarded ports to your Asus - honeyports (forwardport)
$ipt -A INPUT -p tcp -m multiport --destination-port $forwardport -j SCANNER
$ipt -A INPUT -m recent --rcheck --seconds 86400 --name portscan --rsource -j LOG --log-prefix "[SCANNER banned] "
$ipt -A INPUT -m recent --update --seconds 86400 --name portscan --rsource -j DROP

#Limit the number of new parallel connections per class C network (netmask 8) to protect your server
#Keep the allowed max. connections as low as possible - run some tests.....(set var connlimit to true or false)
if $conlimit ; then
$ipt -A INPUT -p tcp --syn -m connlimit --connlimit-above $maxconn --connlimit-mask 8 -j LOG --log-prefix "[Too much connections] "
$ipt -A INPUT -p tcp --syn -m connlimit --connlimit-above $maxconn --connlimit-mask 8 -j DROP
fi

# Set proofed limits for http 1.1 clients (1.0 does not use pipelining), this part is taken from debianroot.de
$ipt -A INPUT -p tcp --syn -j limitlog
###############################END OF LIMITS AND GENERAL PROTECTION########################################################

#Protect your webserver
$ipt -A INPUT -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW -j webprotect

#FTP&SSH check for new connections and count at chain BRUTE
$ipt -A INPUT -p tcp -m multiport --destination-port $ftp_ssh_ports -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j BRUTE
$ipt -A INPUT -p tcp -m multiport --destination-port $ftp_ssh_ports -m conntrack --ctstate NEW -j BRUTE

#When you need external access to your routers webinterface on port 88
#$ipt -A INPUT -p tcp --dport 88 -j logaccept   #This is from wan to your webinterface
#$ipt -A INPUT -p tcp --dport 88 -s 192.168.0.0/16 -j logaccept  #Just from your network in case you need it

#All other tcp packets are logged and rejected, have a closer look at your modem/router, something is wrong!!
$ipt -A INPUT -p tcp -j logonly
$ipt -A INPUT -p tcp -j REJECT --reject-with tcp-reset

#This is for broadcast udp packets from your network. Such a packet is logged
$ipt -A INPUT -p udp -j UDPCHECK

#Consider, when you need udp you have to add a chain/rule here to allow udp
$ipt -A INPUT -j DROP
###################### END OF INPUT CHAIN ###############################

#chain banned, log depending to protocol and drop 
$ipt -A Banned -p tcp -m limit --limit 1/min --limit-burst 5 -j LOG --log-prefix "[TCP Banned] " --log-level=info
$ipt -A Banned -p udp -m limit --limit 1/min --limit-burst 5 -j LOG --log-prefix "[UDP Banned] " --log-level=info
$ipt -A Banned -p icmp -m limit --limit 1/min --limit-burst 5 -j LOG --log-prefix "[ICMP Banned] " --log-level=info
$ipt -A Banned -j DROP

#allow half of maxconn up to maxconn connections per minute
$ipt -A limitlog -m limit  --limit $(( $maxconn/2 ))/min --limit-burst $maxconn -j RETURN
$ipt -A limitlog -m limit --limit 1/min --limit-burst 2 -j LOG --log-prefix "[Limit exceeded] "
$ipt -A limitlog -j DROP

#Block nmap and other port scanner
$ipt -A SCANNER -j LOG --log-prefix "[Portscan] "
$ipt -A SCANNER -m recent --set --name portscan --rsource -j DROP

#Do not allow too much new connections to your webserver
$ipt -A webprotect -m recent --name webprotect --rcheck --seconds $block_time_http --hitcount $webhitcount --rsource -j LOG --log-prefix "[IP banned from Webserver] "
$ipt -A webprotect -m recent --name webprotect --update --seconds $block_time_http --hitcount $webhitcount --rsource -j DROP
$ipt -A webprotect -m recent --set --name webprotect --rsource -j logaccept

#... handling of white/blacklists in BRUTE chain
$ipt -A BRUTE -m recent --rcheck --seconds $block_time_ssh --hitcount $ssh_hitcount --name BRUTE --rsource -j LOG --log-prefix "[BRUTE FORCE IP banned] "
$ipt -A BRUTE -m recent --update --seconds $block_time_ssh --hitcount $ssh_hitcount --name BRUTE --rsource -j DROP
$ipt -A BRUTE -m recent --set --name BRUTE --rsource -j logaccept

#Write to log and accept
$ipt -A logaccept -m conntrack --ctstate NEW -j LOG --log-prefix "[ACCEPT] " --log-tcp-sequence --log-tcp-options --log-ip-options --log-macdecode
$ipt -A logaccept -j ACCEPT

#Write to log and drop
$ipt -A logdrop -m conntrack --ctstate NEW -j LOG --log-prefix "[DROP] " --log-tcp-sequence --log-tcp-options --log-ip-options --log-macdecode
$ipt -A logdrop -m conntrack --ctstate INVALID -m limit --limit 5/min -j LOG --log-prefix "[INVALID] " --log-level=info
$ipt -A logdrop -j DROP

#When you find the message "End of input chain" you forward other ports as 21,22 and 80 (and maybe 88), so something can be wrong 
$ipt -A logonly -p tcp -j LOG --log-prefix "[End of Input chain] " --log-tcp-sequence --log-tcp-options --log-ip-options --log-macdecode
$ipt -A logonly -j RETURN

#Chain udpcheck write to log any startup of a device inside your network
#broadcast messages from your network, RFC 919, 922
$ipt -A UDPCHECK -s 0.0.0.0 -d 255.255.255.255 -m limit --limit 1/h --limit-burst 1 -j LOG --log-prefix "[LAN-PC/DEVICE-STARTUP] "
$ipt -A UDPCHECK -s 0.0.0.0 -d 255.255.255.255 -j ACCEPT
$ipt -A UDPCHECK -j RETURN

#chain logintern, log depending to protocol and ACCEPT (Consider, only new packets are logged)
$ipt -A logintern -p tcp -m limit --limit 1/min --limit-burst 2 -j LOG --log-prefix "[TCP intern] " --log-level=info
$ipt -A logintern -p udp -m limit --limit 1/min --limit-burst 2 -j LOG --log-prefix "[UDP intern] " --log-level=info
$ipt -A logintern -p icmp -m limit --limit 2/min --limit-burst 3 -j LOG --log-prefix "[ICMP intern] " --log-level=info
$ipt -A logintern -j ACCEPT

#Chain BLOCKIT is just a placeholder for possibility to block bad ip's before any other rule, but it is not needed!
#see script checklog and add a checklog call to crontab every x minute.
#$ipt -A BLOCKIT -j RETURN
