#!/bin/sh
# this program is used to check tcp/ip connections
# and block those ip with excessive connections
# my version
myver="1.0RC1"
# wake up every 120s if last check found abuse client
wakeup_time_min=120
# wake up every 300s if last check found no abuse client
wakeup_time_max=300
# rule timeout 3600s
rule_timeout=3600
# check port list
portlist="80"
# max established connection per ip
max_active_conn=8
# iptables chain name
iptables_chain_name="RH-Lokkit-0-50-INPUT"
# log facility
log_facility="local0"
# Block policy
ipchains_block_policy="DENY"
iptables_block_policy="REJECT"
# myself
myself=`basename $0`
mylogger_info()
{
logger -p $log_facility.info -t $myself $@ 2>/dev/null
}
mylogger_debug()
{
logger -p $log_facility.debug -t $myself $@ 2>/dev/null
}
mylogger_notice()
{
logger -p $log_facility.notice -t $myself $@ 2>/dev/null
}
dotimeout()
{
mylogger_info "reset firewall when timeout arrives"
case "$firewall" in
ipchains)
/etc/init.d/ipchains restart 1>/dev/null 2>/dev/null
if [ $? = 0 ] ; then
mylogger_info "ipchains restarted"
else
mylogger_notice "ipchains restart failed"
fi
;;
iptables)
/etc/init.d/iptables restart 1>/dev/null 2>/dev/null
if [ $? = 0 ] ; then
mylogger_info "iptables restarted"
else
mylogger_notice "iptables restart failed"
fi
;;
*)
mylogger_notice "neither ipchains nor iptables"
;;
esac
}
blockclient()
{
if [ -z "$1" ] || [ -z "$2" ]; then
mylogger_notice "blockclient() missing client or port to block"
return
fi
local ip port
ip=$1
port=$2
case "$firewall" in
ipchains)
mylogger_notice "blocking $1 to $2 via ipchains"
found=`ipchains -nL | egrep "^$ipchains_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+\->[[:space:]]+$port"`
if [ -z "$found" ] ; then
cmd="ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null"
mylogger_debug "cmd: $cmd"
`ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null`
if [ $? != 0 ] ; then
mylogger_notice "$cmd call failed"
return
fi
new_block=1
ever_block=1
else
mylogger_info "$ip already blocked to $port"
fi
;;
iptables)
mylogger_notice "blocking $1 to $2 via iptables"
found=`iptables -nL | egrep "^$iptables_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+dptport[[:space:]]+"`
if [ -z "$found" ] ; then
cmd="iptables -I $iptables_chain_name 1 -p tcp -m tcp -s $ip --dport $port -j $iptables_block_policy 1>/dev/null 2>/dev/null"
mylogger_debug "cmd: $cmd"
`iptables -I $iptables_chain_name 1 -p tcp -m tcp -s $ip --dport $port -j $iptables_block_policy 1>/dev/null 2>/dev/null`
if [ $? != 0 ] ; then
mylogger_notice "$cmd call failed"
return
fi
new_block=1
ever_block=1
else
mylogger_info "$ip already blocked to $port"
fi
;;
*)
mylogger_notice "neither ipchains nor iptables"
;;
esac
}
restartservice()
{
local service
if [ -z "$1" ] ; then
mylogger_notice "no port given to see which service to be restart"
return
fi
case "$1" in
80)
service="httpd"
;;
25)
service="postfix"
;;
110)
service="courier-pop3d"
;;
21)
service="muddleftpd"
;;
53)
service="named"
;;
3306)
service="mysqld"
;;
esac
if [ ! -z "$service" ] ; then
/etc/init.d/$service restart 1>/dev/null 2>/dev/null
if [ $? = 0 ] ; then
mylogger_notice "$service restarted"
else
mylogger_notice "$service restart failed"
fi
fi
}
docheckport()
{
mylogger_info "do check port $1"
local port last_client count client total_count
if [ -z "$1" ] ; then
mylogger_notice "docheckport() port not given"
return
fi
port=$1
clientlist=`netstat -an --tcp| grep ESTABLISHED | awk "{ if ( index(\\$4,\"port\" ) print \\$5}" | awk -F ':' '{print $1}'|sort`
if [ $? != 0 ] ; then
mylogger_notice "netstat call failed"
return
fi
#echo $clientlist
# reset new_block
new_block=0
count=0
total_count=0
last_client=""
for client in $clientlist
do
#echo "client is $client"
if [ -z "$last_client" ] ; then
count=$((count+1))
total_count=$((total_count+1))
last_client=$client
else
if [ "$client" = "$last_client" ] ; then
count=$((count+1))
total_count=$((total_count+1))
else
mylogger_debug "$last_client $count connections"
if [ $count -ge $max_active_conn ] ; then
mylogger_notice "client $last_client connection $count >= $max_active_conn"
blockclient $last_client $port
fi
count=1
total_count=$((total_count+1))
last_client=$client
fi
fi
done
# check the last client
if [ ! -z "$client" ] ; then
count=$((count+1))
total_count=$((total_count+1))
mylogger_debug "$client $count connections"
if [ $count -ge $max_active_conn ] ; then
mylogger_notice "client $client connection $count >= $max_active_conn"
blockclient $client $port
fi
fi
mylogger_info "total connections on port $port: $total_count"
if [ $new_block = 1 ] ; then
restartservice $port
fi
}
docheckall()
{
# reset wakeup_time
wakeup_time=$wakeup_time_max
for port in $portlist
do
docheckport $port
if [ $new_block = 1 ] ; then
# set wakeup_time shorter cause we found some abuse client
wakeup_time=$wakeup_time_min
fi
done
}
if [ -z "$firewall" ] && [ -f /etc/sysconfig/ipchains ] ; then
firewall="ipchains"
fi
if [ -z "$firewall" ] && [ -f /etc/sysconfig/iptables ] ; then
firewall="iptables"
fi
if [ -z "$firewall" ] ; then
echo "Error: This machine does not have ipchains or iptables firewall support"
exit 1
fi
mylogger_info "firewall.sh v$myver ValueOf.com starting"
mylogger_info "Firewall is: $firewall"
mylogger_info "ort protected: $portlist"
mylogger_info "Max connection per ip: $max_active_conn"
mylogger_info "Min time to check: $wakeup_time_min""s"
mylogger_info "Max time to check: $wakeup_time_max""s"
mylogger_info "Timeout circle: $rule_timeout""s"
mylogger_info "Output is logged to: $log_facility"
# if new ip blocked at this check run?
new_block=0
# if new ip blocked at this timeout run?
ever_block=0
# reset wakeup_time
wakeup_time=$wakeup_time_max
lasttime=`date +%s`
while [ 1 ]
do
curtime=`date +%s`
timediff=$((curtime-lasttime))
#echo "timediff: $timediff"
if [ $timediff -ge $rule_timeout ] && [ $ever_block = 1 ] ; then
lasttime=$curtime
ever_block=0
dotimeout
fi
docheckall
mylogger_info "sleep for $wakeup_time""s"
sleep $wakeup_time
done
http://www.hzbase.cn/thread-62-1-1.html