用函数式思维写 shell 之 Nginx 脚本
shell 练习:用函数式思维写 shell,以服务器安全-封锁 ip/解封 ip 作为示例。
Nginx 脚本代码
bash
#!/bin/bash
# desc: 使用 nginx host deny 文件实现封禁 ip,不影响 ssh 登录,但需重启 nginx
# date: 2023-12-04 15:00
# author: echoxu
# 功能: 生成 nginx host deny 文件并封禁 ip
. lib/common
# 获取 nginx 程序路径
get_nginx_path(){
nginx_bin_path=`ps aux|grep nginx |grep "master process"|awk -F ' ' '{print $14}'`
echo $nginx_bin_path
}
# 检查 nginx 是否安装以及状态
# 使用这种方案需要 nginx 安装了 xx 模块,即必须要求 nginx 版本高于 1.18
valid_nginx_status(){
isnginx_runing=`ps aux|grep nginx|grep -v grep|wc -l`
if [ "$isnginx_runing" -lt 2 ];then
return 205
fi
nginx_version=''
nginx_bin_path=$(get_nginx_path)
nginx_version_info=`$nginx_bin_path -v 2>&1`
if [ ! -z "$nginx_version_info" ];then
nginx_version_of_number="${nginx_version_info#*/}"
nginx_version=$nginx_version_of_number
fi
get_second_number=`echo $nginx_version |awk -F '.' '{print $2}'`
if [ $get_second_number -lt 18 ];then
return 206
fi
}
# 验证数据是否存在
isipexist_in_nginx_deny_file(){
flag=200 # 200 表示记录已存在
file_path=$1
ip=$2
ip_is_exist=`cat $file_path |grep -Fx "$ip"|wc -l` # -Fx 完全匹配
if [ $ip_is_exist -eq 0 ];then
# 144 表示该记录没有被找到
flag=144
fi
return $flag
}
# 获取 nginx 配置文件路径
get_nginx_conf_path(){
valid_nginx_status
code=$?
if [ $code != 0 ];then
case "$code" in
205)
err_code 205 "Nginx 未运行,请先启动它..."
exit 1
;;
206)
err_code 206 "Nginx 版本过低,请升级至 nginx 1.18.0 以上版本..."
exit 1
;;
esac
fi
nginx=`$nginx_bin_path -t 2>&1 | grep configuration`
if [ ! -z "$nginx" ];then
nginxtmp="${nginx#*file}"
nginxf="${nginxtmp%test*}"
nginx_conf="${nginxf#*file}"
echo $nginx_conf
fi
}
get_nginx_host_deny_dir(){
nginx_conf=$(get_nginx_conf_path)
if [ ! -f $nginx_conf ];then
err_code 104 "Nginx 配置文件: $nginx_conf 不存在..."
exit 1
fi
nginx_conf_dir=`dirname $nginx_conf`
nginx_conf_site_conf_dir=$nginx_conf_dir/conf.d
if [ ! -d "$nginx_conf_site_conf_dir" ];then
sudo mkdir -p $nginx_conf_site_conf_dir
fi
echo $nginx_conf_site_conf_dir
}
# 获取 nginx host deny file 路径
get_nginx_host_deny_path(){
host_deny_dir=$(get_nginx_host_deny_dir)
host_deny_file_path=''
if [ -f $host_deny_dir/block_ip.conf ];then
host_deny_file_path=$host_deny_dir/block_ip.conf
else
set_nginx_host_deny_path $host_deny_dir/block_ip.conf
host_deny_file_path=$host_deny_dir/block_ip.conf
fi
echo $host_deny_file_path
}
# 设置 nginx host deny file 文件路径
set_nginx_host_deny_path(){
deny_file_input=$1
nginx_conf=$(get_nginx_conf_path)
nginx_conf_site_conf_dir=$(get_nginx_host_deny_dir)
sudo touch $deny_file_input
sudo chmod 666 $deny_file_input
is_add_site_conf=`cat $nginx_conf|grep "include ${nginx_conf_site_conf_dir}" |wc -l`
if [ $is_add_site_conf -eq 0 ];then
# 往 nginx.conf 的倒数第二行插入数据
sed -i '$i include '"${nginx_conf_site_conf_dir}"'/*.conf;' $nginx_conf;
fi
}
# 往 nginx host deny file 中添加数据
nginx_record_add(){
to_add=$1
format_ip=`echo deny $to_add\;`
nginx_host_deny_file=$(get_nginx_host_deny_path)
# 必须这样写,不然会导致 add_ip_to_blacklist_with_logs 中写入日志的 ip 格式错误
isin_res=$(isipexist_in_nginx_deny_file $nginx_host_deny_file "$format_ip")
code=$?
if [ $code -eq 200 ];then
err_code $code "IP: $to_add 在 Nginx host deny 中已存在,请勿重复添加..."
return 200
fi
echo "deny $to_add;" >> $nginx_host_deny_file
echo -e "${Succeed}: IP: $to_add 已添加进 Nginx host deny 中."
md5sum $nginx_host_deny_file |awk '{print $1}' > /tmp/.nginx_deny_md5
rm -rf /tmp/nginx_deny_file_back
cp $nginx_host_deny_file /tmp/nginx_deny_file_back
}
# 从 host deny 中删除记录
nginx_record_remove(){
to_remove=$1
format_ip=`echo deny $to_remove\;`
nginx_host_deny_file=$(get_nginx_host_deny_path)
isin_res=$(isipexist_in_nginx_deny_file $nginx_host_deny_file "$format_ip")
code=$?
if [ $code -eq 144 ];then
err_code $code "IP: $to_remove 在 Nginx host deny 中没有找到..."
return 144
fi
sudo sed -i '/^'"${format_ip}"'$/d' $nginx_host_deny_file
echo -e "${Succeed}: IP: $to_remove 已从 Nginx host deny 中删除."
sudo md5sum $nginx_host_deny_file |awk '{print $1}' > /tmp/.nginx_deny_md5
rm -rf /tmp/nginx_deny_file_back
cp $nginx_host_deny_file /tmp/nginx_deny_file_back
}
# 打印 nginx host deny file 数据
list(){
nginx_host_deny_file=$(get_nginx_host_deny_path)
for ip in `cat $nginx_host_deny_file`
do
echo $ip
done
}
# 当手动修改了 nginx host deny file 时要重启 nginx
check_nginx_deny_file(){
nginx_host_deny_file=$(get_nginx_host_deny_path)
current_md5=`md5sum $nginx_host_deny_file |awk '{print $1}'`
last_record_md5=`cat /tmp/.nginx_deny_md5`
if [ "$current_md5" = "$last_record_md5" ];then
echo -e "${Info}: Nginx Host Deny File 数据未发生更改。"
else
nginx_data_proofreading
md5sum $nginx_host_deny_file |awk '{print $1}' > /tmp/.nginx_deny_md5
echo -e "${Succeed}: 完成数据校对。"
fi
}
nginx_data_proofreading(){
nginx_host_deny_file=$(get_nginx_host_deny_path)
log_path=$(get_section_value_from_config_path server_secure_log_path)
code=$?
print_return_code_message_of_get_section_path $code
if [ ! -f $log_path ];then
err_code 104 "操作日志记录文件: $log_path 不存在..."
exit 1
fi
if [ ! -f "/tmp/nginx_deny_file_back" ];then
cp $nginx_host_deny_file /tmp/nginx_deny_file_back
fi
current_nginx_deny_count=`cat $nginx_host_deny_file|wc -l`
last_nginx_deny_count=`cat /tmp/nginx_deny_file_back|wc -l`
cat $nginx_host_deny_file /tmp/nginx_deny_file_back |sort|uniq -d > /tmp/nginx_last_common.txt
# 手动增加数据
if [ "$current_nginx_deny_count" -gt "$last_nginx_deny_count" ];then
add_count=`expr $current_nginx_deny_count - $last_nginx_deny_count`
echo -e "${Info}: nginx host deny file 中新增了 $add_count 条数据,等待重启 Nginx..." && echo
cat $nginx_host_deny_file /tmp/nginx_last_common.txt |sort|uniq -u > /tmp/nginx_add.txt # 获取 nginx 新增的内容
while read line || [ -n "$line" ]
do
ip=`echo $line |awk -F ' ' '{print $2}'|awk -F ';' '{print $1}'`
echo "$(date +'%F-%T') 已封禁入侵ip(nvalid+): $ip" >> $log_path
done < "/tmp/nginx_add.txt"
reload_nginx
rm -rf /tmp/nginx_last_common.txt /tmp/nginx_add.txt
rm -rf /tmp/nginx_deny_file_back
cp $nginx_host_deny_file /tmp/nginx_deny_file_back
sleep 1
return 0
fi
# 手动删减数据
if [ "$current_nginx_deny_count" -lt "$last_nginx_deny_count" ];then
remove_count=`expr $last_nginx_deny_count - $current_nginx_deny_count`
echo -e "${Info}: nginx host deny file 中减少了 $remove_count 条数据,等待重启 Nginx..." && echo
cat /tmp/nginx_deny_file_back /tmp/nginx_last_common.txt |sort|uniq -u > /tmp/nginx_remove.txt # nginx 删减的数据
while read line || [ -n "$line" ]
do
ip=`echo $line |awk -F ' ' '{print $2}'|awk -F ';' '{print $1}'`
echo "$(date +'%F-%T') 已解封ip(nvalid-): $ip" >> $log_path
done < "/tmp/nginx_remove.txt"
reload_nginx
rm -rf /tmp/nginx_last_common.txt /tmp/nginx_remove.txt
rm -rf /tmp/nginx_deny_file_back
cp $nginx_host_deny_file /tmp/nginx_deny_file_back
sleep 1
return 0
fi
}
# 重启 Nginx
reload_nginx(){
ngx_bin=$(get_nginx_path)
sudo $ngx_bin -s reload
echo -e "${Succeed}: 重启了 Nginx"
}
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296