gentoo,linux上用iptables自动封ip的bash脚本

为了防止各种各样的不规则访问和攻击,利用iptables来进行自动封ip
测试机器 2.6.31-gentoo-r10 x86_64

先装iptables
[ccn lang="bash" tab_size="4" theme="blackboard" width="900" ]
emerge -av iptables
[/ccn]
然后执行下面的脚本,让其自动在后台运行
[ccn lang="bash" tab_size="4" theme="blackboard" width="900" ]
# nohup sh ~/scripts/drop_ips.sh &
[/ccn]

[ccn lang="bash" tab_size="4" theme="blackboard" width="900" ]

#! /bin/bash

###########################################
# 封锁ip 用iptables
# usage:
#
# create date 2010-11-11
# update date 2010-11-12
###########################################

# 定义端口
CHK_PORT="80 25"

# 定义输出文件
IPTABLE_OUTPUT=/tmp/ip_drop_tables
# 定义输出文件备份
IPTABLE_OUTPUT_BAK=/tmp/ip_drop_tables.bak

# 扫描ip的 间隔时间
SCAN_HTTP_IP_TIMEOUT=20

# 处理ip的间隔时间
HANDLE_IP_TIMEOUT=120

# 连接数量最大限制
MAX_CONNECT_IP_NUM=100

# 排除在外的ip
ACCEPT_IP="203.95.110.2"

# 已经封锁的ip
DROP_IP_RECORD_FILE=/tmp/drop_ip_record

#################################################################
#定义方法
#################################################################
# 输出ip到文件
output_ip_table()
{
# 拿到端口号
port_num=$1
# 查此端口上的连接ip 输出到指定的目录
#echo "start scan ......"
netstat -na --tcp| grep ESTABLISHED | awk '{ if ( index($4,":"'"$port_num"'"") ) print $5}' | awk -F ':' '{print $1}' | sort >> $IPTABLE_OUTPUT
#echo "scan end ......"
}

# 把需要观测端口列出
check_port()
{
for port_td in $CHK_PORT
do
# echo "port : "$port_td
# 扫描此端口
output_ip_table $port_td
done
}

# 封杀ip
drop_ip_from_table()
{
iptables -I INPUT -s "$1" -j DROP
}

# 排除ip
accept_ip()
{
for access_ip in $ACCEPT_IP
do
iptables -I INPUT -s "$access_ip" -j ACCEPT
done
}

# 提取需要的ip
get_iptable()
{
# 如果已经存在就删除
if [ -e $IPTABLE_OUTPUT_BAK ] ; then
rm -rf $IPTABLE_OUTPUT_BAK
fi
# copy 一份出去
cp $IPTABLE_OUTPUT $IPTABLE_OUTPUT_BAK
# 排序 数组
declare -a ip_array_org=($(cat ${IPTABLE_OUTPUT_BAK} | sort))
# 循环
# 比对用的ip 初始化
tmp_ip=0.0.0.0
let "tmp_ip_count=1"
for tmp_element in "${ip_array_org[@]}"
do
# 初始化 没有特殊设置为排除ip
is_not_set_accept="true"
# 初始化 是否已封杀了
is_not_drop="true"
# 如果相等
if [ "$tmp_ip" = "$tmp_element" ] ; then
let "tmp_ip_count+=1"
else
# 打印
echo "ip: $tmp_ip count: $tmp_ip_count"
# 如果大于某个数字 就封杀
if (( $tmp_ip_count >= $MAX_CONNECT_IP_NUM )) ; then
# 如果没有记录就封杀
if cat /tmp/drop_ip_record | grep "$tmp_ip" > /dev/null ; then
echo "this ip $tmp_ip has been mask !"
is_not_drop="false"
else
# 循环 需要排除ip
for tmp_access_ip in $ACCEPT_IP
do
# 如果排除ip里有 就去封锁此ip
if [ "$tmp_access_ip" = "$tmp_ip" ] ; then
echo "this ip $tmp_ip was mark to accept !"
is_not_set_accept="false"
fi
done
fi
if [ $is_not_set_accept = "true" ] && [ $is_not_drop = "true"] ; then
echo "add a new ip to drop : $tmp_ip"
drop_ip_from_table $tmp_ip
# 记录ip
echo "$tmp_ip" >> $DROP_IP_RECORD_FILE
fi
fi
# 归零
let "tmp_ip_count=1"
tmp_ip=$tmp_element
fi
done
# 全部处理完了 删除原件
rm -rf $IPTABLE_OUTPUT
# 排除ip
# accept_ip

}

# 扫描ip
scan_http_access_ip()
{
# 获取当前时间作为开始时间
start_time=`date +%s`
# 循环开始
while true
do
# 开始检查 扫描ip
check_port
# 线程停止
sleep $SCAN_HTTP_IP_TIMEOUT
# 获取当前时间
cur_time=`date +%s`
# 时间差
let "time_out=$cur_time-$start_time"
echo "time_out : "$time_out
# 超过2分钟
if (( $time_out >= $HANDLE_IP_TIMEOUT )) ; then
# 整理一次ip表
echo " times up"
get_iptable
# 重置开始时间
start_time=`date +%s`
fi
done
}

# 程序执行入口
main_app()
{
# 定时扫描ip
scan_http_access_ip
}

main_app
[/ccn]