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.

1363 lines
40 KiB

  1. #!/bin/sh
  2. # dns based ad/abuse domain blocking
  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. adb_ver="3.8.9"
  14. adb_basever=""
  15. adb_enabled=0
  16. adb_debug=0
  17. adb_forcedns=0
  18. adb_maxqueue=4
  19. adb_mail=0
  20. adb_mcnt=0
  21. adb_trigger="wan"
  22. adb_triggerdelay=0
  23. adb_backupdir="/tmp"
  24. adb_fetchutil="uclient-fetch"
  25. adb_dns="dnsmasq"
  26. adb_dnsvariant="nxdomain"
  27. adb_dnsprefix="adb_list"
  28. adb_dnsfile="${adb_dnsprefix}.overall"
  29. adb_dnsfilereset="false"
  30. adb_maxtld=100000
  31. adb_dnsflush=0
  32. adb_blacklist="/etc/adblock/adblock.blacklist"
  33. adb_whitelist="/etc/adblock/adblock.whitelist"
  34. adb_rtfile="/tmp/adb_runtime.json"
  35. adb_portlist="53 853 5353"
  36. adb_report=0
  37. adb_repiface="br-lan"
  38. adb_replisten="53"
  39. adb_repdir="/tmp"
  40. adb_reputil="$(command -v tcpdump)"
  41. adb_repchunkcnt="5"
  42. adb_repchunksize="1"
  43. adb_logger="$(command -v logger)"
  44. adb_action="${1:-"start"}"
  45. adb_pidfile="/var/run/adblock.pid"
  46. adb_ubusservice="/etc/adblock/adblock.service"
  47. adb_mailservice="/etc/adblock/adblock.mail"
  48. adb_sources=""
  49. adb_cnt=""
  50. # load adblock environment
  51. #
  52. f_load()
  53. {
  54. local dns_up cnt=0
  55. # get system information
  56. #
  57. adb_sysver="$(ubus -S call system board 2>/dev/null | jsonfilter -e '@.model' -e '@.release.description' | \
  58. awk 'BEGIN{ORS=", "}{print $0}' | awk '{print substr($0,1,length($0)-2)}')"
  59. # parse 'global' and 'extra' section by callback
  60. #
  61. config_cb()
  62. {
  63. local type="${1}"
  64. if [ "${type}" = "adblock" ]
  65. then
  66. option_cb()
  67. {
  68. local option="${1}"
  69. local value="${2}"
  70. eval "${option}=\"${value}\""
  71. }
  72. else
  73. reset_cb
  74. fi
  75. }
  76. # parse 'source' typed sections
  77. #
  78. parse_config()
  79. {
  80. local value opt section="${1}" options="enabled adb_src adb_src_rset adb_src_cat"
  81. eval "adb_sources=\"${adb_sources} ${section}\""
  82. for opt in ${options}
  83. do
  84. config_get value "${section}" "${opt}"
  85. if [ -n "${value}" ]
  86. then
  87. eval "${opt}_${section}=\"${value}\""
  88. fi
  89. done
  90. }
  91. # load adblock config
  92. #
  93. config_load adblock
  94. config_foreach parse_config source
  95. # version check
  96. #
  97. if [ -z "${adb_basever}" ] || [ "${adb_ver%.*}" != "${adb_basever}" ]
  98. then
  99. f_log "info" "your adblock config seems to be too old, please update your config with the '--force-maintainer' opkg option"
  100. f_rmtemp
  101. exit 0
  102. fi
  103. # set dns backend
  104. #
  105. case "${adb_dns}" in
  106. "dnsmasq")
  107. adb_dnsinotify="${adb_dnsinotify:-"false"}"
  108. adb_dnsinstance="${adb_dnsinstance:-"0"}"
  109. adb_dnsuser="${adb_dnsuser:-"dnsmasq"}"
  110. adb_dnsdir="${adb_dnsdir:-"/tmp"}"
  111. adb_dnsheader=""
  112. if [ "${adb_dnsvariant}" = "nxdomain" ]
  113. then
  114. adb_dnsdeny="awk '{print \"server=/\"\$0\"/\"}'"
  115. adb_dnsallow="awk '{print \"server=/\"\$0\"/#\"}'"
  116. elif [ "${adb_dnsvariant}" = "null (IPv4)" ]
  117. then
  118. adb_dnsdeny="awk '{print \"0.0.0.0\\t\"\$0\"\"}'"
  119. adb_dnsallow=""
  120. elif [ "${adb_dnsvariant}" = "null (IPv4/IPv6)" ]
  121. then
  122. adb_dnsdeny="awk '{print \"0.0.0.0\\t\"\$0\"\\n::\\t\"\$0\"\"}'"
  123. adb_dnsallow=""
  124. fi
  125. ;;
  126. "unbound")
  127. adb_dnsinotify="${adb_dnsinotify:-"false"}"
  128. adb_dnsuser="${adb_dnsuser:-"unbound"}"
  129. adb_dnsdir="${adb_dnsdir:-"/var/lib/unbound"}"
  130. adb_dnsheader=""
  131. adb_dnsdeny="awk '{print \"local-zone: \\042\"\$0\"\\042 static\"}'"
  132. adb_dnsallow="awk '{print \"local-zone: \\042\"\$0\"\\042 transparent\"}'"
  133. ;;
  134. "named")
  135. adb_dnsinotify="${adb_dnsinotify:-"false"}"
  136. adb_dnsuser="${adb_dnsuser:-"bind"}"
  137. adb_dnsdir="${adb_dnsdir:-"/var/lib/bind"}"
  138. adb_dnsheader="\$TTL 2h"$'\n'"@ IN SOA localhost. root.localhost. (1 6h 1h 1w 2h)"$'\n'" IN NS localhost."
  139. adb_dnsdeny="awk '{print \"\"\$0\" CNAME .\\n*.\"\$0\" CNAME .\"}'"
  140. adb_dnsallow="awk '{print \"\"\$0\" CNAME rpz-passthru.\\n*.\"\$0\" CNAME rpz-passthru.\"}'"
  141. ;;
  142. "kresd")
  143. adb_dnsinotify="${adb_dnsinotify:-"false"}"
  144. adb_dnsuser="${adb_dnsuser:-"root"}"
  145. adb_dnsdir="${adb_dnsdir:-"/etc/kresd"}"
  146. adb_dnsheader="\$TTL 2h"$'\n'"@ IN SOA localhost. root.localhost. (1 6h 1h 1w 2h)"$'\n'" IN NS localhost."
  147. adb_dnsdeny="awk '{print \"\"\$0\" CNAME .\\n*.\"\$0\" CNAME .\"}'"
  148. adb_dnsallow="awk '{print \"\"\$0\" CNAME rpz-passthru.\\n*.\"\$0\" CNAME rpz-passthru.\"}'"
  149. ;;
  150. esac
  151. # status check
  152. #
  153. if [ "${adb_enabled}" -eq 0 ]
  154. then
  155. f_extconf
  156. f_temp
  157. f_rmdns
  158. f_bgserv "stop"
  159. f_jsnup "disabled"
  160. f_log "info" "adblock is currently disabled, please set the config option 'adb_enabled' to '1' to use this service"
  161. exit 0
  162. fi
  163. # dns backend check
  164. #
  165. if [ -d "${adb_dnsdir}" ] && [ ! -f "${adb_dnsdir}/${adb_dnsfile}" ]
  166. then
  167. printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
  168. fi
  169. if [ "${adb_action}" = "start" ] && [ "${adb_trigger}" = "timed" ]
  170. then
  171. sleep "${adb_triggerdelay}"
  172. fi
  173. if [ "${adb_action}" != "stop" ]
  174. then
  175. while [ "${cnt}" -le 30 ]
  176. do
  177. dns_up="$(ubus -S call service list "{\"name\":\"${adb_dns}\"}" 2>/dev/null | jsonfilter -l1 -e "@[\"${adb_dns}\"].instances.*.running" 2>/dev/null)"
  178. if [ "${dns_up}" = "true" ]
  179. then
  180. break
  181. fi
  182. sleep 1
  183. cnt=$((cnt+1))
  184. done
  185. if [ "${dns_up}" != "true" ] || [ -z "${adb_dns}" ] || [ ! -x "$(command -v "${adb_dns}")" ]
  186. then
  187. f_log "err" "dns backend '${adb_dns}' not running or executable"
  188. elif [ ! -d "${adb_dnsdir}" ]
  189. then
  190. f_log "err" "dns backend directory '${adb_dnsdir}' not found"
  191. fi
  192. fi
  193. # inotify check
  194. #
  195. if [ "${adb_dnsinotify}" = "true" ]
  196. then
  197. if [ "${adb_dnsfilereset}" = "true" ]
  198. then
  199. adb_dnsfilereset="false"
  200. fi
  201. f_log "info" "inotify is enabled for '${adb_dns}', adblock restart and file reset will be disabled"
  202. fi
  203. }
  204. # check & set environment
  205. #
  206. f_env()
  207. {
  208. local ssl_lib
  209. f_log "info" "adblock instance started ::: action: ${adb_action}, priority: ${adb_nice:-"0"}, pid: ${$}"
  210. f_jsnup "running"
  211. f_extconf
  212. # check backup directory
  213. #
  214. if [ ! -d "${adb_backupdir}" ]
  215. then
  216. f_log "err" "backup directory '${adb_backupdir}' does not exist/is not mounted yet, please create the directory or raise the 'adb_triggerdelay' to defer the adblock start"
  217. fi
  218. # check fetch utility
  219. #
  220. case "${adb_fetchutil}" in
  221. "uclient-fetch")
  222. if [ -f "/lib/libustream-ssl.so" ]
  223. then
  224. adb_fetchparm="${adb_fetchparm:-"--timeout=10 --no-check-certificate -O"}"
  225. ssl_lib="libustream-ssl"
  226. else
  227. adb_fetchparm="${adb_fetchparm:-"--timeout=10 -O"}"
  228. fi
  229. ;;
  230. "wget")
  231. adb_fetchparm="${adb_fetchparm:-"--no-cache --no-cookies --max-redirect=0 --timeout=10 --no-check-certificate -O"}"
  232. ssl_lib="built-in"
  233. ;;
  234. "wget-nossl")
  235. adb_fetchparm="${adb_fetchparm:-"--no-cache --no-cookies --max-redirect=0 --timeout=10 -O"}"
  236. ;;
  237. "busybox")
  238. adb_fetchparm="${adb_fetchparm:-"-O"}"
  239. ;;
  240. "curl")
  241. adb_fetchparm="${adb_fetchparm:-"--connect-timeout 10 --insecure -o"}"
  242. ssl_lib="built-in"
  243. ;;
  244. "aria2c")
  245. adb_fetchparm="${adb_fetchparm:-"--timeout=10 --allow-overwrite=true --auto-file-renaming=false --check-certificate=false -o"}"
  246. ssl_lib="built-in"
  247. ;;
  248. esac
  249. adb_fetchutil="$(command -v "${adb_fetchutil}")"
  250. if [ ! -x "${adb_fetchutil}" ] || [ -z "${adb_fetchutil}" ] || [ -z "${adb_fetchparm}" ]
  251. then
  252. f_log "err" "download utility not found, please install 'uclient-fetch' with 'libustream-mbedtls' or the full 'wget' package"
  253. fi
  254. adb_fetchinfo="${adb_fetchutil} (${ssl_lib:-"-"})"
  255. f_temp
  256. }
  257. # create temporary files and directories
  258. #
  259. f_temp()
  260. {
  261. if [ -d "/tmp" ] && [ -z "${adb_tmpdir}" ]
  262. then
  263. adb_tmpdir="$(mktemp -p /tmp -d)"
  264. adb_tmpfile="$(mktemp -p "${adb_tmpdir}" -tu)"
  265. elif [ ! -d "/tmp" ]
  266. then
  267. f_log "err" "the temp directory '/tmp' does not exist/is not mounted yet, please create the directory or raise the 'adb_triggerdelay' to defer the adblock start"
  268. fi
  269. if [ ! -f "${adb_pidfile}" ] || [ ! -s "${adb_pidfile}" ]
  270. then
  271. printf "%s" "${$}" > "${adb_pidfile}"
  272. fi
  273. }
  274. # remove temporary files and directories
  275. #
  276. f_rmtemp()
  277. {
  278. if [ -d "${adb_tmpdir}" ]
  279. then
  280. rm -rf "${adb_tmpdir}"
  281. fi
  282. > "${adb_pidfile}"
  283. }
  284. # remove dns related files, services and directories
  285. #
  286. f_rmdns()
  287. {
  288. local status dns_status rc
  289. status="$(ubus -S call service list '{"name":"adblock"}' 2>/dev/null | jsonfilter -l1 -e '@["adblock"].instances.*.running' 2>/dev/null)"
  290. if [ -n "${adb_dns}" ] && [ -n "${status}" ]
  291. then
  292. dns_status="$(ubus -S call service list "{\"name\":\"${adb_dns}\"}" 2>/dev/null | jsonfilter -l1 -e "@[\"${adb_dns}\"].instances.*.running" 2>/dev/null)"
  293. printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
  294. > "${adb_rtfile}"
  295. rm "${adb_backupdir}/${adb_dnsprefix}".*.gz 2>/dev/null
  296. rc="${?}"
  297. if [ "${rc}" -eq 0 ] && [ -n "${dns_status}" ]
  298. then
  299. f_dnsup 4
  300. fi
  301. fi
  302. f_rmtemp
  303. f_log "debug" "f_rmdns ::: status: ${status:-"-"}, dns_status: ${dns_status:-"-"}, rc: ${rc:-"-"}, dns: ${adb_dns}, dns_dir: ${adb_dnsdir}, dns_file: ${adb_dnsfile}, rt_file: ${adb_rtfile}, backup_dir: ${adb_backupdir}"
  304. }
  305. # commit uci changes
  306. #
  307. f_uci()
  308. {
  309. local change config="${1}"
  310. if [ -n "${config}" ]
  311. then
  312. change="$(uci -q changes "${config}" | awk '{ORS=" "; print $0}')"
  313. if [ -n "${change}" ]
  314. then
  315. uci_commit "${config}"
  316. case "${config}" in
  317. "firewall")
  318. "/etc/init.d/firewall" reload >/dev/null 2>&1
  319. ;;
  320. "dhcp"|"resolver")
  321. printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
  322. f_count
  323. f_jsnup "running"
  324. "/etc/init.d/${adb_dns}" reload >/dev/null 2>&1
  325. ;;
  326. esac
  327. fi
  328. f_log "debug" "f_uci ::: config: ${config}, change: ${change}"
  329. fi
  330. }
  331. # set/reset the global counter
  332. #
  333. f_count()
  334. {
  335. local mode="${1}"
  336. adb_cnt=0
  337. case "${mode}" in
  338. "blacklist")
  339. if [ -s "${adb_tmpfile}.blacklist" ]
  340. then
  341. adb_cnt="$(wc -l 2>/dev/null < "${adb_tmpfile}.blacklist")"
  342. fi
  343. ;;
  344. "whitelist")
  345. if [ -s "${adb_tmpdir}/tmp.raw.whitelist" ]
  346. then
  347. adb_cnt="$(wc -l 2>/dev/null < "${adb_tmpdir}/tmp.raw.whitelist")"
  348. fi
  349. ;;
  350. "merge")
  351. if [ -s "${adb_tmpdir}/${adb_dnsfile}" ]
  352. then
  353. adb_cnt="$(wc -l 2>/dev/null < "${adb_tmpdir}/${adb_dnsfile}")"
  354. fi
  355. ;;
  356. "download"|"backup"|"restore")
  357. if [ -s "${src_tmpfile}" ]
  358. then
  359. adb_cnt="$(wc -l 2>/dev/null < "${src_tmpfile}")"
  360. fi
  361. ;;
  362. "final")
  363. if [ -s "${adb_dnsdir}/${adb_dnsfile}" ]
  364. then
  365. adb_cnt="$(wc -l 2>/dev/null < "${adb_dnsdir}/${adb_dnsfile}")"
  366. if [ -s "${adb_tmpdir}/tmp.add.whitelist" ]
  367. then
  368. adb_cnt="$((adb_cnt-$(wc -l 2>/dev/null < "${adb_tmpdir}/tmp.add.whitelist")))"
  369. fi
  370. if [ "${adb_dns}" = "named" ] || [ "${adb_dns}" = "kresd" ] || { [ "${adb_dns}" = "dnsmasq" ] && [ "${adb_dnsvariant}" = "null (IPv4/IPv6)" ]; }
  371. then
  372. adb_cnt="$(((adb_cnt-$(printf "%s" "${adb_dnsheader}" | grep -c "^"))/2))"
  373. fi
  374. fi
  375. ;;
  376. esac
  377. }
  378. # set external config options
  379. #
  380. f_extconf()
  381. {
  382. local config port fwcfg
  383. case "${adb_dns}" in
  384. "dnsmasq")
  385. config="dhcp"
  386. if [ "${adb_dnsvariant}" = "nxdomain" ]
  387. then
  388. if [ "${adb_enabled}" -eq 1 ] && [ -z "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  389. then
  390. uci_set dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile "${adb_dnsdir}/${adb_dnsfile}"
  391. if [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  392. then
  393. uci -q del_list dhcp.@dnsmasq[${adb_dnsinstance}].addnhosts="${adb_dnsdir}/${adb_dnsfile}"
  394. fi
  395. elif [ "${adb_enabled}" -eq 0 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  396. then
  397. uci_remove dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile
  398. fi
  399. elif [ "${adb_dnsvariant% *}" = "null" ]
  400. then
  401. if [ "${adb_enabled}" -eq 1 ] && [ -z "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  402. then
  403. uci -q add_list dhcp.@dnsmasq[${adb_dnsinstance}].addnhosts="${adb_dnsdir}/${adb_dnsfile}"
  404. if [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  405. then
  406. uci_remove dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile
  407. fi
  408. elif [ "${adb_enabled}" -eq 0 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  409. then
  410. uci_remove dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts
  411. fi
  412. fi
  413. ;;
  414. "kresd")
  415. config="resolver"
  416. if [ "${adb_enabled}" -eq 1 ] && [ -z "$(uci_get resolver kresd rpz_file | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  417. then
  418. uci -q add_list resolver.kresd.rpz_file="${adb_dnsdir}/${adb_dnsfile}"
  419. elif [ "${adb_enabled}" -eq 0 ] && [ -n "$(uci_get resolver kresd rpz_file | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
  420. then
  421. uci -q del_list resolver.kresd.rpz_file="${adb_dnsdir}/${adb_dnsfile}"
  422. fi
  423. if [ "${adb_enabled}" -eq 1 ] && [ "${adb_dnsflush}" -eq 0 ] && [ "$(uci_get resolver kresd keep_cache)" != "1" ]
  424. then
  425. uci_set resolver kresd keep_cache "1"
  426. elif [ "${adb_enabled}" -eq 0 ] || { [ "${adb_dnsflush}" -eq 1 ] && [ "$(uci_get resolver kresd keep_cache)" = "1" ]; }
  427. then
  428. uci_set resolver kresd keep_cache "0"
  429. fi
  430. ;;
  431. esac
  432. f_uci "${config}"
  433. config="firewall"
  434. fwcfg="$(uci -qNX show "${config}")"
  435. if [ "${adb_enabled}" -eq 1 ] && [ "${adb_forcedns}" -eq 1 ] && \
  436. [ "$(/etc/init.d/firewall enabled; printf "%u" ${?})" -eq 0 ]
  437. then
  438. for port in ${adb_portlist}
  439. do
  440. if [ -z "$(printf "%s" "${fwcfg}" | grep -Fo -m1 "adblock_dns_${port}")" ]
  441. then
  442. uci_add firewall "redirect" "adblock_dns_${port}"
  443. uci_set firewall "adblock_dns_${port}" "name" "Adblock DNS, port ${port}"
  444. uci_set firewall "adblock_dns_${port}" "src" "lan"
  445. uci_set firewall "adblock_dns_${port}" "proto" "tcp udp"
  446. uci_set firewall "adblock_dns_${port}" "src_dport" "${port}"
  447. uci_set firewall "adblock_dns_${port}" "dest_port" "${port}"
  448. uci_set firewall "adblock_dns_${port}" "target" "DNAT"
  449. fi
  450. done
  451. elif [ "${adb_enabled}" -eq 0 ] || [ "${adb_forcedns}" -eq 0 ]
  452. then
  453. for port in ${adb_portlist}
  454. do
  455. if [ -n "$(printf "%s" "${fwcfg}" | grep -Fo -m1 "adblock_dns_${port}")" ]
  456. then
  457. uci_remove firewall "adblock_dns_${port}"
  458. fi
  459. done
  460. fi
  461. f_uci "${config}"
  462. }
  463. # restart of the dns backend
  464. #
  465. f_dnsup()
  466. {
  467. local dns_service dns_up dns_pid dns_procfile cache_util cache_rc cnt=0 out_rc=4 in_rc="${1:-0}"
  468. if [ "${in_rc}" -eq 0 ] && [ "${adb_dnsinotify}" = "true" ]
  469. then
  470. out_rc=0
  471. else
  472. if [ "${in_rc}" -eq 0 ] && [ "${adb_dnsflush}" -eq 0 ] && [ "${adb_enabled}" -eq 1 ]
  473. then
  474. case "${adb_dns}" in
  475. "dnsmasq")
  476. killall -q -HUP "${adb_dns}"
  477. cache_rc="${?}"
  478. ;;
  479. "unbound")
  480. cache_util="$(command -v unbound-control)"
  481. if [ -x "${cache_util}" ] && [ -d "${adb_tmpdir}" ] && [ -f "${adb_dnsdir}/unbound.conf" ]
  482. then
  483. "${cache_util}" -c "${adb_dnsdir}/unbound.conf" dump_cache > "${adb_tmpdir}/adb_cache.dump" 2>/dev/null
  484. fi
  485. "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
  486. ;;
  487. "kresd")
  488. "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
  489. cache_rc="${?}"
  490. ;;
  491. "named")
  492. cache_util="$(command -v rndc)"
  493. if [ -x "${cache_util}" ] && [ -f "/etc/bind/rndc.conf" ]
  494. then
  495. "${cache_util}" -c "/etc/bind/rndc.conf" reload >/dev/null 2>&1
  496. cache_rc="${?}"
  497. else
  498. "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
  499. fi
  500. ;;
  501. esac
  502. else
  503. "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
  504. fi
  505. while [ "${cnt}" -le 10 ]
  506. do
  507. dns_service="$(ubus -S call service list "{\"name\":\"${adb_dns}\"}")"
  508. dns_up="$(printf "%s" "${dns_service}" | jsonfilter -l1 -e "@[\"${adb_dns}\"].instances.*.running")"
  509. dns_pid="$(printf "%s" "${dns_service}" | jsonfilter -l1 -e "@[\"${adb_dns}\"].instances.*.pid")"
  510. dns_procfile="$(ls -l "/proc/${dns_pid}/fd" 2>/dev/null | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")"
  511. if [ "${dns_up}" = "true" ] && [ -n "${dns_pid}" ] && [ -z "${dns_procfile}" ]
  512. then
  513. case "${adb_dns}" in
  514. "unbound")
  515. cache_util="$(command -v unbound-control)"
  516. if [ -x "${cache_util}" ] && [ -d "${adb_tmpdir}" ] && [ -s "${adb_tmpdir}/adb_cache.dump" ]
  517. then
  518. while [ "${cnt}" -le 10 ]
  519. do
  520. "${cache_util}" -c "${adb_dnsdir}/unbound.conf" load_cache < "${adb_tmpdir}/adb_cache.dump" >/dev/null 2>&1
  521. cache_rc="${?}"
  522. if [ "${cache_rc}" -eq 0 ]
  523. then
  524. break
  525. fi
  526. cnt=$((cnt+1))
  527. sleep 1
  528. done
  529. fi
  530. ;;
  531. esac
  532. out_rc=0
  533. sleep 1
  534. break
  535. fi
  536. cnt=$((cnt+1))
  537. sleep 1
  538. done
  539. fi
  540. f_log "debug" "f_dnsup ::: inotify: ${adb_dnsinotify}, cache_util: ${cache_util:-"-"}, cache_flush: ${adb_dnsflush}, cache_rc: ${cache_rc:-0}, dns_cnt: ${cnt}, in_rc: ${in_rc}, out_rc: ${out_rc}"
  541. return "${out_rc}"
  542. }
  543. # backup/restore/remove blocklists
  544. #
  545. f_list()
  546. {
  547. local hold file name out_rc mode="${1}" in_rc="${src_rc:-0}" cnt=1
  548. case "${mode}" in
  549. "blacklist"|"whitelist")
  550. if [ "${mode}" = "blacklist" ] && [ -s "${adb_blacklist}" ]
  551. then
  552. adb_blacklist_rset="/^([[:alnum:]_-]+\\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}"
  553. awk "${adb_blacklist_rset}" "${adb_blacklist}" > "${adb_tmpfile}.${mode}"
  554. out_rc="${?}"
  555. elif [ "${mode}" = "whitelist" ] && [ -s "${adb_whitelist}" ]
  556. then
  557. adb_whitelist_rset="/^([[:alnum:]_-]+\\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}"
  558. awk "${adb_whitelist_rset}" "${adb_whitelist}" > "${adb_tmpdir}/tmp.raw.${mode}"
  559. out_rc="${?}"
  560. if [ "${out_rc}" -eq 0 ]
  561. then
  562. adb_whitelist_rset="/^([[:alnum:]_-]+\\.)+[[:alpha:]]+([[:space:]]|$)/{gsub(\"\\\\.\",\"\\\\.\",\$1);print tolower(\"^\"\$1\"\\\\|\\\\.\"\$1)}"
  563. awk "${adb_whitelist_rset}" "${adb_tmpdir}/tmp.raw.${mode}" > "${adb_tmpdir}/tmp.rem.${mode}"
  564. out_rc="${?}"
  565. if [ "${out_rc}" -eq 0 ] && [ -n "${adb_dnsallow}" ]
  566. then
  567. eval "${adb_dnsallow}" "${adb_tmpdir}/tmp.raw.${mode}" > "${adb_tmpdir}/tmp.add.${mode}"
  568. out_rc="${?}"
  569. fi
  570. fi
  571. fi
  572. ;;
  573. "backup")
  574. gzip -cf "${src_tmpfile}" 2>/dev/null > "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz"
  575. out_rc="${?}"
  576. ;;
  577. "restore")
  578. if [ -n "${src_name}" ] && [ -s "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz" ]
  579. then
  580. zcat "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz" 2>/dev/null > "${src_tmpfile}"
  581. out_rc="${?}"
  582. elif [ -z "${src_name}" ]
  583. then
  584. for file in "${adb_backupdir}/${adb_dnsprefix}".*.gz
  585. do
  586. name="${file##*/}"
  587. name="${name%.*}"
  588. zcat "${file}" 2>/dev/null > "${adb_tmpfile}.${name}" &
  589. hold=$((cnt%adb_maxqueue))
  590. if [ "${hold}" -eq 0 ]
  591. then
  592. wait
  593. fi
  594. cnt=$((cnt+1))
  595. done
  596. wait
  597. out_rc="${?}"
  598. fi
  599. ;;
  600. "remove")
  601. if [ -f "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz" ]
  602. then
  603. rm -f "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz"
  604. out_rc="${?}"
  605. fi
  606. ;;
  607. "merge")
  608. > "${adb_tmpdir}/${adb_dnsfile}"
  609. for file in "${adb_tmpfile}".*
  610. do
  611. cat "${file}" 2>/dev/null >> "${adb_tmpdir}/${adb_dnsfile}"
  612. out_rc="${?}"
  613. if [ "${out_rc}" -ne 0 ]
  614. then
  615. break
  616. fi
  617. done
  618. rm -f "${adb_tmpfile}".*
  619. ;;
  620. "final")
  621. > "${adb_dnsdir}/${adb_dnsfile}"
  622. if [ -s "${adb_tmpdir}/tmp.add.whitelist" ]
  623. then
  624. cat "${adb_tmpdir}/tmp.add.whitelist" >> "${adb_dnsdir}/${adb_dnsfile}"
  625. fi
  626. if [ -s "${adb_tmpdir}/tmp.rem.whitelist" ]
  627. then
  628. grep -vf "${adb_tmpdir}/tmp.rem.whitelist" "${adb_tmpdir}/${adb_dnsfile}" | eval "${adb_dnsdeny}" >> "${adb_dnsdir}/${adb_dnsfile}"
  629. else
  630. eval "${adb_dnsdeny}" "${adb_tmpdir}/${adb_dnsfile}" >> "${adb_dnsdir}/${adb_dnsfile}"
  631. fi
  632. if [ -n "${adb_dnsheader}" ]
  633. then
  634. printf "%s\\n" "${adb_dnsheader}" | cat - "${adb_dnsdir}/${adb_dnsfile}" > "${adb_tmpdir}/${adb_dnsfile}"
  635. mv -f "${adb_tmpdir}/${adb_dnsfile}" "${adb_dnsdir}/${adb_dnsfile}"
  636. fi
  637. out_rc="${?}"
  638. ;;
  639. esac
  640. f_count "${mode}"
  641. out_rc="${out_rc:-"${in_rc}"}"
  642. f_log "debug" "f_list ::: name: ${src_name:-"-"}, mode: ${mode}, cnt: ${adb_cnt}, in_rc: ${in_rc}, out_rc: ${out_rc}"
  643. return "${out_rc}"
  644. }
  645. # top level domain compression
  646. #
  647. f_tld()
  648. {
  649. local cnt cnt_srt cnt_tld source="${1}" temp_tld="${1}.tld" tld_ok="false"
  650. cnt="${adb_cnt}"
  651. if [ "${adb_dnsvariant% *}" != "null" ] && [ "${adb_cnt}" -le "${adb_maxtld}" ]
  652. then
  653. awk 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "${source}" > "${temp_tld}"
  654. if [ "${?}" -eq 0 ]
  655. then
  656. sort -u "${temp_tld}" > "${source}"
  657. if [ "${?}" -eq 0 ]
  658. then
  659. cnt_srt="$(wc -l 2>/dev/null < "${source}")"
  660. awk '{if(NR==1){tld=$NF};while(getline){if($NF!~tld"\\."){print tld;tld=$NF}}print tld}' "${source}" > "${temp_tld}"
  661. if [ "${?}" -eq 0 ]
  662. then
  663. awk 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "${temp_tld}" > "${source}"
  664. if [ "${?}" -eq 0 ]
  665. then
  666. rm -f "${temp_tld}"
  667. cnt_tld="$(wc -l 2>/dev/null < "${source}")"
  668. tld_ok="true"
  669. fi
  670. fi
  671. fi
  672. fi
  673. else
  674. sort -u "${source}" > "${temp_tld}"
  675. if [ "${?}" -eq 0 ]
  676. then
  677. mv -f "${temp_tld}" "${source}"
  678. cnt_srt="$(wc -l 2>/dev/null < "${source}")"
  679. tld_ok="true"
  680. fi
  681. fi
  682. if [ "${tld_ok}" = "false" ]
  683. then
  684. unset cnt_srt cnt_tld
  685. rm -f "${temp_tld}" "${source}"
  686. f_list blacklist
  687. f_list whitelist
  688. f_list restore
  689. f_list merge
  690. f_list final
  691. cnt="${adb_cnt}"
  692. fi
  693. f_log "debug" "f_tld ::: source: ${source}, max_tld: ${adb_maxtld}, cnt: ${cnt:-"-"}, cnt_srt: ${cnt_srt:-"-"}, cnt_tld: ${cnt_tld:-"-"}, tld_ok: ${tld_ok}"
  694. }
  695. # suspend/resume adblock processing
  696. #
  697. f_switch()
  698. {
  699. local status done="false" mode="${1}"
  700. json_load_file "${adb_rtfile}" >/dev/null 2>&1
  701. json_select "data" >/dev/null 2>&1
  702. json_get_var status "adblock_status"
  703. if [ "${mode}" = "suspend" ] && [ "${status}" = "enabled" ]
  704. then
  705. f_jsnup "running"
  706. f_temp
  707. printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
  708. f_count
  709. done="true"
  710. elif [ "${mode}" = "resume" ] && [ "${status}" = "paused" ]
  711. then
  712. f_jsnup "running"
  713. f_temp
  714. f_list blacklist
  715. f_list whitelist
  716. f_list restore
  717. f_list merge
  718. f_tld "${adb_tmpdir}/${adb_dnsfile}"
  719. f_list final
  720. done="true"
  721. fi
  722. if [ "${done}" = "true" ]
  723. then
  724. if [ "${mode}" = "suspend" ]
  725. then
  726. f_bgserv "stop"
  727. fi
  728. f_dnsup
  729. if [ "${mode}" = "resume" ]
  730. then
  731. f_bgserv "start"
  732. fi
  733. f_jsnup "${mode}"
  734. f_log "info" "${mode} adblock processing"
  735. f_rmtemp
  736. fi
  737. }
  738. # query blocklist for certain (sub-)domains
  739. #
  740. f_query()
  741. {
  742. local search result prefix suffix field domain="${1}" tld="${1#*.}"
  743. if [ -z "${domain}" ] || [ "${domain}" = "${tld}" ]
  744. then
  745. printf "%s\\n" "::: invalid domain input, please submit a single domain, e.g. 'doubleclick.net'"
  746. else
  747. case "${adb_dns}" in
  748. "dnsmasq")
  749. if [ "${adb_dnsvariant}" = "nxdomain" ]
  750. then
  751. prefix=".*[\\/\\.]"
  752. suffix="(\\/)"
  753. field=2
  754. elif [ "${adb_dnsvariant% *}" = "null" ]
  755. then
  756. prefix="0\\..*[\\t\\.]"
  757. suffix=""
  758. field=2
  759. fi
  760. ;;
  761. "unbound")
  762. prefix=".*[\"\\.]"
  763. suffix="(static)"
  764. field=3
  765. ;;
  766. "named")
  767. prefix="[^\\*].*[\\.]"
  768. suffix="( \\.)"
  769. field=1
  770. ;;
  771. "kresd")
  772. prefix="[^\\*].*[\\.]"
  773. suffix="( \\.)"
  774. field=1
  775. ;;
  776. esac
  777. if [ "${adb_dnsfilereset}" = "false" ]
  778. then
  779. while [ "${domain}" != "${tld}" ]
  780. do
  781. search="${domain//[+*~%\$&\"\']/}"
  782. search="${search//./\\.}"
  783. result="$(awk -F '/|\"|\t| ' "/^(${search}|${prefix}+${search}.*${suffix}$)/{i++;{printf(\" + %s\\n\",\$${field})};if(i>9){printf(\" + %s\\n\",\"[...]\");exit}}" "${adb_dnsdir}/${adb_dnsfile}")"
  784. printf "%s\\n%s\\n%s\\n" ":::" "::: results for domain '${domain}' in active blocklist" ":::"
  785. printf "%s\\n\\n" "${result:-" - no match"}"
  786. domain="${tld}"
  787. tld="${domain#*.}"
  788. done
  789. fi
  790. if [ -d "${adb_backupdir}" ]
  791. then
  792. search="${1//[+*~%\$&\"\']/}"
  793. search="${search//./\\.}"
  794. printf "%s\\n%s\\n%s\\n" ":::" "::: results for domain '${1}' in backups and black-/whitelist" ":::"
  795. for file in "${adb_backupdir}/${adb_dnsprefix}".*.gz "${adb_blacklist}" "${adb_whitelist}"
  796. do
  797. suffix="${file##*.}"
  798. if [ "${suffix}" = "gz" ]
  799. then
  800. zcat "${file}" 2>/dev/null | awk -v f="${file##*/}" "/^($search|.*\\.${search})/{i++;{printf(\" + %-30s%s\\n\",f,\$1)};if(i>=3){printf(\" + %-30s%s\\n\",f,\"[...]\");exit}}"
  801. else
  802. awk -v f="${file##*/}" "/^($search|.*\\.${search})/{i++;{printf(\" + %-30s%s\\n\",f,\$1)};if(i>=3){printf(\" + %-30s%s\\n\",f,\"[...]\");exit}}" "${file}"
  803. fi
  804. done
  805. fi
  806. fi
  807. }
  808. # update runtime information
  809. #
  810. f_jsnup()
  811. {
  812. local run_time bg_pid status="${1:-"enabled"}"
  813. case "${status}" in
  814. "enabled"|"error")
  815. run_time="$(/bin/date "+%d.%m.%Y %H:%M:%S")"
  816. ;;
  817. "suspend")
  818. status="paused"
  819. ;;
  820. "resume")
  821. status=""
  822. ;;
  823. esac
  824. json_load_file "${adb_rtfile}" >/dev/null 2>&1
  825. json_select "data" >/dev/null 2>&1
  826. if [ "${?}" -eq 0 ]
  827. then
  828. if [ -z "${adb_fetchinfo}" ]
  829. then
  830. json_get_var adb_fetchinfo "fetch_utility"
  831. fi
  832. if [ -z "${adb_cnt}" ]
  833. then
  834. json_get_var adb_cnt "overall_domains"
  835. adb_cnt="${adb_cnt%% *}"
  836. fi
  837. if [ -z "${run_time}" ]
  838. then
  839. json_get_var run_time "last_rundate"
  840. fi
  841. fi
  842. > "${adb_rtfile}"
  843. json_load_file "${adb_rtfile}" >/dev/null 2>&1
  844. json_init
  845. json_add_object "data"
  846. json_add_string "adblock_status" "${status:-"enabled"}"
  847. json_add_string "adblock_version" "${adb_ver}"
  848. json_add_string "overall_domains" "${adb_cnt:-0}"
  849. json_add_string "fetch_utility" "${adb_fetchinfo:-"-"}"
  850. json_add_string "dns_backend" "${adb_dns}, ${adb_dnsdir}"
  851. json_add_string "dns_variant" "${adb_dnsvariant}, ${adb_dnsfilereset:-"false"}"
  852. json_add_string "backup_dir" "${adb_backupdir}"
  853. json_add_string "last_rundate" "${run_time:-"-"}"
  854. json_add_string "system_release" "${adb_sysver}"
  855. json_close_object
  856. json_dump > "${adb_rtfile}"
  857. if [ "${adb_mail}" -eq 1 ] && [ -x "${adb_mailservice}" ] && \
  858. { [ "${status}" = "error" ] || { [ "${status}" = "enabled" ] && [ "${adb_cnt}" -le "${adb_mcnt}" ]; } }
  859. then
  860. ("${adb_mailservice}" "${adb_ver}" >/dev/null 2>&1)&
  861. bg_pid="${!}"
  862. fi
  863. f_log "debug" "f_jsnup ::: status: ${status:-"-"}, cnt: ${adb_cnt}, mail: ${adb_mail}, mail_service: ${adb_mailservice}, mail_cnt: ${adb_mcnt}, mail_pid: ${bg_pid:-"-"}"
  864. }
  865. # write to syslog
  866. #
  867. f_log()
  868. {
  869. local class="${1}" log_msg="${2}"
  870. if [ -n "${log_msg}" ] && { [ "${class}" != "debug" ] || [ "${adb_debug}" -eq 1 ]; }
  871. then
  872. if [ -x "${adb_logger}" ]
  873. then
  874. "${adb_logger}" -p "${class}" -t "adblock-${adb_ver}[${$}]" "${log_msg}"
  875. else
  876. printf "%s %s %s\\n" "${class}" "adblock-${adb_ver}[${$}]" "${log_msg}"
  877. fi
  878. if [ "${class}" = "err" ]
  879. then
  880. f_rmdns
  881. f_bgserv "stop"
  882. f_jsnup "error"
  883. exit 1
  884. fi
  885. fi
  886. }
  887. # start ubus monitor service to trace dns backend events
  888. #
  889. f_bgserv()
  890. {
  891. local bg_pid status="${1}"
  892. bg_pid="$(pgrep -f "^/bin/sh ${adb_ubusservice}.*|^/bin/ubus -S -M r -m invoke monitor|^grep -qF \"method\":\"set\",\"data\":\\{\"name\":\"${adb_dns}\"" | awk '{ORS=" "; print $1}')"
  893. if [ -z "${bg_pid}" ] && [ "${status}" = "start" ] \
  894. && [ -x "${adb_ubusservice}" ] && [ "${adb_dnsfilereset}" = "true" ]
  895. then
  896. ( "${adb_ubusservice}" "${adb_ver}" & )
  897. elif [ -n "${bg_pid}" ] && [ "${status}" = "stop" ]
  898. then
  899. kill -HUP "${bg_pid}" 2>/dev/null
  900. fi
  901. f_log "debug" "f_bgserv ::: status: ${status:-"-"}, bg_pid: ${bg_pid:-"-"}, dns_filereset: ${adb_dnsfilereset:-"-"}, ubus_service: ${adb_ubusservice:-"-"}"
  902. }
  903. # main function for blocklist processing
  904. #
  905. f_main()
  906. {
  907. local src_tmpload src_tmpfile src_name src_rset src_url src_log src_arc src_cat src_item src_rc list entry suffix mem_total mem_free enabled cnt=1
  908. mem_total="$(awk '/^MemTotal/ {print int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
  909. mem_free="$(awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
  910. f_log "debug" "f_main ::: dns: ${adb_dns}, fetch_util: ${adb_fetchinfo}, force_dns: ${adb_forcedns}, mem_total: ${mem_total:-0}, mem_free: ${mem_free:-0}, max_queue: ${adb_maxqueue}"
  911. # main loop
  912. #
  913. f_list blacklist
  914. f_list whitelist
  915. for src_name in ${adb_sources}
  916. do
  917. enabled="$(eval printf "%s" \"\$\{enabled_${src_name}\}\")"
  918. src_url="$(eval printf "%s" \"\$\{adb_src_${src_name}\}\")"
  919. src_rset="$(eval printf "%s" \"\$\{adb_src_rset_${src_name}\}\")"
  920. src_cat="$(eval printf "%s" \"\$\{adb_src_cat_${src_name}\}\")"
  921. src_tmpload="${adb_tmpfile}.${src_name}.load"
  922. src_tmpfile="${adb_tmpfile}.${src_name}.file"
  923. src_rc=4
  924. # basic pre-checks
  925. #
  926. f_log "debug" "f_main ::: name: ${src_name}, enabled: ${enabled}"
  927. if [ "${enabled}" != "1" ] || [ -f "${src_url}" ] || [ -z "${src_url}" ] || [ -z "${src_rset}" ]
  928. then
  929. f_list remove
  930. continue
  931. fi
  932. # backup mode
  933. #
  934. if [ "${adb_action}" = "start" ]
  935. then
  936. f_list restore
  937. if [ "${?}" -eq 0 ] && [ -s "${src_tmpfile}" ]
  938. then
  939. continue
  940. fi
  941. fi
  942. # download queue processing
  943. #
  944. if [ -n "${src_cat}" ]
  945. then
  946. (
  947. src_arc="${adb_tmpdir}/${src_url##*/}"
  948. src_log="$("${adb_fetchutil}" ${adb_fetchparm} "${src_arc}" "${src_url}" 2>&1)"
  949. src_rc="${?}"
  950. if [ "${src_rc}" -eq 0 ] && [ -s "${src_arc}" ]
  951. then
  952. list="$(tar -tzf "${src_arc}")"
  953. suffix="$(eval printf "%s" \"\$\{adb_src_suffix_${src_name}:-\"domains\"\}\")"
  954. for src_item in ${src_cat}
  955. do
  956. entry="$(printf "%s" "${list}" | grep -E "[\\^/]+${src_item}/${suffix}")"
  957. if [ -n "${entry}" ]
  958. then
  959. tar -xOzf "${src_arc}" "${entry}" >> "${src_tmpload}"
  960. src_rc="${?}"
  961. if [ "${src_rc}" -ne 0 ]
  962. then
  963. break
  964. fi
  965. fi
  966. done
  967. else
  968. src_log="$(printf "%s" "${src_log}" | awk '{ORS=" ";print $0}')"
  969. f_log "debug" "f_main ::: name: ${src_name}, url: ${src_url}, rc: ${src_rc}, log: ${src_log:-"-"}"
  970. fi
  971. if [ "${src_rc}" -eq 0 ] && [ -s "${src_tmpload}" ]
  972. then
  973. rm -f "${src_arc}"
  974. awk "${src_rset}" "${src_tmpload}" 2>/dev/null > "${src_tmpfile}"
  975. src_rc="${?}"
  976. if [ "${src_rc}" -eq 0 ] && [ -s "${src_tmpfile}" ]
  977. then
  978. rm -f "${src_tmpload}"
  979. f_list download
  980. f_list backup
  981. elif [ "${adb_action}" != "start" ]
  982. then
  983. f_list restore
  984. fi
  985. elif [ "${adb_action}" != "start" ]
  986. then
  987. f_list restore
  988. fi
  989. )&
  990. else
  991. (
  992. src_log="$("${adb_fetchutil}" ${adb_fetchparm} "${src_tmpload}" "${src_url}" 2>&1)"
  993. src_rc="${?}"
  994. if [ "${src_rc}" -eq 0 ] && [ -s "${src_tmpload}" ]
  995. then
  996. awk "${src_rset}" "${src_tmpload}" 2>/dev/null > "${src_tmpfile}"
  997. src_rc="${?}"
  998. if [ "${src_rc}" -eq 0 ] && [ -s "${src_tmpfile}" ]
  999. then
  1000. rm -f "${src_tmpload}"
  1001. f_list download
  1002. f_list backup
  1003. elif [ "${adb_action}" != "start" ]
  1004. then
  1005. f_list restore
  1006. fi
  1007. else
  1008. src_log="$(printf "%s" "${src_log}" | awk '{ORS=" ";print $0}')"
  1009. f_log "debug" "f_main ::: name: ${src_name}, url: ${src_url}, rc: ${src_rc}, log: ${src_log:-"-"}"
  1010. if [ "${adb_action}" != "start" ]
  1011. then
  1012. f_list restore
  1013. fi
  1014. fi
  1015. )&
  1016. fi
  1017. hold=$((cnt%adb_maxqueue))
  1018. if [ "${hold}" -eq 0 ]
  1019. then
  1020. wait
  1021. fi
  1022. cnt=$((cnt+1))
  1023. done
  1024. wait
  1025. unset src_name
  1026. f_list merge
  1027. # tld compression and dns restart
  1028. #
  1029. if [ "${?}" -eq 0 ] && [ -s "${adb_tmpdir}/${adb_dnsfile}" ]
  1030. then
  1031. f_tld "${adb_tmpdir}/${adb_dnsfile}"
  1032. f_list final
  1033. else
  1034. > "${adb_dnsdir}/${adb_dnsfile}"
  1035. fi
  1036. chown "${adb_dnsuser}" "${adb_dnsdir}/${adb_dnsfile}" 2>/dev/null
  1037. f_dnsup
  1038. if [ "${?}" -eq 0 ]
  1039. then
  1040. f_jsnup "enabled"
  1041. if [ "${adb_dnsfilereset}" = "true" ]
  1042. then
  1043. printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
  1044. f_log "info" "blocklist with overall ${adb_cnt} domains loaded successfully and reset afterwards (${adb_sysver})"
  1045. f_bgserv "start"
  1046. else
  1047. f_log "info" "blocklist with overall ${adb_cnt} domains loaded successfully (${adb_sysver})"
  1048. fi
  1049. else
  1050. f_log "err" "dns backend restart with active blocklist failed"
  1051. fi
  1052. f_rmtemp
  1053. }
  1054. # trace dns queries via tcpdump and prepare a report
  1055. #
  1056. f_report()
  1057. {
  1058. local bg_pid status total blocked percent rep_clients rep_domains rep_blocked index hold ports cnt=0 search="${1}" count="${2}" filter="${3}" print="${4}"
  1059. if [ "${adb_report}" -eq 1 ] && [ ! -x "${adb_reputil}" ]
  1060. then
  1061. f_log "info" "Please install the package 'tcpdump' or 'tcpdump-mini' to use the adblock reporting feature!"
  1062. elif [ "${adb_report}" -eq 0 ] && [ "${adb_action}" = "report" ]
  1063. then
  1064. f_log "info" "Please enable the extra option 'adb_report' to use the adblock reporting feature!"
  1065. fi
  1066. if [ -x "${adb_reputil}" ]
  1067. then
  1068. bg_pid="$(pgrep -f "^${adb_reputil}.*adb_report\\.pcap$" | awk '{ORS=" "; print $1}')"
  1069. if [ "${adb_report}" -eq 0 ] || { [ -n "${bg_pid}" ] && { [ "${adb_action}" = "stop" ] || [ "${adb_action}" = "restart" ]; } }
  1070. then
  1071. if [ -n "${bg_pid}" ]
  1072. then
  1073. kill -HUP "${bg_pid}" 2>/dev/null
  1074. while $(kill -0 "${bg_pid}" 2>/dev/null)
  1075. do
  1076. sleep 1
  1077. done
  1078. unset bg_pid
  1079. fi
  1080. fi
  1081. fi
  1082. if [ -x "${adb_reputil}" ] && [ "${adb_report}" -eq 1 ]
  1083. then
  1084. if [ -z "${bg_pid}" ] && [ "${adb_action}" != "report" ] && [ "${adb_action}" != "stop" ]
  1085. then
  1086. for port in ${adb_replisten}
  1087. do
  1088. if [ -z "${ports}" ]
  1089. then
  1090. ports="port ${port}"
  1091. else
  1092. ports="${ports} or port ${port}"
  1093. fi
  1094. done
  1095. ( "${adb_reputil}" -nn -s0 -l -i ${adb_repiface} ${ports} -C${adb_repchunksize} -W${adb_repchunkcnt} -w "${adb_repdir}/adb_report.pcap" >/dev/null 2>&1 & )
  1096. bg_pid="$(pgrep -f "^${adb_reputil}.*adb_report\\.pcap$" | awk '{ORS=" "; print $1}')"
  1097. fi
  1098. if [ "${adb_action}" = "report" ] && [ "${filter}" = "false" ]
  1099. then
  1100. > "${adb_repdir}/adb_report.raw"
  1101. for file in "${adb_repdir}/adb_report.pcap"*
  1102. do
  1103. (
  1104. "${adb_reputil}" -tttt -r "${file}" 2>/dev/null | \
  1105. awk -v cnt="${cnt}" '!/\.lan\. /&&/ A[\? ]+|NXDomain|0\.0\.0\.0/{a=$1;b=substr($2,0,8);c=$4;sub(/\.[0-9]+$/,"",c);d=cnt $7;sub(/\*$/,"",d);
  1106. e=$(NF-1);sub(/[0-9]\/[0-9]\/[0-9]|0\.0\.0\.0/,"NX",e);sub(/\.$/,"",e);sub(/([0-9]{1,3}\.){3}[0-9]{1,3}/,"OK",e);printf("%s\t%s\t%s\t%s\t%s\n", a,b,c,d,e)}' >> "${adb_repdir}/adb_report.raw"
  1107. )&
  1108. hold=$((cnt%adb_maxqueue))
  1109. if [ "${hold}" -eq 0 ]
  1110. then
  1111. wait
  1112. fi
  1113. cnt=$((cnt+1))
  1114. done
  1115. wait
  1116. if [ -s "${adb_repdir}/adb_report.raw" ]
  1117. then
  1118. awk '{printf("%s\t%s\t%s\t%s\t%s\t%s\n", $4,$5,$1,$2,$3,$4)}' "${adb_repdir}/adb_report.raw" | \
  1119. sort -ur | uniq -uf2 | awk '{currA=($6+0);currB=$6;currC=substr($6,length($6),1);
  1120. if(reqA==currB){reqA=0;printf("%s\t%s\n",d,$2)}else if(currC=="+"){reqA=currA;d=$3"\t"$4"\t"$5"\t"$2}}' | sort -ur > "${adb_repdir}/adb_report"
  1121. fi
  1122. if [ -s "${adb_repdir}/adb_report" ]
  1123. then
  1124. total="$(wc -l < "${adb_repdir}/adb_report")"
  1125. blocked="$(awk '{if($5=="NX")print $4}' "${adb_repdir}/adb_report" | wc -l)"
  1126. percent="$(awk -v t="${total}" -v b="${blocked}" 'BEGIN{printf("%.2f %s\n",b/t*100, "%")}')"
  1127. rep_clients="$(awk '{print $3}' "${adb_repdir}/adb_report" | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10) printf("%s_%s ",$1,$2)}')"
  1128. rep_domains="$(awk '{if($5!="NX")print $4}' "${adb_repdir}/adb_report" | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10)printf("%s_%s ",$1,$2)}')"
  1129. rep_blocked="$(awk '{if($5=="NX")print $4}' "${adb_repdir}/adb_report" | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10)printf("%s_%s ",$1,$2)}')"
  1130. > "${adb_repdir}/adb_report.json"
  1131. json_load_file "${adb_repdir}/adb_report.json" >/dev/null 2>&1
  1132. json_init
  1133. json_add_object "data"
  1134. json_add_string "start_date" "$(awk 'END{printf("%s",$1)}' "${adb_repdir}/adb_report")"
  1135. json_add_string "start_time" "$(awk 'END{printf("%s",$2)}' "${adb_repdir}/adb_report")"
  1136. json_add_string "end_date" "$(awk 'NR==1{printf("%s",$1)}' "${adb_repdir}/adb_report")"
  1137. json_add_string "end_time" "$(awk 'NR==1{printf("%s",$2)}' "${adb_repdir}/adb_report")"
  1138. json_add_string "total" "${total}"
  1139. json_add_string "blocked" "${blocked}"
  1140. json_add_string "percent" "${percent}"
  1141. json_close_array
  1142. json_add_array "top_clients"
  1143. for client in ${rep_clients}
  1144. do
  1145. json_add_object
  1146. json_add_string "count" "${client%%_*}"
  1147. json_add_string "address" "${client#*_}"
  1148. json_close_object
  1149. done
  1150. json_close_array
  1151. json_add_array "top_domains"
  1152. for domain in ${rep_domains}
  1153. do
  1154. json_add_object
  1155. json_add_string "count" "${domain%%_*}"
  1156. json_add_string "address" "${domain#*_}"
  1157. json_close_object
  1158. done
  1159. json_close_array
  1160. json_add_array "top_blocked"
  1161. for block in ${rep_blocked}
  1162. do
  1163. json_add_object
  1164. json_add_string "count" "${block%%_*}"
  1165. json_add_string "address" "${block#*_}"
  1166. json_close_object
  1167. done
  1168. json_close_object
  1169. json_dump > "${adb_repdir}/adb_report.json"
  1170. fi
  1171. rm -f "${adb_repdir}/adb_report.raw"
  1172. fi
  1173. if [ -s "${adb_repdir}/adb_report" ]
  1174. then
  1175. search="${search//./\\.}"
  1176. search="${search//[+*~%\$&\"\' ]/}"
  1177. > "${adb_repdir}/adb_report.final"
  1178. awk "BEGIN{i=0}/(${search})/{i++;if(i<=${count}){printf \"%s\\t%s\\t%s\\t%s\\t%s\\n\",\$1,\$2,\$3,\$4,\$5}}" "${adb_repdir}/adb_report" > "${adb_repdir}/adb_report.final"
  1179. if [ ! -s "${adb_repdir}/adb_report.final" ]
  1180. then
  1181. printf "%s\\t%s\\t%s\\t%s\\t%s\\n" "-" "-" "-" "-" "-" > "${adb_repdir}/adb_report.final"
  1182. fi
  1183. fi
  1184. if [ "${print}" = "true" ]
  1185. then
  1186. if [ -s "${adb_repdir}/adb_report.json" ]
  1187. then
  1188. printf "%s\\n%s\\n%s\\n" ":::" "::: Adblock DNS-Query Report" ":::"
  1189. json_load_file "${adb_repdir}/adb_report.json"
  1190. json_select "data"
  1191. json_get_keys keylist
  1192. for key in ${keylist}
  1193. do
  1194. json_get_var value "${key}"
  1195. eval "${key}=\"${value}\""
  1196. done
  1197. printf " + %s\\n + %s\\n" "Start ::: ${start_date}, ${start_time}" "End ::: ${end_date}, ${end_time}"
  1198. printf " + %s\\n + %s %s\\n" "Total ::: ${total}" "Blocked ::: ${blocked}" "(${percent})"
  1199. json_select ".."
  1200. if json_get_type status "top_clients" && [ "${status}" = "array" ]
  1201. then
  1202. printf "%s\\n%s\\n%s\\n" ":::" "::: Top 10 Clients" ":::"
  1203. json_select "top_clients"
  1204. index=1
  1205. while json_get_type status "${index}" && [ "${status}" = "object" ]
  1206. do
  1207. json_get_values client "${index}"
  1208. printf " + %-9s::: %s\\n" ${client}
  1209. index=$((index+1))
  1210. done
  1211. fi
  1212. json_select ".."
  1213. if json_get_type status "top_domains" && [ "${status}" = "array" ]
  1214. then
  1215. printf "%s\\n%s\\n%s\\n" ":::" "::: Top 10 Domains" ":::"
  1216. json_select "top_domains"
  1217. index=1
  1218. while json_get_type status "${index}" && [ "${status}" = "object" ]
  1219. do
  1220. json_get_values domain "${index}"
  1221. printf " + %-9s::: %s\\n" ${domain}
  1222. index=$((index+1))
  1223. done
  1224. fi
  1225. json_select ".."
  1226. if json_get_type status "top_blocked" && [ "${status}" = "array" ]
  1227. then
  1228. printf "%s\\n%s\\n%s\\n" ":::" "::: Top 10 Blocked Domains" ":::"
  1229. json_select "top_blocked"
  1230. index=1
  1231. while json_get_type status "${index}" && [ "${status}" = "object" ]
  1232. do
  1233. json_get_values blocked "${index}"
  1234. printf " + %-9s::: %s\\n" ${blocked}
  1235. index=$((index+1))
  1236. done
  1237. fi
  1238. if [ -s "${adb_repdir}/adb_report.final" ]
  1239. then
  1240. printf "%s\\n%s\\n%s\\n" ":::" "::: Latest DNS Queries" ":::"
  1241. printf "%-15s%-15s%-45s%-50s%s\\n" "Date" "Time" "Client" "Domain" "Answer"
  1242. awk '{printf "%-15s%-15s%-45s%-50s%s\n",$1,$2,$3,$4,$5}' "${adb_repdir}/adb_report.final"
  1243. fi
  1244. else
  1245. printf "%s\\n%s\\n%s\\n" ":::" "::: no reporting data available yet" ":::"
  1246. fi
  1247. fi
  1248. fi
  1249. f_log "debug" "f_report ::: action: ${adb_action}, report: ${adb_report}, search: ${1}, count: ${2}, filter: ${3}, print: ${4}, reputil: ${adb_reputil}, repdir: ${adb_repdir}, repiface: ${adb_repiface}, replisten: ${adb_replisten}, repchunksize: ${adb_repchunksize}, repchunkcnt: ${adb_repchunkcnt}, bg_pid: ${bg_pid}"
  1250. }
  1251. # source required system libraries
  1252. #
  1253. if [ -r "/lib/functions.sh" ] && [ -r "/usr/share/libubox/jshn.sh" ]
  1254. then
  1255. . "/lib/functions.sh"
  1256. . "/usr/share/libubox/jshn.sh"
  1257. else
  1258. f_log "err" "system libraries not found"
  1259. fi
  1260. # handle different adblock actions
  1261. #
  1262. f_load
  1263. case "${adb_action}" in
  1264. "stop")
  1265. f_bgserv "stop"
  1266. f_report "+" "50" "false" "false"
  1267. f_rmdns
  1268. ;;
  1269. "restart")
  1270. f_bgserv "stop"
  1271. f_report "+" "50" "false" "false"
  1272. f_rmdns
  1273. f_env
  1274. f_main
  1275. ;;
  1276. "suspend")
  1277. f_switch suspend
  1278. ;;
  1279. "resume")
  1280. f_switch resume
  1281. ;;
  1282. "report")
  1283. f_report "${2}" "${3}" "${4}" "${5}"
  1284. ;;
  1285. "query")
  1286. f_query "${2}"
  1287. ;;
  1288. "start"|"reload")
  1289. f_bgserv "stop"
  1290. f_report "+" "50" "false" "false"
  1291. f_env
  1292. f_main
  1293. ;;
  1294. esac