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.

1804 lines
56 KiB

  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. #
  7. # (s)hellcheck exceptions
  8. # shellcheck disable=1091,2030,2031,2034,2039,2086,2129,2140,2143,2154,2181,2183,2188
  9. # set initial defaults
  10. #
  11. export LC_ALL=C
  12. export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
  13. set -o pipefail
  14. ban_ver="0.7.3"
  15. ban_enabled="0"
  16. ban_mail_enabled="0"
  17. ban_proto4_enabled="0"
  18. ban_proto6_enabled="0"
  19. ban_logsrc_enabled="0"
  20. ban_logdst_enabled="0"
  21. ban_monitor_enabled="0"
  22. ban_autodetect="1"
  23. ban_autoblacklist="1"
  24. ban_autowhitelist="1"
  25. ban_logterms=""
  26. ban_loglimit="100"
  27. ban_ssh_logcount="3"
  28. ban_luci_logcount="3"
  29. ban_nginx_logcount="5"
  30. ban_mailactions=""
  31. ban_search=""
  32. ban_devs=""
  33. ban_ifaces=""
  34. ban_debug="0"
  35. ban_maxqueue="4"
  36. ban_fetchutil=""
  37. ban_ip_cmd="$(command -v ip)"
  38. ban_ipt4_cmd="$(command -v iptables)"
  39. ban_ipt4_savecmd="$(command -v iptables-save)"
  40. ban_ipt4_restorecmd="$(command -v iptables-restore)"
  41. ban_ipt6_cmd="$(command -v ip6tables)"
  42. ban_ipt6_savecmd="$(command -v ip6tables-save)"
  43. ban_ipt6_restorecmd="$(command -v ip6tables-restore)"
  44. ban_ipset_cmd="$(command -v ipset)"
  45. ban_logger_cmd="$(command -v logger)"
  46. ban_logread="$(command -v logread)"
  47. ban_allsources=""
  48. ban_sources=""
  49. ban_asns=""
  50. ban_countries=""
  51. ban_settype_src=""
  52. ban_settype_dst=""
  53. ban_settype_all=""
  54. ban_lan_inputchains_4=""
  55. ban_lan_inputchains_6=""
  56. ban_lan_forwardchains_4=""
  57. ban_lan_forwardchains_6=""
  58. ban_wan_inputchains_4=""
  59. ban_wan_inputchains_6=""
  60. ban_wan_forwardchains_4=""
  61. ban_wan_forwardchains_6=""
  62. ban_action="${1:-"start"}"
  63. ban_pidfile="/var/run/banip.pid"
  64. ban_tmpbase="/tmp"
  65. ban_rtfile="${ban_tmpbase}/ban_runtime.json"
  66. ban_srcfile="${ban_tmpbase}/ban_sources.json"
  67. ban_reportdir="${ban_tmpbase}/banIP-Report"
  68. ban_backupdir="${ban_tmpbase}/banIP-Backup"
  69. ban_srcarc="/etc/banip/banip.sources.gz"
  70. ban_mailservice="/etc/banip/banip.mail"
  71. ban_logservice="/etc/banip/banip.service"
  72. ban_maclist="/etc/banip/banip.maclist"
  73. ban_blacklist="/etc/banip/banip.blacklist"
  74. ban_whitelist="/etc/banip/banip.whitelist"
  75. ban_setcnt="0"
  76. ban_cnt="0"
  77. # load environment
  78. #
  79. f_load()
  80. {
  81. # get system information
  82. #
  83. ban_sysver="$(ubus -S call system board 2>/dev/null | jsonfilter -e '@.model' -e '@.release.description' | \
  84. awk 'BEGIN{ORS=", "}{print $0}' | awk '{print substr($0,1,length($0)-2)}')"
  85. # load config
  86. #
  87. f_conf
  88. # check status
  89. #
  90. if [ "${ban_enabled}" = "0" ]
  91. then
  92. f_bgsrv "stop"
  93. f_ipset "destroy"
  94. f_jsnup "disabled"
  95. f_rmbckp
  96. f_rmtmp
  97. f_log "info" "banIP is currently disabled, please set the config option 'ban_enabled' to '1' to use this service"
  98. exit 0
  99. fi
  100. f_dir "${ban_backupdir}"
  101. f_dir "${ban_reportdir}"
  102. }
  103. # check/create directories
  104. #
  105. f_dir()
  106. {
  107. local dir="${1}"
  108. if [ ! -d "${dir}" ]
  109. then
  110. mkdir -p "${dir}"
  111. if [ "${?}" = "0" ]
  112. then
  113. f_log "debug" "directory '${dir}' created"
  114. else
  115. f_log "err" "directory '${dir}' could not be created"
  116. fi
  117. else
  118. f_log "debug" "directory '${dir}' is used"
  119. fi
  120. }
  121. # load banIP config
  122. #
  123. f_conf()
  124. {
  125. if [ ! -r "/etc/config/banip" ] || [ -z "$(uci -q show banip.global.ban_autodetect)" ]
  126. then
  127. f_log "err" "no valid banIP config found, please re-install the package via opkg with the '--force-reinstall --force-maintainer' options"
  128. fi
  129. config_cb()
  130. {
  131. option_cb()
  132. {
  133. local option="${1}"
  134. local value="${2}"
  135. eval "${option}=\"${value}\""
  136. }
  137. list_cb()
  138. {
  139. local option="${1}"
  140. local value="${2}"
  141. if [ "${option}" = "ban_ifaces" ]
  142. then
  143. eval "${option}=\"$(printf "%s" "${ban_ifaces}")${value} \""
  144. elif [ "${option}" = "ban_sources" ]
  145. then
  146. eval "${option}=\"$(printf "%s" "${ban_sources}")${value} \""
  147. elif [ "${option}" = "ban_localsources" ]
  148. then
  149. eval "${option}=\"$(printf "%s" "${ban_localsources}")${value} \""
  150. elif [ "${option}" = "ban_extrasources" ]
  151. then
  152. eval "${option}=\"$(printf "%s" "${ban_extrasources}")${value} \""
  153. elif [ "${option}" = "ban_settype_src" ]
  154. then
  155. eval "${option}=\"$(printf "%s" "${ban_settype_src}")${value} \""
  156. elif [ "${option}" = "ban_settype_dst" ]
  157. then
  158. eval "${option}=\"$(printf "%s" "${ban_settype_dst}")${value} \""
  159. elif [ "${option}" = "ban_settype_all" ]
  160. then
  161. eval "${option}=\"$(printf "%s" "${ban_settype_all}")${value} \""
  162. elif [ "${option}" = "ban_mailactions" ]
  163. then
  164. eval "${option}=\"$(printf "%s" "${ban_mailactions}")${value} \""
  165. elif [ "${option}" = "ban_logterms" ]
  166. then
  167. eval "${option}=\"$(printf "%s" "${ban_logterms}")${value} \""
  168. elif [ "${option}" = "ban_countries" ]
  169. then
  170. eval "${option}=\"$(printf "%s" "${ban_countries}")${value} \""
  171. elif [ "${option}" = "ban_asns" ]
  172. then
  173. eval "${option}=\"$(printf "%s" "${ban_asns}")${value} \""
  174. elif [ "${option}" = "ban_lan_inputchains_4" ]
  175. then
  176. eval "${option}=\"$(printf "%s" "${ban_lan_inputchains_4}")${value} \""
  177. elif [ "${option}" = "ban_lan_inputchains_6" ]
  178. then
  179. eval "${option}=\"$(printf "%s" "${ban_lan_inputchains_6}")${value} \""
  180. elif [ "${option}" = "ban_lan_forwardchains_4" ]
  181. then
  182. eval "${option}=\"$(printf "%s" "${ban_lan_forwardchains_4}")${value} \""
  183. elif [ "${option}" = "ban_lan_forwardchains_6" ]
  184. then
  185. eval "${option}=\"$(printf "%s" "${ban_lan_forwardchains_6}")${value} \""
  186. elif [ "${option}" = "ban_wan_inputchains_4" ]
  187. then
  188. eval "${option}=\"$(printf "%s" "${ban_wan_inputchains_4}")${value} \""
  189. elif [ "${option}" = "ban_wan_inputchains_6" ]
  190. then
  191. eval "${option}=\"$(printf "%s" "${ban_wan_inputchains_6}")${value} \""
  192. elif [ "${option}" = "ban_wan_forwardchains_4" ]
  193. then
  194. eval "${option}=\"$(printf "%s" "${ban_wan_forwardchains_4}")${value} \""
  195. elif [ "${option}" = "ban_wan_forwardchains_6" ]
  196. then
  197. eval "${option}=\"$(printf "%s" "${ban_wan_forwardchains_6}")${value} \""
  198. fi
  199. }
  200. }
  201. config_load banip
  202. ban_chain="${ban_chain:-"banIP"}"
  203. ban_global_settype="${ban_global_settype:-"src+dst"}"
  204. ban_target_src="${ban_target_src:-"DROP"}"
  205. ban_target_dst="${ban_target_dst:-"REJECT"}"
  206. ban_lan_inputchains_4="${ban_lan_inputchains_4:-"input_lan_rule"}"
  207. ban_lan_inputchains_6="${ban_lan_inputchains_6:-"input_lan_rule"}"
  208. ban_lan_forwardchains_4="${ban_lan_forwardchains_4:-"forwarding_lan_rule"}"
  209. ban_lan_forwardchains_6="${ban_lan_forwardchains_6:-"forwarding_lan_rule"}"
  210. ban_wan_inputchains_4="${ban_wan_inputchains_4:-"input_wan_rule"}"
  211. ban_wan_inputchains_6="${ban_wan_inputchains_6:-"input_wan_rule"}"
  212. ban_wan_forwardchains_4="${ban_wan_forwardchains_4:-"forwarding_wan_rule"}"
  213. ban_wan_forwardchains_6="${ban_wan_forwardchains_6:-"forwarding_wan_rule"}"
  214. ban_logchain_src="${ban_logchain_src:-"${ban_chain}_log_src"}"
  215. ban_logchain_dst="${ban_logchain_dst:-"${ban_chain}_log_dst"}"
  216. ban_logtarget_src="${ban_target_src}"
  217. ban_logtarget_dst="${ban_target_dst}"
  218. if [ "${ban_logsrc_enabled}" = "1" ]
  219. then
  220. ban_logprefix_src="${ban_logprefix_src:-"[banIP-${ban_ver%-*}, src/${ban_target_src}] "}"
  221. ban_logopts_src="${ban_logopts_src:-"-m limit --limit 2/sec"}"
  222. ban_target_src="${ban_logchain_src}"
  223. fi
  224. if [ "${ban_logdst_enabled}" = "1" ]
  225. then
  226. ban_logprefix_dst="${ban_logprefix_dst:-"[banIP-${ban_ver%-*}, dst/${ban_target_dst}] "}"
  227. ban_logopts_dst="${ban_logopts_dst:-"-m limit --limit 2/sec"}"
  228. ban_target_dst="${ban_logchain_dst}"
  229. fi
  230. ban_localsources="${ban_localsources:-"maclist whitelist blacklist"}"
  231. ban_logterms="${ban_logterms:-"dropbear sshd luci nginx"}"
  232. f_log "debug" "f_conf ::: ifaces: ${ban_ifaces:-"-"}, chain: ${ban_chain}, set_type: ${ban_global_settype}, log_chains (src/dst): ${ban_logchain_src}/${ban_logchain_dst}, targets (src/dst): ${ban_target_src}/${ban_target_dst}"
  233. f_log "debug" "f_conf ::: lan_inputs (4/6): ${ban_lan_inputchains_4}/${ban_lan_inputchains_6}, lan_forwards (4/6): ${ban_lan_forwardchains_4}/${ban_lan_forwardchains_6}, wan_inputs (4/6): ${ban_wan_inputchains_4}/${ban_wan_inputchains_6}, wan_forwards (4/6): ${ban_wan_forwardchains_4}/${ban_wan_forwardchains_6}"
  234. f_log "debug" "f_conf ::: local_sources: ${ban_localsources:-"-"}, extra_sources: ${ban_extrasources:-"-"}, log_terms: ${ban_logterms:-"-"}, log_prefixes (src/dst): ${ban_logprefix_src}/${ban_logprefix_dst}, log_options (src/dst): ${ban_logopts_src}/${ban_logopts_dst}"
  235. }
  236. # check environment
  237. #
  238. f_env()
  239. {
  240. local util utils packages iface tmp cnt="0" cnt_max="10"
  241. ban_starttime="$(date "+%s")"
  242. f_jsnup "running"
  243. f_log "info" "start banIP processing (${ban_action})"
  244. # create temp directory & files
  245. #
  246. f_tmp
  247. # get wan devices and wan subnets
  248. #
  249. if [ "${ban_autodetect}" = "1" ] && [ -z "${ban_ifaces}" ]
  250. then
  251. while [ "${cnt}" -le "${cnt_max}" ]
  252. do
  253. network_find_wan iface
  254. if [ -n "${iface}" ] && [ -z "$(printf "%s\n" "${ban_ifaces}" | grep -F "${iface}")" ]
  255. then
  256. ban_proto4_enabled="1"
  257. ban_ifaces="${ban_ifaces}${iface} "
  258. uci_set banip global ban_proto4_enabled "1"
  259. uci_add_list banip global ban_ifaces "${iface}"
  260. fi
  261. network_find_wan6 iface
  262. if [ -n "${iface}" ] && [ -z "$(printf "%s\n" "${ban_ifaces}" | grep -F "${iface}")" ]
  263. then
  264. ban_proto6_enabled="1"
  265. ban_ifaces="${ban_ifaces}${iface} "
  266. uci_set banip global ban_proto6_enabled "1"
  267. uci_add_list banip global ban_ifaces "${iface}"
  268. fi
  269. if [ -z "${ban_ifaces}" ]
  270. then
  271. if [ "${cnt}" -le "${cnt_max}" ]
  272. then
  273. network_flush_cache
  274. cnt=$((cnt+1))
  275. sleep 1
  276. else
  277. break
  278. fi
  279. else
  280. if [ -n "$(uci -q changes "banip")" ]
  281. then
  282. uci_commit "banip"
  283. fi
  284. break
  285. fi
  286. done
  287. fi
  288. while [ "${cnt}" -le "${cnt_max}" ]
  289. do
  290. for iface in ${ban_ifaces}
  291. do
  292. network_get_device tmp "${iface}"
  293. if [ -n "${tmp}" ] && [ -z "$(printf "%s\n" "${ban_devs}" | grep -F "${tmp}")" ]
  294. then
  295. ban_devs="${ban_devs} ${tmp}"
  296. else
  297. network_get_physdev tmp "${iface}"
  298. if [ -n "${tmp}" ] && [ -z "$(printf "%s\n" "${ban_devs}" | grep -F "${tmp}")" ]
  299. then
  300. ban_devs="${ban_devs} ${tmp}"
  301. fi
  302. fi
  303. network_get_subnet tmp "${iface}"
  304. if [ -n "${tmp}" ] && [ -z "$(printf "%s\n" "${ban_subnets}" | grep -F "${tmp}")" ]
  305. then
  306. ban_subnets="${ban_subnets} ${tmp}"
  307. fi
  308. network_get_subnet6 tmp "${iface}"
  309. if [ -n "${tmp}" ] && [ -z "$(printf "%s\n" "${ban_subnets}" | grep -F "${tmp}")" ]
  310. then
  311. ban_subnets="${ban_subnets} ${tmp}"
  312. fi
  313. done
  314. if [ -z "${ban_devs}" ] || [ -z "${ban_subnets}" ]
  315. then
  316. if [ "${cnt}" -le "${cnt_max}" ]
  317. then
  318. network_flush_cache
  319. cnt=$((cnt+1))
  320. sleep 1
  321. else
  322. break
  323. fi
  324. else
  325. break
  326. fi
  327. done
  328. ban_ipdevs="$("${ban_ip_cmd}" link show 2>/dev/null | awk 'BEGIN{FS="[@: ]"}/^[0-9:]/{if($3!="lo"){ORS=" ";print $3}}')"
  329. if [ -z "${ban_ifaces}" ] || [ -z "${ban_devs}" ] || [ -z "${ban_ipdevs}" ]
  330. then
  331. f_log "err" "logical wan interface(s)/device(s) '${ban_ifaces:-"-"}/${ban_devs:-"-"}' not found, please please check your configuration"
  332. elif [ -z "${ban_ipdevs}" ]
  333. then
  334. f_log "err" "ip device(s) '${ban_ipdevs:-"-"}' not found, please please check your configuration"
  335. fi
  336. # check ipset/iptables utility
  337. #
  338. if [ ! -x "${ban_ipset_cmd}" ]
  339. then
  340. f_log "err" "ipset utility '${ban_ipset_cmd:-"-"}' not executable, please install package 'ipset'"
  341. fi
  342. if { [ "${ban_proto4_enabled}" = "1" ] && { [ ! -x "${ban_ipt4_cmd}" ] || [ ! -x "${ban_ipt4_savecmd}" ] || [ ! -x "${ban_ipt4_restorecmd}" ]; }; } || \
  343. { [ "${ban_proto6_enabled}" = "1" ] && { [ ! -x "${ban_ipt6_cmd}" ] || [ ! -x "${ban_ipt6_savecmd}" ] || [ ! -x "${ban_ipt6_restorecmd}" ]; }; }
  344. then
  345. f_log "err" "iptables utilities '${ban_ipt4_cmd:-"-"}, ${ban_ipt4_savecmd:-"-"}, ${ban_ipt4_restorecmd:-"-"}/${ban_ipt6_cmd:-"-"}', ${ban_ipt6_savecmd:-"-"}, ${ban_ipt6_restorecmd:-"-"} not executable, please install the relevant iptables packages"
  346. fi
  347. # check download utility
  348. #
  349. if [ -z "${ban_fetchutil}" ]
  350. then
  351. while [ -z "${packages}" ] && [ "${cnt}" -le "${cnt_max}" ]
  352. do
  353. packages="$(opkg list-installed 2>/dev/null)"
  354. cnt=$((cnt+1))
  355. sleep 1
  356. done
  357. if [ -z "${packages}" ]
  358. then
  359. f_log "err" "local opkg package repository is not available, please set 'ban_fetchutil' manually"
  360. fi
  361. utils="aria2c curl wget uclient-fetch"
  362. for util in ${utils}
  363. do
  364. if { [ "${util}" = "uclient-fetch" ] && [ -n "$(printf "%s" "${packages}" | grep "^libustream-")" ]; } || \
  365. { [ "${util}" = "wget" ] && [ -n "$(printf "%s" "${packages}" | grep "^wget -")" ]; } || \
  366. [ "${util}" = "curl" ] || [ "${util}" = "aria2c" ]
  367. then
  368. if [ -x "$(command -v "${util}")" ]
  369. then
  370. ban_fetchutil="${util}"
  371. uci_set banip global ban_fetchutil "${util}"
  372. uci_commit "banip"
  373. break
  374. fi
  375. fi
  376. done
  377. elif [ ! -x "$(command -v "${ban_fetchutil}")" ]
  378. then
  379. unset ban_fetchutil
  380. fi
  381. case "${ban_fetchutil}" in
  382. "aria2c")
  383. ban_fetchparm="${ban_fetchparm:-"--timeout=20 --allow-overwrite=true --auto-file-renaming=false --check-certificate=true --log-level=warn --dir=/ -o"}"
  384. ;;
  385. "curl")
  386. ban_fetchparm="${ban_fetchparm:-"--connect-timeout 20 --silent --show-error --location -o"}"
  387. ;;
  388. "uclient-fetch")
  389. ban_fetchparm="${ban_fetchparm:-"--timeout=20 -O"}"
  390. ;;
  391. "wget")
  392. ban_fetchparm="${ban_fetchparm:-"--no-cache --no-cookies --max-redirect=0 --timeout=20 -O"}"
  393. ;;
  394. esac
  395. if [ -n "${ban_fetchutil}" ] && [ -n "${ban_fetchparm}" ]
  396. then
  397. ban_fetchutil="$(command -v "${ban_fetchutil}")"
  398. else
  399. 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'"
  400. fi
  401. # load JSON source file
  402. #
  403. if [ ! -r "${ban_srcfile}" ]
  404. then
  405. if [ -r "${ban_srcarc}" ]
  406. then
  407. zcat "${ban_srcarc}" > "${ban_srcfile}"
  408. else
  409. f_log "err" "banIP source archive not found"
  410. fi
  411. fi
  412. if [ -r "${ban_srcfile}" ]
  413. then
  414. json_load_file "${ban_srcfile}"
  415. json_get_keys ban_allsources
  416. ban_allsources="${ban_allsources} ${ban_localsources}"
  417. else
  418. f_log "err" "banIP source file not found"
  419. fi
  420. f_log "debug" "f_env ::: auto_detect: ${ban_autodetect}, fetch_util: ${ban_fetchutil:-"-"}, fetch_parm: ${ban_fetchparm:-"-"}, src_file: ${ban_srcfile:-"-"}, log_terms: ${ban_logterms}, interfaces: ${ban_ifaces:-"-"}, devices: ${ban_devs:-"-"}, subnets: ${ban_subnets:-"-"}, ip_devices: ${ban_ipdevs:-"-"}, protocols (4/6): ${ban_proto4_enabled}/${ban_proto6_enabled}"
  421. }
  422. # create temporary files and directories
  423. #
  424. f_tmp()
  425. {
  426. f_dir "${ban_tmpbase}"
  427. ban_tmpdir="$(mktemp -p "${ban_tmpbase}" -d)"
  428. ban_tmpfile="$(mktemp -p "${ban_tmpdir}" -tu)"
  429. if [ ! -f "${ban_pidfile}" ] || [ ! -s "${ban_pidfile}" ]
  430. then
  431. printf "%s" "${$}" > "${ban_pidfile}"
  432. fi
  433. f_log "debug" "f_tmp ::: tmp_base: ${ban_tmpbase:-"-"}, tmp_dir: ${ban_tmpdir:-"-"}, pid_file: ${ban_pidfile:-"-"}"
  434. }
  435. # remove temporary files and directories
  436. #
  437. f_rmtmp()
  438. {
  439. if [ -d "${ban_tmpdir}" ]
  440. then
  441. rm -rf "${ban_tmpdir}"
  442. fi
  443. rm -f "${ban_srcfile}"
  444. > "${ban_pidfile}"
  445. f_log "debug" "f_rmtmp ::: tmp_base: ${ban_tmpbase:-"-"}, tmp_dir: ${ban_tmpdir:-"-"}, pid_file: ${ban_pidfile:-"-"}"
  446. }
  447. # remove backup files
  448. #
  449. f_rmbckp()
  450. {
  451. if [ -d "${ban_backupdir}" ]
  452. then
  453. rm -f "${ban_backupdir}/banIP."*".gz"
  454. fi
  455. }
  456. # status helper function
  457. #
  458. f_char()
  459. {
  460. local result input="${1}"
  461. if [ "${input}" = "1" ]
  462. then
  463. result="✔"
  464. else
  465. result="✘"
  466. fi
  467. printf "%s" "${result}"
  468. }
  469. # apply iptables rules
  470. #
  471. f_iptrule()
  472. {
  473. local rc timeout="-w 5" action="${1}" chain="${2}" rule="${3}" pos="${4}"
  474. if [ "${src_name}" = "maclist" ] || [ "${src_name##*_}" = "4" ]
  475. then
  476. rc="$("${ban_ipt4_cmd}" "${timeout}" -C ${chain} ${rule} 2>/dev/null; printf "%u" ${?})"
  477. if { [ "${rc}" != "0" ] && { [ "${action}" = "-A" ] || [ "${action}" = "-I" ]; }; } || \
  478. { [ "${rc}" = "0" ] && [ "${action}" = "-D" ]; }
  479. then
  480. "${ban_ipt4_cmd}" "${timeout}" "${action}" ${chain} ${pos} ${rule} 2>/dev/null
  481. rc="${?}"
  482. else
  483. rc=0
  484. fi
  485. fi
  486. if [ "${src_name}" = "maclist" ] || [ "${src_name##*_}" = "6" ]
  487. then
  488. rc="$("${ban_ipt6_cmd}" "${timeout}" -C ${chain} ${rule} 2>/dev/null; printf "%u" ${?})"
  489. if { [ "${rc}" != "0" ] && { [ "${action}" = "-A" ] || [ "${action}" = "-I" ]; }; } || \
  490. { [ "${rc}" = "0" ] && [ "${action}" = "-D" ]; }
  491. then
  492. "${ban_ipt6_cmd}" "${timeout}" "${action}" ${chain} ${pos} ${rule} 2>/dev/null
  493. rc="${?}"
  494. else
  495. rc=0
  496. fi
  497. fi
  498. if [ -n "${rc}" ] && [ "${rc}" != "0" ]
  499. then
  500. > "${tmp_err}"
  501. f_log "info" "iptables action '${action:-"-"}' failed with '${chain}, ${pos:-"-"}, ${rule:-"-"}'"
  502. fi
  503. }
  504. # iptables controller
  505. #
  506. f_iptables()
  507. {
  508. local destroy="${1}" dev
  509. if [ "${ban_action}" != "refresh" ] && [ "${ban_action}" != "resume" ]
  510. then
  511. for dev in ${ban_ipdevs}
  512. do
  513. if [ "${src_name}" = "maclist" ]
  514. then
  515. f_iptrule "-D" "${ban_chain}" "-o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j RETURN"
  516. elif [ "${src_name%_*}" = "whitelist" ]
  517. then
  518. f_iptrule "-D" "${ban_chain}" "-i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j RETURN"
  519. f_iptrule "-D" "${ban_chain}" "-o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j RETURN"
  520. else
  521. f_iptrule "-D" "${ban_chain}" "-i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j ${ban_logtarget_src}"
  522. f_iptrule "-D" "${ban_chain}" "-o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${ban_logtarget_dst}"
  523. f_iptrule "-D" "${ban_chain}" "-i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j ${ban_logchain_src}"
  524. f_iptrule "-D" "${ban_chain}" "-o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${ban_logchain_dst}"
  525. fi
  526. done
  527. fi
  528. if [ -z "${destroy}" ] && [ "${cnt}" -gt "0" ]
  529. then
  530. if [ "${src_settype}" != "dst" ]
  531. then
  532. if [ "${src_name##*_}" = "4" ]
  533. then
  534. for chain in ${ban_wan_inputchains_4}
  535. do
  536. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  537. done
  538. for chain in ${ban_wan_forwardchains_4}
  539. do
  540. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  541. done
  542. f_iptrule "-A" "${ban_chain}" "-p udp --dport 67:68 --sport 67:68 -j RETURN"
  543. elif [ "${src_name##*_}" = "6" ]
  544. then
  545. for chain in ${ban_wan_inputchains_6}
  546. do
  547. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  548. done
  549. for chain in ${ban_wan_forwardchains_6}
  550. do
  551. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  552. done
  553. f_iptrule "-A" "${ban_chain}" "-p ipv6-icmp -s fe80::/10 -d fe80::/10 -j RETURN"
  554. f_iptrule "-A" "${ban_chain}" "-p udp -s fc00::/6 --sport 547 -d fc00::/6 --dport 546 -j RETURN"
  555. fi
  556. for dev in ${ban_devs}
  557. do
  558. if [ "${src_name}" = "maclist" ]
  559. then
  560. f_iptrule "-I" "${ban_chain}" "-o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j RETURN" "1"
  561. elif [ "${src_name%_*}" = "whitelist" ]
  562. then
  563. f_iptrule "-I" "${ban_chain}" "-i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j RETURN" "2"
  564. else
  565. f_iptrule "${action:-"-A"}" "${ban_chain}" "-i ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} src -j ${ban_target_src}"
  566. fi
  567. done
  568. fi
  569. if [ "${src_settype}" != "src" ]
  570. then
  571. if [ "${src_name##*_}" = "4" ]
  572. then
  573. for chain in ${ban_lan_inputchains_4}
  574. do
  575. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  576. done
  577. for chain in ${ban_lan_forwardchains_4}
  578. do
  579. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  580. done
  581. f_iptrule "-A" "${ban_chain}" "-p udp --dport 67:68 --sport 67:68 -j RETURN"
  582. elif [ "${src_name##*_}" = "6" ]
  583. then
  584. for chain in ${ban_lan_inputchains_6}
  585. do
  586. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  587. done
  588. for chain in ${ban_lan_forwardchains_6}
  589. do
  590. f_iptrule "-I" "${chain}" "-j ${ban_chain}"
  591. done
  592. f_iptrule "-A" "${ban_chain}" "-p ipv6-icmp -s fe80::/10 -d fe80::/10 -j RETURN"
  593. f_iptrule "-A" "${ban_chain}" "-p udp -s fc00::/6 --sport 547 -d fc00::/6 --dport 546 -j RETURN"
  594. fi
  595. for dev in ${ban_devs}
  596. do
  597. if [ "${src_name%_*}" = "whitelist" ]
  598. then
  599. f_iptrule "-I" "${ban_chain}" "-o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j RETURN" "3"
  600. elif [ "${src_name}" != "maclist" ]
  601. then
  602. f_iptrule "${action:-"-A"}" "${ban_chain}" "-o ${dev} -m conntrack --ctstate NEW -m set --match-set ${src_name} dst -j ${ban_target_dst}"
  603. fi
  604. done
  605. fi
  606. else
  607. "${ban_ipset_cmd}" -q destroy "${src_name}"
  608. fi
  609. }
  610. # ipset controller
  611. #
  612. f_ipset()
  613. {
  614. local src src_list action rule ipt_cmd out_rc cnt="0" cnt_ip="0" cnt_cidr="0" cnt_mac="0" timeout="-w 5" mode="${1}" in_rc="4"
  615. case "${mode}" in
  616. "backup")
  617. gzip -cf "${tmp_load}" 2>/dev/null > "${ban_backupdir}/banIP.${src_name}.gz"
  618. out_rc="${?}"
  619. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
  620. return "${out_rc}"
  621. ;;
  622. "restore")
  623. if [ -f "${ban_backupdir}/banIP.${src_name}.gz" ]
  624. then
  625. zcat "${ban_backupdir}/banIP.${src_name}.gz" 2>/dev/null > "${tmp_load}"
  626. out_rc="${?}"
  627. else
  628. out_rc="${in_rc}"
  629. fi
  630. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
  631. return "${out_rc}"
  632. ;;
  633. "remove")
  634. if [ -f "${ban_backupdir}/banIP.${src_name}.gz" ]
  635. then
  636. rm -f "${ban_backupdir}/banIP.${src_name}.gz"
  637. out_rc="${?}"
  638. else
  639. out_rc="${in_rc}"
  640. fi
  641. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
  642. return "${out_rc}"
  643. ;;
  644. "initial")
  645. for proto in "4" "6"
  646. do
  647. if [ "${proto}" = "4" ]
  648. then
  649. ipt_cmd="${ban_ipt4_cmd}"
  650. chainsets="${ban_lan_inputchains_4} ${ban_lan_forwardchains_4} ${ban_wan_inputchains_4} ${ban_wan_forwardchains_4}"
  651. elif [ "${proto}" = "6" ]
  652. then
  653. ipt_cmd="${ban_ipt6_cmd}"
  654. chainsets="${ban_lan_inputchains_6} ${ban_lan_forwardchains_6} ${ban_wan_inputchains_6} ${ban_wan_forwardchains_6}"
  655. fi
  656. if [ -z "$("${ipt_cmd}" "${timeout}" -nL "${ban_chain}" 2>/dev/null)" ]
  657. then
  658. "${ipt_cmd}" "${timeout}" -N "${ban_chain}" 2>/dev/null
  659. out_rc="${?}"
  660. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, chain: ${ban_chain:-"-"}, out_rc: ${out_rc}"
  661. else
  662. out_rc=0
  663. for chain in ${chainsets}
  664. do
  665. f_iptrule "-D" "${chain}" "-j ${ban_chain}"
  666. done
  667. fi
  668. if [ "${ban_logsrc_enabled}" = "1" ] && [ "${out_rc}" = "0" ] && [ -z "$("${ipt_cmd}" "${timeout}" -nL "${ban_logchain_src}" 2>/dev/null)" ]
  669. then
  670. "${ipt_cmd}" "${timeout}" -N "${ban_logchain_src}" 2>/dev/null
  671. out_rc="${?}"
  672. if [ "${out_rc}" = "0" ]
  673. then
  674. "${ipt_cmd}" "${timeout}" -A "${ban_logchain_src}" -j LOG ${ban_logopts_src} --log-prefix "${ban_logprefix_src}"
  675. out_rc="${?}"
  676. if [ "${out_rc}" = "0" ]
  677. then
  678. "${ipt_cmd}" "${timeout}" -A "${ban_logchain_src}" -j "${ban_logtarget_src}"
  679. out_rc="${?}"
  680. fi
  681. fi
  682. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, logchain_src: ${ban_logchain_src:-"-"}, out_rc: ${out_rc}"
  683. fi
  684. if [ "${ban_logdst_enabled}" = "1" ] && [ "${out_rc}" = "0" ] && [ -z "$("${ipt_cmd}" "${timeout}" -nL "${ban_logchain_dst}" 2>/dev/null)" ]
  685. then
  686. "${ipt_cmd}" "${timeout}" -N "${ban_logchain_dst}" 2>/dev/null
  687. out_rc="${?}"
  688. if [ "${out_rc}" = "0" ]
  689. then
  690. "${ipt_cmd}" "${timeout}" -A "${ban_logchain_dst}" -j LOG ${ban_logopts_dst} --log-prefix "${ban_logprefix_dst}"
  691. out_rc="${?}"
  692. if [ "${out_rc}" = "0" ]
  693. then
  694. "${ipt_cmd}" "${timeout}" -A "${ban_logchain_dst}" -j "${ban_logtarget_dst}"
  695. out_rc="${?}"
  696. fi
  697. fi
  698. f_log "debug" "f_ipset ::: name: initial, mode: ${mode:-"-"}, logchain_dst: ${ban_logchain_dst:-"-"}, out_rc: ${out_rc}"
  699. fi
  700. done
  701. out_rc="${out_rc:-"${in_rc}"}"
  702. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
  703. return "${out_rc}"
  704. ;;
  705. "create")
  706. if [ -s "${tmp_file}" ] && [ -z "$("${ban_ipset_cmd}" -q -n list "${src_name}")" ]
  707. then
  708. cnt="$(awk 'END{print NR}' "${tmp_file}" 2>/dev/null)"
  709. cnt=$((cnt+262144))
  710. if [ "${src_name}" = "maclist" ]
  711. then
  712. "${ban_ipset_cmd}" create "${src_name}" hash:mac hashsize 64 maxelem "${cnt}" counters timeout "${ban_maclist_timeout:-"0"}"
  713. out_rc="${?}"
  714. elif [ "${src_name%_*}" = "whitelist" ]
  715. then
  716. "${ban_ipset_cmd}" create "${src_name}" hash:net hashsize 64 maxelem "${cnt}" family "${src_ipver}" counters timeout "${ban_whitelist_timeout:-"0"}"
  717. out_rc="${?}"
  718. elif [ "${src_name%_*}" = "blacklist" ]
  719. then
  720. "${ban_ipset_cmd}" create "${src_name}" hash:net hashsize 64 maxelem "${cnt}" family "${src_ipver}" counters timeout "${ban_blacklist_timeout:-"0"}"
  721. out_rc="${?}"
  722. else
  723. "${ban_ipset_cmd}" create "${src_name}" hash:net hashsize 64 maxelem "${cnt}" family "${src_ipver}" counters
  724. out_rc="${?}"
  725. fi
  726. else
  727. "${ban_ipset_cmd}" -q flush "${src_name}"
  728. out_rc="${?}"
  729. fi
  730. if [ -s "${tmp_file}" ] && [ "${out_rc}" = "0" ]
  731. then
  732. "${ban_ipset_cmd}" -q -! restore < "${tmp_file}"
  733. out_rc="${?}"
  734. if [ "${out_rc}" = "0" ]
  735. then
  736. src_list="$("${ban_ipset_cmd}" -q list "${src_name}")"
  737. cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
  738. cnt_mac="$(printf "%s\n" "${src_list}" | grep -cE "^(([0-9A-Z][0-9A-Z]:){5}[0-9A-Z]{2} packets)")"
  739. cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "(/[0-9]{1,3} packets)")"
  740. cnt_ip=$((cnt-cnt_cidr-cnt_mac))
  741. printf "%s\n" "${cnt}" > "${tmp_cnt}"
  742. fi
  743. fi
  744. f_iptables
  745. end_ts="$(date +%s)"
  746. out_rc="${out_rc:-"${in_rc}"}"
  747. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, ipver: ${src_ipver:-"-"}, settype: ${src_settype:-"-"}, count(sum/ip/cidr/mac): ${cnt}/${cnt_ip}/${cnt_cidr}/${cnt_mac}, time: $((end_ts-start_ts)), out_rc: ${out_rc}"
  748. return "${out_rc}"
  749. ;;
  750. "refresh")
  751. if [ -n "$("${ban_ipset_cmd}" -q -n list "${src_name}")" ]
  752. then
  753. out_rc=0
  754. src_list="$("${ban_ipset_cmd}" -q list "${src_name}")"
  755. cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
  756. cnt_mac="$(printf "%s\n" "${src_list}" | grep -cE "^(([0-9A-Z][0-9A-Z]:){5}[0-9A-Z]{2} packets)")"
  757. cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "(/[0-9]{1,3} packets)")"
  758. cnt_ip=$((cnt-cnt_cidr-cnt_mac))
  759. printf "%s\n" "${cnt}" > "${tmp_cnt}"
  760. f_iptables
  761. fi
  762. end_ts="$(date +%s)"
  763. out_rc="${out_rc:-"${in_rc}"}"
  764. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, count(sum/ip/cidr/mac): ${cnt}/${cnt_ip}/${cnt_cidr}/${cnt_mac}, time: $((end_ts-start_ts)), out_rc: ${out_rc}"
  765. return "${out_rc}"
  766. ;;
  767. "suspend")
  768. for src in ${ban_sources} ${ban_localsources}
  769. do
  770. if [ "${src}" = "maclist" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${src}")" ]
  771. then
  772. tmp_file="${ban_backupdir}/${src}.file"
  773. "${ban_ipset_cmd}" -q save "${src}" | tail -n +2 > "${tmp_file}"
  774. "${ban_ipset_cmd}" -q flush "${src}"
  775. else
  776. for proto in "4" "6"
  777. do
  778. if [ -n "$("${ban_ipset_cmd}" -q -n list "${src}_${proto}")" ]
  779. then
  780. tmp_file="${ban_backupdir}/${src}_${proto}.file"
  781. "${ban_ipset_cmd}" -q save "${src}_${proto}" | tail -n +2 > "${tmp_file}"
  782. "${ban_ipset_cmd}" -q flush "${src}_${proto}"
  783. fi
  784. done
  785. fi
  786. done
  787. f_log "debug" "f_ipset ::: name: ${src:-"-"}, mode: ${mode:-"-"}"
  788. ;;
  789. "resume")
  790. if [ -f "${ban_backupdir}/${src_name}.file" ]
  791. then
  792. "${ban_ipset_cmd}" -q -! restore < "${ban_backupdir}/${src_name}.file"
  793. out_rc="${?}"
  794. if [ "${out_rc}" = "0" ]
  795. then
  796. rm -f "${ban_backupdir}/${src_name}.file"
  797. src_list="$("${ban_ipset_cmd}" -q list "${src_name}")"
  798. cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
  799. cnt_mac="$(printf "%s\n" "${src_list}" | grep -cE "^(([0-9A-Z][0-9A-Z]:){5}[0-9A-Z]{2} packets)")"
  800. cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "(/[0-9]{1,3} packets)")"
  801. cnt_ip=$((cnt-cnt_cidr-cnt_mac))
  802. printf "%s\n" "${cnt}" > "${tmp_cnt}"
  803. fi
  804. f_iptables
  805. fi
  806. end_ts="$(date +%s)"
  807. out_rc="${out_rc:-"${in_rc}"}"
  808. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, ipver: ${src_ipver:-"-"}, settype: ${src_settype:-"-"}, count(sum/ip/cidr/mac): ${cnt}/${cnt_ip}/${cnt_cidr}/${cnt_mac}, time: $((end_ts-start_ts)), out_rc: ${out_rc}"
  809. return "${out_rc}"
  810. ;;
  811. "flush")
  812. if [ -n "$("${ban_ipset_cmd}" -q -n list "${src_name}")" ]
  813. then
  814. f_iptables "destroy"
  815. out_rc=0
  816. fi
  817. out_rc="${out_rc:-"${in_rc}"}"
  818. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}, out_rc: ${out_rc}"
  819. return "${out_rc}"
  820. ;;
  821. "destroy")
  822. for chain in ${ban_chain} ${ban_logchain_src} ${ban_logchain_dst}
  823. do
  824. if [ -n "$("${ban_ipt4_cmd}" "${timeout}" -nL "${chain}" 2>/dev/null)" ]
  825. then
  826. "${ban_ipt4_savecmd}" | grep -v -- "-j ${chain}" | "${ban_ipt4_restorecmd}"
  827. "${ban_ipt4_cmd}" "${timeout}" -F "${chain}" 2>/dev/null
  828. "${ban_ipt4_cmd}" "${timeout}" -X "${chain}" 2>/dev/null
  829. fi
  830. if [ -n "$("${ban_ipt6_cmd}" "${timeout}" -nL "${chain}" 2>/dev/null)" ]
  831. then
  832. "${ban_ipt6_savecmd}" | grep -v -- "-j ${chain}" | "${ban_ipt6_restorecmd}"
  833. "${ban_ipt6_cmd}" "${timeout}" -F "${chain}" 2>/dev/null
  834. "${ban_ipt6_cmd}" "${timeout}" -X "${chain}" 2>/dev/null
  835. fi
  836. done
  837. for src in ${ban_sources} ${ban_localsources}
  838. do
  839. if [ "${src}" = "maclist" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${src}")" ]
  840. then
  841. "${ban_ipset_cmd}" -q destroy "${src}"
  842. else
  843. for proto in "4" "6"
  844. do
  845. if [ -n "$("${ban_ipset_cmd}" -q -n list "${src}_${proto}")" ]
  846. then
  847. "${ban_ipset_cmd}" -q destroy "${src}_${proto}"
  848. fi
  849. done
  850. fi
  851. done
  852. f_log "debug" "f_ipset ::: name: ${src_name:-"-"}, mode: ${mode:-"-"}"
  853. ;;
  854. esac
  855. }
  856. # write to syslog
  857. #
  858. f_log()
  859. {
  860. local class="${1}" log_msg="${2}"
  861. if [ -n "${log_msg}" ] && { [ "${class}" != "debug" ] || [ "${ban_debug}" = "1" ]; }
  862. then
  863. if [ -x "${ban_logger_cmd}" ]
  864. then
  865. "${ban_logger_cmd}" -p "${class}" -t "banIP-${ban_ver%-*}[${$}]" "${log_msg}"
  866. else
  867. printf "%s %s %s\n" "${class}" "banIP-${ban_ver%-*}[${$}]" "${log_msg}"
  868. fi
  869. if [ "${class}" = "err" ]
  870. then
  871. f_jsnup "error"
  872. f_ipset "destroy"
  873. f_rmbckp
  874. f_rmtmp
  875. exit 1
  876. fi
  877. fi
  878. }
  879. # start log service to trace failed ssh/luci logins
  880. #
  881. f_bgsrv()
  882. {
  883. local bg_pid action="${1}"
  884. bg_pid="$(pgrep -f "^/bin/sh ${ban_logservice}|${ban_logread}|^grep -qE Exit before auth|^grep -qE error: maximum|^grep -qE luci: failed|^grep -qE nginx" | awk '{ORS=" "; print $1}')"
  885. if [ "${action}" = "start" ] && [ -x "${ban_logservice}" ] && [ "${ban_monitor_enabled}" = "1" ]
  886. then
  887. if [ -n "${bg_pid}" ]
  888. then
  889. kill -HUP "${bg_pid}" 2>/dev/null
  890. fi
  891. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "dropbear")" ]
  892. then
  893. ban_search="Exit before auth from|"
  894. fi
  895. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "sshd")" ]
  896. then
  897. ban_search="${ban_search}error: maximum authentication attempts exceeded|sshd.*Connection closed by.*\[preauth\]|"
  898. fi
  899. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "luci")" ]
  900. then
  901. ban_search="${ban_search}luci: failed login|"
  902. fi
  903. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "nginx")" ]
  904. then
  905. ban_search="${ban_search}nginx\[[0-9]+\]:.*\[error\].*open().*client: [[:alnum:].:]+|"
  906. fi
  907. ( "${ban_logservice}" "${ban_ver}" "${ban_search%?}" & )
  908. elif [ "${action}" = "stop" ] && [ -n "${bg_pid}" ]
  909. then
  910. kill -HUP "${bg_pid}" 2>/dev/null
  911. fi
  912. f_log "debug" "f_bgsrv ::: action: ${action:-"-"}, bg_pid: ${bg_pid:-"-"}, monitor_enabled: ${ban_monitor_enabled:-"-"}, log_service: ${ban_logservice:-"-"}"
  913. }
  914. # download controller
  915. #
  916. f_down()
  917. {
  918. local src_name="${1}" proto="${2}" src_ipver="${3}" src_url="${4}" src_rule="${5}" src_comp="${6}"
  919. local ip start_ts end_ts src_settype src_log src_rc tmp_load tmp_file tmp_raw tmp_cnt tmp_err
  920. start_ts="$(date +%s)"
  921. if [ -n "$(printf "%s\n" "${ban_settype_src}" | grep -F "${src_name}")" ]
  922. then
  923. src_settype="src"
  924. elif [ -n "$(printf "%s\n" "${ban_settype_dst}" | grep -F "${src_name}")" ]
  925. then
  926. src_settype="dst"
  927. elif [ -n "$(printf "%s\n" "${ban_settype_all}" | grep -F "${src_name}")" ]
  928. then
  929. src_settype="src+dst"
  930. else
  931. src_settype="${ban_global_settype}"
  932. fi
  933. src_name="${src_name}_${proto}"
  934. tmp_load="${ban_tmpfile}.${src_name}.load"
  935. tmp_file="${ban_tmpfile}.${src_name}.file"
  936. tmp_raw="${tmp_file}.raw"
  937. tmp_cnt="${tmp_file}.cnt"
  938. tmp_err="${tmp_file}.err"
  939. # 'resume' mode
  940. #
  941. if [ "${ban_action}" = "resume" ]
  942. then
  943. if [ "${src_name%_*}" = "maclist" ]
  944. then
  945. src_name="maclist"
  946. fi
  947. f_ipset "resume"
  948. src_rc="${?}"
  949. if [ "${src_rc}" = "0" ]
  950. then
  951. return
  952. fi
  953. fi
  954. # handle local downloads
  955. #
  956. case "${src_name%_*}" in
  957. "blacklist"|"whitelist")
  958. awk "${src_rule}" "${src_url}" > "${tmp_file}"
  959. src_rc="${?}"
  960. if [ "${src_rc}" = "0" ]
  961. then
  962. f_ipset "create"
  963. else
  964. f_log "debug" "f_down ::: name: ${src_name}, url: ${src_url}, rule: ${src_rule}, rc: ${src_rc}"
  965. fi
  966. return
  967. ;;
  968. "maclist")
  969. src_name="${src_name%_*}"
  970. tmp_file="${ban_tmpfile}.${src_name}.file"
  971. tmp_cnt="${tmp_file}.cnt"
  972. tmp_err="${tmp_file}.err"
  973. awk "${src_rule}" "${src_url}" > "${tmp_file}"
  974. src_rc="${?}"
  975. if [ "${src_rc}" = "0" ]
  976. then
  977. f_ipset "create"
  978. else
  979. f_log "debug" "f_down ::: name: ${src_name}, url: ${src_url}, rule: ${src_rule}, rc: ${src_rc}"
  980. fi
  981. return
  982. ;;
  983. esac
  984. # 'refresh' mode
  985. #
  986. if [ "${ban_action}" = "refresh" ]
  987. then
  988. f_ipset "refresh"
  989. src_rc="${?}"
  990. if [ "${src_rc}" = "0" ]
  991. then
  992. return
  993. fi
  994. fi
  995. # 'start' mode
  996. #
  997. if [ "${ban_action}" = "start" ]
  998. then
  999. f_ipset "restore"
  1000. fi
  1001. src_rc="${?}"
  1002. if [ "${src_rc}" = "0" ]
  1003. then
  1004. awk "${src_rule}" "${tmp_load}" 2>/dev/null > "${tmp_file}"
  1005. src_rc="${?}"
  1006. if [ "${src_rc}" = "0" ]
  1007. then
  1008. f_ipset "create"
  1009. src_rc="${?}"
  1010. if [ "${src_rc}" = "0" ]
  1011. then
  1012. return
  1013. fi
  1014. fi
  1015. fi
  1016. # handle country related downloads
  1017. #
  1018. if [ "${src_name%_*}" = "country" ]
  1019. then
  1020. for country in ${ban_countries}
  1021. do
  1022. src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}${country}-aggregated.zone" 2>&1)"
  1023. src_rc="${?}"
  1024. if [ "${src_rc}" = "0" ]
  1025. then
  1026. cat "${tmp_raw}" 2>/dev/null >> "${tmp_load}"
  1027. else
  1028. continue
  1029. fi
  1030. done
  1031. # handle asn related downloads
  1032. #
  1033. elif [ "${src_name%_*}" = "asn" ]
  1034. then
  1035. for asn in ${ban_asns}
  1036. do
  1037. src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}AS${asn}" 2>&1)"
  1038. src_rc="${?}"
  1039. if [ "${src_rc}" = "0" ]
  1040. then
  1041. cat "${tmp_raw}" 2>/dev/null >> "${tmp_load}"
  1042. else
  1043. continue
  1044. fi
  1045. done
  1046. # handle compressed downloads
  1047. #
  1048. elif [ -n "${src_comp}" ]
  1049. then
  1050. case "${src_comp}" in
  1051. "gz")
  1052. src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_raw}" "${src_url}" 2>&1)"
  1053. src_rc="${?}"
  1054. if [ "${src_rc}" -eq 0 ]
  1055. then
  1056. zcat "${tmp_raw}" 2>/dev/null > "${tmp_load}"
  1057. src_rc="${?}"
  1058. fi
  1059. ;;
  1060. esac
  1061. # handle normal downloads
  1062. #
  1063. else
  1064. src_log="$("${ban_fetchutil}" ${ban_fetchparm} "${tmp_load}" "${src_url}" 2>&1)"
  1065. src_rc="${?}"
  1066. fi
  1067. # download post-processing (backup, restore, regex)
  1068. #
  1069. if [ "${src_rc}" = "0" ]
  1070. then
  1071. f_ipset "backup"
  1072. src_rc="${?}"
  1073. elif [ "${ban_action}" != "start" ] && [ "${ban_action}" != "refresh" ]
  1074. then
  1075. f_ipset "restore"
  1076. src_rc="${?}"
  1077. fi
  1078. if [ "${src_rc}" = "0" ]
  1079. then
  1080. awk "${src_rule}" "${tmp_load}" 2>/dev/null > "${tmp_file}"
  1081. src_rc="${?}"
  1082. if [ "${src_rc}" = "0" ]
  1083. then
  1084. f_ipset "create"
  1085. src_rc="${?}"
  1086. elif [ "${ban_action}" != "refresh" ]
  1087. then
  1088. f_ipset "refresh"
  1089. src_rc="${?}"
  1090. fi
  1091. else
  1092. src_log="$(printf "%s" "${src_log}" | awk '{ORS=" ";print $0}')"
  1093. if [ "${ban_action}" != "refresh" ]
  1094. then
  1095. f_ipset "refresh"
  1096. src_rc="${?}"
  1097. fi
  1098. f_log "debug" "f_down ::: name: ${src_name}, url: ${src_url}, rule: ${src_rule}, rc: ${src_rc}, log: ${src_log:-"-"}"
  1099. fi
  1100. }
  1101. # main controller
  1102. #
  1103. f_main()
  1104. {
  1105. local src_name src_url_4 src_rule_4 src_url_6 src_rule_6 src_comp src_rc src_ts log_raw log_merge log_ips log_count hold err_file cnt_file cnt=0
  1106. # prepare logfile excerpts (dropbear, sshd, luci)
  1107. #
  1108. if [ "${ban_autoblacklist}" = "1" ] || [ "${ban_monitor_enabled}" = "1" ]
  1109. then
  1110. log_raw="$(${ban_logread} -l "${ban_loglimit}")"
  1111. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "dropbear")" ]
  1112. then
  1113. log_ips="$(printf "%s\n" "${log_raw}" | grep -E "Exit before auth from" | \
  1114. awk 'match($0,/<[0-9A-f:\.]+:/){printf "%s\n",substr($0,RSTART+1,RLENGTH-2)}' | awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
  1115. for ip in ${log_ips}
  1116. do
  1117. log_count="$(printf "%s\n" "${log_raw}" | grep -cE "Exit before auth from <${ip}")"
  1118. if [ "${log_count}" -ge "${ban_ssh_logcount}" ]
  1119. then
  1120. log_merge="${log_merge} ${ip}"
  1121. fi
  1122. done
  1123. fi
  1124. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "sshd")" ]
  1125. then
  1126. log_ips="$(printf "%s\n" "${log_raw}" | grep -E "error: maximum authentication attempts exceeded|sshd.*Connection closed by.*\[preauth\]" | \
  1127. awk 'match($0,/[0-9A-f:\.]+ port/){printf "%s\n",substr($0,RSTART,RLENGTH-5)}' | awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
  1128. for ip in ${log_ips}
  1129. do
  1130. log_count="$(printf "%s\n" "${log_raw}" | grep -cE "error: maximum authentication attempts exceeded.*${ip}|sshd.*Connection closed by.*${ip}.*\[preauth\]")"
  1131. if [ "${log_count}" -ge "${ban_ssh_logcount}" ]
  1132. then
  1133. log_merge="${log_merge} ${ip}"
  1134. fi
  1135. done
  1136. fi
  1137. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "luci")" ]
  1138. then
  1139. log_ips="$(printf "%s\n" "${log_raw}" | grep -E "luci: failed login on " | \
  1140. awk 'match($0,/[0-9A-f:\.]+$/){printf "%s\n",substr($0,RSTART,RLENGTH)}' | awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
  1141. for ip in ${log_ips}
  1142. do
  1143. log_count="$(printf "%s\n" "${log_raw}" | grep -cE "luci: failed login on .*from ${ip}")"
  1144. if [ "${log_count}" -ge "${ban_luci_logcount}" ]
  1145. then
  1146. log_merge="${log_merge} ${ip}"
  1147. fi
  1148. done
  1149. fi
  1150. if [ -n "$(printf "%s\n" "${ban_logterms}" | grep -F "nginx")" ]
  1151. then
  1152. log_ips="$(printf "%s\n" "${log_raw}" | grep -oE "nginx\[[0-9]+\]:.*\[error\].*open().*client: [[:alnum:].:]+" | \
  1153. awk '!seen[$NF]++' | awk '{ORS=" ";print $NF}')"
  1154. for ip in ${log_ips}
  1155. do
  1156. log_count="$(printf "%s\n" "${log_raw}" | grep -cE "nginx\[[0-9]+\]:.*\[error\].*open().*client: ${ip}")"
  1157. if [ "${log_count}" -ge "${ban_nginx_logcount}" ]
  1158. then
  1159. log_merge="${log_merge} ${ip}"
  1160. fi
  1161. done
  1162. fi
  1163. fi
  1164. # prepare new black- and whitelist entries
  1165. #
  1166. if [ "${ban_autowhitelist}" = "1" ] && [ -f "${ban_whitelist}" ]
  1167. then
  1168. for ip in ${ban_subnets}
  1169. do
  1170. if [ -z "$(grep -F "${ip}" "${ban_whitelist}")" ]
  1171. then
  1172. src_ts="# added on $(date "+%d.%m.%Y %H:%M:%S")"
  1173. printf "%-42s%s\n" "${ip}" "${src_ts}" >> "${ban_whitelist}"
  1174. f_log "info" "IP address '${ip}' added to whitelist"
  1175. fi
  1176. done
  1177. fi
  1178. if [ "${ban_autoblacklist}" = "1" ] && [ -f "${ban_blacklist}" ]
  1179. then
  1180. for ip in ${log_merge}
  1181. do
  1182. if [ -z "$(grep -F "${ip}" "${ban_blacklist}")" ]
  1183. then
  1184. src_ts="# added on $(date "+%d.%m.%Y %H:%M:%S")"
  1185. printf "%-42s%s\n" "${ip}" "${src_ts}" >> "${ban_blacklist}"
  1186. f_log "info" "IP address '${ip}' added to blacklist"
  1187. fi
  1188. done
  1189. fi
  1190. # initial ipset/iptables creation
  1191. #
  1192. f_ipset "initial"
  1193. if [ "${?}" != "0" ]
  1194. then
  1195. f_log "err" "banIP processing failed, fatal error during ipset/iptables creation (${ban_sysver})"
  1196. fi
  1197. # load local source files (maclist, blacklist, whitelist)
  1198. #
  1199. for src_name in ${ban_localsources}
  1200. do
  1201. if [ "${src_name}" = "maclist" ] && [ -s "${ban_maclist}" ]
  1202. then
  1203. (
  1204. src_rule_4="/^([0-9A-z][0-9A-z]:){5}[0-9A-z]{2}([[:space:]]|$)/{print \"add ${src_name} \"toupper(\$1)}"
  1205. f_down "${src_name}" "mac" "mac" "${ban_maclist}" "${src_rule_4}"
  1206. )&
  1207. fi
  1208. if [ "${ban_proto4_enabled}" = "1" ]
  1209. then
  1210. if [ "${src_name}" = "blacklist" ] && [ -s "${ban_blacklist}" ]
  1211. then
  1212. (
  1213. src_rule_4="/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add ${src_name}_4 \"\$1}"
  1214. f_down "${src_name}" "4" "inet" "${ban_blacklist}" "${src_rule_4}"
  1215. )&
  1216. elif [ "${src_name}" = "whitelist" ] && [ -s "${ban_whitelist}" ]
  1217. then
  1218. (
  1219. src_rule_4="/^(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]|$)/{print \"add ${src_name}_4 \"\$1}"
  1220. f_down "${src_name}" "4" "inet" "${ban_whitelist}" "${src_rule_4}"
  1221. )&
  1222. fi
  1223. fi
  1224. if [ "${ban_proto6_enabled}" = "1" ]
  1225. then
  1226. if [ "${src_name}" = "blacklist" ] && [ -s "${ban_blacklist}" ]
  1227. then
  1228. (
  1229. src_rule_6="/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add ${src_name}_6 \"\$1}"
  1230. f_down "${src_name}" "6" "inet6" "${ban_blacklist}" "${src_rule_6}"
  1231. )&
  1232. elif [ "${src_name}" = "whitelist" ] && [ -s "${ban_whitelist}" ]
  1233. then
  1234. (
  1235. src_rule_6="/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)([[:space:]]|$)/{print \"add ${src_name}_6 \"\$1}"
  1236. f_down "${src_name}" "6" "inet6" "${ban_whitelist}" "${src_rule_6}"
  1237. )&
  1238. fi
  1239. fi
  1240. done
  1241. wait
  1242. # loop over all external sources
  1243. #
  1244. for src_name in ${ban_sources}
  1245. do
  1246. # get source data from JSON file
  1247. #
  1248. json_select "${src_name}" >/dev/null 2>&1
  1249. if [ "${?}" != "0" ]
  1250. then
  1251. continue
  1252. fi
  1253. json_objects="url_4 rule_4 url_6 rule_6 comp"
  1254. for object in ${json_objects}
  1255. do
  1256. eval json_get_var src_${object} "\${object}" >/dev/null 2>&1
  1257. done
  1258. json_select ..
  1259. # handle external IPv4 source downloads in a subshell
  1260. #
  1261. if [ "${ban_proto4_enabled}" = "1" ] && [ -n "${src_url_4}" ] && [ -n "${src_rule_4}" ]
  1262. then
  1263. (
  1264. f_down "${src_name}" "4" "inet" "${src_url_4}" "${src_rule_4}" "${src_comp}"
  1265. )&
  1266. fi
  1267. # handle external IPv6 source downloads in a subshell
  1268. #
  1269. if [ "${ban_proto6_enabled}" = "1" ] && [ -n "${src_url_6}" ] && [ -n "${src_rule_6}" ]
  1270. then
  1271. (
  1272. f_down "${src_name}" "6" "inet6" "${src_url_6}" "${src_rule_6}" "${src_comp}"
  1273. )&
  1274. fi
  1275. # control/limit download queues
  1276. #
  1277. hold=$((cnt%ban_maxqueue))
  1278. if [ "${hold}" = "0" ]
  1279. then
  1280. wait
  1281. fi
  1282. cnt=$((cnt+1))
  1283. done
  1284. wait
  1285. # error out
  1286. #
  1287. for err_file in "${ban_tmpfile}."*".err"
  1288. do
  1289. if [ -f "${err_file}" ]
  1290. then
  1291. f_log "err" "banIP processing failed, fatal iptables errors during subshell processing (${ban_sysver})"
  1292. fi
  1293. done
  1294. # finish processing
  1295. #
  1296. ban_sources=""
  1297. for cnt_file in "${ban_tmpfile}."*".cnt"
  1298. do
  1299. if [ -f "${cnt_file}" ]
  1300. then
  1301. read -r cnt < "${cnt_file}"
  1302. ban_cnt=$((ban_cnt+cnt))
  1303. ban_setcnt=$((ban_setcnt+1))
  1304. src_name="$(printf "%s" "${cnt_file}" | grep -Eo "[a-z0-9_]+.file.cnt")"
  1305. src_name="${src_name%%.*}"
  1306. if [ -z "$(printf "%s" "${ban_sources}" | grep -F "${src_name%_*}")" ]
  1307. then
  1308. ban_sources="${ban_sources} ${src_name%_*}"
  1309. ban_allsources="${ban_allsources/${src_name%_*}/}"
  1310. fi
  1311. fi
  1312. done
  1313. for src_name in ${ban_allsources}
  1314. do
  1315. if [ "${src_name}" = "maclist" ]
  1316. then
  1317. f_ipset "flush"
  1318. else
  1319. for proto in "4" "6"
  1320. do
  1321. src_name="${src_name%_*}_${proto}"
  1322. f_ipset "flush"
  1323. if [ "${src_name%_*}" != "blacklist" ] && [ "${src_name%_*}" != "whitelist" ]
  1324. then
  1325. f_ipset "remove"
  1326. fi
  1327. done
  1328. fi
  1329. done
  1330. f_log "info" "${ban_setcnt} IPSets with overall ${ban_cnt} IPs/Prefixes loaded successfully (${ban_sysver})"
  1331. f_jsnup
  1332. f_rmtmp
  1333. f_bgsrv "start"
  1334. }
  1335. # query ipsets for certain IP
  1336. #
  1337. f_query()
  1338. {
  1339. local src proto result query_start query_end query_timeout="30" match="0" search="${1}"
  1340. if [ -z "${search}" ]
  1341. then
  1342. printf "%s\n" "::: missing search term, please submit a single ip or mac address :::"
  1343. else
  1344. query_start="$(date "+%s")"
  1345. printf "%s\n%s\n%s\n" ":::" "::: search '${search}' in banIP related IPSets" ":::"
  1346. for src in ${ban_localsources} ${ban_sources} ${ban_extrasources}
  1347. do
  1348. if [ "${src}" = "maclist" ] && [ -n "$("${ban_ipset_cmd}" -q -n list "${src}")" ]
  1349. then
  1350. result="$(ipset -q test ${src} ${search} >/dev/null 2>&1; printf "%u" "${?}")"
  1351. if [ "${result}" = "0" ]
  1352. then
  1353. match="1"
  1354. printf "%s\n" " - found in IPSet '${src}'"
  1355. break
  1356. fi
  1357. else
  1358. for proto in "4" "6"
  1359. do
  1360. if [ -n "$("${ban_ipset_cmd}" -q -n list "${src}_${proto}")" ]
  1361. then
  1362. result="$(ipset -q test ${src}_${proto} ${search} >/dev/null 2>&1; printf "%u" "${?}")"
  1363. if [ "${result}" = "0" ]
  1364. then
  1365. match="1"
  1366. printf "%s\n" " - found in IPSet '${src}_${proto}'"
  1367. fi
  1368. fi
  1369. done
  1370. fi
  1371. query_end="$(date "+%s")"
  1372. if [ "$((query_end-query_start))" -gt "${query_timeout}" ]
  1373. then
  1374. printf "%s\n\n" " - [...]"
  1375. break
  1376. fi
  1377. done
  1378. if [ "${match}" = "0" ]
  1379. then
  1380. printf "%s\n\n" " - no match"
  1381. fi
  1382. fi
  1383. }
  1384. # generate statistics
  1385. #
  1386. f_report()
  1387. {
  1388. local report_json report_txt bg_pid content proto src src_list cnt cnt_mac cnt_cidr cnt_ip cnt_acc cnt_sum="0" cnt_set_sum="1" cnt_acc_sum="0" cnt_mac_sum="0" cnt_ip_sum="0" cnt_cidr_sum="0" cnt_set_sum="0" action="${1}"
  1389. report_json="${ban_reportdir}/ban_report.json"
  1390. report_txt="${ban_reportdir}/ban_mailreport.txt"
  1391. # build json file
  1392. #
  1393. if [ "${action}" != "json" ] && { [ -n "$("${ban_ipt4_savecmd}" | grep " ${ban_chain} ")" ] || [ -n "$("${ban_ipt6_savecmd}" | grep " ${ban_chain} ")" ]; }
  1394. then
  1395. > "${report_json}"
  1396. > "${report_txt}"
  1397. printf "%s\n" "{" >> "${report_json}"
  1398. printf "\t%s\n" "\"ipsets\": {" >> "${report_json}"
  1399. for src in ${ban_localsources} ${ban_sources} ${ban_extrasources}
  1400. do
  1401. if [ -n "$(printf "%s" "${ban_extrasources}" | grep -F "${src}")" ]
  1402. then
  1403. set_type="n/a"
  1404. else
  1405. if [ -n "$(printf "%s\n" "${ban_settype_src}" | grep -F "${src}")" ]
  1406. then
  1407. set_type="src"
  1408. elif [ -n "$(printf "%s\n" "${ban_settype_dst}" | grep -F "${src}")" ]
  1409. then
  1410. set_type="dst"
  1411. elif [ -n "$(printf "%s\n" "${ban_settype_all}" | grep -F "${src}")" ]
  1412. then
  1413. set_type="src+dst"
  1414. else
  1415. set_type="${ban_global_settype}"
  1416. fi
  1417. fi
  1418. if [ "${src}" = "maclist" ]
  1419. then
  1420. src_list="$("${ban_ipset_cmd}" -q list "${src}")"
  1421. if [ -n "${src_list}" ]
  1422. then
  1423. cnt="$(printf "%s" "${src_list}" | awk '/^Number of entries:/{print $4}')"
  1424. cnt_acc="$(printf "%s" "${src_list}" | grep -cE " packets [1-9]+")"
  1425. cnt_acc_sum=$((cnt_acc_sum+cnt_acc))
  1426. cnt_mac_sum="${cnt}"
  1427. cnt_sum=$((cnt_sum+cnt))
  1428. if [ "${cnt_set_sum}" != "0" ]
  1429. then
  1430. printf "%s\n" "," >> "${report_json}"
  1431. fi
  1432. printf "\t\t%s\n" "\"${src}\": {" >> "${report_json}"
  1433. printf "\t\t\t%s\n" "\"type\": \"${set_type}\"," >> "${report_json}"
  1434. printf "\t\t\t%s\n" "\"count\": \"${cnt}\"," >> "${report_json}"
  1435. printf "\t\t\t%s\n" "\"count_ip\": \"0\"," >> "${report_json}"
  1436. printf "\t\t\t%s\n" "\"count_cidr\": \"0\"," >> "${report_json}"
  1437. printf "\t\t\t%s\n" "\"count_mac\": \"${cnt}\"," >> "${report_json}"
  1438. printf "\t\t\t%s" "\"count_acc\": \"${cnt_acc}\"" >> "${report_json}"
  1439. printf ",\n\t\t\t%s" "\"member_acc\": [" >> "${report_json}"
  1440. printf "%s" "${src_list}" | awk 'match($0,/ packets [1-9]+/){printf "%s %s\n",$1,substr($0,RSTART+9,RLENGTH-9)}' | \
  1441. awk 'BEGIN{i=0};{i=i+1;if(i==1){printf "\n\t\t\t\t\t{\n\t\t\t\t\t\t\"member\": \"%s\",\n\t\t\t\t\t\t\"packets\": \"%s\"\n\t\t\t\t\t}",$1,$2}else{printf ",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"member\": \"%s\",\n\t\t\t\t\t\t\t\"packets\": \"%s\"\n\t\t\t\t\t\t}",$1,$2}}' >> "${report_json}"
  1442. printf "\n\t\t\t%s\n" "]" >> "${report_json}"
  1443. printf "\t\t%s" "}" >> "${report_json}"
  1444. cnt_set_sum=$((cnt_set_sum+1))
  1445. fi
  1446. else
  1447. for proto in "4" "6"
  1448. do
  1449. src_list="$("${ban_ipset_cmd}" -q list "${src}_${proto}")"
  1450. if [ -n "${src_list}" ]
  1451. then
  1452. cnt="$(printf "%s\n" "${src_list}" | awk '/^Number of entries:/{print $4}')"
  1453. cnt_cidr="$(printf "%s\n" "${src_list}" | grep -cE "/[0-9]{1,3} packets [0-9]+")"
  1454. cnt_ip=$((cnt-cnt_cidr-cnt_mac))
  1455. cnt_acc="$(printf "%s\n" "${src_list}" | grep -cE " packets [1-9]+")"
  1456. cnt_cidr_sum=$((cnt_cidr_sum+cnt_cidr))
  1457. cnt_ip_sum=$((cnt_ip_sum+cnt_ip))
  1458. cnt_acc_sum=$((cnt_acc_sum+cnt_acc))
  1459. cnt_sum=$((cnt_sum+cnt))
  1460. if [ "${cnt_set_sum}" != "0" ]
  1461. then
  1462. printf "%s\n" "," >> "${report_json}"
  1463. fi
  1464. printf "\t\t%s\n" "\"${src}_${proto}\": {" >> "${report_json}"
  1465. printf "\t\t\t%s\n" "\"type\": \"${set_type}\"," >> "${report_json}"
  1466. printf "\t\t\t%s\n" "\"count\": \"${cnt}\"," >> "${report_json}"
  1467. printf "\t\t\t%s\n" "\"count_ip\": \"${cnt_ip}\"," >> "${report_json}"
  1468. printf "\t\t\t%s\n" "\"count_cidr\": \"${cnt_cidr}\"," >> "${report_json}"
  1469. printf "\t\t\t%s\n" "\"count_mac\": \"0\"," >> "${report_json}"
  1470. printf "\t\t\t%s" "\"count_acc\": \"${cnt_acc}\"" >> "${report_json}"
  1471. printf ",\n\t\t\t%s" "\"member_acc\": [" >> "${report_json}"
  1472. printf "%s" "${src_list}" | awk 'match($0,/ packets [1-9]+/){printf "%s %s\n",$1,substr($0,RSTART+9,RLENGTH-9)}' | \
  1473. awk 'BEGIN{i=0};{i=i+1;if(i==1){printf "\n\t\t\t\t\t{\n\t\t\t\t\t\t\"member\": \"%s\",\n\t\t\t\t\t\t\"packets\": \"%s\"\n\t\t\t\t\t}",$1,$2}else{printf ",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"member\": \"%s\",\n\t\t\t\t\t\t\t\"packets\": \"%s\"\n\t\t\t\t\t\t}",$1,$2}}' >> "${report_json}"
  1474. printf "\n\t\t\t%s\n" "]" >> "${report_json}"
  1475. printf "\t\t%s" "}" >> "${report_json}"
  1476. cnt_set_sum=$((cnt_set_sum+1))
  1477. fi
  1478. done
  1479. fi
  1480. done
  1481. printf "\n\t%s" "}" >> "${report_json}"
  1482. printf ",\n\t%s\n" "\"timestamp\": \"$(date "+%d.%m.%Y %H:%M:%S")\"," >> "${report_json}"
  1483. printf "\t%s\n" "\"cnt_set_sum\": \"${cnt_set_sum}\"," >> "${report_json}"
  1484. printf "\t%s\n" "\"cnt_ip_sum\": \"${cnt_ip_sum}\"," >> "${report_json}"
  1485. printf "\t%s\n" "\"cnt_cidr_sum\": \"${cnt_cidr_sum}\"," >> "${report_json}"
  1486. printf "\t%s\n" "\"cnt_mac_sum\": \"${cnt_mac_sum}\"," >> "${report_json}"
  1487. printf "\t%s\n" "\"cnt_sum\": \"${cnt_sum}\"," >> "${report_json}"
  1488. printf "\t%s\n" "\"cnt_acc_sum\": \"${cnt_acc_sum}\"" >> "${report_json}"
  1489. printf "%s\n" "}" >> "${report_json}"
  1490. fi
  1491. # output preparation
  1492. #
  1493. if [ -s "${report_json}" ] && { [ "${action}" = "cli" ] || [ "${action}" = "mail" ]; }
  1494. then
  1495. printf "%s\n%s\n%s\n" ":::" "::: report on all banIP related IPSets" ":::" >> "${report_txt}"
  1496. json_load_file "${report_json}" >/dev/null 2>&1
  1497. json_get_var value "timestamp" >/dev/null 2>&1
  1498. printf " + %s\n" "Report timestamp ::: ${value}" >> "${report_txt}"
  1499. json_get_var value "cnt_set_sum" >/dev/null 2>&1
  1500. printf " + %s\n" "Number of all IPSets ::: ${value:-"0"}" >> "${report_txt}"
  1501. json_get_var value "cnt_sum" >/dev/null 2>&1
  1502. printf " + %s\n" "Number of all entries ::: ${value:-"0"}" >> "${report_txt}"
  1503. json_get_var value "cnt_ip_sum" >/dev/null 2>&1
  1504. printf " + %s\n" "Number of IP entries ::: ${value:-"0"}" >> "${report_txt}"
  1505. json_get_var value "cnt_cidr_sum" >/dev/null 2>&1
  1506. printf " + %s\n" "Number of CIDR entries ::: ${value:-"0"}" >> "${report_txt}"
  1507. json_get_var value "cnt_mac_sum" >/dev/null 2>&1
  1508. printf " + %s\n" "Number of MAC entries ::: ${value:-"0"}" >> "${report_txt}"
  1509. json_get_var value "cnt_acc_sum" >/dev/null 2>&1
  1510. printf " + %s\n" "Number of accessed entries ::: ${value:-"0"}" >> "${report_txt}"
  1511. json_select "ipsets"
  1512. json_get_keys ipsetlist
  1513. if [ -n "${ipsetlist}" ]
  1514. then
  1515. printf "%s\n%s\n%s\n" ":::" "::: IPSet details" ":::" >> "${report_txt}"
  1516. printf "%-25s%-12s%-11s%-10s%-10s%-10s%-10s%s\n" " Name" "Type" "Count" "Cnt_IP" "Cnt_CIDR" "Cnt_MAC" "Cnt_ACC" "Entry details (Entry/Count)" >> "${report_txt}"
  1517. printf "%s\n" " --------------------------------------------------------------------------------------------------------------------" >> "${report_txt}"
  1518. fi
  1519. for ipset in ${ipsetlist}
  1520. do
  1521. set_info="${ipset}"
  1522. acc_info=""
  1523. json_select "${ipset}"
  1524. json_get_keys detaillist
  1525. for detail in ${detaillist}
  1526. do
  1527. if [ "${detail}" != "member_acc" ]
  1528. then
  1529. json_get_var value "${detail}" >/dev/null 2>&1
  1530. set_info="${set_info} ${value}"
  1531. elif [ "${detail}" = "member_acc" ]
  1532. then
  1533. index=1
  1534. json_select "${detail}"
  1535. while json_get_type type "${index}" && [ "${type}" = "object" ]
  1536. do
  1537. json_get_values values "${index}" >/dev/null 2>&1
  1538. acc_info="${acc_info} ${values}"
  1539. index=$((index+1))
  1540. done
  1541. json_select ".."
  1542. fi
  1543. done
  1544. printf " %-21s%-12s%-11s%-10s%-10s%-10s%s\n" ${set_info} >> "${report_txt}"
  1545. if [ -n "${acc_info}" ]
  1546. then
  1547. printf " %-25s%s\n" ${acc_info} >> "${report_txt}"
  1548. fi
  1549. printf "%s\n" " --------------------------------------------------------------------------------------------------------------------" >> "${report_txt}"
  1550. json_select ".."
  1551. done
  1552. content="$(cat "${report_txt}" 2>/dev/null)"
  1553. fi
  1554. # report output
  1555. #
  1556. if [ "${action}" = "cli" ]
  1557. then
  1558. printf "%s\n" "${content}"
  1559. elif [ "${action}" = "json" ]
  1560. then
  1561. cat "${ban_reportdir}/ban_report.json"
  1562. elif [ "${action}" = "mail" ] && [ "${ban_mail_enabled}" = "1" ] && [ -x "${ban_mailservice}" ]
  1563. then
  1564. ( "${ban_mailservice}" "${ban_ver}" "${content}" >/dev/null 2>&1 )&
  1565. bg_pid="${!}"
  1566. fi
  1567. f_log "debug" "f_report ::: action: ${action}, report_json: ${report_json}, report_txt: ${report_txt}, bg_pid: ${bg_pid:-"-"}"
  1568. }
  1569. # update runtime information
  1570. #
  1571. f_jsnup()
  1572. {
  1573. local memory entry runtime cnt_info status="${1:-"enabled"}"
  1574. if [ "${status}" = "enabled" ] || [ "${status}" = "error" ]
  1575. then
  1576. ban_endtime="$(date "+%s")"
  1577. cnt_info="${ban_setcnt} IPSets with ${ban_cnt} IPs/Prefixes"
  1578. memory="$(awk '/^MemTotal|^MemFree|^MemAvailable/{ORS="/"; print int($2/1000)}' "/proc/meminfo" 2>/dev/null | awk '{print substr($0,1,length($0)-1)}')"
  1579. if [ "$(( (ban_endtime-ban_starttime)/60 ))" -lt "60" ]
  1580. then
  1581. runtime="${ban_action}, $(( (ban_endtime-ban_starttime)/60 ))m $(( (ban_endtime-ban_starttime)%60 ))s, ${memory:-0}, $(date "+%d.%m.%Y %H:%M:%S")"
  1582. else
  1583. runtime="${ban_action}, n/a, ${memory:-0}, $(date "+%d.%m.%Y %H:%M:%S")"
  1584. fi
  1585. fi
  1586. > "${ban_rtfile}"
  1587. json_load_file "${ban_rtfile}" >/dev/null 2>&1
  1588. json_init
  1589. json_add_string "status" "${status}"
  1590. json_add_string "version" "${ban_ver}"
  1591. json_add_string "ipset_info" "${cnt_info:-"-"}"
  1592. json_add_array "active_sources"
  1593. if [ "${status}" = "running" ] || [ "${status}" = "error" ]
  1594. then
  1595. json_add_object
  1596. json_add_string "source" "-"
  1597. json_close_object
  1598. else
  1599. for entry in ${ban_sources}
  1600. do
  1601. json_add_object
  1602. json_add_string "source" "${entry}"
  1603. json_close_object
  1604. done
  1605. fi
  1606. json_close_array
  1607. json_add_array "active_devs"
  1608. for entry in ${ban_devs}
  1609. do
  1610. json_add_object
  1611. json_add_string "dev" "${entry}"
  1612. json_close_object
  1613. done
  1614. json_close_array
  1615. json_add_array "active_ifaces"
  1616. for entry in ${ban_ifaces}
  1617. do
  1618. json_add_object
  1619. json_add_string "iface" "${entry}"
  1620. json_close_object
  1621. done
  1622. json_close_array
  1623. json_add_array "active_logterms"
  1624. for entry in ${ban_logterms}
  1625. do
  1626. json_add_object
  1627. json_add_string "term" "${entry}"
  1628. json_close_object
  1629. done
  1630. json_close_array
  1631. json_add_array "active_subnets"
  1632. for entry in ${ban_subnets}
  1633. do
  1634. json_add_object
  1635. json_add_string "subnet" "${entry}"
  1636. json_close_object
  1637. done
  1638. json_close_array
  1639. json_add_string "run_infos" "settype: ${ban_global_settype}, backup_dir: ${ban_backupdir}, report_dir: ${ban_reportdir}"
  1640. json_add_string "run_flags" "protocols (4/6): $(f_char ${ban_proto4_enabled})/$(f_char ${ban_proto6_enabled}), log (src/dst): $(f_char ${ban_logsrc_enabled})/$(f_char ${ban_logdst_enabled}), monitor: $(f_char ${ban_monitor_enabled}), mail: $(f_char ${ban_mail_enabled})"
  1641. json_add_string "last_run" "${runtime:-"-"}"
  1642. json_add_string "system" "${ban_sysver}"
  1643. json_dump > "${ban_rtfile}"
  1644. if [ "${ban_mail_enabled}" = "1" ] && [ -x "${ban_mailservice}" ] && { [ "${status}" = "error" ] || \
  1645. { [ "${status}" = "enabled" ] && { [ -z "${ban_mailactions}" ] || [ -n "$(printf "%s\n" "${ban_mailactions}" | grep -F "${ban_action}")" ]; }; }; }
  1646. then
  1647. ( "${ban_mailservice}" "${ban_ver}" >/dev/null 2>&1 )&
  1648. bg_pid="${!}"
  1649. fi
  1650. f_log "debug" "f_jsnup ::: status: ${status:-"-"}, action: ${ban_action}, mail_enabled: ${ban_mail_enabled}, mail_actions: ${ban_mailactions}, mail_service: ${ban_mailservice}, mail_pid: ${bg_pid:-"-"}"
  1651. }
  1652. # source required system libraries
  1653. #
  1654. if [ -r "/lib/functions.sh" ] && [ -r "/lib/functions/network.sh" ] && [ -r "/usr/share/libubox/jshn.sh" ]
  1655. then
  1656. . "/lib/functions.sh"
  1657. . "/lib/functions/network.sh"
  1658. . "/usr/share/libubox/jshn.sh"
  1659. else
  1660. f_log "err" "system libraries not found"
  1661. fi
  1662. if [ "${ban_action}" = "suspend" ] || [ "${ban_action}" = "resume" ] || \
  1663. [ "${ban_action}" = "report" ] || [ "${ban_action}" = "query" ]
  1664. then
  1665. json_load_file "${ban_rtfile}" >/dev/null 2>&1
  1666. json_get_var ban_status "status"
  1667. fi
  1668. # version information
  1669. #
  1670. if [ "${ban_action}" = "version" ]
  1671. then
  1672. printf "%s\n" "${ban_ver}"
  1673. exit 0
  1674. fi
  1675. # handle different banIP actions
  1676. #
  1677. f_load
  1678. case "${ban_action}" in
  1679. "stop")
  1680. f_bgsrv "stop"
  1681. f_ipset "destroy"
  1682. f_jsnup "stopped"
  1683. f_rmbckp
  1684. ;;
  1685. "restart")
  1686. f_ipset "destroy"
  1687. f_rmbckp
  1688. f_env
  1689. f_main
  1690. ;;
  1691. "suspend")
  1692. if [ "${ban_status}" = "enabled" ]
  1693. then
  1694. f_bgsrv "stop"
  1695. f_jsnup "running"
  1696. f_ipset "suspend"
  1697. f_jsnup "paused"
  1698. fi
  1699. f_rmtmp
  1700. ;;
  1701. "resume")
  1702. if [ "${ban_status}" = "paused" ]
  1703. then
  1704. f_env
  1705. f_main
  1706. else
  1707. f_rmtmp
  1708. fi
  1709. ;;
  1710. "query")
  1711. if [ "${ban_status}" = "enabled" ]
  1712. then
  1713. f_query "${2}"
  1714. fi
  1715. ;;
  1716. "report")
  1717. if [ "${ban_status}" = "enabled" ] || [ "${2}" = "json" ]
  1718. then
  1719. f_report "${2}"
  1720. fi
  1721. ;;
  1722. "start"|"reload"|"refresh")
  1723. f_env
  1724. f_main
  1725. ;;
  1726. esac