另存为 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 ValueOf.com 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 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 即将其终止 |
|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )
GMT+8, 2024-9-29 17:35 , Processed in 0.212160 second(s), 12 queries , Gzip On, MemCache On.
Powered by Discuz! X3.5
© 2001-2023 Discuz! Team.