-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
blockip.sh
174 lines (167 loc) · 7.68 KB
/
blockip.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/bin/bash
#功能描述(Description):分析系统登陆日志,过滤异常IP地址,并通过防火墙禁用该IP.
#强制退出时关闭所有后台进程.
trap 'kill $one_pid; kill $five_pid; kill $fifteen_pid; exit' EXIT INT
#日志文件路径.
LOGFILE=/var/log/secure
BLOCKFILE=/tmp/blockip.txt
one_minute(){
while :
do
#获取计算机当前时间,以及1分钟前的时间,时间格式:
#%b(月份简写,Jan) %e(日期,1) %T(时间 18:00:00)
#LANG=C的作用是否防止输出中文.
#使用local定义局部变量的好处是多个函数使用相同的变量名也不会冲突.
local curtime_month=$(LANG=C date +"%b")
local curtime_day=$(LANG=C date +"%e")
local curtime_time=$(LANG=C date +"%T")
local one_minus_ago=$(LANG=C date -d "1 minutes ago" +"%T")
#将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算.
local curtime_seconds=$(LANG=C date +"%s")
#分析1分钟内所有的日志,如果密码失败则过滤倒数第4列的IP地址.
#通过管道对过滤的IP进行计数统计,提取密码失败次数大于等于3次的IP地址.
#awk调用外部Shell的变量时,双引号在外面表示字符串("''"),单引号在外边表示数字('""').
pass_fail_ip=$(awk '
$1=="'$curtime_month'" && \
$2=='"$curtime_day"' && \
$3>="'$one_minus_ago'" && \
$3<="'$curtime_time'" \
{ if($6=="Failed" && $9!="invalid") {print $(NF-3)}}' $LOGFILE | \
awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }')
#将密码失败次数大于3次的IP写入黑名单文件,
#每次写入前都需要判断黑名单中是否已经存在该IP.
#写入黑名单时附加时间标记,实现仅将IP放入黑名单特定的时间,
#如:密码失败3次后,禁止该IP在20分钟内再次访问服务器.
for i in $pass_fail_ip
do
if ! grep -q "$i" $BLOCKFILE ;then
echo "$curtime_seconds $i" >> $BLOCKFILE
fi
done
#提取无效账户登陆服务器3次的IP地址,并将其加入黑名单.
user_invalid_ip=$(awk '
$1=="'$curtime_month'" && \
$2=='"$curtime_day"' && \
$3>="'$one_minus_ago'" && \
$3<="'$curtime_time'" \
{ if($6=="Invalid") {print $(NF-2)}}' $LOGFILE | \
awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }')
for j in $user_invalid_ip
do
if ! grep -q "$j" $BLOCKFILE ;then
echo "$curtime_seconds $j" >> $BLOCKFILE
fi
done
sleep 60
done
}
five_minutes(){
while :
do
#获取计算机当前时间,以及5分钟前的时间,时间格式:
#%b(月份简写,Jan) %e(日期,1) %T(时间 18:00:00)
#使用local定义局部变量的好处是多个函数使用相同的变量名也不会冲突.
local curtime_month=$(LANG=C date +"%b")
local curtime_day=$(LANG=C date +"%e")
local curtime_time=$(LANG=C date +"%T")
local one_minus_ago=$(LANG=C date -d "5 minutes ago" +"%T")
#将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算.
local curtime_seconds=$(LANG=C date +"%s")
#分析5分钟内所有的日志,提取3次密码错误的IP地址并加入黑名单.
pass_fail_ip=$(awk '
$1=="'$curtime_month'" && \
$2=='"$curtime_day"' && \
$3>="'$one_minus_ago'" && \
$3<="'$curtime_time'" \
{ if($6=="Failed" && $9!="invalid") {print $(NF-3)}}' $LOGFILE | \
awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }')
for i in $pass_fail_ip
do
if ! grep -q "$i" $BLOCKFILE ;then
echo "$curtime_seconds $i" >> $BLOCKFILE
fi
done
#提取错误用户名登陆服务器3次的IP地址,并将其加入黑名单.
user_invalid_ip=$(awk '
$1=="'$curtime_month'" && \
$2=='"$curtime_day"' && \
$3>="'$one_minus_ago'" && \
$3<="'$curtime_time'" \
{ if($6=="Invalid") {print $(NF-2)}}' $LOGFILE | \
awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }')
for j in $user_invalid_ip
do
if ! grep -q "$j" $BLOCKFILE ;then
echo "$curtime_seconds $j" >> $BLOCKFILE
fi
done
sleep 300
done
}
fifteen_minutes(){
while :
do
#获取计算机当前时间,以及15分钟前的时间,时间格式:
#%b(月份简写,Jan) %e(日期,1) %T(时间 18:00:00)
#使用local定义局部变量的好处是多个函数使用相同的变量名也不会冲突.
local curtime_month=$(LANG=C date +"%b")
local curtime_day=$(LANG=C date +"%e")
local curtime_time=$(LANG=C date +"%T")
local one_minus_ago=$(LANG=C date -d "15 minutes ago" +"%T")
#将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算.
local curtime_seconds=$(LANG=C date +"%s")
#分析15分钟内所有的日志,提取3次密码错误的IP地址并加入黑名单.
pass_fail_ip=$(awk '
$1=="'$curtime_month'" && \
$2=='"$curtime_day"' && \
$3>="'$one_minus_ago'" && \
$3<="'$curtime_time'" \
{ if($6=="Failed" && $9!="invalid") {print $(NF-3)}}' $LOGFILE | \
awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }')
for i in $pass_fail_ip
do
if ! grep -q "$i" $BLOCKFILE ;then
echo "$curtime_seconds $i" >> $BLOCKFILE
fi
done
#提取错误用户名登陆服务器3次的IP地址,并将其加入黑名单.
user_invalid_ip=$(awk '
$1=="'$curtime_month'" && \
$2=='"$curtime_day"' && \
$3>="'$one_minus_ago'" && \
$3<="'$curtime_time'" \
{ if($6=="Invalid") {print $(NF-2)}}' $LOGFILE | \
awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }')
for j in $user_invalid_ip
do
if ! grep -q "$j" $BLOCKFILE ;then
echo "$curtime_seconds $j" >> $BLOCKFILE
fi
done
sleep 1200
done
}
#每隔20分钟检查一次黑名单,清理大于20分钟的黑名单IP.
clear_blockip(){
while :
do
sleep 1200
#将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算.
local curtime_seconds=$(LANG=C date +"%s")
#awk调用外部shell变量的另一种方式是使用-v选项.
#当前时间减去黑名单中的时间标记,大于等于1200秒(20分钟)则将其从黑名单中删除.
tmp=$(awk -v now=$curtime_seconds '(now-$1)>=1200 {print $2}' $BLOCKFILE)
for i in $tmp
do
sed -i "/$i/d" $BLOCKFILE
done
done
}
> $BLOCKFILE
one_minute &
one_pid="$!"
five_minutes &
five_pid="$!"
fifteen_minutes &
fifteen_pid="$!"
clear_blockip