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.

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