[原創] [分享] 一支反砍站的 iptables script
发表于:2007-07-04来源:作者:点击数:
标签:
所謂"砍站"就是使用teleport,getright等離線閱覽軟件, 對某一站台進行持續性的完整下載。 這對於只使用靜態網頁的站台來說,應還可以接受, 但對那些運行大量CGI或需要調用後端數據庫的站台來說, 一旦連線數目過多或CPU不夠力,則很容易被"砍倒"... 相信絕
所謂"砍站"就是使用 teleport, getright 等離線閱覽軟件,
對某一站台進行持續性的完整下載。
這對於只使用靜態網頁的站台來說,應還可以接受,
但對那些運行大量 CGI 或需要調用後端數據庫的站台來說,
一旦連線數目過多或 CPU 不夠力,則很容易被"砍倒"...
相信絕大多數的網站管理員都不歡迎此類行為,
若你也為此所苦,又同時使用
Linux 系統、且能執行 iptables 程式的話,
那本 script 或可值一試的。
不過,聲明在先:
1) 本 script 僅在 RedHat Linux 7.x 平台上測試過,不保證也能用於其他系統版本。
2) script 不盡完善,錯漏難免。請自行評估風險。
3) 若 script 造成任何損失,作者概不負責。
script 的大致工作原理如下:
1) 偵測系統連線數目及 CPU 使用情況,若皆在可接受範圍內,不作任何限制處理。
2) 若超過限制值,從連線抓出黑名單。
3) 第一次抓獲,並不作處分。若被抓獲一定次數(可調整變量),
則啟用 iptables 的 limit 規則,將連線限制於每秒一個封包。
4) 若接線出現在 limit 清單中一定次數(可調整變量),
則啟用 iptables 的 DROP 規則,暫時阻斷該連線來源。
5) script 每次重跑,都會更新黑名單。
若在清單出現次數下降到限制值以下,則刪除該連線的 DROP 或 limit 規則。
6) 若接線出現在 DROP 清單中一定次數(可調整變量),
則啟用 iptables 的永久 DROP 規則,不再刪除其 DROP 規則。
script 執行需知:
1) 你需要 root 權限來執行 script ,script 會在 /root 目錄下建立 BLOCK 子目錄。
2) script 本身沒設循環,請自行設定 crontab 以決定 script 的執行間隔時間。
3) 若系統還有其他 iptables 重整設定(如 portsentry 之類),請自行解決規則一致性。
4) script 建立的永久性 DROP 規則,請自行決定刪除時機。(可另寫 script 再設 crontab)
5) script 會針對 httpd 作重啟偵測處理。
若對 web server 造成不便,請自行註解或刪除程式碼。
(段落提示:#-- restart httpd if dead --# )
script 代碼(歡迎一起 de
bug):
[code:1:6a93f03b61]#!/bin/bash
# Purpose: to block httpd connection
# Author: netman(netman@study-area.org)
# Lisence: GPL
# Date: 2003/10/09
# Version: 1.19
#-- change log --#
# [deleted]
PATH=$PATH:/sbin:/usr/sbin
EXT_IF=eth0 # extenal interface
HTTP_NU=16 # connection number to be added to list
LIMIT_NU=2 # number to be limited
DROP_NU=5 # number to be dropped
PERM_NU=5 # number to be dropped permanently
CL_S=8 # CPU loading for system
CL_U=65 # CPU loading for user
HC_N=200 # HTTP connection number for session
HC_U=20 # HTTP connection number for source
TW_N=40 # TIME_WAIT number for session
HTTP_PORT=80 # HTTP port number
UD_HTTP=30 # minutes to update http list
UD_LIMIT=2 # hours to update limit list
UD_DROP=1 # days to update drop list
HTTP_SCRIPT=/etc/rc.d/init.d/httpd
HTTP_USER=apache
HTTP_CMD=httpd
IPCRM_CMD=ipcrm
IPCS_CMD=ipcs
SAR_CMD=sar
NETSTAT_CMD=netstat
MAIL_CMD=mail
AWK_CMD=awk
IPT_CMD=iptables
IPT_SAVE_CMD=iptables-save
BASED_DIR=/root/BLOCK
PID_FILE=${BASED_DIR}/${0##*/}.pid
HTTP_LIST=${BASED_DIR}/http.list
HTTP_LIST_TMP=${HTTP_LIST}.tmp
HTTP_TW_TMP=${HTTP_LIST}.tw
LIMIT_LIST=${HTTP_LIST}.limit
DROP_LIST=${HTTP_LIST}.drop
PERM_LIST=${HTTP_LIST}.perm
# NOTE: using '|' between each ip in a single line in the EXCP_LIST
EXCP_LIST=${HTTP_LIST}.excp
#-- check programs --#
for pgr in $HTTP_CMD $IPCRM_CMD $SAR_CMD $NETSTAT_CMD $MAIL_CMD $AWK_CMD $IPT_CMD $IPT_SAVE_CMD
do
which $pgr &>/dev/null || {
echo "${0##*/}: ERROR: $pgr not found or not in the PATH."
exit 1
}
done
#-- create based dir --#
if [ ! -d $BASED_DIR ]; then
mkdir $BASED_DIR || {
echo "${0##*/}: ERROR: can NOT create directory $BASED_DIR."
exit 2
}
fi
#-- create file and set timestampt --#
touch --date="$UD_HTTP minutes ago" $HTTP_LIST
touch --date="$UD_LIMIT hours ago" $LIMIT_LIST
touch --date="$UD_DROP days ago" $DROP_LIST
touch $EXCP_LIST
touch $PERM_LIST
#-- detect process --#
if [ -e $PID_FILE ]; then
echo "${0##*/}: WARNING: There is a running copy of script."
echo " exiting..."
exit 3
else
echo "$$" > $PID_FILE
fi
#-- restart httpd if dead --#
ps u -C $HTTP_CMD | grep -q -E -v '^USER|^root' || {
$HTTP_SCRIPT stop
sleep 2
for i in $($IPCS_CMD | sed '/semid/,/^---/!d' \
| awk '/^0x/ {print $2}'); do
$IPCRM_CMD sem $i
done
$HTTP_SCRIPT start
date | $MAIL_CMD -s "httpd restarted" root
exit 3
}
#-- create source list --#
touch $HTTP_LIST_TMP
$NETSTAT_CMD -na | grep ":$HTTP_PORT " | awk '{print $5}' | cut -d: -f1 | sort \
| sed&nbs'''/0.0.0.0''' > $HTTP_LIST_TMP
$NETSTAT_CMD -na | grep ":$HTTP_PORT " | grep "TIME_WAIT" | awk&nbs'''{print $5''' \
| cut -d: -f1 | sort | sed&nb;'''/0.0.0.d''' > $HTTP_TW_TMP
#-- check loading --#
cpuload=$($SAR_CMD -u 1 3 | tail -1 | awk&nb;'''{printf("%i:%i",$3,$5)''')
cpuusr=${cpuload%:*}
cpusys=${cpuload#*:}
http_cn=$(cat $HTTP_LIST_TMP | wc -l)
http_un=$(uniq $HTTP_LIST_TMP | wc -l)
http_tw=$(uniq $HTTP_TW_TMP | wc -l)
echo " limit current"
echo "CL_U: $CL_U $cpuusr"
echo "CL_S: $CL_S $cpusys"
echo "HC_N: $HC_N ${http_cn##* }"
echo "HC_U: $HC_U ${http_un##* }"
echo "TW_N: $TW_N ${http_tw##* }"
#-- function update lists --#
ud_list () {
for i in $@; do
touch ${i}.1 ${i}.2 ${i}.3 ${i}.4
mv ${i}.4 ${i}.5
mv ${i}.3 ${i}.4
mv ${i}.2 ${i}.3
mv ${i}.1 ${i}.2
mv ${i} ${i}.1
sort ${i}.[1-5] > ${i}.new
done
}
#-- list is added? or nothing change in the period? --#
if [ -s $HTTP_LIST -o $HTTP_LIST.new -ot $HTTP_LIST ]; then
#-- remove old limit rules --#
for i in $(cat $LIMIT_LIST); do
echo remove $i from LIMIT
$IPT_CMD -D INPUT -p TCP --dport $HTTP_PORT \
-s $i -m limit --limit 1/s -j A
CCEPT
$IPT_CMD -D INPUT -p TCP --dport $HTTP_PORT \
-s $i -j DROP
done
#-- update http list --#
ud_list $HTTP_LIST
fi
if [ -s $LIMIT_LIST -o $LIMIT_LIST.new -ot $LIMIT_LIST ]; then
#-- remove old drop rules --#
for i in $(cat $DROP_LIST); do
echo remove $i from DROP
$IPT_CMD -D INPUT -p TCP --dport $HTTP_PORT \
-s $i -j DROP
done
#-- update limit list --#
ud_list $LIMIT_LIST
fi
if [ -s $DROP_LIST -o $DROP_LIST.new -ot $DROP_LIST ]; then
#-- update drop list --#
ud_list $DROP_LIST
#-- sort perm list --#
sort -u $PERM_LIST > $DROP_LIST.new
cat $DROP_LIST.new > $PERM_LIST
fi
#-- limiting http connection --#
if [ "$cpusys" -gt "$CL_S" -o "$cpuusr" -gt "$CL_U" -o "$http_cn" -gt "$HC_N" \
-o "$http_un" -gt "$HC_U" -o "$http_tw" -gt "$TW_N" ]
then
#-- function: create list --#
cr_list () {
address="0.0.0.0"
count=1
for i in $(cat $1); do
if [ "$address" != "$i" ]; then
if [ "$count" -ge "$2" ]; then
echo $address >> $3
fi
address=$i
count=1
else
count=$(($count+1))
fi
done
if [ "$count" -ge "$2" ]; then
echo $address >> $3
fi
}
#-- collect high rate connection --#
cr_list $HTTP_LIST_TMP $HTTP_NU $HTTP_LIST
#-- create limit list --#
if [ -s $HTTP_LIST ]; then
cr_list $HTTP_LIST.new $LIMIT_NU $LIMIT_LIST
#-- make exception --#
if [ -s $EXCP_LIST ]; then
grep -v -E -f $EXCP_LIST $LIMIT_LIST \
> $HTTP_LIST_TMP
mv $HTTP_LIST_TMP $LIMIT_LIST
fi
fi
#-- create drop list --#
if [ -s $LIMIT_LIST ]; then
cr_list ${LIMIT_LIST}.new $DROP_NU $DROP_LIST
fi
#-- create perm list --#
if [ -s $DROP_LIST ]; then
cr_list ${DROP_LIST}.new $PERM_NU $PERM_LIST
fi
#-- start limit --#
for i in $(cat $LIMIT_LIST); do
echo LIMIT $i
$IPT_CMD -I INPUT -p TCP --dport $HTTP_PORT -s $i \
-j DROP
$IPT_CMD -I INPUT -p TCP --dport $HTTP_PORT -s $i \
-m limit --limit 1/s -j ACCEPT
done
#-- start blocking --#
for i in $(cat $DROP_LIST); do
echo DROP $i
$IPT_CMD -I INPUT -p TCP --dport $HTTP_PORT -s $i -j DROP
done
#-- start permanent blocking --#
for i in $(cat $PERM_LIST); do
$IPT_SAVE_CMD | grep $i | grep $EXT_IF &>/dev/null || {
host $i | $MAIL_CMD -s "drop $i" root
echo permanently DROP $i
$IPT_CMD -I INPUT -p TCP --dport $HTTP_PORT \
-s $i -i $EXT_IF -j DROP
}
done
fi
#-- clean PID file --#
rm -f $PID_FILE
exit 0[/code:1:6a93f03b61]
本 script 最新版本可以從如下 URL 下載:
http://study-area.ks.edu.tw/linux/src/block.http.sh.tgz
frankzh 回复于:2003-11-20 09:00:19 |
好文章 我试试
|
b2linux 回复于:2003-11-20 10:18:11 |
uping
|
Raad 回复于:2003-11-20 11:49:43 |
好呀,试试
|
tiansgx 回复于:2003-11-20 14:40:59 |
up
|
cau_eric 回复于:2003-11-27 11:21:02 |
哇,这么长啊,有空慢慢看:)
|
gunguymadman007 回复于:2003-11-27 12:46:34 |
up
|
haohaoo 回复于:2003-11-27 13:32:15 |
对于流量大的站点这个东西还是不要用为妙
原文转自:http://www.ltesting.net
|