DDoS deflate其实是一个Shell脚本,使用netstat和iptables工具,对那些链接数过多的IP进行封锁,能有效防止通用的恶意扫描器,但它并不是真正有效的DDoS防御工具。
工作过程描述:
同一个IP链接到服务器的连接数到达设置的伐值后,所有超过伐值的IP将被屏蔽,同时把屏蔽的IP写入ignore.ip.list文件中,与此同时会在tmp中生成一个脚本文件,这个脚本文件马上被执行,但是一运行就遇到sleep 预设的秒,当睡眠了这么多的时间后,解除被屏蔽的IP,同时把之前写入ignore.ip.list文件中的这个被封锁的IP删除,然后删除临时生成的文件。
一个事实:如果被屏蔽的IP手工解屏蔽,那么如果这个IP继续产生攻击,那么脚本将不会再次屏蔽它(因为加入到了ignore.ip.list),直到在预设的时间之后才能起作用,加入到了ignore.ip.list中的IP是检测的时候忽略的IP。可以把IP写入到这个文件以避免这些IP被堵塞,已经堵塞了的IP也会加入到ignore.ip.list中,但堵塞了预定时间后会从它之中删除。
安装: wget http://www.inetbase.com/scripts/ddos/install.sh chmod 0700 install.sh ./install.sh
卸载: wget http://www.inetbase.com/scripts/ddos/uninstall.ddos chmod 0700 uninstall.ddos ./uninstall.ddos
安装完成后在/usr/local/ddos目录下产生了ddos.conf、ddos.sh、ignore.ip.list和LICENSE这四个文件,ddos.conf是配置文件,ddos.sh是一个Shell文件,ignore.ip.list是存放忽略IP的文件,LICENSE是版权声明文件,安装完成后还在/etc/cron.d/下生产了ddos.cron文件,内容如下:
SHELL=/bin/sh
0-59/1 * * * * root /usr/local/ddos/ddos.sh >/dev/null 2>&1
意思是每隔一分钟执行一下/usr/local/ddos/ddos.sh
这个cron任务是依赖ddos.conf文件中的NO_OF_CONNECTIONS变量产生的,如果修改了此值,可以通过运行如下命令更新(实际也是在安装是运行了如下命令):
/usr/local/ddos/ddos.sh -c 或 /usr/local/ddos/ddos.sh –cron
以下主要针对ddos.conf和ddos.sh进行分析:
ddos.conf内容:
##### Paths of the script and other files PROGDIR="/usr/local/ddos" PROG="/usr/local/ddos/ddos.sh" IGNORE_IP_LIST="/usr/local/ddos/ignore.ip.list" CRON="/etc/cron.d/ddos.cron" APF="/etc/apf/apf" IPT="/sbin/iptables" ##### frequency in minutes for running the script ##### Caution: Every time this setting is changed, run the script with --cron ##### option so that the new frequency takes effect # 设置检测时间间隔,默认是分钟,由于系统使用crontab功能,最小单位是分钟 FREQ=1 ##### How many connections define a bad IP? Indicate that below. # NO_OF_CONNECTIONS默认是150,这是一个经验值,如果服务器性能比较高,可以设置200以上,以避免误杀 NO_OF_CONNECTIONS=150 ##### APF_BAN=1 (Make sure your APF version is atleast 0.96) ##### APF_BAN=0 (Uses iptables for banning ips instead of APF) # 使用APF屏蔽IP,如果设置为0就使用iptables,如果使用APF则需要先安装,比如centos中默认就没有安装 APF_BAN=0 ##### KILL=0 (Bad IPs are'nt banned, good for interactive execution of script) ##### KILL=1 (Recommended setting) KILL=1 ##### An email is sent to the following address when an IP is banned. ##### Blank would suppress sending of mails # 如果不希望发送邮件,设置为空 EMAIL_TO="" ##### Number of seconds the banned ip should remain in blacklist. # 解锁的时间,单位为秒,可以设置更长时间 BAN_PERIOD=86400
ddos.sh内容:
# 载入配置文件 load_conf() { CONF="/usr/local/ddos/ddos.conf" # $CONF是文件,使用source载入 if [ -f "$CONF" ] && [ ! "$CONF" == "" ]; then source $CONF else head echo "\$CONF not found." exit 1 fi } # 头部输出 head() { echo "DDoS-Deflate version 0.6" echo "Copyright (C) 2005, Zaf <zaf@vsnl.com>" echo } # 显示帮助,比如如果要收到干掉当前超过N个连接的IP,使用sh ddos.sh -k 150, sh ddos.sh -h 显示帮助, sh ddos.sh -c创建cron job showhelp() { head echo 'Usage: ddos.sh [OPTIONS] [N]' echo 'N : number of tcp/udp connections (default 150)' echo 'OPTIONS:' echo '-h | --help: Show this help screen' echo '-c | --cron: Create cron job to run this script regularly (default 1 mins)' echo '-k | --kill: Block the offending ip making more than N connections ' } # 解除对IP的封锁 unbanip() { UNBAN_SCRIPT=`mktemp /tmp/unban.XXXXXXXX` # 产生随机文件,解除IP封锁时 TMP_FILE=`mktemp /tmp/unban.XXXXXXXX` # 临时文件 UNBAN_IP_LIST=`mktemp /tmp/unban.XXXXXXXX` # 将被解除封锁的IP echo '#!/bin/sh' > $UNBAN_SCRIPT # 产生解除IP封锁的脚本内容 echo "sleep $BAN_PERIOD" >> $UNBAN_SCRIPT # $BAN_PERIOD睡眠时间,表示$UNBAN_SCRIPT睡眠多久后继续,这个变量在配置文件中定义 if [ $APF_BAN -eq 1 ]; then # 使用APF堵塞IP while read line; do echo "$APF -u $line" >> $UNBAN_SCRIPT echo $line >> $UNBAN_IP_LIST done < $BANNED_IP_LIST else # 使用iptables封锁IP while read line; do echo "$IPT -D INPUT -s $line -j DROP" >> $UNBAN_SCRIPT # 解除IP封锁 echo $line >> $UNBAN_IP_LIST # 把将要解除堵塞的IP写入$UNBAN_IP_LIST,跟当前的$BANNED_IP_LIST是对应的 done < $BANNED_IP_LIST # 输入重定向,行对于$line变量,是当前需要堵塞的IP,脚本运行过程中产生 fi echo "grep -v --file=$UNBAN_IP_LIST $IGNORE_IP_LIST > $TMP_FILE" >> $UNBAN_SCRIPT # 从$IGNORE_IP_LIST中去掉$UNBAN_IP_LIST,把结果写入$TMP_FILE echo "mv $TMP_FILE $IGNORE_IP_LIST" >> $UNBAN_SCRIPT # 移动$TMP_FILE到$IGNORE_IP_LIST,$IGNORE_IP_LIST在配置文件中定义,则本次操作是覆盖 echo "rm -f $UNBAN_SCRIPT" >> $UNBAN_SCRIPT # 删除$UNBAN_SCRIPT echo "rm -f $UNBAN_IP_LIST" >> $UNBAN_SCRIPT # 删除$UNBAN_IP_LIST echo "rm -f $TMP_FILE" >> $UNBAN_SCRIPT # 删除$TMP_FILE,经过上面的移动操作,$TMP_FILE其实已经不存在 . $UNBAN_SCRIPT & # 在后台运行$UNBAN_SCRIPT } # 添加到计划任务 add_to_cron() { rm -f $CRON # 删除/etc/cron.d/ddos.cron sleep 1 service crond restart # 计划任务重启 sleep 1 echo "SHELL=/bin/sh" > $CRON # 创建计划任务 if [ $FREQ -le 2 ]; then # $FREQ在配置文件中定义,表示多少分钟执行一次,如果小于2,Linux最小是每分钟 # 以下语句得到 0-59/1 * * * * root /usr/local/ddos/ddos.sh >/dev/null 2>&1,每分钟以root执行ddos.sh,把输出结果丢弃 echo "0-59/$FREQ * * * * root /usr/local/ddos/ddos.sh >/dev/null 2>&1" >> $CRON else # 大于1分钟设置 let "START_MINUTE = $RANDOM % ($FREQ - 1)" # $RANDOM是环境变量随机数 let是shell内建命令,就是执行计算 let "START_MINUTE = $START_MINUTE + 1" let "END_MINUTE = 60 - $FREQ + $START_MINUTE" echo "$START_MINUTE-$END_MINUTE/$FREQ * * * * root /usr/local/ddos/ddos.sh >/dev/null 2>&1" >> $CRON fi service crond restart } # 加载配置 load_conf # 判断$1,是第一个参数,提供帮助,如果没有提供则不会进入循环 while [ $1 ]; do case $1 in '-h' | '--help' | '?' ) showhelp # 显示帮助 exit ;; '--cron' | '-c' ) add_to_cron # 添加到计划任务 exit ;; '--kill' | '-k' ) KILL=1 # KILL在配置文件中指定,用来指定是否堵塞IP ;; *[0-9]* ) NO_OF_CONNECTIONS=$1 # 第二个参数,指定阀值,NO_OF_CONNECTIONS在配置文件中指定,这里覆盖 ;; * ) showhelp exit ;; esac shift # 减少变量,就是现在$1是原来的$2,shift后可以指定减少几个 done TMP_PREFIX='/tmp/ddos' TMP_FILE="mktemp $TMP_PREFIX.XXXXXXXX" BANNED_IP_MAIL=`$TMP_FILE` # 产生临时文件,发送邮件,邮件内容 BANNED_IP_LIST=`$TMP_FILE` # 产生临时文件,存放已经被堵塞的IP echo "Banned the following ip addresses on `date`" > $BANNED_IP_MAIL 构建邮件内容 echo >> $BANNED_IP_MAIL BAD_IP_LIST=`$TMP_FILE` # 产生临时文件,存放当前可能被堵塞的IP netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr > $BAD_IP_LIST cat $BAD_IP_LIST # 输出这个列表 if [ $KILL -eq 1 ]; then # 如果配置为需要堵塞 IP_BAN_NOW=0 while read line; do CURR_LINE_CONN=$(echo $line | cut -d" " -f1) # 当前这个IP有多少个连接 CURR_LINE_IP=$(echo $line | cut -d" " -f2) # 当前IP if [ $CURR_LINE_CONN -lt $NO_OF_CONNECTIONS ]; then # 如果这个IP链接数小于预设,终止(因为数据经过排序) break fi IGNORE_BAN=`grep -c $CURR_LINE_IP $IGNORE_IP_LIST` # 计算当前IP在$IGNORE_IP_LIST出现了多少次 if [ $IGNORE_BAN -ge 1 ]; then # 如果当前IP已经在$IGNORE_IP_LIST,跳过,可以通过这个方式设置永不堵塞某些IP continue fi IP_BAN_NOW=1 # 进入到这里表示当前必定有IP要被堵塞 echo "$CURR_LINE_IP with $CURR_LINE_CONN connections" >> $BANNE_IP_MAIL # 把堵塞信息写入邮件内容 echo $CURR_LINE_IP >> $BANNED_IP_LIST # 添加堵塞了的IP到当前堵塞列表,$BANNED_IP_LIST会应用到下面的unbanip函数 echo $CURR_LINE_IP >> $IGNORE_IP_LIST # 添加堵塞了的IP到$IGNORE_IP_LIST if [ $APF_BAN -eq 1 ]; then $APF -d $CURR_LINE_IP else $IPT -I INPUT -s $CURR_LINE_IP -j DROP # 开始iptables封锁 fi done < $BAD_IP_LIST if [ $IP_BAN_NOW -eq 1 ]; then # $IP_BAN_NOW等于1表示有IP被封锁了 dt=`date` if [ $EMAIL_TO != "" ]; then # $EMAIL_TO设置不为空则发邮件,留空则不发邮件 cat $BANNED_IP_MAIL | mail -s "IP addresses banned on $dt" $EMAIL_TO # $EMAIL_TO在配置文件中指定 fi unbanip # 同时开始运行解除堵塞程序 fi fi rm -f $TMP_PREFIX.* # 清除临时产生的文件
可以看到如果有堵塞IP,将调用mail发送邮件,但是作为前端代理,视乎没有必要特意去安装sendmail,所以我们可以使用curl把数据推送到远程,由另一台专门的服务器发送这些信息,改造如下:
if [ $EMAIL_TO != "" ]; then
cat $BANNED_IP_MAIL | mail -s "IP addresses banned on $dt" $EMAIL_TO
else
curl --data "d=IP addresses banned on $dt -- $(cat $BANNED_IP_MAIL)" "http://domain.com/blockip.php" >> /dev/null
fi
除此,尽管默认到达150才堵塞,但你可能希望把那些超过100链接的IP都记录下来,可以在cat $BAD_IP_LIST之后添加如下代码:
NUM_CONNECTIONS=100 # 超过100就记录
# 按照日期存放
CNTS_LOG="/usr/local/ddos/$(date +%Y)/$(date +%m)/"
mkdir -p $CNTS_LOG
CNTS_LOG="$CNTS_LOG$(date +%Y%m%d).log"
while read line; do
CURR_CONN=$(echo $line | cut -d" " -f1)
CURR_IP=$(echo $line | cut -d" " -f2)
if [ $CURR_CONN -lt $NUM_CONNECTIONS ]; then
break
fi
echo "$CURR_IP with $CURR_CONN connections at `date`" >> $CNTS_LOG
done < $BAD_IP_LIST
收藏了…我之前玩过一个叫树莓派的小型linux服务器,但幸好没遇到过DDOS,先收着以后或许用到~~