linux自动屏蔽IP
linux自动屏蔽IP
当服务器遭受SYN_RECV攻击时,也许下边的小工具Firewall.sh能派上用场。
内容如下:
====================================================================
#!/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:]]+dpt:$port[[: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 starting"
mylogger_info "Firewall is: $firewall"
mylogger_info "Port 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
====================================================================
帮助说明:firewall.sh 1.0b
1. 说明
firewall.sh是一个shell脚本程序,每隔一段时间检查tcp连接的统计信息,如果来自某个ip对某个端口的活动连接超过规定的最大数量,
则自动将该IP对该端口的访问屏蔽,并重新启动相应的服务。再每隔一段时间,会重设防火墙到初始状态。
该程序可以同时保护多个端口
2. 安装
tar zxf firewall-1.0b.tar.gz
cd firewall-1.0b
install -m 700 firewall.sh /usr/prima/sbin/firewall.sh
3. 配置
主要配置项目如下:
# 最小检查周期,缺省为120秒
wakeup_time_min=120
# 最大检查周期,缺省为300秒
wakeup_time_max=600
# 重设防火墙状态的时间,缺省为3600秒
rule_timeout=3600
# 保护的端口列表,缺省为80和25,支持的其他端口包括21(ftp), 110(pop3), 53(named), 3306(mysql)
# 一般的网络攻击都是针对80和25,又以80居多
portlist="80 25"
# 每个ip可占用的最大活动(Established)连接数
max_active_conn=8
# iptables防火墙规则链名称,必须和/etc/sysconfig/iptables中一致
# 如果用的是ipchains,可以忽略此项
iptables_chain_name="RH-Lokkit-0-50-INPUT"
# 日志输出目标
log_facility="local0"
**** 关于检查周期 ****
程序定义了两个检查周期,如果上次检查中屏蔽了某个IP,则程序会更频繁地检查连接情况,反之则等待更长时间。通过检查周期
的动态调整,可以有效调度在遭受攻击和正常状态下程序的运行次数。
**** ipchains vs iptables ****
目前该程序支持ipchains和iptables两种软件防火墙,使用何种是由程序启动时自动检测的。如果/etc/sysconfig/ipchains和
/etc/sysconfig/iptables都没有检测到,则报错退出。
**** 日志输出 ****
程序的输出信息记录在系统日志中,目标是local0。如果没有特殊配置,可以在/var/log/messages中看到。建议在/etc/syslog.conf
中加入一条:
local0.* /var/log/firewall.log
然后重新启动syslog
/etc/init.d/syslog restart
这样,可以将firewall.sh输出的日志单独记到文件/var/log/firewall.log里。
4. 运行
/usr/prima/sbin/firewall.sh &
范例输出:
*** firewall.sh v1.0b ValueOf.com***
Firewall is: ipchains
Port protected: 80 25
Max connection per ip: 8
Min time to check: 120s
Max time to check: 300s
Timeout circle: 3600s
Output is logged to: local0
察看/var/log/firewall.log,可以看到:
Oct 16 14:08:55 server firewall.sh: do check port 80 // 检查80端口
Oct 16 14:08:55 server firewall.sh: 192.168.0.60 2 connections // 有两个来自192.168.0.60的连接
Oct 16 14:08:55 server firewall.sh: total connections on port 80: 2 // 80端口总共2个连接
Oct 16 14:08:55 server firewall.sh: do check port 25 // 检查25端口
Oct 16 14:08:55 server firewall.sh: total connections on port 25: 0 // 25端口没有连接
Oct 16 14:08:55 server firewall.sh: sleep for 300s // 等待300秒
5. 停止
先用ps命令察看firewall.sh进程的进程号,然后用kill命令将其终止,如
# ps auxww|grep firewall.sh
root 27932 0.0 0.5 2312 1060 pts/2 S 12:38 0:00 /bin/sh /usr/prima/sbin/firewall.sh
root 27967 0.0 0.3 1732 592 pts/2 S 12:39 0:00 grep firewall.sh
第一行即firewall.sh的进程,用kill命令:
# kill 27932
[1] Terminated /usr/prima/sbin/firewall.sh
即将其终止
目录 返回
首页