deserts |
2008-01-26 02:12 |
另存为 firewall.sh 给执行的权限
MTUJsH\ "[M k5tM #!/bin/sh t9(sSl # this program is used to check tcp/ip connections JMIS*njq^ # and block those ip with excessive connections /+{]?y, c"x-_Uk # my version s%p,cz;
, myver="1.0RC1" e~iPN.'1 _8eN^oc% # wake up every 120s if last check found abuse client BiI}JEp4o wakeup_time_min=120 Z{gJ m9 4kqgZtg. # wake up every 300s if last check found no abuse client 8M9}os wakeup_time_max=300 i!k5P".o^ 4~
YPLu # rule timeout 3600s 6}xFE]Df-Y rule_timeout=3600 x8q3 Njr xHo
iu$i6 # check port list uBXl ltU portlist="80" M);@XcS &9:"X # max established connection per ip ZlxJY%oeu max_active_conn=8 U9ZWSDs 3$Y(swc # iptables chain name JVx
,1lth iptables_chain_name="RH-Lokkit-0-50-INPUT" 1P1"x
T 1O{x9a5Z?O # log facility 8LZmr|/F* log_facility="local0"
S_EN,2'e K9 tuiD+j # Block policy fZ)M
Dq ipchains_block_policy="DENY" vn0}l6n3s iptables_block_policy="REJECT" f3u^:6U~ H*M )<"X # myself &!E+l<.RF myself=`basename $0` }VUrn2@-4 4?3*%_bDJ, mylogger_info() ?h*Ngbj> { %1Pn;bUU! logger -p $log_facility.info -t $myself $@ 2>/dev/null M],}.l } (E.,kcAJ SK@%r mylogger_debug() ,( ?q { nM?mdb logger -p $log_facility.debug -t $myself $@ 2>/dev/null TrBBV]4 } .*bu:FuDE p[zKc2 TPk mylogger_notice() 3
~mi { ^lp#j;Df logger -p $log_facility.notice -t $myself $@ 2>/dev/null j
m]d:=4_
} !((J-:= #EO@<
>I dotimeout() TfbB1 {
<Xsy{7 mylogger_info "reset firewall when timeout arrives" dV( "g], case "$firewall" in
*88Q6=Mm ipchains) (zO)J`z> /etc/init.d/ipchains restart 1>/dev/null 2>/dev/null v%=@_`Ht if [ $? = 0 ] ; then /ehmy
(zL mylogger_info "ipchains restarted" ey~5DY7 else xxsa
x/h mylogger_notice "ipchains restart failed" DLWG0$#! fi >+P5Zm(_ ;; ^Pq4 n%x iptables) j!It1B /etc/init.d/iptables restart 1>/dev/null 2>/dev/null h
"Mi
D if [ $? = 0 ] ; then [T(XwA) mylogger_info "iptables restarted" 'nrXRDb else $ e<1 08)] mylogger_notice "iptables restart failed" s?:&# fi bI_6';hq
! ;; rY~!hZ *) _DlX F mylogger_notice "neither ipchains nor iptables" k"kGQk4 ;; CWTPf1?eB esac 7O=N78M e|t@"MxvC } ]WsQ= uX!5G:x] blockclient() / bxu{|. { i1(}E# if [ -z "$1" ] || [ -z "$2" ]; then |2$
wJ$I mylogger_notice "blockclient() missing client or port to block" VP7g::Ab return B#|c$s{ fi fAMk<? local ip port Skbd'j vky@L! &, ip=$1 ,esryFRG port=$2 B$Z%_j& u{6b>c|,X case "$firewall" in THVF(M4v ipchains) \6{w#HsP8 mylogger_notice "blocking $1 to $2 via ipchains"
!nBE[& found=`ipchains -nL | egrep "^$ipchains_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+\->[[:space:]]+$port"` ,w9:)B7 if [ -z "$found" ] ; then Z7="on4 cmd="ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null" cbton<r~ mylogger_debug "cmd: $cmd" eTe
Z^G `ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null` HGwSsoS if [ $? != 0 ] ; then c*k%r2' mylogger_notice "$cmd call failed" 8JFns-5 return yx@%x?B fi At0ahy+ new_block=1 Fx3CY W ever_block=1 (2SmB`g else Cwh*AKq( mylogger_info "$ip already blocked to $port" SqF `xw fi YUGEGXw ;; B%.vEk)* iptables) w
|k?2 ?& mylogger_notice "blocking $1 to $2 via iptables" S{0iPdUC found=`iptables -nL | egrep "^$iptables_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+dpt:$port[[:space:]]+"` BM
vGw if [ -z "$found" ] ; then <27:O,I 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" Rs +), mylogger_debug "cmd: $cmd" <TDp8t9bU `iptables -I $iptables_chain_name 1 -p tcp -m tcp -s $ip --dport $port -j $iptables_block_policy 1>/dev/null 2>/dev/null` }MiEbLduN if [ $? != 0 ] ; then q;)+O#CR mylogger_notice "$cmd call failed" ;h-W&i7 return vg"$&YX9" fi J-k/#A4o new_block=1 XaxM$ ever_block=1 Bn<1zg5 else jY +u OH mylogger_info "$ip already blocked to $port" YjR`}rdwo fi #$
^vP/"$ ;; ,O'#7Dj *) 0XWhSrHM mylogger_notice "neither ipchains nor iptables" JS^QfT,zE ;; %@~;PS3kd esac &<>NP?j} } ^aONuG9 GL^84[f-T
restartservice() Pe,:FIp, { xe&w.aBI> local service N fBH if [ -z "$1" ] ; then @4]} J-3 mylogger_notice "no port given to see which service to be restart" ]F#}8$ return "|^-Yk\U fi v[+ ] TCL XO0 case "$1" in @km@\w 80) NE)Yd7m- service="httpd" |\<L7|hb9 ;; oO4hBM([ 25) R8%%EEB service="postfix" M->BV9 ;; &`%J1[dy 110) nXT/zfS service="courier-pop3d" PY76;D*` ;; +/n<]?(T 21) HPc~wX service="muddleftpd" [e f&|Pi- ;; cfC}"As 53) $z[@DB[ service="named" PSHzB!
H=n ;; 3]li3B' 3306) Y.b?.)u& service="mysqld" 7ND4Booul ;; ^ u:bgwP esac hlBMRx49 if [ ! -z "$service" ] ; then {HtW`r1)Tt /etc/init.d/$service restart 1>/dev/null 2>/dev/null
@gnLY if [ $? = 0 ] ; then ;Sl%I+? mylogger_notice "$service restarted" 7DPxz'7): else /d*[za'0 mylogger_notice "$service restart failed" $U4[a: fi Gzc`5n{" fi UB,0c) } sLd%m+*p }z F,dst docheckport() -
VdCj%r> { NXMZTZpB7 mylogger_info "do check port $1" 8[H bg local port last_client count client total_count c"diNbm[ 3Mq%3jX if [ -z "$1" ] ; then ?
=I']$MH mylogger_notice "docheckport() port not given" >VppM ` return i1 c[Gk.o fi B9wQ;[gQB ?_d3|]N port=$1 %6
la@i 1}~ZsrF clientlist=`netstat -an --tcp| grep ESTABLISHED | awk "{ if ( index(\\$4,\":$port\") ) print \\$5}" | awk -F ':' '{print $1}'|sort` P2F8[o!< if [ $? != 0 ] ; then (6i4N2
mylogger_notice "netstat call failed" %<|cWYM="z return !p Q*m`Xo fi |-TxX:O- #echo $clientlist IdCE<Oj\ # reset new_block TQykXZ2Yb) new_block=0 K j~!E
H" count=0 6,!$S2(zT total_count=0 ,/"0tP&_; last_client="" d4) 0G-| for client in $clientlist 1.5R`vKn] do ,u9>c*Ss\ #echo "client is $client" &[
,* if [ -z "$last_client" ] ; then .LGA
0 count=$((count+1)) bAld'z# total_count=$((total_count+1)) ;M"[dy`dY last_client=$client yH9&HFDp else 4?]s%2U6 if [ "$client" = "$last_client" ] ; then >3}N; count=$((count+1)) ^a$L9p( total_count=$((total_count+1)) 4wWfaL5" else 1B
eh&pl^ mylogger_debug "$last_client $count connections" a*t>Ks'C if [ $count -ge $max_active_conn ] ; then Qn.3B mylogger_notice "client $last_client connection $count >= $max_active_conn" 1~E;@eK' blockclient $last_client $port 3S1{r
)[j fi NN5G
'|i count=1 T-]UAN"O total_count=$((total_count+1)) w_DaldK* last_client=$client L* ScSxw fi g`~;"%u7cn fi Io tc>! done ..w$p-1 # check the last client Hz=s)6$ey if [ ! -z "$client" ] ; then 2`> (LH count=$((count+1)) orbz`IQc total_count=$((total_count+1)) 93ggCOaYA mylogger_debug "$client $count connections" Cq3Au%7 if [ $count -ge $max_active_conn ] ; then x=X&b%09 mylogger_notice "client $client connection $count >= $max_active_conn" @!|h!p; blockclient $client $port mo,"3YW fi 1:_}`x=hM fi Vt-V'`Y mylogger_info "total connections on port $port: $total_count" eR/X9< %d<UMbS^ if [ $new_block = 1 ] ; then l@]Fzl restartservice $port s@Loax6@B fi 2sVDv@2 } j^eMi *~w?@,} docheckall() C4t~k { i8DYC=r # reset wakeup_time j 2
0mZ wakeup_time=$wakeup_time_max XpA|
<s for port in $portlist F=f9##Y?7M do ldc`Y/:{ docheckport $port lE*.9T if [ $new_block = 1 ] ; then KXUJ*l-5 # set wakeup_time shorter cause we found some abuse client Hq>rK` wakeup_time=$wakeup_time_min Ri}JM3\J fi 6;Mv)|FJF done y+izC+ } q!q=axfMD pBn;:
if [ -z "$firewall" ] && [ -f /etc/sysconfig/ipchains ] ; then -qLNs_
_k firewall="ipchains" qQS&K%F fi }/g1 ZB5NTNf> if [ -z "$firewall" ] && [ -f /etc/sysconfig/iptables ] ; then RhE|0N= firewall="iptables" Lo"s12fr fi 6c}nP[6| s5X51#J#~ if [ -z "$firewall" ] ; then ENf(E9O echo "Error: This machine does not have ipchains or iptables firewall support" NI C.c3 exit 1 t3!~=U fi 0f;|0siTAm wqyF"^It" mylogger_info "firewall.sh v$myver ValueOf.com starting" '47E8PIJ| mylogger_info "Firewall is: $firewall" 0iz\<'
p mylogger_info "Port protected: $portlist" ={{q_G\WD mylogger_info "Max connection per ip: $max_active_conn" Owh:(E
J"d mylogger_info "Min time to check: $wakeup_time_min""s" <,9rXjeRl mylogger_info "Max time to check: $wakeup_time_max""s" d2g7,axi mylogger_info "Timeout circle: $rule_timeout""s" =':B mylogger_info "Output is logged to: $log_facility" }w)wW1& t<+g
yAW # if new ip blocked at this check run? @~IZ%lEQsD new_block=0 <In+V # if new ip blocked at this timeout run? IN"6=2: ever_block=0 Q*/jQC # reset wakeup_time c2yZvi wakeup_time=$wakeup_time_max -V||1@
| &=lhKt lasttime=`date +%s` Oq95zo pAcu{5#7 while [ 1 ] 1*B'o<?P1 do PB@jh} curtime=`date +%s` "GAKi}y">v timediff=$((curtime-lasttime)) 8ya|eJ]/L #echo "timediff: $timediff" YKa9]Q if [ $timediff -ge $rule_timeout ] && [ $ever_block = 1 ] ; then +qyx3c+ lasttime=$curtime ^i17MvT'
ever_block=0 N\x<'P4q dotimeout prVqV-S6TY fi ABhQ7
x| docheckall t},71Ry mylogger_info "sleep for $wakeup_time""s" DXfQy6
k' sleep $wakeup_time "D
ivsq^ done QH6_nZY !]#;' >):>Pz%U u:\DqdlU` 1. 说明 v79\(BX firewall.sh是一个shell脚本程序,每隔一段时间检查tcp连接的统计信息,如果来自某个ip对某个端口的活动连接超过规定的最大数量,
v$R7" 则自动将该IP对该端口的访问屏蔽,并重新启动相应的服务。再每隔一段时间,会重设防火墙到初始状态。 \p J<@ 该程序可以同时保护多个端口 p 4l B# AJt4I
W@ 2. 安装 c nV2}U/\ tar zxf firewall-1.0b.tar.gz R,W
w/D cd firewall-1.0b q]m$%> install -m 700 firewall.sh /usr/prima/sbin/firewall.sh 5f#]dgBe -2y>X`1Y 3. 配置 4NmLbM&C8 主要配置项目如下: (e[8`C # 最小检查周期,缺省为120秒 4G=KyRKh wakeup_time_min=120 bH_zWk . AX6xc6
# 最大检查周期,缺省为300秒 =' #yG(h wakeup_time_max=600 E%\Ohs7 &, WQr # 重设防火墙状态的时间,缺省为3600秒 wRj&k(?* rule_timeout=3600 %weG}gCM Y
f;Slps # 保护的端口列表,缺省为80和25,支持的其他端口包括21(ftp), 110(pop3), 53(named), 3306(mysql) 0-zIohSJdQ # 一般的网络攻击都是针对80和25,又以80居多 n
Sh}1Arp/ portlist="80 25" X?q,m4+ NEX{vZkgw # 每个ip可占用的最大活动(Established)连接数 %8T"h max_active_conn=8 dO\irv) 0]`%iG| # iptables防火墙规则链名称,必须和/etc/sysconfig/iptables中一致 )nA fT0()0 # 如果用的是ipchains,可以忽略此项 Y@[Dy iptables_chain_name="RH-Lokkit-0-50-INPUT" ;Fm7!@u^0 y4~;H{! # 日志输出目标 c*`=o(S log_facility="local0" 8yn}|Y9Fu &\/p5RX **** 关于检查周期 **** [5TGCGxP{ 程序定义了两个检查周期,如果上次检查中屏蔽了某个IP,则程序会更频繁地检查连接情况,反之则等待更长时间。通过检查周期 (uskVK>L 的动态调整,可以有效调度在遭受攻击和正常状态下程序的运行次数。 U<mFwJ C] @EzO
bE{ **** ipchains vs iptables ****
uj9I
K 目前该程序支持ipchains和iptables两种软件防火墙,使用何种是由程序启动时自动检测的。如果/etc/sysconfig/ipchains和 or]kXefG3 /etc/sysconfig/iptables都没有检测到,则报错退出。
7>>6c7e ~V<imF **** 日志输出 **** !`?*zf 程序的输出信息记录在系统日志中,目标是local0。如果没有特殊配置,可以在/var/log/messages中看到。建议在/etc/syslog.conf /4PV<
[
:_ 中加入一条: E8s&.:;+ local0.* /var/log/firewall.log 1Ydym2 然后重新启动syslog j^'op|l /etc/init.d/syslog restart V8{5 y
<Y> 这样,可以将firewall.sh输出的日志单独记到文件/var/log/firewall.log里。 UN6Du\)]d R#
UcwX}o 4. 运行 |T@\-8Ok /usr/prima/sbin/firewall.sh & 7Ta",S@m WbW@V_rr 范例输出: yC]X&1,:z *** firewall.sh v1.0b ValueOf.com*** :RE
.m d Firewall is: ipchains 5??\[C^"} Port protected: 80 25 Z U^dLN-N Max connection per ip: 8 kxp, ZP Min time to check: 120s Eax^1 |6 Max time to check: 300s 3
A(sT} Timeout circle: 3600s 8Vb.%f&I Output is logged to: local0 ZfYva(zP{Q 6*n<emP 察看/var/log/firewall.log,可以看到: bEJz>oyW" Oct 16 14:08:55 server firewall.sh: do check port 80 // 检查80端口 <cn{S` Oct 16 14:08:55 server firewall.sh: 192.168.0.60 2 connections // 有两个来自192.168.0.60的连接 (79y!&9p Oct 16 14:08:55 server firewall.sh: total connections on port 80: 2 // 80端口总共2个连接 dM
nJ)R Oct 16 14:08:55 server firewall.sh: do check port 25 // 检查25端口 K9YD)351t Oct 16 14:08:55 server firewall.sh: total connections on port 25: 0 // 25端口没有连接 ymxYE#q Oct 16 14:08:55 server firewall.sh: sleep for 300s // 等待300秒 o`8dqP dDAIfe2y 5. 停止 ?x|8"*N 先用ps命令察看firewall.sh进程的进程号,然后用kill命令将其终止,如 ;%_fQNFb # ps auxww|grep firewall.sh _ZnVQ,zY root 27932 0.0 0.5 2312 1060 pts/2 S 12:38 0:00 /bin/sh /usr/prima/sbin/firewall.sh b`=\<u8 root 27967 0.0 0.3 1732 592 pts/2 S 12:39 0:00 grep firewall.sh H |1owmbD 第一行即firewall.sh的进程,用kill命令: 9bL`0L # kill 27932 sMq*X^z
)? [1] Terminated /usr/prima/sbin/firewall.sh `Eijy3>h 即将其终止 |
|