用函数式思维写 shell 之 black_list 脚本
shell 练习:用函数式思维写 shell,以服务器安全-封锁 ip/解封 ip 作为示例。
black_list 脚本代码
bash
#!/bin/bash
# desc: ip 黑名单的路由函数,其核心在 lib/blacklist 中
# author: echoxu
. lib/blacklist
. lib/common
. lib/firewall
. lib/nginx
args_arry=()
analysis_args(){
args=$@
for arg in $args
do
args_arr[${#args_arr[*]}]=${arg}
done
}
# 重启 nginx/firewalld 的 handler 函数
relaod_handler(){
block_ip_type=$(get_section_value_from_config_path block_ip_type)
code=$?
print_return_code_message_of_get_section_path $code
case "$block_ip_type" in
firewalld)
block_ip_type=firewalld_reload
;;
nginx)
block_ip_type=reload_nginx
;;
esac
echo $block_ip_type
}
# 统计返回值,当返回值为 0 的个数大于 1 时才能重启防火墙
# 也可以通过判断 blacklist 或者 blockip.conf 文件是否被修改来决定是否重启
reload_of_block_ip_type(){
succeed_code_count=0
for i in `cat /tmp/add_ip_to_blacklist_return_code`
do
if [ $i -eq 0 ];then
let succeed_code_count++
fi
done
if [ $succeed_code_count -gt 0 ];then
reload_res=$(relaod_handler)
$reload_res
fi
}
# 添加黑名单数据的路由函数
add_ip_to_blacklist_router(){
args_number=$#
second_flag=$2
input_filepath=$3
# 清空返回值
cat /dev/null > /tmp/add_ip_to_blacklist_return_code
case "$second_flag" in
-i)
analysis_args $@
if [ $args_number -lt 3 ];then
echo -e "${Error}: 总参数个数不能小于 3"
exit 1
fi
# 设置切片长度,排除了前两个元素
not_flags_len=`expr ${#args_arr[*]} - 2`
# 数组切片:打印第三个元素到末尾的所有元素
for ip in "${args_arr[@]:2:$not_flags_len}"
do
add_ip_to_blacklist_with_input $ip
return_code=$?
# 记录返回值用于判断是否重启防护墙
echo $return_code >> /tmp/add_ip_to_blacklist_return_code
if [ $return_code != 0 ];then
continue
fi
done
;;
-f)
if [[ $args_number -gt 3 || $args_number -lt 3 ]];then
echo -e "${Error}: 总参数个数不能小于 2 且不能大于 3"
exit 1
fi
add_ip_to_blacklist_with_file $input_filepath
;;
"")
add_ip_to_blacklist_with_logs
;;
*)
echo -e "${Error}: 传参错误,只能传递 -i、-f 或者为空"
esac
reload_of_block_ip_type
}
# 删除黑名单数据的路由函数(解封 ip)
delete_ip_from_blacklist_router(){
args_number=$#
second_flag=$2
input_filepath=$3
# 清空返回值
cat /dev/null > /tmp/add_ip_to_blacklist_return_code
# 如果第二个参数为 -f 将执行批量删除黑名单的操作
if [ "$second_flag" = "-f" ];then
if [[ $args_number -gt 3 || $args_number -lt 3 ]];then
echo -e "${Error}: 总参数个数不能小于 2 且不能大于 3"
exit 1
fi
batch_delete_ip_from_blacklist $input_filepath
reload_of_block_ip_type
return 0 # 终断下面的程序继续执行
fi
# 当第二个参数不是 -f 时将接收到的数据传到 黑名单删除函数 中
analysis_args $@
if [ $args_number -lt 2 ];then
echo -e "${Error}: 总参数个数不能小于 2"
exit 1
fi
not_flags_len=`expr ${#args_arr[*]} - 1`
for ip in "${args_arr[@]:1:$not_flags_len}"
do
delete_ip_from_blacklist_with_input $ip
return_code=$?
echo $return_code >> /tmp/add_ip_to_blacklist_return_code
if [ $return_code != 0 ];then
continue
fi
done
reload_of_block_ip_type
}
# 路由函数
blacklist_router(){
flag=$1
# 下面的四个路径变量是为了避免代码很冗余才写到这里,不然每次内层函数调用都要获取文件路径
# 获取 封禁/解禁 ip 的方式
block_ip_type=$(get_section_value_from_config_path block_ip_type)
code=$?
print_return_code_message_of_get_section_path $code
block_ip_type_result=$(get_block_ip_type_of_block_ip_handler $block_ip_type)
unban_the_ip_type_result=$(get_block_ip_type_of_unban_ip_handler)
# 获取日志文件存储路径
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
# 获取黑名单路径
blacklist_path=$(get_section_value_from_config_path blacklist_path)
code=$?
print_return_code_message_of_get_section_path $code
if [ ! -f $blacklist_path ];then
err_code 104 "黑名单文件: $blacklist_path 不存在..."
exit 1
fi
# 获取白名单路径
whitelist_path=$(get_section_value_from_config_path whitelist_path)
code=$?
print_return_code_message_of_get_section_path $code
if [ ! -f $whitelist_path ];then
err_code 104 "白名单文件: $whitelist_path 不存在..."
exit 1
fi
# 参数判断
case "$flag" in
add)
add_ip_to_blacklist_router $@
;;
remove)
delete_ip_from_blacklist_router $@
;;
list)
print_blacklist
;;
merge|test|check)
check_block_type_file_status
;;
*)
echo -e "${Error}: Usage: $0 {add -i|-f|为空}|{remove -i|-f|为空}|list"
echo -e "${Info}: $0 add: 会自动查找 nginx secure 日志并封禁 ip"
echo -e "${Info}: $0 add -i: 获取命令行中输入的 ip 并封禁,支持输入多个 ip"
echo -e "${Info}: $0 add -f: 读取指定文件里的 ip 然后封禁"
echo -e "${Info}: $0 remove: 解禁从命令行中输入的 ip, 支持输入多个 ip"
echo -e "${Info}: $0 remove -f: 解禁从指定文件中读取到的 ip"
echo -e "${Info}: $0 list: 打印黑名单列表"
echo -e "${Info}: $0 test: 数据校对"
exit 1
;;
esac
}
blacklist_router $@
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
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