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.

573 lines
18 KiB

  1. #!/bin/sh
  2. ##############################################
  3. # function library used by adblock-update.sh #
  4. # written by Dirk Brenken (dirk@brenken.org) #
  5. ##############################################
  6. #####################################
  7. # f_envload: load adblock environment
  8. #
  9. f_envload()
  10. {
  11. # source in openwrt function library
  12. #
  13. if [ -r "/lib/functions.sh" ]
  14. then
  15. . /lib/functions.sh
  16. else
  17. /usr/bin/logger -t "adblock[${pid}]" "error: openwrt function library not found"
  18. f_deltemp
  19. exit 10
  20. fi
  21. # source in openwrt json helpers library
  22. #
  23. if [ -r "/usr/share/libubox/jshn.sh" ]
  24. then
  25. . "/usr/share/libubox/jshn.sh"
  26. else
  27. /usr/bin/logger -t "adblock[${pid}]" "error: openwrt json helpers library not found"
  28. f_deltemp
  29. exit 15
  30. fi
  31. # get list with all installed openwrt packages
  32. #
  33. pkg_list="$(opkg list-installed 2>/dev/null)"
  34. if [ -z "${pkg_list}" ]
  35. then
  36. /usr/bin/logger -t "adblock[${pid}]" "error: empty openwrt package list"
  37. f_deltemp
  38. exit 20
  39. fi
  40. }
  41. ######################################################
  42. # f_envparse: parse adblock config and set environment
  43. #
  44. f_envparse()
  45. {
  46. # function to read/set global options by callback,
  47. # prepare list items and build option list for all others
  48. #
  49. config_cb()
  50. {
  51. local type="${1}"
  52. local name="${2}"
  53. if [ "${type}" = "adblock" ]
  54. then
  55. option_cb()
  56. {
  57. local option="${1}"
  58. local value="${2}"
  59. eval "${option}=\"${value}\""
  60. }
  61. else
  62. option_cb()
  63. {
  64. local option="${1}"
  65. local value="${2}"
  66. local opt_out="$(printf "${option}" | sed -n '/.*_ITEM[0-9]$/p; /.*_LENGTH$/p; /enabled/p')"
  67. if [ -z "${opt_out}" ]
  68. then
  69. all_options="${all_options} ${option}"
  70. fi
  71. }
  72. list_cb()
  73. {
  74. local list="${1}"
  75. local value="${2}"
  76. if [ "${list}" = "adb_wanlist" ]
  77. then
  78. adb_wandev="${adb_wandev} ${value}"
  79. elif [ "${list}" = "adb_ntplist" ]
  80. then
  81. adb_ntpsrv="${adb_ntpsrv} ${value}"
  82. elif [ "${list}" = "adb_catlist" ]
  83. then
  84. adb_cat_shalla="${adb_cat_shalla} ${value}"
  85. fi
  86. }
  87. fi
  88. }
  89. # function to iterate through option list, read/set all options in "enabled" sections
  90. #
  91. parse_config()
  92. {
  93. local config="${1}"
  94. config_get switch "${config}" "enabled"
  95. if [ "${switch}" = "1" ]
  96. then
  97. for option in ${all_options}
  98. do
  99. config_get value "${config}" "${option}"
  100. if [ -n "${value}" ]
  101. then
  102. local opt_src="$(printf "${option}" | sed -n '/^adb_src_[a-z0-9]*$/p')"
  103. if [ -n "${opt_src}" ]
  104. then
  105. adb_sources="${adb_sources} ${value}"
  106. else
  107. eval "${option}=\"${value}\""
  108. fi
  109. fi
  110. done
  111. elif [ "${config}" = "wancheck" ]
  112. then
  113. unset adb_wandev
  114. elif [ "${config}" = "ntpcheck" ]
  115. then
  116. unset adb_ntpsrv
  117. elif [ "${config}" = "shalla" ]
  118. then
  119. unset adb_cat_shalla
  120. fi
  121. }
  122. # load adblock config and start parsing functions
  123. #
  124. config_load adblock
  125. config_foreach parse_config service
  126. config_foreach parse_config source
  127. # set temp variables and counter
  128. #
  129. adb_tmpfile="$(mktemp -tu)"
  130. adb_tmpdir="$(mktemp -d)"
  131. cnt=0
  132. max_cnt=30
  133. max_time=60
  134. # set adblock source ruleset definitions
  135. #
  136. rset_start="sed -r 's/[[:space:]]|[\[!#/:;_].*|[0-9\.]*localhost//g; s/[\^#/:;_\.\t ]*$//g'"
  137. rset_end="sed '/^[#/:;_\s]*$/d'"
  138. rset_default="${rset_start} | ${rset_end}"
  139. rset_yoyo="${rset_start} | sed 's/,/\n/g' | ${rset_end}"
  140. rset_shalla="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}$//g' | ${rset_end}"
  141. rset_spam404="${rset_start} | sed 's/^\|\|//g' | ${rset_end}"
  142. rset_winhelp="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-1]\{1,1\}//g' | ${rset_end}"
  143. # set adblock/dnsmasq destination file and format
  144. #
  145. adb_dnsfile="/tmp/dnsmasq.d/adlist.conf"
  146. adb_dnsformat="sed 's/^/address=\//;s/$/\/'${adb_ip}'/'"
  147. }
  148. #############################################
  149. # f_envcheck: check environment prerequisites
  150. #
  151. f_envcheck()
  152. {
  153. # check adblock network device configuration
  154. #
  155. if [ ! -d "/sys/class/net/${adb_dev}" ]
  156. then
  157. /usr/bin/logger -t "adblock[${pid}]" "error: invalid adblock network device input (${adb_dev})"
  158. f_deltemp
  159. exit 25
  160. fi
  161. # check adblock network interface configuration
  162. #
  163. check_if="$(printf "${adb_if}" | sed -n '/[^_0-9A-Za-z]/p')"
  164. banned_if="$(printf "${adb_if}" | sed -n '/.*lan.*\|.*wan.*\|.*switch.*\|main\|globals\|loopback\|px5g/p')"
  165. if [ -n "${check_if}" ] || [ -n "${banned_if}" ]
  166. then
  167. /usr/bin/logger -t "adblock[${pid}]" "error: invalid adblock network interface input (${adb_if})"
  168. f_deltemp
  169. exit 30
  170. fi
  171. # check adblock ip address configuration
  172. #
  173. check_ip="$(printf "${adb_ip}" | sed -n '/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/p')"
  174. if [ -z "${check_ip}" ]
  175. then
  176. /usr/bin/logger -t "adblock[${pid}]" "error: invalid adblock ip address input (${adb_ip})"
  177. f_deltemp
  178. exit 35
  179. fi
  180. # check adblock blacklist/whitelist configuration
  181. #
  182. if [ ! -r "${adb_blacklist}" ]
  183. then
  184. /usr/bin/logger -t "adblock[${pid}]" "error: adblock blacklist not found"
  185. f_deltemp
  186. exit 40
  187. elif [ ! -r "${adb_whitelist}" ]
  188. then
  189. /usr/bin/logger -t "adblock[${pid}]" "error: adblock whitelist not found"
  190. f_deltemp
  191. exit 45
  192. fi
  193. # check wan update configuration
  194. #
  195. if [ -n "${adb_wandev}" ]
  196. then
  197. wan_ok="true"
  198. else
  199. wan_ok="false"
  200. /usr/bin/logger -t "adblock[${pid}]" "info: wan update check will be disabled"
  201. fi
  202. # check ntp sync configuration
  203. #
  204. if [ -n "${adb_ntpsrv}" ]
  205. then
  206. ntp_ok="true"
  207. else
  208. ntp_ok="false"
  209. /usr/bin/logger -t "adblock[${pid}]" "info: ntp time sync will be disabled"
  210. fi
  211. # check backup configuration
  212. #
  213. adb_backupdir="${adb_backupfile%/*}"
  214. if [ -n "${adb_backupdir}" ] && [ -d "${adb_backupdir}" ]
  215. then
  216. backup_ok="true"
  217. adb_mounts="${adb_backupdir} ${adb_tmpdir}"
  218. else
  219. backup_ok="false"
  220. /usr/bin/logger -t "adblock[${pid}]" "info: backup/restore will be disabled"
  221. fi
  222. # check error log configuration
  223. #
  224. adb_logdir="${adb_logfile%/*}"
  225. if [ -n "${adb_logfile}" ] && [ "${adb_logfile}" = "/dev/stdout" ]
  226. then
  227. log_ok="true"
  228. adb_logfile="/proc/self/fd/1"
  229. elif [ -n "${adb_logdir}" ] && [ -d "${adb_logdir}" ] && [ "${ntp_ok}" = "true" ]
  230. then
  231. log_ok="true"
  232. adb_mounts="${adb_mounts} ${adb_logdir}"
  233. else
  234. log_ok="false"
  235. adb_logfile="/dev/null"
  236. /usr/bin/logger -t "adblock[${pid}]" "info: error logging will be disabled"
  237. fi
  238. # check dns query log configuration
  239. #
  240. adb_querydir="${adb_queryfile%/*}"
  241. query_pid="/var/run/adb_query.pid"
  242. if [ -n "${adb_querydir}" ] && [ -d "${adb_querydir}" ]
  243. then
  244. # check find capabilities
  245. #
  246. check="$(find --help 2>&1 | grep "mtime")"
  247. if [ -z "${check}" ]
  248. then
  249. query_ok="false"
  250. /usr/bin/logger -t "adblock[${pid}]" "info: busybox without 'find/mtime' support (min. r47362), dns query logging will be disabled"
  251. else
  252. query_ok="true"
  253. query_name="${adb_queryfile##*/}"
  254. query_ip="${adb_ip//./\\.}"
  255. adb_mounts="${adb_mounts} ${adb_querydir}"
  256. fi
  257. else
  258. query_ok="false"
  259. if [ -s "${query_pid}" ]
  260. then
  261. kill -9 $(cat "${query_pid}") 2>/dev/null
  262. > "${query_pid}"
  263. /usr/bin/logger -t "adblock[${pid}]" "info: remove old dns query log background process"
  264. fi
  265. /usr/bin/logger -t "adblock[${pid}]" "info: dns query logging will be disabled"
  266. fi
  267. # check mount points & space requirements
  268. #
  269. adb_mounts="${adb_mounts} ${adb_tmpdir}"
  270. for mp in ${adb_mounts}
  271. do
  272. df "${mp}" 2>/dev/null |\
  273. tail -n1 |\
  274. while read filesystem overall used available scrap
  275. do
  276. av_space="${available}"
  277. if [ $((av_space)) -eq 0 ]
  278. then
  279. /usr/bin/logger -t "adblock[${pid}]" "error: no space left on device/not mounted (${mp})"
  280. exit 50
  281. elif [ $((av_space)) -lt $((adb_minspace)) ]
  282. then
  283. /usr/bin/logger -t "adblock[${pid}]" "error: not enough space left on device (${mp})"
  284. exit 55
  285. fi
  286. done
  287. # subshell return code handling
  288. #
  289. rc=$?
  290. if [ $((rc)) -ne 0 ]
  291. then
  292. f_deltemp
  293. exit ${rc}
  294. fi
  295. done
  296. # check curl package dependency
  297. #
  298. check="$(printf "${pkg_list}" | grep "^curl")"
  299. if [ -z "${check}" ]
  300. then
  301. /usr/bin/logger -t "adblock[${pid}]" "error: curl package not found"
  302. f_deltemp
  303. exit 60
  304. fi
  305. # check wget package dependency
  306. #
  307. check="$(printf "${pkg_list}" | grep "^wget")"
  308. if [ -z "${check}" ]
  309. then
  310. /usr/bin/logger -t "adblock[${pid}]" "error: wget package not found"
  311. f_deltemp
  312. exit 65
  313. fi
  314. # check dynamic/volatile adblock network interface configuration
  315. #
  316. rc="$(ifstatus "${adb_if}" >/dev/null 2>&1; printf $?)"
  317. if [ $((rc)) -ne 0 ]
  318. then
  319. json_init
  320. json_add_string name "${adb_if}"
  321. json_add_string ifname "${adb_dev}"
  322. json_add_string proto "static"
  323. json_add_array ipaddr
  324. json_add_string "" "${adb_ip}"
  325. json_close_array
  326. json_close_object
  327. ubus call network add_dynamic "$(json_dump)"
  328. /usr/bin/logger -t "adblock[${pid}]" "info: created new dynamic/volatile network interface (${adb_if}, ${adb_ip})"
  329. fi
  330. # check dynamic/volatile adblock uhttpd instance configuration
  331. #
  332. rc="$(ps | grep "[u]httpd.*\-r ${adb_if}" >/dev/null 2>&1; printf $?)"
  333. if [ $((rc)) -ne 0 ]
  334. then
  335. uhttpd -h "/www/adblock" -r "${adb_if}" -E "/adblock.html" -p "${adb_ip}:80"
  336. /usr/bin/logger -t "adblock[${pid}]" "info: created new dynamic/volatile uhttpd instance (${adb_if}, ${adb_ip})"
  337. fi
  338. }
  339. ###################################################
  340. # f_deltemp: delete temporary files and directories
  341. #
  342. f_deltemp()
  343. {
  344. if [ -f "${adb_tmpfile}" ]
  345. then
  346. rm -f "${adb_tmpfile}" 2>/dev/null
  347. fi
  348. if [ -d "${adb_tmpdir}" ]
  349. then
  350. rm -rf "${adb_tmpdir}" 2>/dev/null
  351. fi
  352. }
  353. ################################################################
  354. # f_remove: remove temporary files, start and maintain query log
  355. #
  356. f_remove()
  357. {
  358. # delete temporary files and directories
  359. #
  360. f_deltemp
  361. # remove existing domain query log background process,
  362. # do housekeeping and start a new process on daily basis
  363. #
  364. if [ "${query_ok}" = "true" ] && [ "${ntp_ok}" = "true" ]
  365. then
  366. query_date="$(date "+%Y%m%d")"
  367. if [ -s "${query_pid}" ] && [ ! -f "${adb_queryfile}.${query_date}" ]
  368. then
  369. kill -9 $(cat "${query_pid}") 2>/dev/null
  370. > "${query_pid}"
  371. find "${adb_backupdir}" -maxdepth 1 -type f -mtime +${adb_queryhistory} -name "${query_name}.*" -exec rm -f {} \; 2>/dev/null
  372. /usr/bin/logger -t "adblock[${pid}]" "info: remove old dns query log background process and do logfile housekeeping"
  373. fi
  374. if [ ! -s "${query_pid}" ]
  375. then
  376. ( logread -f 2>/dev/null & printf "$!" > "${query_pid}" ) | egrep -o "(query\[A\].*)|([a-z0-9\.\-]* is ${query_ip}$)" >> "${adb_queryfile}.${query_date}" &
  377. /usr/bin/logger -t "adblock[${pid}]" "info: start new domain query log background process"
  378. fi
  379. fi
  380. # final log entry
  381. #
  382. /usr/bin/logger -t "adblock[${pid}]" "info: domain adblock processing finished (${adb_version})"
  383. }
  384. #####################################################
  385. # f_restore: if available, restore last adlist backup
  386. #
  387. f_restore()
  388. {
  389. if [ -z "${restore_msg}" ]
  390. then
  391. restore_msg="unknown"
  392. fi
  393. if [ "${backup_ok}" = "true" ] && [ -f "${adb_backupfile}" ]
  394. then
  395. cp -f "${adb_backupfile}" "${adb_dnsfile}" 2>/dev/null
  396. /usr/bin/logger -t "adblock[${pid}]" "error: ${restore_msg}, adlist backup restored"
  397. printf "%s\n" "$(/bin/date "+%d.%m.%Y %H:%M:%S") - error: ${restore_msg}, adlist backup restored" >> "${adb_logfile}"
  398. else
  399. > "${adb_dnsfile}"
  400. /usr/bin/logger -t "adblock[${pid}]" "error: ${restore_msg}, empty adlist generated"
  401. printf "%s\n" "$(/bin/date "+%d.%m.%Y %H:%M:%S") - error: ${restore_msg}, empty adlist generated" >> "${adb_logfile}"
  402. fi
  403. # restart dnsmasq
  404. #
  405. /etc/init.d/dnsmasq restart >/dev/null 2>&1
  406. # remove files and exit
  407. #
  408. f_remove
  409. exit 100
  410. }
  411. #######################################################
  412. # f_wancheck: check for usable adblock update interface
  413. #
  414. f_wancheck()
  415. {
  416. if [ "${wan_ok}" = "true" ]
  417. then
  418. # wait for wan update interface(s)
  419. #
  420. while [ $((cnt)) -le $((max_cnt)) ]
  421. do
  422. for dev in ${adb_wandev}
  423. do
  424. if [ -d "/sys/class/net/${dev}" ]
  425. then
  426. dev_out="$(cat /sys/class/net/${dev}/operstate 2>/dev/null)"
  427. if [ "${dev_out}" = "up" ]
  428. then
  429. /usr/bin/logger -t "adblock[${pid}]" "info: get wan/update interface: ${dev}, after ${cnt} loops"
  430. break 2
  431. fi
  432. fi
  433. if [ $((cnt)) -eq $((max_cnt)) ]
  434. then
  435. wan_ok="false"
  436. /usr/bin/logger -t "adblock[${pid}]" "error: no wan/update interface(s) found (${adb_wandev})"
  437. printf "%s\n" "$(/bin/date "+%d.%m.%Y %H:%M:%S") - error: no wan/update interface(s) found (${adb_wandev})" >> "${adb_logfile}"
  438. restore_msg="no wan/update interface(s)"
  439. f_restore
  440. fi
  441. done
  442. sleep 1
  443. cnt=$((cnt + 1))
  444. done
  445. fi
  446. }
  447. #####################################
  448. # f_ntpcheck: check/get ntp time sync
  449. #
  450. f_ntpcheck()
  451. {
  452. if [ "${ntp_ok}" = "true" ]
  453. then
  454. # prepare ntp server pool
  455. #
  456. unset ntp_pool
  457. for srv in ${adb_ntpsrv}
  458. do
  459. ntp_pool="${ntp_pool} -p ${srv}"
  460. done
  461. # wait for ntp time sync
  462. #
  463. while [ $((cnt)) -le $((max_cnt)) ]
  464. do
  465. /usr/sbin/ntpd -nq ${ntp_pool} >/dev/null 2>&1
  466. rc=$?
  467. if [ $((rc)) -eq 0 ]
  468. then
  469. /usr/bin/logger -t "adblock[${pid}]" "info: get ntp time sync (${adb_ntpsrv}), after ${cnt} loops"
  470. break
  471. fi
  472. if [ $((cnt)) -eq $((max_cnt)) ]
  473. then
  474. ntp_ok="false"
  475. /usr/bin/logger -t "adblock[${pid}]" "error: ntp time sync failed (${adb_ntpsrv})"
  476. printf "%s\n" "$(/bin/date "+%d.%m.%Y %H:%M:%S") - error: ntp time sync failed (${adb_ntpsrv})" >> "${adb_logfile}"
  477. restore_msg="time sync failed"
  478. f_restore
  479. fi
  480. sleep 1
  481. cnt=$((cnt + 1))
  482. done
  483. fi
  484. }
  485. #################################################################
  486. # f_dnscheck: dnsmasq health check with newly generated blocklist
  487. #
  488. f_dnscheck()
  489. {
  490. # check 1: dnsmasq startup
  491. #
  492. dns_status="$(logread -l 20 -e "dnsmasq" -e "FAILED to start up")"
  493. if [ -z "${dns_status}" ]
  494. then
  495. # check 2: nslookup probe
  496. #
  497. dns_status="$(nslookup "${adb_domain}" 2>/dev/null | grep "${adb_ip}")"
  498. if [ -z "${dns_status}" ]
  499. then
  500. # create backup of new block list only, if both checks are OK and backup enabled
  501. #
  502. if [ "${backup_ok}" = "true" ]
  503. then
  504. cp -f "${adb_dnsfile}" "${adb_backupfile}" 2>/dev/null
  505. /usr/bin/logger -t "adblock[${pid}]" "info: new block list with ${adb_count} domains loaded, backup generated"
  506. else
  507. /usr/bin/logger -t "adblock[${pid}]" "info: new block list with ${adb_count} domains loaded, no backup"
  508. fi
  509. else
  510. restore_msg="nslookup probe failed"
  511. f_restore
  512. fi
  513. else
  514. restore_msg="dnsmasq probe failed"
  515. f_restore
  516. fi
  517. }
  518. ##########################################################
  519. # f_footer: write footer with a few statistics to dns file
  520. #
  521. f_footer()
  522. {
  523. adb_count="$(wc -l < "${adb_dnsfile}")"
  524. printf "%s\n" "###################################################" >> "${adb_dnsfile}"
  525. printf "%s\n" "# last adblock file update: $(date +"%d.%m.%Y - %T")" >> "${adb_dnsfile}"
  526. printf "%s\n" "# ${0##*/} (${adb_version}) - ${adb_count} ad/abuse domains blocked" >> "${adb_dnsfile}"
  527. printf "%s\n" "# domain blacklist sources:" >> "${adb_dnsfile}"
  528. for src in ${adb_sources}
  529. do
  530. url="${src//\&ruleset=*/}"
  531. printf "%s\n" "# ${url}" >> "${adb_dnsfile}"
  532. done
  533. printf "%s\n" "###################################################" >> "${adb_dnsfile}"
  534. printf "%s\n" "# domain whitelist source:" >> "${adb_dnsfile}"
  535. printf "%s\n" "# ${adb_whitelist}" >> "${adb_dnsfile}"
  536. printf "%s\n" "###################################################" >> "${adb_dnsfile}"
  537. }