You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

887 lines
26 KiB

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