deserts |
2008-01-26 02:12 |
另存为 firewall.sh 给执行的权限 t*COzE ? f%@8%px #!/bin/sh IcA]<}0!"v # this program is used to check tcp/ip connections c6e?)(V> # and block those ip with excessive connections 2-$R@
SVy 7B'0(70 # my version O".#B myver="1.0RC1" dZZHk \\[P^ tsF # wake up every 120s if last check found abuse client $hA[vi\5 wakeup_time_min=120 Sna7r~j +jHL==W& # wake up every 300s if last check found no abuse client 9;:Lf wakeup_time_max=300 0n5N-b?G-@ zhFGMF1 # rule timeout 3600s v=|ahsYC rule_timeout=3600 T,k`WR
vh((HS-) # check port list RF qbwPX portlist="80" s$m
cIMqs <
=sO@0(< # max established connection per ip {gzL}KL max_active_conn=8 ao Y"uT+ j:rGFd # iptables chain name `ez_
{ iptables_chain_name="RH-Lokkit-0-50-INPUT" 5v8_ji#l[ @99@do|C # log facility `5Q0U%`W log_facility="local0" 0zetOlFbO RY/9Ku ` # Block policy ux'!1mN ipchains_block_policy="DENY" (;V6L{Rf> iptables_block_policy="REJECT" ?(4=:o w
m!Y5 # myself c&J,O1){\ myself=`basename $0` D!+d]A[r D `c
YQ- mylogger_info() JT#jJ/^ { Hcq?7_) logger -p $log_facility.info -t $myself $@ 2>/dev/null +QGZ2_vW } N*gnwrP{ >/9f>d?w^ mylogger_debug() V)mitRaV { 8m\*~IX= logger -p $log_facility.debug -t $myself $@ 2>/dev/null jhOQ)QE| } #(=8
RA:@ JvX]^t/} mylogger_notice() T{<riJ`O { 4i|yEf logger -p $log_facility.notice -t $myself $@ 2>/dev/null 7u73v+9qn: } <[Oe.0SGu %38HGjS dotimeout() H3CG'?{ _ { @K
.{o' mylogger_info "reset firewall when timeout arrives" +?
y ', Ir case "$firewall" in +L(|?|i8 ipchains) DXA<m2&64N /etc/init.d/ipchains restart 1>/dev/null 2>/dev/null 5argw+2s4$ if [ $? = 0 ] ; then ~j3O0s<gK mylogger_info "ipchains restarted" ,Y9bXC8+dU else Sq22] mylogger_notice "ipchains restart failed" +;,65j+n
fi Z:eB9R#2y ;; KEfN!6 iptables) Ln
+;HorZ] /etc/init.d/iptables restart 1>/dev/null 2>/dev/null T8^`<gr. if [ $? = 0 ] ; then VN3[B
eH mylogger_info "iptables restarted" pSa
pF)1> else okm
}%#| mylogger_notice "iptables restart failed" Hnft1
fi i 1dE.f; ;; f/PqkHF *) e@h(Zwp mylogger_notice "neither ipchains nor iptables" l"zwH ;; *q&^tn b esac +7\"^D B@j2^Dr~! } K>2M*bGcp
1SF8D`3 blockclient() Np"~1z.(b { nV:RL|p2jw if [ -z "$1" ] || [ -z "$2" ]; then
5[y+X|Am mylogger_notice "blockclient() missing client or port to block" 5pU/X.lc return dOT7;@ fi f"z;' local ip port S3UJ)@
E ~ <36vsk ip=$1 )DGJr/) port=$2 .~C%:bDnX7 |%oI,d=ycv case "$firewall" in !k Heslvi ipchains) -^Qm_lN mylogger_notice "blocking $1 to $2 via ipchains" |>RNIJ] found=`ipchains -nL | egrep "^$ipchains_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+\->[[:space:]]+$port"` xO^lE@a o if [ -z "$found" ] ; then ~/qBOeU3 cmd="ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null" ejia4(Cd mylogger_debug "cmd: $cmd" 0|<9eD\I= `ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null` D\Y,2!I if [ $? != 0 ] ; then R.?PD$;_M mylogger_notice "$cmd call failed" ({zWyl
return UfIr"bU6 fi AB{zkEuK new_block=1 Be9,m!on ever_block=1 c39j|/!;Y else MsZx 0] mylogger_info "$ip already blocked to $port" G3 |x%/Fbp fi sH>`eqY ;; {\vVzy,t7 iptables) %NfXe[T mylogger_notice "blocking $1 to $2 via iptables" 6#AEVRJKU@ found=`iptables -nL | egrep "^$iptables_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+dpt:$port[[:space:]]+"` Dw.I<fns^B if [ -z "$found" ] ; then Bd7B\zM 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" MN8>I=p mylogger_debug "cmd: $cmd" ZyDNtX% `iptables -I $iptables_chain_name 1 -p tcp -m tcp -s $ip --dport $port -j $iptables_block_policy 1>/dev/null 2>/dev/null` Faa>bc~E if [ $? != 0 ] ; then `N&*+!O% mylogger_notice "$cmd call failed" Te[v+jgLY, return 7{
(UiQbf fi z9g ++]rkJ new_block=1 4'=Q:o*w` ever_block=1 wViTMlq else nGe4IY\-w mylogger_info "$ip already blocked to $port" jpO0dtn3= fi LT
Pr8^ ;; |(ab0b # *) oe.Jm#?2. mylogger_notice "neither ipchains nor iptables" "?F[]8F.b ;; 4r`
I) esac $~G5s<r } qD4s?j-9 QNINn>2 restartservice() Pj]^p{> { .B-b51Uz local service C4$P#DZT^ if [ -z "$1" ] ; then N2U&TCc mylogger_notice "no port given to see which service to be restart" -&`_bf%M return >;1w-n fi n}F$kyI s|H7;.3gp case "$1" in jvsSP?]n 80) [n| }> service="httpd" m!G(vhA,_w ;; H[p~1%Lq 25) 9ybR+dGm+ service="postfix" "lu^ ;; ^i#0aq2}
110) >*gf1"
service="courier-pop3d" Uz,P^\8^$ ;; N*|EfI|X 21) o
g9|}E> service="muddleftpd" XchD3p+uB ;; g]HxPq+O 53) iUh7eR9 service="named" EH2): ;; CPNV\qCY 3306) 4`#%<G service="mysqld" 3=ME$%f ;; ~l'[P=R+8 esac 8q9^ if [ ! -z "$service" ] ; then `k
I}p /etc/init.d/$service restart 1>/dev/null 2>/dev/null wjX0r7^@ if [ $? = 0 ] ; then oSMIWwg7G mylogger_notice "$service restarted" Uhh[le2 % else ;MYK TE>m mylogger_notice "$service restart failed" 7]L}~ fi QrmGrRH fi FN sSJU3ld } hZ<FCY,/? Qx EmuiN docheckport() C\C*@9=&x { ^JIs:\g<< mylogger_info "do check port $1" TffeCaBv local port last_client count client total_count m7>)p]] >>-{AR0 if [ -z "$1" ] ; then xWQQX mylogger_notice "docheckport() port not given" 0#e
Pg6n return ,+n
{xI2 fi g( eA? 1@]gBv< port=$1 4NFvX4 :(jovse\ clientlist=`netstat -an --tcp| grep ESTABLISHED | awk "{ if ( index(\\$4,\":$port\") ) print \\$5}" | awk -F ':' '{print $1}'|sort` .a]av if [ $? != 0 ] ; then
5&U?\YNLa mylogger_notice "netstat call failed"
+N:M;uTS return 3 _DJ fi ?
i|
LO #echo $clientlist RjR # reset new_block :?gk=JH: new_block=0 Q
S.w#"X[ count=0 6$$ku total_count=0 T
3+lYE last_client="" pB]+c%\ for client in $clientlist !RdubM do ..ht)Gex #echo "client is $client" RT=(vq @ if [ -z "$last_client" ] ; then h)C`w'L count=$((count+1)) NA8$G|.? total_count=$((total_count+1)) RV+0C&0ff last_client=$client ?`D/#P else ob.=QQQs
if [ "$client" = "$last_client" ] ; then Bso3Z ^X. count=$((count+1)) $5/lU
}To total_count=$((total_count+1)) d_}q.%* else }x
M >F% mylogger_debug "$last_client $count connections" 4ky@rcD 1 if [ $count -ge $max_active_conn ] ; then G+xd
h mylogger_notice "client $last_client connection $count >= $max_active_conn" ~<#!yRy>r blockclient $last_client $port {m+(j (6- fi ta 66AE
c9 count=1 mN:p=.&
< total_count=$((total_count+1)) $R[ggH&
last_client=$client ,s,VOyr @F fi yqw#= fy fi @ukIt done ,D`iV| ( # check the last client \We\*7^E if [ ! -z "$client" ] ; then q-fxs8+m| count=$((count+1)) 5xawa:K total_count=$((total_count+1)) _cY!\' mylogger_debug "$client $count connections" dt(#|8i% if [ $count -ge $max_active_conn ] ; then iwl\&uNQU mylogger_notice "client $client connection $count >= $max_active_conn" zMkjdjb blockclient $client $port jz%%r Q( fi ;oQ*gd fi jQp7TdvLE$ mylogger_info "total connections on port $port: $total_count" $Xf gY1S ESl-k2 if [ $new_block = 1 ] ; then PyD'lsV
restartservice $port Xq9n-;%zL fi a+TlZE>8 } DA_[pR ZLBv\VQ docheckall() SEn-8ZF { `,mE
'3& # reset wakeup_time c5?;^a[ wakeup_time=$wakeup_time_max 0Dj<-n{9 for port in $portlist EROf%oaz= do &wbe^Wp docheckport $port .u3!%{/v(c if [ $new_block = 1 ] ; then HL;y5o? # set wakeup_time shorter cause we found some abuse client n{dl-P wakeup_time=$wakeup_time_min (Yz EsY fi c7mIwMhl~ done aVI/x5p~ } d`D<PT(\ .0l0*~[ if [ -z "$firewall" ] && [ -f /etc/sysconfig/ipchains ] ; then Xqt3p6 firewall="ipchains" yUF<qB fi hr&&"d {s D2 o,K&V if [ -z "$firewall" ] && [ -f /etc/sysconfig/iptables ] ; then fD3}s#M*G firewall="iptables" RF/I*5 fi \|\D
c0p} (0jT#&# if [ -z "$firewall" ] ; then *NdSL echo "Error: This machine does not have ipchains or iptables firewall support" 1
"'t5?XW exit 1 RG [*:ReB9 fi J0BA@jH5 &kKopJH mylogger_info "firewall.sh v$myver ValueOf.com starting" (Zi(6 T\z mylogger_info "Firewall is: $firewall" h2g|D(u) mylogger_info "Port protected: $portlist" 5)fEs.r0
U mylogger_info "Max connection per ip: $max_active_conn" h#Cq-^D#~ mylogger_info "Min time to check: $wakeup_time_min""s" n82N@z<8] mylogger_info "Max time to check: $wakeup_time_max""s" 9%e&Z'l mylogger_info "Timeout circle: $rule_timeout""s" <11
pk mylogger_info "Output is logged to: $log_facility" ,7:_M>-3g Fm(~Vt;%u # if new ip blocked at this check run? ?0_Bs4O\ new_block=0 1:]iV}OFqR # if new ip blocked at this timeout run? Mf)0Y~_:R# ever_block=0 ~ B0L7}d # reset wakeup_time 44T>Yp09 wakeup_time=$wakeup_time_max gJn|G#! xBH`=e< lasttime=`date +%s` u/?s_OR |0 #J=am while [ 1 ] KLpu7D5(| do UN{_f)E? curtime=`date +%s` %Od?(m"& timediff=$((curtime-lasttime)) 9-)D"ZhLe #echo "timediff: $timediff" ;WX)g&
19x if [ $timediff -ge $rule_timeout ] && [ $ever_block = 1 ] ; then Mx<V;GPm lasttime=$curtime d~f_wN&r ever_block=0 P,y*H_@k dotimeout 2
8qTC? fi 4QbD DvRQ^ docheckall ql,k 5.l mylogger_info "sleep for $wakeup_time""s" *FoH'\= sleep $wakeup_time G+Ft2/+\ done df_hmkyj u0M[B7Q <GoUth.# k}T#-Gb 1. 说明 E ,5XX;| firewall.sh是一个shell脚本程序,每隔一段时间检查tcp连接的统计信息,如果来自某个ip对某个端口的活动连接超过规定的最大数量, c#'t][Ii 则自动将该IP对该端口的访问屏蔽,并重新启动相应的服务。再每隔一段时间,会重设防火墙到初始状态。 M
VdX 该程序可以同时保护多个端口 kSJWXNC /NvHM$5O% 2. 安装 A1Tk6i<F1 tar zxf firewall-1.0b.tar.gz JJ\|FZN cd firewall-1.0b '1'#,u! install -m 700 firewall.sh /usr/prima/sbin/firewall.sh %j3XoRex>< ;S
Re` 3. 配置 #{-l(016y 主要配置项目如下: )b^yAzL? # 最小检查周期,缺省为120秒 D#VUx9kugv wakeup_time_min=120 YN.[KQ(! |~)!8N.{ # 最大检查周期,缺省为300秒 y
5>X0tT wakeup_time_max=600 Mn`);[ IRWVoCc9/\ # 重设防火墙状态的时间,缺省为3600秒 }Xa1K;KM{ rule_timeout=3600 ,x (?7ZW> . W ~&d_n # 保护的端口列表,缺省为80和25,支持的其他端口包括21(ftp), 110(pop3), 53(named), 3306(mysql) 7T[Kjn^{Oj # 一般的网络攻击都是针对80和25,又以80居多 94uAt&&b( portlist="80 25" CEQs}bz iX]tL:,~i # 每个ip可占用的最大活动(Established)连接数 &YiUhK max_active_conn=8 ?$v*_*:2h W}6OMAbsE; # iptables防火墙规则链名称,必须和/etc/sysconfig/iptables中一致 _bsAF^ ; # 如果用的是ipchains,可以忽略此项 &9j*Y iptables_chain_name="RH-Lokkit-0-50-INPUT" Z'!Ii+'6 lf`" (:./ # 日志输出目标 IjaFNZZC! log_facility="local0" lGhh
H_ _&SST)Y| **** 关于检查周期 **** %4$J.6M 程序定义了两个检查周期,如果上次检查中屏蔽了某个IP,则程序会更频繁地检查连接情况,反之则等待更长时间。通过检查周期 &s0_^5B0 的动态调整,可以有效调度在遭受攻击和正常状态下程序的运行次数。 :|&S7&l] R+&{lc **** ipchains vs iptables **** >1*Dg?/=S 目前该程序支持ipchains和iptables两种软件防火墙,使用何种是由程序启动时自动检测的。如果/etc/sysconfig/ipchains和 {3@"}Eh /etc/sysconfig/iptables都没有检测到,则报错退出。 nvInq2T1 MhDPf]`
Gg **** 日志输出 **** zqCr'$ 程序的输出信息记录在系统日志中,目标是local0。如果没有特殊配置,可以在/var/log/messages中看到。建议在/etc/syslog.conf Q=u [j|0mc 中加入一条: tq.g4X ;_ local0.* /var/log/firewall.log U6IvN@
g 然后重新启动syslog JWsOze8# /etc/init.d/syslog restart ]N^>>k 这样,可以将firewall.sh输出的日志单独记到文件/var/log/firewall.log里。 tSX,*cz M?v`C>j 4. 运行 g0M/Sv /usr/prima/sbin/firewall.sh & ;mauA#vd \E8CC>Jd 范例输出: 9Itj@ps *** firewall.sh v1.0b ValueOf.com*** l0BYv&tu Firewall is: ipchains /g\m7m)u Port protected: 80 25 ?{(Jy* Max connection per ip: 8 YPmgR]=6 Min time to check: 120s '-[?iF@l Max time to check: 300s dk.VH!uVb Timeout circle: 3600s 9;L50q>s Output is logged to: local0 %-O[%Dy icXeB_&cS 察看/var/log/firewall.log,可以看到: )(DX]Tr` Oct 16 14:08:55 server firewall.sh: do check port 80 // 检查80端口 j9O"!9$vQ Oct 16 14:08:55 server firewall.sh: 192.168.0.60 2 connections // 有两个来自192.168.0.60的连接 *:,y`!F=y Oct 16 14:08:55 server firewall.sh: total connections on port 80: 2 // 80端口总共2个连接 Qe4"a*l-r Oct 16 14:08:55 server firewall.sh: do check port 25 // 检查25端口 JAS!eF Oct 16 14:08:55 server firewall.sh: total connections on port 25: 0 // 25端口没有连接 3sz?49tX Oct 16 14:08:55 server firewall.sh: sleep for 300s // 等待300秒 r=:o$e a{
!
8T 5. 停止 ky{-NrK 先用ps命令察看firewall.sh进程的进程号,然后用kill命令将其终止,如 )jm u*D5N # ps auxww|grep firewall.sh wf
/DLAC root 27932 0.0 0.5 2312 1060 pts/2 S 12:38 0:00 /bin/sh /usr/prima/sbin/firewall.sh ]?n~?dD{] root 27967 0.0 0.3 1732 592 pts/2 S 12:39 0:00 grep firewall.sh p'YNj3&u 第一行即firewall.sh的进程,用kill命令: .J.|
S4D # kill 27932 "6xTh0D
[1] Terminated /usr/prima/sbin/firewall.sh 8~eYN-#W& 即将其终止 |
|