Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1438034
  • 博文数量: 704
  • 博客积分: 10140
  • 博客等级: 上将
  • 技术积分: 6230
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-15 20:41
文章分类

全部博文(704)

文章存档

2013年(1)

2012年(16)

2011年(536)

2010年(151)

分类:

2011-12-29 20:56:20

    上周日在家写了个防止SYN洪水攻击的脚本,很实用,如果服务器经常有这样的骚扰,不妨用我的这个脚本抵挡之
 
#! /bin/sh
# 防止SYN_RECV攻击的脚本
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
# 设置某个ip需要被列入黑名单的时间,单位是分钟
TIME_ZONE=30
DATE_ZONE=30
SYN_critical=500
DATE=$(date +%Y%m%d)
HOUR=$(date +%H)
MINITE=$(date +%M)
DATE_AGO=$(date -d "$DATE_ZONE days ago" +%Y%m%d)
DATE_1D_AGO=$(date -d "1 days ago" +%Y%m%d)
TIME_AGO=$(date -d "$TIME_ZONE min ago" +%H%M)
# 正常日志
LOG=/home/tools/syn_flood/syn.log
# 30分钟前的ip记录
LOG_ago=/home/tools/syn_flood/syn.log.ago
# 30分钟以内的ip记录
LOG_current=/home/tools/syn_flood/syn.log.current
#设置轮转日志的大小范围,单位k
LIMIT=16384
export PATH TIME_ZONE DATE_ZONE SYN_critical DATE HOUR MINITE DATE_AGO DATE_1D_AGO TIME_AGO
# 将proc文件系统的文件放入tmp
cat /proc/net/tcp6 /proc/net/tcp 2>/dev/null > /tmp/syn_recv
# 取到黑名单列表
awk '{print $2,$3,$4}' /tmp/syn_recv | awk '
BEGIN { # set fs
        FS = "[ ]*|:" ; }
# 只处理第五列是SYN_RECV的行
( $5 ~ /03/ ){
 # get ipv4addr from file /proc/net/tcp
 if (length($1) == 8)
 {
  rem_addr_ip4 =  strtonum("0x"substr($3,1,2)) ;
  rem_addr_ip3 =  strtonum("0x"substr($3,3,2)) ;
  rem_addr_ip2 =  strtonum("0x"substr($3,5,2)) ;
  rem_addr_ip1 =  strtonum("0x"substr($3,7,2)) ;
 }
 else
 # get ipv6addr from file /proc/net/tcp6
 {
  rem_addr_ip4 =  strtonum("0x"substr($3,25,2)) ;
  rem_addr_ip3 =  strtonum("0x"substr($3,27,2)) ;
  rem_addr_ip2 =  strtonum("0x"substr($3,29,2)) ;
  rem_addr_ip1 =  strtonum("0x"substr($3,31,2)) ;
 }
 printf("%d.%d.%d.%d\n",rem_addr_ip1,rem_addr_ip2,rem_addr_ip3,rem_addr_ip4);
}' | uniq -c | grep -v '192.168.'  | awk  'BEGIN{
 SYN_critical =  ENVIRON["SYN_critical"];
 DATE = ENVIRON["DATE"];
 HOUR = ENVIRON["HOUR"];
 MINITE = ENVIRON["MINITE"];
}
( $1 >= SYN_critical ){ printf("[ %d %d%d ] %s %d\n",DATE,HOUR,MINITE,$2,$1) }'  >> $LOG
# 得到旧的ip列表
if [ $HOUR = "00" ] && [ $MINITE -le 30 ]
 then
 export DATE=$DATE_1D_AGO
fi
awk  'BEGIN{
 DATE = ENVIRON["DATE"];
 time_ago = ENVIRON["TIME_AGO"];
}
( $2 == DATE && $3 < time_ago ){ print $5 }' $LOG | uniq > $LOG_ago

# 得到30分钟内的ip列表
awk  'BEGIN{
 DATE = ENVIRON["DATE"];
 time_ago = ENVIRON["TIME_AGO"];
}
( $2 == DATE && $3 > time_ago ){ print $5 }' $LOG | uniq > $LOG_current
NUM_LOG_ago=$(wc -l $LOG_ago | awk '{print $1}' )
NUM_LOG_current=$(wc -l $LOG_current | awk '{print $1}' )
# 看iptables是否运行
IPTAB_STATUS=$(service iptables status | grep -c 'Firewall is stopped.')
# 如果30分钟以前有ip被列入黑名单,则删除掉
if [ $NUM_LOG_ago -ge 1 ]
 then
  if [ $IPTAB_STATUS -eq 0 ]
   then
   
   for IP in $(cat $LOG_ago)
    do
      # 确认此ip是否在当前iptables列表中,在则删除该ip
      NUM_ip=$(grep -c $IP /etc/sysconfig/iptables)
      if [ $NUM_ip -ge 1 ]
       then
       iptables -D INPUT -s $IP  -i eth0 -j DROP
       service iptables save
      fi
    done
  fi
fi
# 处理30分钟内的ip列表,如果不在iptables里,则判断iptables的状态,并加入黑名单
if [ $NUM_LOG_current -ge 1 ]
 then
 # 看iptables是否打开
 if [ $IPTAB_STATUS -eq 1 ]
  then
  service iptables start
 fi
 # 把ip加进去
 for IP in $(cat $LOG_current)
  do
   # 确认此ip是否在当前iptables列表中,不在则加进去
    NUM_ip=$(grep -c $IP /etc/sysconfig/iptables)
    if [ $NUM_ip -eq 0 ]
     then
     iptables -A INPUT -s $IP  -i eth0 -j DROP
     service iptables save
    fi
  done
fi

# 如果iptables列表为空,判断其状态,如果是start ,则stop它
 if [ $IPTAB_STATUS -eq 0 ]
  then
  # 判断iptables列表是否为空
  NUM=$(iptables -L -n | wc -l)
  if [ $NUM -eq 8 ]
   then
   service iptables stop
  fi
 fi
# 按大小轮转日志,注意,日志轮转都放在晚上1点,这样节省脚本每次运行的if判断开销
################################## 日志轮转  #######################################
#if [ $HOUR == "01" ]
# then
#  size=$(ls -l -k $LOG | cut -d " " -f 6)
#
#  echo "$LOG size is $size, limit is $LIMIT"
#
#  if [ $size -ge $LIMIT ]
#
#    then
#
#    echo "rolling log file"
#    awk  'BEGIN{
#    DATE = ENVIRON["DATE"];
#    time_ago = ENVIRON["TIME_AGO"];
#    }
#
#     ( $1 == DATE && $3 > time_ago ){ print }' $LOG > /tmp/syn_log_tmp
#    cp $LOG $LOG.$DATE
#    mv -f /tmp/syn_log_tmp $LOG
#
#    else
#
#    echo "not big enough"
#
#  fi
#
#  # 按日期轮转日志
#  # 如果30天前有日志,说明是该到轮转的时候了
#  DATE_NUM=$(grep "$DATE_AGO" $LOG | head | wc -l | awk '{print $1}')
#  if [ $DATE_NUM -ge 1 ]
#   then
#    awk  'BEGIN{
#    DATE = ENVIRON["DATE"];
#    time_ago = ENVIRON["TIME_AGO"];
#    }
#
#     ( $1 == DATE && $3 > time_ago ){ print }' $LOG > /tmp/syn_log_tmp
#    cp $LOG $LOG.$DATE
#    mv -f /tmp/syn_log_tmp $LOG
#
#  fi
#
#fi
################################## 日志轮转  #######################################
阅读(533) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~