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.

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