banip: update 0.3.1
[feed/packages.git] / net / banip / files / banip.sh
1 #!/bin/sh
2 # banIP - ban incoming and outgoing ip adresses/subnets via ipset
3 # written by Dirk Brenken (dev@brenken.org)
4
5 # This is free software, licensed under the GNU General Public License v3.
6 # You should have received a copy of the GNU General Public License
7 # along with this program. If not, see <http://www.gnu.org/licenses/>.
8
9 # (s)hellcheck exceptions
10 # shellcheck disable=1091 disable=2039 disable=2143 disable=2181 disable=2188
11
12 # set initial defaults
13 #
14 LC_ALL=C
15 PATH="/usr/sbin:/usr/bin:/sbin:/bin"
16 ban_ver="0.3.1"
17 ban_basever=""
18 ban_enabled=0
19 ban_automatic="1"
20 ban_sources=""
21 ban_iface=""
22 ban_debug=0
23 ban_backupdir="/mnt"
24 ban_maxqueue=4
25 ban_autoblacklist=1
26 ban_autowhitelist=1
27 ban_realtime="false"
28 ban_fetchutil=""
29 ban_ip="$(command -v ip)"
30 ban_ipt="$(command -v iptables)"
31 ban_ipt_save="$(command -v iptables-save)"
32 ban_ipt_restore="$(command -v iptables-restore)"
33 ban_ipt6="$(command -v ip6tables)"
34 ban_ipt6_save="$(command -v ip6tables-save)"
35 ban_ipt6_restore="$(command -v ip6tables-restore)"
36 ban_ipset="$(command -v ipset)"
37 ban_chain="banIP"
38 ban_action="${1:-"start"}"
39 ban_pidfile="/var/run/banip.pid"
40 ban_rtfile="/tmp/ban_runtime.json"
41 ban_logservice="/etc/banip/banip.service"
42 ban_sshdaemon="dropbear"
43 ban_setcnt=0
44 ban_cnt=0
45
46 # load environment
47 #
48 f_envload()
49 {
50 # get system information
51 #
52 ban_sysver="$(ubus -S call system board 2>/dev/null | jsonfilter -e '@.model' -e '@.release.description' | \
53 awk 'BEGIN{ORS=", "}{print $0}' | awk '{print substr($0,1,length($0)-2)}')"
54
55 # parse 'global' and 'extra' section by callback
56 #
57 config_cb()
58 {
59 local type="${1}"
60 if [ "${type}" = "banip" ]
61 then
62 option_cb()
63 {
64 local option="${1}"
65 local value="${2}"
66 eval "${option}=\"${value}\""
67 }
68 else
69 reset_cb
70 fi
71 }
72
73 # parse 'source' typed sections
74 #
75 parse_config()
76 {
77 local value opt section="${1}" options="ban_src ban_src_6 ban_src_rset ban_src_rset_6 ban_src_settype ban_src_ruletype ban_src_on ban_src_on_6 ban_src_cat"
78 for opt in ${options}
79 do
80 config_get value "${section}" "${opt}"
81 if [ -n "${value}" ]
82 then
83 eval "${opt}_${section}=\"${value}\""
84 if [ "${opt}" = "ban_src" ]
85 then
86 eval "ban_sources=\"${ban_sources} ${section}\""
87 elif [ "${opt}" = "ban_src_6" ]
88 then
89 eval "ban_sources=\"${ban_sources} ${section}_6\""
90 fi
91 fi
92 done
93 }
94
95 # load config
96 #
97 config_load banip
98 config_foreach parse_config source
99
100 # version check
101 #
102 if [ -z "${ban_basever}" ] || [ "${ban_ver%.*}" != "${ban_basever}" ]
103 then
104 f_log "info" "your banIP config seems to be too old, please update your config with the '--force-maintainer' opkg option"
105 exit 0
106 fi
107
108 # create temp directory & files
109 #
110 f_temp
111
112 # check status
113 #
114 if [ "${ban_enabled}" -eq 0 ]
115 then
116 f_bgserv "stop"
117 f_jsnup disabled
118 f_ipset destroy
119 f_rmbackup
120 f_rmtemp
121 f_log "info" "banIP is currently disabled, please set ban_enabled to '1' to use this service"
122 exit 0
123 fi
124 }
125
126 # check environment
127 #
128 f_envcheck()
129 {
130 local util utils packages iface tmp cnt=0 cnt_max=0
131
132 # check backup directory
133 #
134 if [ ! -d "${ban_backupdir}" ]
135 then
136 f_log "err" "the backup directory '${ban_backupdir}' does not exist/is not mounted yet, please create the directory or raise the 'ban_triggerdelay' to defer the banIP start"
137 fi
138
139 # check fetch utility
140 #
141 if [ -z "${ban_fetchutil}" ]
142 then
143 utils="aria2c curl wget uclient-fetch"
144 packages="$(opkg list-installed 2>/dev/null)"
145 for util in ${utils}
146 do
147 if { [ "${util}" = "uclient-fetch" ] && [ -n "$(printf "%s\\n" "${packages}" | grep "^libustream-")" ]; } || \
148 { [ "${util}" = "wget" ] && [ -n "$(printf "%s\\n" "${packages}" | grep "^wget -")" ]; } || \
149 { [ "${util}" != "uclient-fetch" ] && [ "${util}" != "wget" ]; }
150 then
151 ban_fetchutil="$(command -v "${util}")"
152 if [ -x "${ban_fetchutil}" ]
153 then
154 break
155 fi
156 fi
157 unset ban_fetchutil util
158 done
159 else
160 util="${ban_fetchutil}"
161 ban_fetchutil="$(command -v "${util}")"
162 if [ ! -x "${ban_fetchutil}" ]
163 then
164 unset ban_fetchutil util
165 fi
166 fi
167 case "${util}" in
168 "aria2c")
169 ban_fetchparm="${ban_fetchparm:-"--timeout=20 --allow-overwrite=true --auto-file-renaming=false --check-certificate=true --dir=" " -o"}"
170 ;;
171 "curl")
172 ban_fetchparm="${ban_fetchparm:-"--connect-timeout 20 -o"}"
173 ;;
174 "uclient-fetch")
175 ban_fetchparm="${ban_fetchparm:-"--timeout=20 -O"}"
176 ;;
177 "wget")
178 ban_fetchparm="${ban_fetchparm:-"--no-cache --no-cookies --max-redirect=0 --timeout=20 -O"}"
179 ;;
180 esac
181 if [ -z "${ban_fetchutil}" ] || [ -z "${ban_fetchparm}" ]
182 then
183 f_log "err" "download utility with SSL support not found, please install 'uclient-fetch' with a 'libustream-*' variant or another download utility like 'wget', 'curl' or 'aria2'"
184 fi
185
186 # get wan device and wan subnets
187 #
188 if [ "${ban_automatic}" = "1" ]
189 then
190 while [ "${cnt}" -le 30 ]
191 do
192 network_find_wan iface
193 if [ -n "${iface}" ] && [ -z "$(printf "%s\\n" "${ban_iface}" | grep -F "${iface}")" ]
194 then
195 ban_iface="${ban_iface} ${iface}"
196 if [ "${cnt_max}" -eq 0 ]
197 then
198 cnt_max=$((cnt+5))
199 fi
200 fi
201 network_find_wan6 iface
202 if [ -n "${iface}" ] && [ -z "$(printf "%s\\n" "${ban_iface}" | grep -F "${iface}")" ]
203 then
204 ban_iface="${ban_iface} ${iface}"
205 if [ "${cnt_max}" -eq 0 ]
206 then
207 cnt_max=$((cnt+5))
208 fi
209 fi
210 if [ -z "${ban_iface}" ] || [ "${cnt}" -le "${cnt_max}" ]
211 then
212 network_flush_cache
213 cnt=$((cnt+1))
214 sleep 1
215 else
216 break
217 fi
218 done
219 fi
220
221 for iface in ${ban_iface}
222 do
223 network_get_device tmp "${iface}"
224 if [ -n "${tmp}" ] && [ -z "$(printf "%s\\n" "${ban_dev}" | grep -F "${tmp}")" ]
225 then
226 ban_dev="${ban_dev} ${tmp}"
227 else
228 network_get_physdev tmp "${iface}"
229 if [ -n "${tmp}" ] && [ -z "$(printf "%s\\n" "${ban_dev}" | grep -F "${tmp}")" ]
230 then
231 ban_dev="${ban_dev} ${tmp}"
232 fi
233 fi
234 network_get_subnets tmp "${iface}"
235 if [ -n "${tmp}" ] && [ -z "$(printf "%s\\n" "${ban_subnets}" | grep -F "${tmp}")" ]
236 then
237 ban_subnets="${ban_subnets} ${tmp}"
238 fi
239 network_get_subnets6 tmp "${iface}"
240 if [ -n "${tmp}" ] && [ -z "$(printf "%s\\n" "${ban_subnets6}" | grep -F "${tmp}")" ]
241 then
242 ban_subnets6="${ban_subnets6} ${tmp}"
243 fi
244 done
245
246 if [ -z "${ban_iface}" ] || [ -z "${ban_dev}" ]
247 then
248 f_log "err" "wan interface(s)/device(s) (${ban_iface:-"-"}/${ban_dev:-"-"}) not found, please please check your configuration"
249 else
250 ban_dev_all="$(${ban_ip} link show | awk 'BEGIN{FS="[@: ]"}/^[0-9:]/{if($3!="lo"){print $3}}')"
251 f_jsnup "running"
252 f_log "info" "start banIP processing (${ban_action})"
253 fi
254 }
255
256 # create temporary files and directories
257 #
258 f_temp()
259 {
260 if [ -d "/tmp" ] && [ -z "${ban_tmpdir}" ]
261 then
262 ban_tmpdir="$(mktemp -p /tmp -d)"
263 ban_tmpload="$(mktemp -p "${ban_tmpdir}" -tu)"
264 ban_tmpfile="$(mktemp -p "${ban_tmpdir}" -tu)"
265 elif [ ! -d "/tmp" ]
266 then
267 f_log "err" "the temp directory '/tmp' does not exist/is not mounted yet, please create the directory or raise the 'ban_triggerdelay' to defer the banIP start"
268 fi
269
270 if [ ! -s "${ban_pidfile}" ]
271 then
272 printf "%s" "${$}" > "${ban_pidfile}"
273 fi
274 }
275
276 # remove temporary files and directories
277 #
278 f_rmtemp()
279 {
280 if [ -d "${ban_tmpdir}" ]
281 then
282 rm -rf "${ban_tmpdir}"
283 fi
284 > "${ban_pidfile}"
285 }
286
287 # remove backup files
288 #
289 f_rmbackup()
290 {
291 if [ -d "${ban_backupdir}" ]
292 then
293 rm -f "${ban_backupdir}"/banIP.*.gz
294 fi
295 }
296
297 # iptables rules engine
298 #
299 f_iptrule()
300 {
301 local rc timeout="-w 5" action="${1}" rule="${2}"
302
303 if [ "${src_name##*_}" = "6" ]
304 then
305 if [ -x "${ban_ipt6}" ]
306 then
307 rc="$("${ban_ipt6}" "${timeout}" -C ${rule} 2>/dev/null; printf "%u" ${?})"
308
309 if { [ "${rc}" -ne 0 ] && { [ "${action}" = "-A" ] || [ "${action}" = "-I" ]; } } || \
310 { [ "${rc}" -eq 0 ] && [ "${action}" = "-D" ]; }
311 then
312 "${ban_ipt6}" "${timeout}" "${action}" ${rule}
313 fi
314 fi
315 else
316 if [ -x "${ban_ipt}" ]
317 then
318 rc="$("${ban_ipt}" "${timeout}" -C ${rule} 2>/dev/null; printf "%u" ${?})"
319
320 if { [ "${rc}" -ne 0 ] && { [ "${action}" = "-A" ] || [ "${action}" = "-I" ]; } } || \
321 { [ "${rc}" -eq 0 ] && [ "${action}" = "-D" ]; }
322 then
323 "${ban_ipt}" "${timeout}" "${action}" ${rule}
324 fi
325 fi
326 fi
327 }
328
329 # remove/add iptables rules
330 #
331 f_iptadd()
332 {
333 local rm="${1}" dev
334
335 for dev in ${ban_dev_all}
336 do
337 f_iptrule "-D" "${ban_chain} -i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j ${target_src}"
338 f_iptrule "-D" "${ban_chain} -o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${target_dst}"
339 done
340
341 if [ -z "${rm}" ] && [ "${cnt}" -gt 0 ]
342 then
343 if [ "${src_ruletype}" != "dst" ]
344 then
345 if [ "${src_name##*_}" = "6" ]
346 then
347 # dummy, special IPv6 rules
348 /bin/true
349 else
350 f_iptrule "-I" "${wan_input} -p udp --dport 67:68 --sport 67:68 -j RETURN"
351 fi
352 f_iptrule "-A" "${wan_input} -j ${ban_chain}"
353 f_iptrule "-A" "${wan_forward} -j ${ban_chain}"
354 for dev in ${ban_dev}
355 do
356 f_iptrule "${action:-"-A"}" "${ban_chain} -i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j ${target_src}"
357 done
358 fi
359 if [ "${src_ruletype}" != "src" ]
360 then
361 if [ "${src_name##*_}" = "6" ]
362 then
363 # dummy, special IPv6 rules
364 /bin/true
365 else
366 f_iptrule "-I" "${lan_input} -p udp --dport 67:68 --sport 67:68 -j RETURN"
367 fi
368 f_iptrule "-A" "${lan_input} -j ${ban_chain}"
369 f_iptrule "-A" "${lan_forward} -j ${ban_chain}"
370 for dev in ${ban_dev}
371 do
372 f_iptrule "${action:-"-A"}" "${ban_chain} -o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${target_dst}"
373 done
374 fi
375 else
376 if [ -x "${ban_ipset}" ] && [ -n "$("${ban_ipset}" -q -n list "${src_name}")" ]
377 then
378 "${ban_ipset}" -q destroy "${src_name}"
379 fi
380 fi
381 }
382
383 # ipset/iptables actions
384 #
385 f_ipset()
386 {
387 local out_rc source action ruleset ruleset_6 rule cnt=0 cnt_ip=0 cnt_cidr=0 timeout="-w 5" mode="${1}" in_rc="${src_rc:-0}"
388
389 if [ "${src_name%_6*}" = "whitelist" ]
390 then
391 target_src="RETURN"
392 target_dst="RETURN"
393 action="-I"
394 fi
395
396 case "${mode}" in
397 "backup")
398 gzip -cf "${tmp_load}" 2>/dev/null > "${ban_backupdir}/banIP.${src_name}.gz"
399 out_rc="${?:-"${in_rc}"}"
400 f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
401 return "${out_rc}"
402 ;;
403 "restore")
404 if [ -f "${ban_backupdir}/banIP.${src_name}.gz" ]
405 then
406 zcat "${ban_backupdir}/banIP.${src_name}.gz" 2>/dev/null > "${tmp_load}"
407 out_rc="${?}"
408 fi
409 out_rc="${out_rc:-"${in_rc}"}"
410 f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
411 return "${out_rc}"
412 ;;
413 "remove")
414 if [ -f "${ban_backupdir}/banIP.${src_name}.gz" ]
415 then
416 rm -f "${ban_backupdir}/banIP.${src_name}.gz"
417 out_rc="${?}"
418 fi
419 out_rc="${out_rc:-"${in_rc}"}"
420 f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
421 return "${out_rc}"
422 ;;
423 "initial")
424 if [ -x "${ban_ipt}" ] && [ -z "$("${ban_ipt}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
425 then
426 "${ban_ipt}" "${timeout}" -N "${ban_chain}"
427 elif [ -x "${ban_ipt}" ]
428 then
429 src_name="ruleset"
430 ruleset="${ban_wan_input_chain:-"input_wan_rule"} ${ban_wan_forward_chain:-"forwarding_wan_rule"} ${ban_lan_input_chain:-"input_lan_rule"} ${ban_lan_forward_chain:-"forwarding_lan_rule"}"
431 for rule in ${ruleset}
432 do
433 f_iptrule "-D" "${rule} -j ${ban_chain}"
434 done
435 fi
436 if [ -x "${ban_ipt6}" ] && [ -z "$("${ban_ipt6}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
437 then
438 "${ban_ipt6}" "${timeout}" -N "${ban_chain}"
439 elif [ -x "${ban_ipt6}" ]
440 then
441 src_name="ruleset_6"
442 ruleset_6="${ban_wan_input_chain_6:-"input_wan_rule"} ${ban_wan_forward_chain_6:-"forwarding_wan_rule"} ${ban_lan_input_chain_6:-"input_lan_rule"} ${ban_lan_forward_chain_6:-"forwarding_lan_rule"}"
443 for rule in ${ruleset_6}
444 do
445 f_iptrule "-D" "${rule} -j ${ban_chain}"
446 done
447 fi
448 f_log "debug" "f_ipset ::: name: -, mode: ${mode:-"-"}, chain: ${ban_chain:-"-"}, ruleset: ${ruleset:-"-"}, ruleset_6: ${ruleset_6:-"-"}"
449 ;;
450 "create")
451 if [ -x "${ban_ipset}" ]
452 then
453 if [ -s "${tmp_file}" ] && [ -z "$("${ban_ipset}" -q -n list "${src_name}")" ]
454 then
455 "${ban_ipset}" -q create "${src_name}" hash:"${src_settype}" hashsize 64 maxelem 262144 family "${src_setipv}" counters
456 else
457 "${ban_ipset}" -q flush "${src_name}"
458 fi
459 if [ -s "${tmp_file}" ]
460 then
461 "${ban_ipset}" -! restore < "${tmp_file}"
462 out_rc="${?}"
463 "${ban_ipset}" -q save "${src_name}" > "${tmp_file}"
464 cnt="$(($(wc -l 2>/dev/null < "${tmp_file}")-1))"
465 cnt_cidr="$(grep -cF "/" "${tmp_file}")"
466 cnt_ip="$((cnt-cnt_cidr))"
467 printf "%s\\n" "1" > "${tmp_set}"
468 printf "%s\\n" "${cnt}" > "${tmp_cnt}"
469 fi
470 f_iptadd
471 fi
472 end_ts="$(date +%s)"
473 out_rc="${out_rc:-"${in_rc}"}"
474 f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, settype: ${src_settype:-"-"}, setipv: ${src_setipv:-"-"}, ruletype: ${src_ruletype:-"-"}, count(sum/ip/cidr): ${cnt}/${cnt_ip}/${cnt_cidr}, time: $((end_ts-start_ts)), out_rc: ${out_rc}"
475 ;;
476 "refresh")
477 if [ -x "${ban_ipset}" ] && [ -n "$("${ban_ipset}" -q -n list "${src_name}")" ]
478 then
479 "${ban_ipset}" -q save "${src_name}" > "${tmp_file}"
480 out_rc="${?}"
481 if [ -s "${tmp_file}" ]
482 then
483 cnt="$(($(wc -l 2>/dev/null < "${tmp_file}")-1))"
484 cnt_cidr="$(grep -cF "/" "${tmp_file}")"
485 cnt_ip="$((cnt-cnt_cidr))"
486 printf "%s\\n" "1" > "${tmp_set}"
487 printf "%s\\n" "${cnt}" > "${tmp_cnt}"
488 fi
489 f_iptadd
490 fi
491 end_ts="$(date +%s)"
492 out_rc="${out_rc:-"${in_rc}"}"
493 f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, count: ${cnt}/${cnt_ip}/${cnt_cidr}, time: $((end_ts-start_ts)), out_rc: ${out_rc}"
494 return "${out_rc}"
495 ;;
496 "flush")
497 f_iptadd "remove"
498
499 if [ -x "${ban_ipset}" ] && [ -n "$("${ban_ipset}" -q -n list "${src_name}")" ]
500 then
501 "${ban_ipset}" -q flush "${src_name}"
502 "${ban_ipset}" -q destroy "${src_name}"
503 fi
504 f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}"
505 ;;
506 "destroy")
507 if [ -x "${ban_ipt}" ] && [ -x "${ban_ipt_save}" ] && [ -x "${ban_ipt_restore}" ] && \
508 [ -n "$("${ban_ipt}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
509 then
510 "${ban_ipt_save}" | grep -v -- "-j ${ban_chain}" | "${ban_ipt_restore}"
511 "${ban_ipt}" "${timeout}" -F "${ban_chain}"
512 "${ban_ipt}" "${timeout}" -X "${ban_chain}"
513 fi
514 if [ -x "${ban_ipt6}" ] && [ -x "${ban_ipt6_save}" ] && [ -x "${ban_ipt6_restore}" ] && \
515 [ -n "$("${ban_ipt6}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
516 then
517 "${ban_ipt6_save}" | grep -v -- "-j ${ban_chain}" | "${ban_ipt6_restore}"
518 "${ban_ipt6}" "${timeout}" -F "${ban_chain}"
519 "${ban_ipt6}" "${timeout}" -X "${ban_chain}"
520 fi
521 for source in ${ban_sources}
522 do
523 if [ -x "${ban_ipset}" ] && [ -n "$("${ban_ipset}" -q -n list "${source}")" ]
524 then
525 "${ban_ipset}" -q destroy "${source}"
526 fi
527 done
528 f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}"
529 ;;
530 esac
531 }
532
533 # write to syslog
534 #
535 f_log()
536 {
537 local class="${1}" log_msg="${2}"
538
539 if [ -n "${log_msg}" ] && { [ "${class}" != "debug" ] || [ "${ban_debug}" -eq 1 ]; }
540 then
541 logger -p "${class}" -t "banIP-${ban_ver}[${$}]" "${log_msg}"
542 if [ "${class}" = "err" ]
543 then
544 f_jsnup error
545 f_ipset destroy
546 f_rmbackup
547 f_rmtemp
548 logger -p "${class}" -t "banIP-${ban_ver}[${$}]" "Please also check 'https://github.com/openwrt/packages/blob/master/net/banip/files/README.md'"
549 exit 1
550 fi
551 fi
552 }
553
554 # start log service to trace failed ssh/luci logins
555 #
556 f_bgserv()
557 {
558 local bg_pid status="${1}"
559
560 bg_pid="$(pgrep -f "^/bin/sh ${ban_logservice}.*|^logread -f -e ${ban_sshdaemon}\|luci: failed login|^grep -qE Exit before auth|luci: failed login|[0-9]+ \[preauth\]$" | awk '{ORS=" "; print $1}')"
561 if [ -z "${bg_pid}" ] && [ "${status}" = "start" ] \
562 && [ -x "${ban_logservice}" ] && [ "${ban_realtime}" = "true" ]
563 then
564 ( "${ban_logservice}" "${ban_ver}" &)
565 elif [ -n "${bg_pid}" ] && [ "${status}" = "stop" ]
566 then
567 kill -HUP "${bg_pid}" 2>/dev/null
568 fi
569 f_log "debug" "f_bgserv ::: status: ${status:-"-"}, bg_pid: ${bg_pid:-"-"}, ban_realtime: ${ban_realtime:-"-"}, log_service: ${ban_logservice:-"-"}"
570 }
571
572 # main function for banIP processing
573 #
574 f_main()
575 {
576 local pid pid_list start_ts end_ts ip tmp_raw tmp_cnt tmp_load tmp_file mem_total mem_free cnt=1
577 local src_name src_on src_url src_rset src_setipv src_settype src_ruletype src_cat src_log src_addon src_ts src_rc
578 local wan_input wan_forward lan_input lan_forward target_src target_dst ssh_log luci_log
579
580 ssh_log="$(logread -e "${ban_sshdaemon}" | grep -o "${ban_sshdaemon}.*" | sed 's/:[0-9]*$//g')"
581 luci_log="$(logread -e "luci: failed login" | grep -o "luci:.*")"
582 mem_total="$(awk '/^MemTotal/ {print int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
583 mem_free="$(awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
584 f_log "debug" "f_main ::: fetch_util: ${ban_fetchutil:-"-"}, fetch_parm: ${ban_fetchparm:-"-"}, ssh_daemon: ${ban_sshdaemon}, interface(s): ${ban_iface:-"-"}, device(s): ${ban_dev:-"-"}, all_devices: ${ban_dev_all:-"-"}, backup_dir: ${ban_backupdir:-"-"}, mem_total: ${mem_total:-0}, mem_free: ${mem_free:-0}, max_queue: ${ban_maxqueue}"
585
586 # main loop
587 #
588 f_ipset initial
589 for src_name in ${ban_sources}
590 do
591 unset src_on
592 if [ "${src_name##*_}" = "6" ]
593 then
594 if [ -x "${ban_ipt6}" ]
595 then
596 src_on="$(eval printf "%s" \"\$\{ban_src_on_6_${src_name%_6*}\}\")"
597 src_url="$(eval printf "%s" \"\$\{ban_src_6_${src_name%_6*}\}\")"
598 src_rset="$(eval printf "%s" \"\$\{ban_src_rset_6_${src_name%_6*}\}\")"
599 src_setipv="inet6"
600 wan_input="${ban_wan_input_chain_6:-"input_wan_rule"}"
601 wan_forward="${ban_wan_forward_chain_6:-"forwarding_wan_rule"}"
602 lan_input="${ban_lan_input_chain_6:-"input_lan_rule"}"
603 lan_forward="${ban_lan_forward_chain_6:-"forwarding_lan_rule"}"
604 target_src="${ban_target_src_6:-"DROP"}"
605 target_dst="${ban_target_dst_6:-"REJECT"}"
606 fi
607 else
608 if [ -x "${ban_ipt}" ]
609 then
610 src_on="$(eval printf "%s" \"\$\{ban_src_on_${src_name}\}\")"
611 src_url="$(eval printf "%s" \"\$\{ban_src_${src_name}\}\")"
612 src_rset="$(eval printf "%s" \"\$\{ban_src_rset_${src_name}\}\")"
613 src_setipv="inet"
614 wan_input="${ban_wan_input_chain:-"input_wan_rule"}"
615 wan_forward="${ban_wan_forward_chain:-"forwarding_wan_rule"}"
616 lan_input="${ban_lan_input_chain:-"input_lan_rule"}"
617 lan_forward="${ban_lan_forward_chain:-"forwarding_lan_rule"}"
618 target_src="${ban_target_src:-"DROP"}"
619 target_dst="${ban_target_dst:-"REJECT"}"
620 fi
621 fi
622 src_settype="$(eval printf "%s" \"\$\{ban_src_settype_${src_name%_6*}\}\")"
623 src_ruletype="$(eval printf "%s" \"\$\{ban_src_ruletype_${src_name%_6*}\}\")"
624 src_cat="$(eval printf "%s" \"\$\{ban_src_cat_${src_name%_6*}\}\")"
625 src_addon=""
626 src_rc=4
627 tmp_load="${ban_tmpload}.${src_name}"
628 tmp_file="${ban_tmpfile}.${src_name}"
629 tmp_raw="${tmp_load}.raw"
630 tmp_cnt="${tmp_file}.cnt"
631 tmp_set="${tmp_file}.setcnt"
632
633 # basic pre-checks
634 #
635 f_log "debug" "f_main ::: name: ${src_name}, src_on: ${src_on:-"-"}"
636
637 if [ -z "${src_on}" ] || [ "${src_on}" != "1" ] || [ -z "${src_url}" ] || \
638 [ -z "${src_rset}" ] || [ -z "${src_settype}" ] || [ -z "${src_ruletype}" ]
639 then
640 f_ipset flush
641 f_ipset remove
642 continue
643 elif [ "${ban_action}" = "refresh" ] && [ ! -f "${src_url}" ]
644 then
645 start_ts="$(date +%s)"
646 f_ipset refresh
647 if [ "${?}" -eq 0 ]
648 then
649 continue
650 fi
651 fi
652
653 # download queue processing
654 #
655 (
656 start_ts="$(date +%s)"
657 if [ "${ban_action}" = "start" ] && [ ! -f "${src_url}" ]
658 then
659 f_ipset restore
660 fi
661 src_rc="${?}"
662 if [ "${src_rc}" -ne 0 ] || [ ! -s "${tmp_load}" ]
663 then
664 if [ -f "${src_url}" ]
665 then
666 src_log="$(cat "${src_url}" 2>/dev/null > "${tmp_load}")"
667 src_rc="${?}"
668 case "${src_name}" in
669 "whitelist")
670 src_addon="${ban_subnets}"
671 ;;
672 "whitelist_6")
673 src_addon="${ban_subnets6}"
674 ;;
675 "blacklist")
676 if [ "${ban_sshdaemon}" = "dropbear" ]
677 then
678 pid_list="$(printf "%s\\n" "${ssh_log}" | grep -F "Exit before auth" | awk 'match($0,/(\[[0-9]+\])/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
679 for pid in ${pid_list}
680 do
681 src_addon="${src_addon} $(printf "%s\\n" "${ssh_log}" | grep -F "${pid}" | awk 'match($0,/([0-9]{1,3}\.){3}[0-9]{1,3}$/){ORS=" ";print substr($0,RSTART,RLENGTH);exit}')"
682 done
683 elif [ "${ban_sshdaemon}" = "sshd" ]
684 then
685 src_addon="$(printf "%s\\n" "${ssh_log}" | grep -E "[0-9]+ \[preauth\]$" | awk 'match($0,/([0-9]{1,3}\.){3}[0-9]{1,3}$/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
686 fi
687 src_addon="${src_addon} $(printf "%s\\n" "${luci_log}" | awk 'match($0,/([0-9]{1,3}\.){3}[0-9]{1,3}$/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
688 ;;
689 "blacklist_6")
690 if [ "${ban_sshdaemon}" = "dropbear" ]
691 then
692 pid_list="$(printf "%s\\n" "${ssh_log}" | grep -F "Exit before auth" | awk 'match($0,/(\[[0-9]+\])/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
693 for pid in ${pid_list}
694 do
695 src_addon="${src_addon} $(printf "%s\\n" "${ssh_log}" | grep -F "${pid}" | awk 'match($0,/(([0-9A-f]{0,4}::?){1,7}[0-9A-f]{0,4}$)/){ORS=" ";print substr($0,RSTART,RLENGTH);exit}')"
696 done
697 elif [ "${ban_sshdaemon}" = "sshd" ]
698 then
699 src_addon="$(printf "%s\\n" "${ssh_log}" | grep -E "[0-9]+ \[preauth\]$" | awk 'match($0,/(([0-9A-f]{0,4}::?){1,7}[0-9A-f]{0,4}$)/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
700 fi
701 src_addon="${src_addon} $(printf "%s\\n" "${luci_log}" | awk 'match($0,/(([0-9A-f]{0,4}::?){1,7}[0-9A-f]{0,4}$)/){ORS=" ";print substr($0,RSTART,RLENGTH)}')"
702 ;;
703 esac
704 for ip in ${src_addon}
705 do
706 if [ -z "$(grep -F "${ip}" "${src_url}")" ]
707 then
708 printf "%s\\n" "${ip}" >> "${tmp_load}"
709 if { [ "${src_name//_*/}" = "blacklist" ] && [ "${ban_autoblacklist}" -eq 1 ]; } || \
710 { [ "${src_name//_*/}" = "whitelist" ] && [ "${ban_autowhitelist}" -eq 1 ]; }
711 then
712 src_ts="# auto-added $(date "+%d.%m.%Y %H:%M:%S")"
713 printf "%s %s\\n" "${ip}" "${src_ts}" >> "${src_url}"
714 fi
715 fi
716 done
717 elif [ -n "${src_cat}" ]
718 then
719 if [ "${src_cat//[0-9]/}" != "${src_cat}" ]
720 then
721 for as in ${src_cat}
722 do
723 src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}AS${as}" 2>&1)"
724 src_rc="${?}"
725 if [ "${src_rc}" -eq 0 ]
726 then
727 jsonfilter -i "${tmp_raw}" -e '@.data.prefixes.*.prefix' 2>/dev/null >> "${tmp_load}"
728 else
729 break
730 fi
731 done
732 if [ "${src_rc}" -eq 0 ]
733 then
734 f_ipset backup
735 elif [ "${ban_action}" != "start" ]
736 then
737 f_ipset restore
738 fi
739 else
740 for co in ${src_cat}
741 do
742 src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}${co}&v4_format=prefix" 2>&1)"
743 src_rc="${?}"
744 if [ "${src_rc}" -eq 0 ]
745 then
746 if [ "${src_name##*_}" = "6" ]
747 then
748 jsonfilter -i "${tmp_raw}" -e '@.data.resources.ipv6.*' 2>/dev/null >> "${tmp_load}"
749 else
750 jsonfilter -i "${tmp_raw}" -e '@.data.resources.ipv4.*' 2>/dev/null >> "${tmp_load}"
751 fi
752 else
753 break
754 fi
755 done
756 if [ "${src_rc}" -eq 0 ]
757 then
758 f_ipset backup
759 elif [ "${ban_action}" != "start" ]
760 then
761 f_ipset restore
762 fi
763 fi
764 else
765 src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}" 2>&1)"
766 src_rc="${?}"
767 if [ "${src_rc}" -eq 0 ]
768 then
769 zcat "${tmp_raw}" 2>/dev/null > "${tmp_load}"
770 src_rc="${?}"
771 if [ "${src_rc}" -ne 0 ]
772 then
773 mv -f "${tmp_raw}" "${tmp_load}"
774 src_rc="${?}"
775 fi
776 if [ "${src_rc}" -eq 0 ]
777 then
778 f_ipset backup
779 src_rc="${?}"
780 fi
781 elif [ "${ban_action}" != "start" ]
782 then
783 f_ipset restore
784 src_rc="${?}"
785 fi
786 fi
787 fi
788
789 if [ "${src_rc}" -eq 0 ]
790 then
791 awk "${src_rset}" "${tmp_load}" 2>/dev/null > "${tmp_file}"
792 src_rc="${?}"
793 if [ "${src_rc}" -eq 0 ]
794 then
795 f_ipset create
796 src_rc="${?}"
797 elif [ "${ban_action}" != "refresh" ]
798 then
799 f_ipset refresh
800 src_rc="${?}"
801 fi
802 else
803 src_log="$(printf "%s" "${src_log}" | awk '{ORS=" ";print $0}')"
804 if [ "${ban_action}" != "refresh" ]
805 then
806 f_ipset refresh
807 src_rc="${?}"
808 fi
809 f_log "debug" "f_main ::: name: ${src_name}, url: ${src_url}, rc: ${src_rc}, log: ${src_log:-"-"}"
810 fi
811 )&
812 hold="$((cnt%ban_maxqueue))"
813 if [ "${hold}" -eq 0 ]
814 then
815 wait
816 fi
817 cnt="$((cnt+1))"
818 done
819 wait
820
821 for cnt in $(cat "${ban_tmpfile}".*.setcnt 2>/dev/null)
822 do
823 ban_setcnt="$((ban_setcnt+cnt))"
824 done
825 for cnt in $(cat "${ban_tmpfile}".*.cnt 2>/dev/null)
826 do
827 ban_cnt="$((ban_cnt+cnt))"
828 done
829 f_log "info" "${ban_setcnt} IPSets with overall ${ban_cnt} IPs/Prefixes loaded successfully (${ban_sysver})"
830 f_bgserv "start"
831 f_jsnup
832 f_rmtemp
833 }
834
835 # update runtime information
836 #
837 f_jsnup()
838 {
839 local rundate status="${1:-"enabled"}"
840
841 rundate="$(date "+%d.%m.%Y %H:%M:%S")"
842 ban_cntinfo="${ban_setcnt} IPSets with overall ${ban_cnt} IPs/Prefixes"
843
844 > "${ban_rtfile}"
845 json_load_file "${ban_rtfile}" >/dev/null 2>&1
846 json_init
847 json_add_object "data"
848 json_add_string "status" "${status}"
849 json_add_string "version" "${ban_ver}"
850 json_add_string "util_info" "${ban_fetchutil:-"-"}, ${ban_realtime:-"-"}"
851 json_add_string "ipset_info" "${ban_cntinfo:-"-"}"
852 json_add_string "backup_dir" "${ban_backupdir}"
853 json_add_string "last_run" "${rundate:-"-"}"
854 json_add_string "system" "${ban_sysver}"
855 json_close_object
856 json_dump > "${ban_rtfile}"
857 f_log "debug" "f_jsnup ::: status: ${status}, setcnt: ${ban_setcnt}, cnt: ${ban_cnt}"
858 }
859
860 # source required system libraries
861 #
862 if [ -r "/lib/functions.sh" ] && [ -r "/lib/functions/network.sh" ] && [ -r "/usr/share/libubox/jshn.sh" ]
863 then
864 . "/lib/functions.sh"
865 . "/lib/functions/network.sh"
866 . "/usr/share/libubox/jshn.sh"
867 else
868 f_log "err" "system libraries not found"
869 fi
870
871 # handle different banIP actions
872 #
873 f_envload
874 case "${ban_action}" in
875 "stop")
876 f_bgserv "stop"
877 f_jsnup stopped
878 f_ipset destroy
879 f_rmbackup
880 f_rmtemp
881 ;;
882 "start"|"restart"|"reload"|"refresh")
883 f_bgserv "stop"
884 f_envcheck
885 f_main
886 ;;
887 esac