deserts |
2008-01-26 02:12 |
另存为 firewall.sh 给执行的权限 D c;k)z= v\_\bT1 #!/bin/sh CD%Cb53 # this program is used to check tcp/ip connections H \'1.8g/ # and block those ip with excessive connections jw
`05rw: i,S1|R # my version
r?!:%L myver="1.0RC1" H:XPl$; '.M4yif\g # wake up every 120s if last check found abuse client v5@M 34 wakeup_time_min=120 lRNm
&3:- oOC&w0 # wake up every 300s if last check found no abuse client v$w}UC%uf wakeup_time_max=300 b*H*(}A6"' ;8dffsyq # rule timeout 3600s 3W]gn8 rule_timeout=3600 *HUXvX|-% qDYNY` # check port list e([>sAx!1 portlist="80" l#%7BGwzY p$qk\efv*4 # max established connection per ip C*3St`2@9 max_active_conn=8 $;'M8L 5bAdF'~ # iptables chain name ^X}r ^ iptables_chain_name="RH-Lokkit-0-50-INPUT" G"OP`OMDc I:G8B5{J # log facility 'Grii, log_facility="local0" 0c`nk\vUy ,[zSz8R # Block policy M<d!j I9) ipchains_block_policy="DENY" q4&! mDU iptables_block_policy="REJECT" jC4>%!{m [l3\0e6-/ # myself iw3\`,5
myself=`basename $0` 7C0xKF 1n +Uv* mylogger_info() A|S)cr8z { ,?erAI logger -p $log_facility.info -t $myself $@ 2>/dev/null 6V%}2YE?X } G<D8a2q !p!Qg1O6o mylogger_debug() \t&! &R# { |1(x2x%}D^ logger -p $log_facility.debug -t $myself $@ 2>/dev/null -X!<$<\y; } _<#92v!F ]tN)HRk1 mylogger_notice() zGR,}v%% { O>qlWPht logger -p $log_facility.notice -t $myself $@ 2>/dev/null z$R&u=J } 5\C(2naf [0y,K{8t dotimeout() Ye&/O<G'V { L?+N:
G
mylogger_info "reset firewall when timeout arrives" //BJaWq case "$firewall" in RU7+$Z0K ipchains) Ja:4EU$Lu /etc/init.d/ipchains restart 1>/dev/null 2>/dev/null \
tYImh if [ $? = 0 ] ; then _>\33V-?b mylogger_info "ipchains restarted" R9R~$@~G else pI-Qq%Nwt mylogger_notice "ipchains restart failed" bWp:!w#K fi s 0Uid&qE ;; (0q`eO2 iptables) NMK$$0U /etc/init.d/iptables restart 1>/dev/null 2>/dev/null \ YF@r7 if [ $? = 0 ] ; then
>~Zj mylogger_info "iptables restarted" pLCj"D).M else yZ,pH1 mylogger_notice "iptables restart failed" \99'#]\_/E fi "[~yu*
S ;; 36(qe"s *) -c?x5/@3 mylogger_notice "neither ipchains nor iptables" Xydx87L/-e ;; 2[`n<R\ esac yg'CL/P #oTVfY# } }C_g;7* I2CI9,0 blockclient() 'XKfKv >; { A+M4= if [ -z "$1" ] || [ -z "$2" ]; then )uHat# mylogger_notice "blockclient() missing client or port to block" 4z5qXI/<m4 return +BtLd+)R fi 6Zn[l,\ local ip port jRC{8^98 jm<^WQ%Cc ip=$1 )
6QJZ$ port=$2 \[{8E}_"^ >g!$H}\ case "$firewall" in !O!:=wq ipchains) vo
}4N[]Sb mylogger_notice "blocking $1 to $2 via ipchains" <`SA>P found=`ipchains -nL | egrep "^$ipchains_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+\->[[:space:]]+$port"` F%y#)53g if [ -z "$found" ] ; then `$1A;wg< cmd="ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null" 0AWxU?$A4 mylogger_debug "cmd: $cmd" -!~pa^j `ipchains -I input 1 -p tcp -s $ip -d 0/0 $port -j $ipchains_block_policy 1>/dev/null 2>/dev/null` E.m2- P;4 if [ $? != 0 ] ; then +76ao7d. mylogger_notice "$cmd call failed" {f4jE#a>v return bvB7d`wx fi !U4YA1>> new_block=1 GL0P&$h ever_block=1 "kcix!}& else 6W YVHG mylogger_info "$ip already blocked to $port" s7}-j2riq fi KI\bV0$p< ;; \25
EI] iptables) #o~C0`8!B= mylogger_notice "blocking $1 to $2 via iptables" _M8'~$Sg found=`iptables -nL | egrep "^$iptables_block_policy.*[[:space:]]+$ip[[:space:]]+.*[[:space:]]+dpt:$port[[:space:]]+"` /z!y[ri+J if [ -z "$found" ] ; then B)DuikV.D 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" vAG|Y'aO@% mylogger_debug "cmd: $cmd" cY!Pv `iptables -I $iptables_chain_name 1 -p tcp -m tcp -s $ip --dport $port -j $iptables_block_policy 1>/dev/null 2>/dev/null` GK6~~
ga= if [ $? != 0 ] ; then &QQ6F>'T mylogger_notice "$cmd call failed" WaX!y$/z return dlZ2iDQ% fi *@@dO_%6 new_block=1 j)ln"u0R^B ever_block=1 mIrN~)C4\ else >U\P^yU mylogger_info "$ip already blocked to $port" |DsT $~D fi 2Gj)fMK38 ;; A[fTpS~~% *) `DGI|3 mylogger_notice "neither ipchains nor iptables" Ke#Rkt ;; z&#^9rM" esac >ZgV8X: } <f)T*E^5% sc-hO9~k restartservice() 7z\#"~(. { mss.\ local service ;U a48pSv if [ -z "$1" ] ; then g^po$%I ' mylogger_notice "no port given to see which service to be restart" iN0'/)ar return e`JWY9% fi eMn'z]M&] HHgv,bC! case "$1" in .*+jD^Gr 80) 3)e{{]6 service="httpd" <dXeP/1w` ;; i&)([C0z$ 25) Wi\k&V.mE service="postfix" 9`H4"H>yG ;; Ck
m:;q 110) _T805<aUW\ service="courier-pop3d" Ui1s]R ;; /#t::b+>x 21) /&czaAR- service="muddleftpd" P_p\OK*l]o ;; sC2NFb-+& 53) N<Ym&$xR service="named" )3f\H ;; S$40nM 3306) ![I|hB service="mysqld" J5<16}* ;; x",ktE>9 esac b53s@7/mq if [ ! -z "$service" ] ; then |-cXb.M[ /etc/init.d/$service restart 1>/dev/null 2>/dev/null OOABn* if [ $? = 0 ] ; then X68.*VHh0 mylogger_notice "$service restarted" (_3'nFg else
;"RyHow mylogger_notice "$service restart failed"
MpJ\4D5G fi TnKOr~@* fi 6iHY{WcDj } >'WTVj` d{B0a1P docheckport() ,I]]52+?4 { |942#rM mylogger_info "do check port $1" Tks1gN^^ local port last_client count client total_count +9yMtR 2FO<Z %Y if [ -z "$1" ] ; then j+gh*\:q mylogger_notice "docheckport() port not given" m*i,|{UZ return 7:JGrO fi Qs8yJH`v yOP$~L#TWs port=$1 )Q}Q -Zt \TDn q!)? clientlist=`netstat -an --tcp| grep ESTABLISHED | awk "{ if ( index(\\$4,\":$port\") ) print \\$5}" | awk -F ':' '{print $1}'|sort` &wu1Zz[qcz if [ $? != 0 ] ; then ^\\9B-MvY mylogger_notice "netstat call failed" VuK>lY& return o>
&pj fi 9d=\BBNZ #echo $clientlist ]'hel#L;l # reset new_block "W9z>ezp new_block=0 ~~t>; count=0 /,$V/q+ total_count=0 I,]q;lEMt last_client="" >Af0S;S
for client in $clientlist Z\n^m^Z
= do aJ1{9 5ea #echo "client is $client" W58%Zz4a if [ -z "$last_client" ] ; then 0|=y#`;,Z count=$((count+1)) @2_E9{T total_count=$((total_count+1))
K]dR%j last_client=$client :n%& else \E05qk_;K if [ "$client" = "$last_client" ] ; then fy&u[Jd{ count=$((count+1)) Q;nC #cg total_count=$((total_count+1)) K(TejW# else X_,R!$wbg: mylogger_debug "$last_client $count connections" V<ilv< if [ $count -ge $max_active_conn ] ; then iYlkc mylogger_notice "client $last_client connection $count >= $max_active_conn" [.CP,Ly blockclient $last_client $port 3&+nV1
fi 'S&Zq: count=1 ETdN<}m total_count=$((total_count+1)) cXYE!( last_client=$client <R%TCVwC@ fi t2m7Yh5B fi J*Cf1 D5! done IaO&f<^#o # check the last client 95ix~cH3q if [ ! -z "$client" ] ; then Ya!PV&"Z count=$((count+1)) )gAqWbkB total_count=$((total_count+1)) RfT)dS+rAh mylogger_debug "$client $count connections" p+7#`iICE if [ $count -ge $max_active_conn ] ; then @_ UI;*V mylogger_notice "client $client connection $count >= $max_active_conn" la^K|!| blockclient $client $port LE?sAN fi ]xbMMax fi ~|LAe-e" mylogger_info "total connections on port $port: $total_count" \#F>R, "QBl
"<<s if [ $new_block = 1 ] ; then J90
)v7 restartservice $port 5Ux=5a fi Q6N?cQtOT } h&~9?B \zOsq5} docheckall() [Ov/&jD" { 'X?Iho # reset wakeup_time 8;,|z%rS" wakeup_time=$wakeup_time_max cu)B!#<!& for port in $portlist :X}Ie P do E[BM0.#bZ docheckport $port J-5kvQi8 if [ $new_block = 1 ] ; then Kp;a(D # set wakeup_time shorter cause we found some abuse client Rh)%; wakeup_time=$wakeup_time_min J.O{+{&cd fi Kb'4W-&u! done w U1[/ } Mh{;1$j# !"'6$"U\K if [ -z "$firewall" ] && [ -f /etc/sysconfig/ipchains ] ; then $)KNpdXh firewall="ipchains" l j+p}dt fi 7 ;2>kgf~ YtXd>@7 if [ -z "$firewall" ] && [ -f /etc/sysconfig/iptables ] ; then +I}!)$/ firewall="iptables" }j!C+i fi &[N_{O| C 7YS>?^] if [ -z "$firewall" ] ; then 0WyOORuK echo "Error: This machine does not have ipchains or iptables firewall support" i<q_d7-W' exit 1 ID<[=es6 fi k`s_31< o"kL,& mylogger_info "firewall.sh v$myver ValueOf.com starting" "{c@}~ mylogger_info "Firewall is: $firewall" \6pQ&an mylogger_info "Port protected: $portlist" 1@F>E;YjL= mylogger_info "Max connection per ip: $max_active_conn" ;*d?Qe: mylogger_info "Min time to check: $wakeup_time_min""s" d ]#`?} mylogger_info "Max time to check: $wakeup_time_max""s"
@l&{ j mylogger_info "Timeout circle: $rule_timeout""s" EoS6t mylogger_info "Output is logged to: $log_facility" 5,\|XQA5! /2Ok;!. # if new ip blocked at this check run? x&$8;2&. new_block=0 %/SHB # if new ip blocked at this timeout run? <~u-zaN<W ever_block=0 E5a7p. # reset wakeup_time AtqsrYj
wakeup_time=$wakeup_time_max Y^XZ.R
=NWzsRl, lasttime=`date +%s` c_aj-`BKp dl6Ju while [ 1 ] NS "1zR+ do A-h[vP!v| curtime=`date +%s` :W+%jn timediff=$((curtime-lasttime)) s%A?B8, #echo "timediff: $timediff" 14(ct if [ $timediff -ge $rule_timeout ] && [ $ever_block = 1 ] ; then ?.c:k;j lasttime=$curtime =%B}8$.| ever_block=0 urQ<r{$x0 dotimeout &egP
3 fi CX;
m8 docheckall 48{B}j%oU mylogger_info "sleep for $wakeup_time""s" vOl3utu7 sleep $wakeup_time $F]*B
` done di<g"8 %H3iX^}* ziv+*Qn_b4 &
sXMB 1. 说明 kZfj"+p_S firewall.sh是一个shell脚本程序,每隔一段时间检查tcp连接的统计信息,如果来自某个ip对某个端口的活动连接超过规定的最大数量, gOp81
) 则自动将该IP对该端口的访问屏蔽,并重新启动相应的服务。再每隔一段时间,会重设防火墙到初始状态。 TeyFq0j@' 该程序可以同时保护多个端口 th5UzpB4 (aB:P03 2. 安装 Qz$Wp* tar zxf firewall-1.0b.tar.gz !yz3:Yz
u cd firewall-1.0b iaQFVROu install -m 700 firewall.sh /usr/prima/sbin/firewall.sh rAD4}A_w 5H(
]"C 3. 配置 9QeBz`lm) 主要配置项目如下:
vF'IK, # 最小检查周期,缺省为120秒 $-(lp0\*
wakeup_time_min=120 1\/~> yz)Nco] # 最大检查周期,缺省为300秒 W~s:SN wakeup_time_max=600 8sq0 BH aaI5x # 重设防火墙状态的时间,缺省为3600秒 2Ic)]6z
R rule_timeout=3600 e'fo^XQn[ qr~zTBT]
E # 保护的端口列表,缺省为80和25,支持的其他端口包括21(ftp), 110(pop3), 53(named), 3306(mysql) gmOP8.g # 一般的网络攻击都是针对80和25,又以80居多 ho!qXS
portlist="80 25" .4y44: T vpdT2/F # 每个ip可占用的最大活动(Established)连接数 r_o\72 max_active_conn=8 J~N!. i Ze?H # iptables防火墙规则链名称,必须和/etc/sysconfig/iptables中一致 yXf+dMv # 如果用的是ipchains,可以忽略此项 G420o}q iptables_chain_name="RH-Lokkit-0-50-INPUT" uY3?(f# Q0L1!}w
# 日志输出目标 _gpf9ad log_facility="local0" HYNpvK 8]4
W@~c **** 关于检查周期 **** yx7y3TSq 程序定义了两个检查周期,如果上次检查中屏蔽了某个IP,则程序会更频繁地检查连接情况,反之则等待更长时间。通过检查周期 NkAu<>
G _ 的动态调整,可以有效调度在遭受攻击和正常状态下程序的运行次数。 (62Sc] MQX9BJ% **** ipchains vs iptables **** qGzF@p(p8 目前该程序支持ipchains和iptables两种软件防火墙,使用何种是由程序启动时自动检测的。如果/etc/sysconfig/ipchains和 `b_n\pf] /etc/sysconfig/iptables都没有检测到,则报错退出。 l_ LH!Tu `a@YbuLd **** 日志输出 **** +t(Gt0+ 程序的输出信息记录在系统日志中,目标是local0。如果没有特殊配置,可以在/var/log/messages中看到。建议在/etc/syslog.conf EEHTlqvR 中加入一条: mzf^`/NO local0.* /var/log/firewall.log 98CS|NEe 然后重新启动syslog WKq{g+a /etc/init.d/syslog restart o9Tsyjbj 这样,可以将firewall.sh输出的日志单独记到文件/var/log/firewall.log里。 Mp@dts/| 6Zv-kG 4. 运行 WogCt, /usr/prima/sbin/firewall.sh & <"7Wb"+ @680.+Kw 范例输出: U<"k- *** firewall.sh v1.0b ValueOf.com*** VzWH9%w Firewall is: ipchains 9ol&p> Port protected: 80 25 f~f)6XU| Max connection per ip: 8 t1!>EI` Min time to check: 120s ,/dW*B Max time to check: 300s w|-m*v
. Timeout circle: 3600s Q|7m9~ Output is logged to: local0 >Xxi2Vy _*wlK;` 察看/var/log/firewall.log,可以看到: 4?c0rC< Oct 16 14:08:55 server firewall.sh: do check port 80 // 检查80端口 N <M6~ Oct 16 14:08:55 server firewall.sh: 192.168.0.60 2 connections // 有两个来自192.168.0.60的连接 xr31<4B Oct 16 14:08:55 server firewall.sh: total connections on port 80: 2 // 80端口总共2个连接 9e;:(jl^ Oct 16 14:08:55 server firewall.sh: do check port 25 // 检查25端口 w$jSlgUHy) Oct 16 14:08:55 server firewall.sh: total connections on port 25: 0 // 25端口没有连接 HHT8_c'CC# Oct 16 14:08:55 server firewall.sh: sleep for 300s // 等待300秒 <_SdW 5BF< yB4
eUa!1 5. 停止 Y"TrF(C 先用ps命令察看firewall.sh进程的进程号,然后用kill命令将其终止,如 bj@f<f` # ps auxww|grep firewall.sh ((6?b5[ root 27932 0.0 0.5 2312 1060 pts/2 S 12:38 0:00 /bin/sh /usr/prima/sbin/firewall.sh Ys<z% root 27967 0.0 0.3 1732 592 pts/2 S 12:39 0:00 grep firewall.sh x.'Ys1M 第一行即firewall.sh的进程,用kill命令: $]4o!Z # kill 27932 VL$?vI' [1] Terminated /usr/prima/sbin/firewall.sh )Dyyb1\) 即将其终止 |
|