2月 21

服务器 自动封锁和解封IP 对付攻击

  服务器流量暴涨,首先通过访问日志查看。每个IP并发不是很高,分布也很广,但是都是只访问主页,可见不是抓取服务导致。通过“netstat -nat|awk ‘{print awk $NF}’|sort|uniq -c|sort -n”t命令查看,连接中还有很多SYN_RECV、TIME_WAIT、ESTABLISHED。看来是小型的攻击。首先是修改web服务的配置,缩减了timeout时间,在nginx上禁止一部分并发比较高的IP,小改系统参数。流量降了20M,但还是太高。nginx虽然禁止了IP,如果用浏览看是一个空白页面,但是每个连接还会产生很小的流量。最后决定将最小的返回值也封掉,直接在iptables上drop掉连接。每个超限IP暂定封2天。写个脚本自动运行。

  此脚本在在centos5.3+python2.6.6使用通过。需要注意,此脚本统计日志完毕会将nginx日志文件清空,如需保留日志,请自行修改。每次加载iptables规则时会清楚上次所有规则,如果有使用其它规则也要自行处理。

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    drop_ip_iptables.py
# Revision:    1.0
# Date:        2013-2-21
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import os
import time
from string import strip


#### 参数和脚本中使用到的系统命令
nginx_log = "/usr/local/nginx/logs/nginx.access.log"
# 统计nginx日志中IP访问数量
check_comm = "/bin/cat %s |awk ' ''{print $1}'|sort |uniq -c|sort -n -k1 -r" % nginx_log
# 放在crontab中10分钟跑一次,访问超出n次的全部封掉
overproof = 3000
# 被封地址记录文件
# 文件中记录封IP时间和IP地址。时间单位为秒
lock_ip_list = "/usr/local/nginx/logs/lock_ip_list.txt"
# 被封地址解开时间。时间单位为秒
unlock_time = 3600*24*2 


def manage_lock_ip():
    # 获取当前时间
    get_now_time = int(time.time())
    # 管理日志字典
    man_ip = {}
    # 处理日志中的IP
    try:
        log_file = open('%s' % lock_ip_list, 'rb').readlines()
        for get_ip_info in log_file:
            _get_ip_info = strip(get_ip_info).split(' ')
            man_ip['%s' % _get_ip_info[1]] = int(_get_ip_info[0])
    except:
        exit(0)
    # 清空iptable列表,和ip记录日志
    os.popen('/sbin/iptables -F')
    clean_file = open('%s' % lock_ip_list, 'rb+')
    clean_file.truncate()
    # 开始处理IP,被封没有超时的IP写入iptables和日志中
    log_file = open('%s' % lock_ip_list, 'ab')
    for loop_ip in man_ip.keys():
        if (get_now_time - man_ip[loop_ip]) < unlock_time:
            os.popen('/sbin/iptables -I INPUT -s %s -j DROP' % loop_ip)
            log_file.write('%s %s\n' % (man_ip[loop_ip], loop_ip))
    log_file.close()
        


def main():
    # 已封IP地址字典
    drop_ip_list = {}
    # 加载已封IP日志
    try:
        log_file = open('%s' % lock_ip_list, 'rb').readlines()
        for get_drop_ip_info in log_file:
            _get_drop_ip_info = strip(get_drop_ip_info).split(' ')
            drop_ip_list['%s' % _get_drop_ip_info[1]] = int(_get_drop_ip_info[0])
    except:
        os.mknod('%s' % lock_ip_list)
    # 获取nginx日志中的访问超高的ip并写入日志
    access_high_ip = os.popen('%s' % check_comm).readlines()
    for get_ip_count in access_high_ip:
        try :
            _get_ip_count = strip(get_ip_count).split(' ')
            _get_ip = _get_ip_count[1]
            _get_count = _get_ip_count[0]
        except:
            pass
        if (int(_get_count) > int(overproof)) and (_get_ip not in drop_ip_list.keys()):
            now_time = int(time.time())
            log_file = open('%s' % lock_ip_list, 'ab+')
            log_file.write('%s %s\n' % (now_time, _get_ip))
            log_file.close()
    # 统计完毕清空nginx日志
    log_file = open('%s' % nginx_log, 'wb')
    log_file.truncate()
    # 处理要封的IP和要解开的IP
    manage_lock_ip()


if __name__ == '__main__':
    main()

再补充两条日志分析命令
# 单位时间内统计单个IP只访问首页的数量:
#check_comm = “/bin/cat %s|grep ‘GET / HTTP/1.1’|awk ‘ ”{print $1}’|sort |uniq -c|sort -n -k1 -r” % nginx_log
# 单位时间内统计单个IP访问相同页面的数量
#check_comm = “/bin/cat %s|awk -F'”‘ ‘{print $1 $2}’|awk ‘ ”{print $1″ “$6” “$7” “$8}’|sort -k2,4 -r|uniq -c|sort -n -k1 -r” % nginx_log

源码下载
drop_ip_tables

3月 25

导出mysql 上传到ftp备份

导出mysql的库上传到ftp服务器备份,上传完毕删除本地文件。用crontab定时运行。用shell也很容以实现,毕竟在学习python,练习一下。

#!/usr/bin/env python
#-*- coding: utf-8 -*-
# ——————————————————————————-
# Filename: Back mysql
# Revision: 1.0
# Date: 2010-03-24
# Author: simon-zzm
# Email: simon-zzm@163.com
# Description:
# ——————————————————————————-
import os,time,sys
from ftplib import FTP
import datetime

###################设置参数
mysql_user=’root’
mysql_pass=’123456′
mysql_comm=’/usr/local/mysql/bin/mysqldump’
mysql_data=[‘test_a’,’test_b’] ###可以填写多个库
mysql_local_path=’/usr/local/checksystem/’
ftp_ip=’x.x.x.x’
ftp_user=’ftpuser’
ftp_pass=’test’
admin_mail=’simon-zzm@163.com’
###################开始运行
#导出的文件为gz的压缩文件,命名格式为ip地址、库名、导出日期组成。
###获得当前时间
get_time_now=time.strftime(‘%Y-%m-%d’)
###获得本机IP地址
ip = os.popen(“/sbin/ifconfig | grep ‘inet addr’ | awk ‘{print $2}'”).read()
get_local_ip = ip[ip.find(‘:’)+1:ip.find(‘n’)]
for i in mysql_data:
###拼成包名
mysql_back_name=mysql_local_path+get_local_ip+’_’+i+’_’+get_time_now+’.gz’
###拼成导出命令
gzip_command = “%s -u%s -p%s –opt %s |gzip >%s” %(mysql_comm,mysql_user,mysql_pass,i,mysql_back_name)
###导出并判断是否成功
if os.system(gzip_command)==0:
print ‘Back Successful’
###导出成功上传到ftp服务器
ftp=FTP()
ftp.set_debuglevel(2)
ftp.connect(ftp_ip,’21’)
ftp.login(ftp_user,ftp_pass)
file_handler = open(mysql_back_name,’rb’)
bufsize = 1024
ftp.storbinary(‘STOR %s’ % os.path.basename(mysql_back_name),file_handler,bufsize)
ftp.set_debuglevel(0)
file_handler.close()
ftp.quit()
print ‘up load over!’
###偷个懒使用linux命令将本地文件删掉。
os.popen(“/usr/bin/find “+mysql_local_path+”* -name *.gz -exec rm -rf {} ; “)
else:
print ‘false’
###如果导出失败,给管理员发个信,偷个懒使用linux命令解决。
mail_url=”/bin/mail -s “+get_local_ip+”back fail “+admin_mail+” os.popen(mail_url)

3月 15

linux定时重启单台上多个tomcat

tomcat长期运行会越来越慢,所以需要定时重启单台上多个tomcat,写一个脚本放在crontab定时运行。脚本如下,需要注意脚本中使用了了linux中的mail命令,在tomcat启动失败时可以发送提醒邮件。(不知道为什么贴到这里格式会乱,只能手动整理)

#!/bin/sh
# ——————————————————————————-
# Filename: tomcat_reboot.sh
# Revision: 1.0
# Date: 2010-03-01
# Author: simon
# Email: simon-zzm@163.com
# Description:
# ——————————————————————————-
# Source function library.
. /etc/init.d/functions
source /etc/profile

#######set tomcat patch
tomcat_path=(“/program/tomcat_a/” “/program/tomcat_b/”)

#######set tomcat_key patch
tom_key_path=(“tomcat_a” “tomcat_b”)

###### set bases data
admin_mail=simon-zzm@163.com
IP=`/sbin/ifconfig |grep ‘inet addr:’|grep -v ‘127.0.0.1’|awk ‘ ”{print $2}’`

###### send alert mail
send_mail()
{
echo ${IP}” “${1}” can not stop…” >${2}tom_mail.log
/bin/mail -s ${1}’-‘${IP} ${admin_mail}<${2}tom_mail.log
/bin/rm -rf ${2}tom_mail.log
}

###### delete tomcat`s work dir and startup server
del_start()
{
/bin/rm -rf ${1}work/*
$1bin/startup.sh
}
######main()
for (( i=0 ; i < ${#tomcat_path[@]} ; i++ ))
do
${tomcat_path[i]}bin/shutdown.sh
sleep 3
get_pid_count=`/bin/ps -ef|grep -v grep|grep ${tom_key_path[i]}|wc -l`
if [ ${get_pid_count} -gt 0 ] ; then
/bin/ps -ef|grep -v grep|grep ${tom_key_path[i]}|awk ‘ ”{print $2}’|xargs kill -9
sleep 5
get_pid_count=`/bin/ps -ef|grep -v grep|grep ${tom_key_path[i]}|wc -l`
if [ ${get_pid_count} -gt 0 ] ; then
send_mail ${tom_key_path[i]} ${tomcat_path[i]}
else
del_start ${tomcat_path[i]}
fi
else
del_start ${tomcat_path[i]}
fi
sleep 3
get_pid_count=`/bin/ps -ef|grep -v grep|grep ${tom_key_path[i]}|wc -l`
if [ ${get_pid_count} -lt 1 ] ; then
send_mail ${tom_key_path[i]} ${tomcat_path[i]}
fi
done