Linux上用iptables自动封ip的bash脚本,这个还是有一定效果的。CentOS 内置了一个非常强劲的防火墙,统称为 iptables,但更正确的名称是 iptables/netfilter。iptables 是一个用户空间的模块。作为用户,你在命令行就是通过它将防火墙规则放进缺省的表里。netfilter 是一个核心模块,它内置于内核中,进行实际的过滤。iptables 有很多前端图像界面可以让用户新增或定义规则,但它们很多时不及使用命令行般有灵活性,而且限制用户了解实际发生的事情。
1. 安先装iptables
这里搬主题就不多描述了,如果是CentOS 6的话,自带iptables防火墙,如果是CentOS 7的话,那还需要卸掉原有防火墙,然后安装iptables防火墙。
2. 下面的脚本保存为drop_ips.sh
#!/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
然后执行下面的脚本,让其自动在后台运行。
sh ~/scripts/drop_ips.sh &
以上是封少量的IP的教程,但是大家知道,iptables封掉少量ip处理是没什么问题的,但是当有大量ip攻击的时候性能就跟不上了,iptables是O(N)的性能。而ipset就像一个集合,把需要封闭的ip地址放入这个集合中,ipset 是O(1)的性能,用的hash方式所以特别快。
一、软件及安装
1、iptables
可参考这篇文章安装:https://www.shoushai.com/p/991
2、ipset:
ubuntu:apt-get install ipset
二、ipset的使用
1、查看ip集的列表信息
ipset list
2、创建ip集
ipset create XXXX hash:ip maxelem 100000 timeout 3600
XXXX:ip集的名字
hash:ip :为指定类型,还有其他好些类型,比如hash:net,hash:net,net等,具体可以man ipset
100000:为最大保存ip的数量
timeout: 为封闭ip的默认时间,这个参数可以不写,这样就永不解封,除非手动解封
3、增加ip地址到ip集
ipset add xxxx 1.1.1.1
增加网段:
ipset add xxxx 1.1.1.0/24
4、删除指定的ip或网段
ipset del xxxx 1.1.1.1 ipset del xxxx 1.1.1.0/24
5、保存ip集到文件
ipset save xxxx>ipset_list.txt
6、还原ip集
ipset restore <ipset_list.txt
三、自动封禁和解封
1、创建ip集
ipset create forbidip hash:ip timeout 172800
2、创建iptables条目
iptables -A INPUT -p tcp -m set --match-set forbidip src -m multiport --dports 443,80 -j DROP
或者
iptables -A INPUT -p tcp -m set –match-set forbidip src -m multiport -j DROP
3、根据条件判断需要封闭的ip
条件:在上一分钟的nginx的请求中,单一ip请求数超过1000及request_uri中包含passwd字符串的ip都直接封禁,1小时后自动解禁。脚本如下
#!/bin/bash FILES="/data/nginx_log/xxxxx/access.log" DATE=`date -d '1 minutes ago' +%Y:%H:%M` grep ${DATE} ${FILES}|awk -F'|' '{print $3}'|sort -n|uniq -c |sort -nr|head -1>/tmp/ips grep ${DATE} ${FILES}|grep -i passwd|awk -F'|' '{print $3}'|sort -n|uniq>/tmp/ippwd NUM=`awk '{print $1}' /tmp/ips` IP=`awk '{print $2}' /tmp/ips` IP2=`cat /tmp/ippwd` threshold=1000 if [[ $NUM -gt $threshold ]];then /sbin/ipset -! add forbidip $IP timeout 3600 fi if [ -s /tmp/ippwd ];then for i in $IP2 do /sbin/ipset -! add forbidip $i done fi
4、脚本自动运行
在crontab中添加此脚本的自动运行
*/1 * * * * bash /path/to/script.sh
原文转自:https://blog.gua5.com/xing/29
本文来自投稿,不代表首晒立场,如若转载,请注明出处:https://www.shoushai.com/p/992