| deserts |
2008-01-26 02:12 |
另存为 firewall.sh 给执行的权限 )+^+sd ("@!>|H #!/bin/sh mv><HqDL1 # this program is used to check tcp/ip connections o-\[,}T)M # and block those ip with excessive connections l{9Y x;S @bY
# my version =I<R! ZSN myver="1.0RC1" (:_$5&i7 965jtn # wake up every 120s if last check found abuse client hgmCRC wakeup_time_min=120 (Z*!#}z
` 6863xOv{T # wake up every 300s if last check found no abuse client h
8P)%p wakeup_time_max=300 s7<AfaJPF | Iib|HQ) # rule timeout 3600s H|*m$|$, rule_timeout=3600 8}[).d160 T%Lx%Qn # check port list Ba,`TJ%y portlist="80" \RiP
y
fSmDPh # max established connection per ip 3F3A%C% max_active_conn=8 8y L Y 3Ul*QN{6 # iptables chain name 3<!7>]A iptables_chain_name="RH-Lokkit-0-50-INPUT" s*[bFJwN A<{{iBEI` # log facility ?}0 ,o. log_facility="local0" Za9qjBH
;'|Ey # Block policy *p U x8yB ipchains_block_policy="DENY" vQCy\Gi iptables_block_policy="REJECT" \85i+q:LuA +rd+0 `}C # myself yAt^; myself=`basename $0` q1,~ Xhm
c6? mylogger_info() !zo{tI19 { CrLrw T logger -p $log_facility.info -t $myself $@ 2>/dev/null EwN}l } wT@og|M l**X^+=$ mylogger_debug() )pa]ui\t { &ncvGDGi logger -p $log_facility.debug -t $myself $@ 2>/dev/null AH^/V}9H } {FkF @dKTx#gZ mylogger_notice() Y]>t[Lo% { 3BI1fXT4=j logger -p $log_facility.notice -t $myself $@ 2>/dev/null R_C) } A^g(k5M* &~CI<\o P dotimeout() gdc<ZYcM { tw;}jh mylogger_info "reset firewall when timeout arrives" [JiH\+XLPs case "$firewall" in -RwE%cr ipchains) :;}P*T*PU /etc/init.d/ipchains restart 1>/dev/null 2>/dev/null I9Xuok!0>= if [ $? = 0 ] ; then G{}VPcrbC mylogger_info "ipchains restarted" fhiM U8(& else ^q5#ihM mylogger_notice "ipchains restart failed" [,Gg^*umS fi +7Gwg ;; L *wYx| iptables) )A6<c%d =x /etc/init.d/iptables restart 1>/dev/null 2>/dev/null /uflpV| if [ $? = 0 ] ; then K;?+8(H mylogger_info "iptables restarted" zhQJy?>'m else {: /}NpA$ mylogger_notice "iptables restart failed" 6K^#?Bn; fi IGl9g_18 ;; HMXE$d=[ *) V3Bz
Mw\9r mylogger_notice "neither ipchains nor iptables" i-1op> Y ;; =_CzH(=f# esac [Xkx_B \bXa&Lq } 4W75T2q# wYea\^co blockclient() z{q`G wW { !
nx{
X if [ -z "$1" ] || [ -z "$2" ]; then ".%k6W<n mylogger_notice "blockclient() missing client or port to block" "+c-pO`Wg return mpyt5#f fi Cp N>p.kM local ip port PT
~D",k V`5O{Gg ip=$1 )J |6 -C port=$2 9c],<;{' ceA9){ case "$firewall" in Om&Dw|xG8 ipchains) Ri'n mylogger_notice "blocking $1 to $2 via ipchains" !D6]JPX found=`ipchains -nL | egrep "^$ipchains_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+\->[[:space:]]+$port"` 3|7QUld if [ -z "$found" ] ; then HW|IILFB cmd="ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null" kfNWI#'9
mylogger_debug "cmd: $cmd" jIyQ]:* p `ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null` ~&O%N if [ $? != 0 ] ; then }]TxlSp!; mylogger_notice "$cmd call failed" V&i;\ 9 return Ac6=(B fi g0H[*"hj new_block=1 P>L +t`' ever_block=1 H]s.=.Ki else llDJ@ mylogger_info "$ip already blocked to $port" B!yr!DWv fi -&f$GUTJ ;; s{++w5s iptables) Cw%{G'O mylogger_notice "blocking $1 to $2 via iptables" PFR:>^wK2 found=`iptables -nL | egrep "^$iptables_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+dpt:$port[[:space:]]+"` _@g;8CA if [ -z "$found" ] ; then !wNO8;( 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" MDN--p08 mylogger_debug "cmd: $cmd" DlT{` `iptables -I $iptables_chain_name 1 -p tcp -m tcp -s $ip --dport $port -j $iptables_block_policy 1>/dev/null 2>/dev/null` BY*Q_Et if [ $? != 0 ] ; then A
>$I
-T+ mylogger_notice "$cmd call failed" uEYt
E7 return u>$t' fi v:p} B$ new_block=1 z2c6T.1M ever_block=1 *A< 5*Db:F else }Lv;! mylogger_info "$ip already blocked to $port" :]c3|J fi :EH=_" ;; "j-CZ\]U| *) $N\Ja*g mylogger_notice "neither ipchains nor iptables" zJXplvaL;
;; /> Nt[o[r esac j4b4!^fV }
Y~Ifj,\ nie% eC&U restartservice() I|J/F}@p { |' . local service i&k7-< if [ -z "$1" ] ; then TKjFp% mylogger_notice "no port given to see which service to be restart" x :7IIvP return 8] ikygt"
fi ?}7p"3j'z 66 Tpi![ case "$1" in rH>)oThA# 80) SB7c.H, service="httpd" -![|}pX ;; %bfZn9_m 25) 8V(pugJ service="postfix" Vg23!E ;; ETLD$=iS 110) # [a*rD%m service="courier-pop3d" j.kG};f ;; go"Hf_ 21) 4X$Qu6#i service="muddleftpd" qw8Rlws% ;; 03(4 x'z 53) v}x&?fU ` service="named" LDD|(KLR*. ;; >*n0n!vF
3306) }{"fJ3] c^ service="mysqld" *:NQ&y*uj ;; _? OG1t! esac U?=Dg1 if [ ! -z "$service" ] ; then ZW}_Qs /etc/init.d/$service restart 1>/dev/null 2>/dev/null +]50D xflA if [ $? = 0 ] ; then :h V7>
rr mylogger_notice "$service restarted" |W\(kb+ else ##o#eZq:" mylogger_notice "$service restart failed" l (%1jC8 fi J'2X&2 fi B+0hzkPY } j w9b) ,u
g@f-T docheckport() 0AV c { {>%&(
mylogger_info "do check port $1" Ydy9 local port last_client count client total_count L~>i, D1mfm.9_r^ if [ -z "$1" ] ; then BRYHX.}h\A mylogger_notice "docheckport() port not given" k: ;WtBC6j return Ip]KPrwp fi 0{[,E. Q1l '7N port=$1 |B2+{@R TvQo? clientlist=`netstat -an --tcp| grep ESTABLISHED | awk "{ if ( index(\\$4,\":$port\") ) print \\$5}" | awk -F ':' '{print $1}'|sort` lUiL\~Gq if [ $? != 0 ] ; then I,'k>@w{s mylogger_notice "netstat call failed"
0nD/;\OU return ED&
`_h7? fi 7(
2{
'r #echo $clientlist
4I?^ t" # reset new_block 4X(H; new_block=0 K:Q<CQ2 count=0 FtC^5{V+V total_count=0 9pxc~= last_client="" )Iq <+IJ for client in $clientlist f.`*Qg L do q\527^ZM #echo "client is $client" e01epVR; if [ -z "$last_client" ] ; then CoAvSw count=$((count+1)) =k:,qft2 total_count=$((total_count+1)) h.s+)
fl\ last_client=$client 7;(UF=4 else yD6[\'% if [ "$client" = "$last_client" ] ; then "4,?uPi count=$((count+1)) Z} r*K% total_count=$((total_count+1)) FzXJ]H else yU}qOgXx mylogger_debug "$last_client $count connections" %lGfAYEM= if [ $count -ge $max_active_conn ] ; then &7wd?)s mylogger_notice "client $last_client connection $count >= $max_active_conn" Hi`//y*92H blockclient $last_client $port TLe~y1dwY= fi M8b;d}XL count=1 WoRZW% total_count=$((total_count+1)) Yv!a88+A8M last_client=$client ]Y8<`;8/ fi !*. -`$x fi [ $n_6 done Um-[~- # check the last client `o8/(`a if [ ! -z "$client" ] ; then M|`U"vO count=$((count+1)) JU5C}%Q6 total_count=$((total_count+1)) ,lA s mylogger_debug "$client $count connections" xZwLlY if [ $count -ge $max_active_conn ] ; then 2M'[,Xe mylogger_notice "client $client connection $count >= $max_active_conn" pF Rg?- blockclient $client $port doy`C)xI fi '>0fWBs fi \EtQ5T*u mylogger_info "total connections on port $port: $total_count" c%G{#}^2 T
iiW p!mX if [ $new_block = 1 ] ; then {Um)15K restartservice $port K[r^'P5m fi F!Q@u } u5: q$P j4`0hnqI docheckall() W=vP]x
>J { Ksj -zR; # reset wakeup_time Slher0.Y wakeup_time=$wakeup_time_max 1@R
Db)<V for port in $portlist kZZh"#W: L do Dq5j1m. docheckport $port p@5`&Em, if [ $new_block = 1 ] ; then 2fR02={- # set wakeup_time shorter cause we found some abuse client (Dl$k Gn wakeup_time=$wakeup_time_min au=o6WRa fi aV?@s4 done )oPLl|=h } J)
~L @&:ar if [ -z "$firewall" ] && [ -f /etc/sysconfig/ipchains ] ; then -}=%/|\FG firewall="ipchains" #Xb+`' fi Rh{zH~oZ A1#%`^W9 if [ -z "$firewall" ] && [ -f /etc/sysconfig/iptables ] ; then aL%AQB, firewall="iptables" 7:3$Ey fi (?{MEwHG j|%HIF25 if [ -z "$firewall" ] ; then .wu
xoq echo "Error: This machine does not have ipchains or iptables firewall support" ?5cI' exit 1 &n?^$LTPY fi q+]h=:5=I I*kK 82
mylogger_info "firewall.sh v$myver ValueOf.com starting" MP 2~;
T}~ mylogger_info "Firewall is: $firewall" :8+Ni d) mylogger_info "Port protected: $portlist" )Z
qJh mylogger_info "Max connection per ip: $max_active_conn" cwWodPNm mylogger_info "Min time to check: $wakeup_time_min""s" oDYRQozo> mylogger_info "Max time to check: $wakeup_time_max""s" y2vUthRwo mylogger_info "Timeout circle: $rule_timeout""s" G\r?f& mylogger_info "Output is logged to: $log_facility" a|=x5`h04~ LLXVNO@e+ # if new ip blocked at this check run? Y=n4K< new_block=0 sZm$|T0 # if new ip blocked at this timeout run? i?e`:}T ever_block=0 /BV03B # reset wakeup_time P7MeX(Tay wakeup_time=$wakeup_time_max S'B|>!z@ dwd:6.J( lasttime=`date +%s` OP|8S k6
r ^=SD9V while [ 1 ] jSuL5|Gui do 9n5<]Q( curtime=`date +%s` B0!"A timediff=$((curtime-lasttime)) fpN-
o #echo "timediff: $timediff" FH%GIi if [ $timediff -ge $rule_timeout ] && [ $ever_block = 1 ] ; then ]mXLg:3B lasttime=$curtime \Z/)Y;|mi0 ever_block=0 0,Y5KE{ dotimeout {$^DMANDx fi 0Ir<y docheckall x5WW--YR+ mylogger_info "sleep for $wakeup_time""s" p6XtTx sleep $wakeup_time dG71*)<)t done Iu*^xn 5W@jfh) L
tKI3ou g@Qgxsyk> 1. 说明 tpTAeQ*:d firewall.sh是一个shell脚本程序,每隔一段时间检查tcp连接的统计信息,如果来自某个ip对某个端口的活动连接超过规定的最大数量, y tf b$;| 则自动将该IP对该端口的访问屏蔽,并重新启动相应的服务。再每隔一段时间,会重设防火墙到初始状态。 {Pu\?Cq 该程序可以同时保护多个端口 awUx=%ERtA hw~a:kD 2. 安装 z5X~3s\dP tar zxf firewall-1.0b.tar.gz VCcr3Dx()F cd firewall-1.0b rUjdq/I:Z install -m 700 firewall.sh /usr/prima/sbin/firewall.sh M}wXJ8aF? s{4 \xAS> 3. 配置 %D`,k*X 主要配置项目如下: ' 2-oh # 最小检查周期,缺省为120秒 Q!FLR>8 wakeup_time_min=120 Lh-`OmO0>F nD2,!71
# 最大检查周期,缺省为300秒 9cv]y# wakeup_time_max=600 x)_@9ldYv tB'V # 重设防火墙状态的时间,缺省为3600秒 y9|K|xO[ rule_timeout=3600 7.+#zyF -gz0md|Y # 保护的端口列表,缺省为80和25,支持的其他端口包括21(ftp), 110(pop3), 53(named), 3306(mysql) do
^RF<G # 一般的网络攻击都是针对80和25,又以80居多 a/uo}[Y portlist="80 25" "XLe3n
S|GWcSg # 每个ip可占用的最大活动(Established)连接数 Ab1/.~^ max_active_conn=8 te4= S
AP\ofLmq # iptables防火墙规则链名称,必须和/etc/sysconfig/iptables中一致 0X(]7b&~R # 如果用的是ipchains,可以忽略此项 BXUF^Hj% iptables_chain_name="RH-Lokkit-0-50-INPUT" jec:i-, V8z`qEPM # 日志输出目标 ; W7Y2Md log_facility="local0" [&P`ak !
qJI'+_ **** 关于检查周期 **** YTU.$t;Ez 程序定义了两个检查周期,如果上次检查中屏蔽了某个IP,则程序会更频繁地检查连接情况,反之则等待更长时间。通过检查周期 O:.,+,BH 的动态调整,可以有效调度在遭受攻击和正常状态下程序的运行次数。 ,c
)g,J9
Z]:BYX' **** ipchains vs iptables **** 3An(jt$%Q 目前该程序支持ipchains和iptables两种软件防火墙,使用何种是由程序启动时自动检测的。如果/etc/sysconfig/ipchains和 Pcu|k/tk /etc/sysconfig/iptables都没有检测到,则报错退出。 s([Wn)I 0d\~"4 R **** 日志输出 **** rvwy
~hO" 程序的输出信息记录在系统日志中,目标是local0。如果没有特殊配置,可以在/var/log/messages中看到。建议在/etc/syslog.conf 7
7:'I 中加入一条: 8HoP(+? local0.* /var/log/firewall.log &(& 然后重新启动syslog a`Z{
xme= /etc/init.d/syslog restart iG[?
]] 这样,可以将firewall.sh输出的日志单独记到文件/var/log/firewall.log里。 F$hZRZ N5q725zJ 4. 运行 j.QHkI1. /usr/prima/sbin/firewall.sh & BQjam+u6 Z|`fHO3j 范例输出: A'"-m)1P *** firewall.sh v1.0b ValueOf.com*** 9)yG.9d1 Firewall is: ipchains bx(w:]2 Port protected: 80 25 ;1LG&h,K Max connection per ip: 8 &jJckT Min time to check: 120s w4:<fnOM Max time to check: 300s J#7(]!;F Timeout circle: 3600s +?e}<#vd'? Output is logged to: local0 org*z!;. 5V|tXsy: 察看/var/log/firewall.log,可以看到: {Nq?#%vdT Oct 16 14:08:55 server firewall.sh: do check port 80 // 检查80端口 ${e&A^h Oct 16 14:08:55 server firewall.sh: 192.168.0.60 2 connections // 有两个来自192.168.0.60的连接 #K`B<2+T Oct 16 14:08:55 server firewall.sh: total connections on port 80: 2 // 80端口总共2个连接 Gj`f--
2GE Oct 16 14:08:55 server firewall.sh: do check port 25 // 检查25端口 %vc'{`P Oct 16 14:08:55 server firewall.sh: total connections on port 25: 0 // 25端口没有连接 Mx
N]7 Oct 16 14:08:55 server firewall.sh: sleep for 300s // 等待300秒 3LrsWAz' R`C.ha 5. 停止 ;xW{Ehq-h 先用ps命令察看firewall.sh进程的进程号,然后用kill命令将其终止,如 qP`?M\!O # ps auxww|grep firewall.sh /'+4vXc@ root 27932 0.0 0.5 2312 1060 pts/2 S 12:38 0:00 /bin/sh /usr/prima/sbin/firewall.sh &enlAV'#)O root 27967 0.0 0.3 1732 592 pts/2 S 12:39 0:00 grep firewall.sh 7z>+w 第一行即firewall.sh的进程,用kill命令: 4JK@<GBK6 # kill 27932 ]n1D1 [1] Terminated /usr/prima/sbin/firewall.sh J=L`]XE 即将其终止 |
|