deserts |
2008-01-26 02:12 |
另存为 firewall.sh 给执行的权限 b2z~C{l {8E
hC/= #!/bin/sh X(/W|RY{@ # this program is used to check tcp/ip connections 6$IAm# # and block those ip with excessive connections LJT+tb?K >Z/,DIn,I # my version idV4hMF9 myver="1.0RC1" f9!wO';P6 Z_S~#[\7^] # wake up every 120s if last check found abuse client R#gip wakeup_time_min=120 7D4P=$UJp /QG8\wXE2 # wake up every 300s if last check found no abuse client m(?M]CH(A wakeup_time_max=300 /mvuSNk Wh"oL;O # rule timeout 3600s `_<K#AGAi rule_timeout=3600 U<*ZY`B3 }9jy)gF*e # check port list Uq7 y4z
J portlist="80" S.BM/M 8LB+}N(8f # max established connection per ip (eSa{C\ max_active_conn=8 F.K7w rj<r6 # iptables chain name !|hv49!H iptables_chain_name="RH-Lokkit-0-50-INPUT" yX?& K}JI GAV|x]R # log facility byoDGUv log_facility="local0" h]&8hl_'m {!@Pho)Q # Block policy s7#w5fe ipchains_block_policy="DENY" fHdPav f,S iptables_block_policy="REJECT" rXdI`l# x<4-Q6'{S # myself H0_hQ:K myself=`basename $0` a=T_I1 kK>PFk( mylogger_info() 7FMO''x { d#T~xGqz logger -p $log_facility.info -t $myself $@ 2>/dev/null ;JFy
8Rj } -=I*{dzly x!"S`AM mylogger_debug() *2Il{KOA^ { POdk0CuX logger -p $log_facility.debug -t $myself $@ 2>/dev/null Tl6%z9rY
@ } be}^}w= 7;ZSeQyC mylogger_notice() p(f
YpD { "JzQCY^C logger -p $log_facility.notice -t $myself $@ 2>/dev/null iqW
T<WY } 3iMh)YH5b =yJJq=! dotimeout() A
M8bem~ { (sSMH6iCif mylogger_info "reset firewall when timeout arrives" :80!-F*\ case "$firewall" in $yS7u ipchains) zZE
2%fqM /etc/init.d/ipchains restart 1>/dev/null 2>/dev/null t&MJSFkiA if [ $? = 0 ] ; then F?TxViL mylogger_info "ipchains restarted"
K6d9[;F else N,6(|,m
mylogger_notice "ipchains restart failed" zcnp?% fi 8(J&_7
u ;; ,g\%P5 iptables) \WKly /etc/init.d/iptables restart 1>/dev/null 2>/dev/null })f4`$qf if [ $? = 0 ] ; then UT!gAU mylogger_info "iptables restarted" ]NgK(IU else 3}V`]B#a mylogger_notice "iptables restart failed" ^o^[p % fi 7.@$D;L9 ;; XG2&_u& *) 0]%0wbY1 mylogger_notice "neither ipchains nor iptables" n%GlOKC ;; _' KJ:3e esac rK 9 } m5AO4: } `@?f@p$(B 9ReH@5_bGM blockclient() ]gI>ay"\QA { GPP{"6q5' if [ -z "$1" ] || [ -z "$2" ]; then =xzDpn>f mylogger_notice "blockclient() missing client or port to block" DL0jA/f return )Lt|]|1B{ fi Zqwxi1 local ip port "o"ujQ(v rw>X JE ip=$1 X]up5tk~ port=$2 ;:(kVdb !J<}=G5 case "$firewall" in %g1{nGah ipchains) 7)iB6RBK mylogger_notice "blocking $1 to $2 via ipchains" x0aPY;,N0 found=`ipchains -nL | egrep "^$ipchains_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+\->[[:space:]]+$port"` -) if [ -z "$found" ] ; then :9`'R0=i^ cmd="ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null" .-Y3oWV mylogger_debug "cmd: $cmd" w#V{'{DKp `ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null` N~I
2~f if [ $? != 0 ] ; then ^@W98_bd; mylogger_notice "$cmd call failed" }*vUOQQp* return (S~|hk^ fi jTVh`d<N new_block=1 }~gBnq_DDU ever_block=1 GS),rNBur else QiDf,$t|, mylogger_info "$ip already blocked to $port" P_:
A%T fi :=
J~t@ ;; 9rhIDA(wc iptables) kz4d"bTb mylogger_notice "blocking $1 to $2 via iptables" LR:Qb]|" found=`iptables -nL | egrep "^$iptables_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+dpt:$port[[:space:]]+"` (W*~3/@D if [ -z "$found" ] ; then Z0yy<9q]2 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" <hG=0Zcr mylogger_debug "cmd: $cmd" F_8<
tA6 `iptables -I $iptables_chain_name 1 -p tcp -m tcp -s $ip --dport $port -j $iptables_block_policy 1>/dev/null 2>/dev/null` Z<7FF}i if [ $? != 0 ] ; then 8Lm}x
_
mylogger_notice "$cmd call failed" S;0,UgB1 return vN=bd7^?= fi "BN-Jvb7q new_block=1 IfyyA ever_block=1 fC!]MhA"i else >3R%GNw mylogger_info "$ip already blocked to $port" [c6I/U=- fi ?NazfK ;; l}|KkW\y *) eURy] mylogger_notice "neither ipchains nor iptables" Q4YIKNN|7 ;; L,I5/K6 esac GyE-fB4C } GWs[a$| WdXi restartservice() MGUzvSf { zbL!q_wO local service cO$
PK if [ -z "$1" ] ; then 4H4U mylogger_notice "no port given to see which service to be restart" Nr.maucny return yGN@Hd:9 fi + V:P-D eT??F case "$1" in W}6(;tI 80) l V[d`%( service="httpd" FU-YI" ;; hr%O4&sa 25) %vPs38Fks service="postfix" ]<z
4p'F1% ;; i#I+ 110) ;lqtw]4v service="courier-pop3d" |
%JJ
S^) ;; imcq
H 21) <{rRcF
R service="muddleftpd" Eq>3|(UT ;; cr!6qv1 53) odxsF(Q0p service="named" J8|F8dcz ;; k/+-Tq; 3306) [n/'JeG5 service="mysqld" $~UQKv> ;; 7_r$zEP6 esac \Q.Qos if [ ! -z "$service" ] ; then fm2,Mx6 /etc/init.d/$service restart 1>/dev/null 2>/dev/null [uxhdR`T if [ $? = 0 ] ; then G)28#aH mylogger_notice "$service restarted" /H+br_D9 else B9`^JYT< mylogger_notice "$service restart failed" X+;F5b9z fi sY__ak!> fi iTTe`Zr5y } %MyA;{-F6 5p6Kq=jhb docheckport() w[w{~`([", { `_Bvaej?, mylogger_info "do check port $1" j.MpQ^eJ7 local port last_client count client total_count [Af&K22M(X G1MuH%4 if [ -z "$1" ] ; then z)Xf6& mylogger_notice "docheckport() port not given" sGIY\% return P 3uAS fi WjZJQK 6zK8-V?9F port=$1 <VV./W8e9
hNB;29r~ clientlist=`netstat -an --tcp| grep ESTABLISHED | awk "{ if ( index(\\$4,\":$port\") ) print \\$5}" | awk -F ':' '{print $1}'|sort` kYBTmz}z if [ $? != 0 ] ; then )@.bkzW mylogger_notice "netstat call failed" "'H$YhY] return `Z]Tp1U fi =jdO2MgSg* #echo $clientlist
qq}EXq^ # reset new_block
&T?>Kx new_block=0 P_+S;(QQ~d count=0 f !t2a// total_count=0 \Ku=a{Ne last_client="" ay6G1\
0W for client in $clientlist LXj2gsURu% do E",s
] #echo "client is $client" *leQd^47 if [ -z "$last_client" ] ; then DUf=\p6`f count=$((count+1)) 6'W79 total_count=$((total_count+1)) xB:,l'\G last_client=$client .>>@q!!s! else "m +Eu|{ if [ "$client" = "$last_client" ] ; then >XP]NY}Po[ count=$((count+1))
VVeO>jd total_count=$((total_count+1)) 8'J>@ uW else g#~jF mylogger_debug "$last_client $count connections" jPYed@[+ if [ $count -ge $max_active_conn ] ; then |Hg)!5EJ mylogger_notice "client $last_client connection $count >= $max_active_conn" #6'oor X blockclient $last_client $port I_.(&hMn fi $7gzu4f count=1 N kp>yVj total_count=$((total_count+1)) %lz\w{ last_client=$client t/WauY2JUC fi qC?J
`
fi <.(IJ done +Y(cs&V* # check the last client bO1J#bcZ if [ ! -z "$client" ] ; then S$\lM<
M count=$((count+1)) *#e%3N05_ total_count=$((total_count+1)) mk_cub@ mylogger_debug "$client $count connections" /pgfa-< if [ $count -ge $max_active_conn ] ; then <ro0}%-z>M mylogger_notice "client $client connection $count >= $max_active_conn" W?~G_4 blockclient $client $port K"VphKvR
fi 2<>n8K fi
%Fq"4% mylogger_info "total connections on port $port: $total_count" A=!&2( ,0NVb7F;k if [ $new_block = 1 ] ; then 7&XU]I restartservice $port +oBf\!{cW fi 0#F3@/1h } A?|KA<&m#u '?t]iRCeI7 docheckall() "5Oog< { *CA|}l # reset wakeup_time u$[
'}z0: wakeup_time=$wakeup_time_max l>h%J,W for port in $portlist r
Efk5R do )`F?{Sg docheckport $port LdR}v%EH if [ $new_block = 1 ] ; then ,=B
"%=S # set wakeup_time shorter cause we found some abuse client SEXe
K2v wakeup_time=$wakeup_time_min ].]yqD4P fi v3[Z]+ ] done 'P32G?1C&p } w;0NtV| ZJsc?*@ if [ -z "$firewall" ] && [ -f /etc/sysconfig/ipchains ] ; then `B) ~ firewall="ipchains" ':!w%& \ fi Z}f$KWj hEsCOcEG if [ -z "$firewall" ] && [ -f /etc/sysconfig/iptables ] ; then r1EccY firewall="iptables" t9&)9,my fi -Vn9YeH+ );@Dr!H if [ -z "$firewall" ] ; then uTA
/E9OY echo "Error: This machine does not have ipchains or iptables firewall support" QOlm#S exit 1 H!4!1J.=xw fi Bt[`p\p@ SWUHHl mylogger_info "firewall.sh v$myver ValueOf.com starting" &fdH
HN mylogger_info "Firewall is: $firewall" "@Bc eD mylogger_info "Port protected: $portlist" VxLq,$B76 mylogger_info "Max connection per ip: $max_active_conn" ;i^p6b j mylogger_info "Min time to check: $wakeup_time_min""s" 49nZWv48"_ mylogger_info "Max time to check: $wakeup_time_max""s" vI{JBWE,S mylogger_info "Timeout circle: $rule_timeout""s" .UakO,"z mylogger_info "Output is logged to: $log_facility" t]P[>{y Ym(^
ih # if new ip blocked at this check run?
g[@K
d new_block=0 f*Xonb # if new ip blocked at this timeout run? Kw3fpNd ever_block=0 =2s5>Oz+ # reset wakeup_time xAYC%) wakeup_time=$wakeup_time_max BXO(B'1)] >{~W" lasttime=`date +%s` Ra'0 ^4t G`ZpFg0Y while [ 1 ] 8U/q3@EC do bEV
9l curtime=`date +%s` mAhtC* timediff=$((curtime-lasttime)) mk~i (Ee #echo "timediff: $timediff" qo}-m7 if [ $timediff -ge $rule_timeout ] && [ $ever_block = 1 ] ; then xH;qJRHa lasttime=$curtime A-~#ydv ever_block=0 wp-5B= #:{ dotimeout ;o,t* fi $)mq docheckall &0K;Vr~D mylogger_info "sleep for $wakeup_time""s" U
u(ysN4` sleep $wakeup_time jj0@ez{3 done 4;M }Jk.c~P) *DLv$/(0 l,1}1{k& 1. 说明 n!|K# firewall.sh是一个shell脚本程序,每隔一段时间检查tcp连接的统计信息,如果来自某个ip对某个端口的活动连接超过规定的最大数量, D7X-|`kH 则自动将该IP对该端口的访问屏蔽,并重新启动相应的服务。再每隔一段时间,会重设防火墙到初始状态。 %/,PY>:| 该程序可以同时保护多个端口 {p|OKf |b;}'
* 2. 安装
t^&:45~Q tar zxf firewall-1.0b.tar.gz n]}+ : cd firewall-1.0b +e)So+.W install -m 700 firewall.sh /usr/prima/sbin/firewall.sh =w?-R\ r6Lb0PzMf 3. 配置
doBfpQ2 主要配置项目如下: ,cWO Ak # 最小检查周期,缺省为120秒
@\i6m]\X wakeup_time_min=120 Y6`9:97
Gs7mO # 最大检查周期,缺省为300秒 C0jmjZ%w@ wakeup_time_max=600 3Ym5SrKK 0Q;T
<%U # 重设防火墙状态的时间,缺省为3600秒 H
#J"' rule_timeout=3600 DGC-`z -vGyEd7 # 保护的端口列表,缺省为80和25,支持的其他端口包括21(ftp), 110(pop3), 53(named), 3306(mysql) ,vrdtL # 一般的网络攻击都是针对80和25,又以80居多 "@gJ[BL# portlist="80 25" nqBZp N^ 9|v
# 每个ip可占用的最大活动(Established)连接数 #v:<\-MjN max_active_conn=8 MEI]N0L3 `-\4Dx1!q # iptables防火墙规则链名称,必须和/etc/sysconfig/iptables中一致 Q[i;IbY # 如果用的是ipchains,可以忽略此项 go]d+lhFB iptables_chain_name="RH-Lokkit-0-50-INPUT" gET& +M Fz?ON1\ # 日志输出目标 Y">Q16( log_facility="local0" H$Q$3Q!` ({m["d **** 关于检查周期 **** u,PrEmy- 程序定义了两个检查周期,如果上次检查中屏蔽了某个IP,则程序会更频繁地检查连接情况,反之则等待更长时间。通过检查周期 RL~\/# 的动态调整,可以有效调度在遭受攻击和正常状态下程序的运行次数。 dDi 1{s '$
s:cS`= **** ipchains vs iptables **** J%aW^+O 目前该程序支持ipchains和iptables两种软件防火墙,使用何种是由程序启动时自动检测的。如果/etc/sysconfig/ipchains和 9=rYzA?)+ /etc/sysconfig/iptables都没有检测到,则报错退出。 ,<R/x[ U>e@m? **** 日志输出 **** ,G"?fQ7zR 程序的输出信息记录在系统日志中,目标是local0。如果没有特殊配置,可以在/var/log/messages中看到。建议在/etc/syslog.conf
G2;Uv/vR 中加入一条: SQvicZAN)` local0.* /var/log/firewall.log i/C#fIB2 然后重新启动syslog U(3LeS;mr /etc/init.d/syslog restart
1ikkm7 这样,可以将firewall.sh输出的日志单独记到文件/var/log/firewall.log里。 d;D^<-[i y|.wL=; 4. 运行 *%B%BJnX /usr/prima/sbin/firewall.sh & cAVe(:k) _=UXNr8S 范例输出: S]<G|mn, *** firewall.sh v1.0b ValueOf.com*** U=Z@Ip
u5T Firewall is: ipchains Y
+HVn0~qz Port protected: 80 25 }mu8fm' Max connection per ip: 8 U!3nn#!yE Min time to check: 120s r\_rnM)_xN Max time to check: 300s
gJs~kQU Timeout circle: 3600s Y)BKRS~ Output is logged to: local0 d@C ;rzR
_qE2r^o"B 察看/var/log/firewall.log,可以看到: Ko/_w_ Oct 16 14:08:55 server firewall.sh: do check port 80 // 检查80端口
168
U-< Oct 16 14:08:55 server firewall.sh: 192.168.0.60 2 connections // 有两个来自192.168.0.60的连接 {sX*SbJt Oct 16 14:08:55 server firewall.sh: total connections on port 80: 2 // 80端口总共2个连接 rQKBT]?y Oct 16 14:08:55 server firewall.sh: do check port 25 // 检查25端口 1;? L:A Oct 16 14:08:55 server firewall.sh: total connections on port 25: 0 // 25端口没有连接 s15f <sp Oct 16 14:08:55 server firewall.sh: sleep for 300s // 等待300秒 -[^wYr= ^,U&v; 5. 停止 ;pAkdX&b 先用ps命令察看firewall.sh进程的进程号,然后用kill命令将其终止,如 lD/+LyTa # ps auxww|grep firewall.sh J3$`bK6F6 root 27932 0.0 0.5 2312 1060 pts/2 S 12:38 0:00 /bin/sh /usr/prima/sbin/firewall.sh P-+^YN, root 27967 0.0 0.3 1732 592 pts/2 S 12:39 0:00 grep firewall.sh 8 ehC^Cg 第一行即firewall.sh的进程,用kill命令: T,WWQm # kill 27932 @M,KA {e [1] Terminated /usr/prima/sbin/firewall.sh BOh&Db* 即将其终止 |
|