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.

669 lines
19 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. rc=510
  18. f_log "openwrt function library not found" "${rc}"
  19. f_deltemp
  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. rc=515
  28. f_log "openwrt json helpers library not found" "${rc}"
  29. f_deltemp
  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. rc=520
  37. f_log "empty openwrt package list" "${rc}"
  38. f_deltemp
  39. fi
  40. }
  41. ######################################################
  42. # f_envparse: parse adblock config and set environment
  43. #
  44. f_envparse()
  45. {
  46. # set the C locale, characters are single bytes, the charset is ASCII
  47. # speeds up sort, grep etc., guarantees unique domains
  48. #
  49. LC_ALL=C
  50. # set initial defaults (may be overwritten by adblock config options)
  51. #
  52. adb_if="adblock"
  53. adb_minspace="20000"
  54. adb_maxtime="60"
  55. adb_maxloop="5"
  56. # adblock device name auto detection
  57. # derived from first entry in openwrt lan ifname config
  58. #
  59. adb_dev="$(uci get network.lan.ifname 2>/dev/null)"
  60. adb_dev="${adb_dev/ *}"
  61. # adblock ntp server name auto detection
  62. # derived from ntp list found in openwrt ntp server config
  63. #
  64. adb_ntpsrv="$(uci get system.ntp.server 2>/dev/null)"
  65. # function to read/set global options by callback,
  66. # prepare list items and build option list for all others
  67. #
  68. config_cb()
  69. {
  70. local type="${1}"
  71. local name="${2}"
  72. if [ "${type}" = "adblock" ]
  73. then
  74. option_cb()
  75. {
  76. local option="${1}"
  77. local value="${2}"
  78. eval "${option}=\"${value}\""
  79. }
  80. else
  81. option_cb()
  82. {
  83. local option="${1}"
  84. local value="${2}"
  85. local opt_out="$(printf "${option}" | sed -n '/.*_ITEM[0-9]$/p; /.*_LENGTH$/p; /enabled/p')"
  86. if [ -z "${opt_out}" ]
  87. then
  88. all_options="${all_options} ${option}"
  89. fi
  90. }
  91. list_cb()
  92. {
  93. local list="${1}"
  94. local value="${2}"
  95. if [ "${list}" = "adb_wanlist" ]
  96. then
  97. adb_wandev="${adb_wandev} ${value}"
  98. elif [ "${list}" = "adb_ntplist" ]
  99. then
  100. adb_ntpsrv="${adb_ntpsrv} ${value}"
  101. elif [ "${list}" = "adb_catlist" ]
  102. then
  103. adb_cat_shalla="${adb_cat_shalla} ${value}"
  104. fi
  105. }
  106. fi
  107. }
  108. # function to iterate through option list, read/set all options in "enabled" sections
  109. #
  110. parse_config()
  111. {
  112. local config="${1}"
  113. config_get switch "${config}" "enabled"
  114. if [ "${switch}" = "1" ]
  115. then
  116. for option in ${all_options}
  117. do
  118. config_get value "${config}" "${option}"
  119. if [ -n "${value}" ]
  120. then
  121. local opt_src="$(printf "${option}" | sed -n '/^adb_src_[a-z0-9]*$/p')"
  122. if [ -n "${opt_src}" ]
  123. then
  124. adb_sources="${adb_sources} ${value}"
  125. else
  126. eval "${option}=\"${value}\""
  127. fi
  128. fi
  129. done
  130. elif [ "${config}" = "wancheck" ]
  131. then
  132. unset adb_wandev 2>/dev/null
  133. elif [ "${config}" = "ntpcheck" ]
  134. then
  135. unset adb_ntpsrv 2>/dev/null
  136. elif [ "${config}" = "shalla" ]
  137. then
  138. unset adb_cat_shalla 2>/dev/null
  139. fi
  140. }
  141. # load adblock config and start parsing functions
  142. #
  143. config_load adblock
  144. config_foreach parse_config service
  145. config_foreach parse_config source
  146. # set temp variables and counter
  147. #
  148. adb_tmpfile="$(mktemp -tu 2>/dev/null)"
  149. adb_tmpdir="$(mktemp -p /tmp -d 2>/dev/null)"
  150. # set adblock source ruleset definitions
  151. #
  152. rset_start="sed -r 's/[[:space:]]|[\[!#/:;_].*|[0-9\.]*localhost//g; s/[\^#/:;_\.\t ]*$//g'"
  153. rset_end="sed '/^[#/:;_\s]*$/d'"
  154. rset_default="${rset_start} | ${rset_end}"
  155. rset_yoyo="${rset_start} | sed 's/,/\n/g' | ${rset_end}"
  156. rset_shalla="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}$//g' | ${rset_end}"
  157. rset_spam404="${rset_start} | sed 's/^\|\|//g' | ${rset_end}"
  158. rset_winhelp="${rset_start} | sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-1]\{1,1\}//g' | ${rset_end}"
  159. # set adblock/dnsmasq destination file and format
  160. #
  161. adb_dnsfile="/tmp/dnsmasq.d/adlist.conf"
  162. adb_dnsformat="sed 's/^/address=\//;s/$/\/'${adb_ip}'/'"
  163. }
  164. #############################################
  165. # f_envcheck: check environment prerequisites
  166. #
  167. f_envcheck()
  168. {
  169. # check required config variables
  170. #
  171. adb_varlist="adb_ip adb_dev adb_if adb_domain adb_minspace adb_maxloop adb_maxtime adb_blacklist adb_whitelist"
  172. for var in ${adb_varlist}
  173. do
  174. if [ -z "$(eval printf \"\$"${var}"\")" ]
  175. then
  176. rc=525
  177. f_log "missing adblock config option (${var})" "${rc}"
  178. f_deltemp
  179. fi
  180. done
  181. # check main uhttpd configuration
  182. #
  183. check_uhttpd="$(uci get uhttpd.main.listen_http 2>/dev/null | grep -o "0.0.0.0")"
  184. if [ -n "${check_uhttpd}" ]
  185. then
  186. rc=530
  187. lan_ip="$(uci get network.lan.ipaddr 2>/dev/null)"
  188. f_log "main uhttpd instance listens to all network interfaces, please bind uhttpd to LAN only (${lan_ip})" "${rc}"
  189. f_deltemp
  190. fi
  191. # check adblock network device configuration
  192. #
  193. if [ ! -d "/sys/class/net/${adb_dev}" ]
  194. then
  195. rc=535
  196. f_log "invalid adblock network device input (${adb_dev})" "${rc}"
  197. f_deltemp
  198. fi
  199. # check adblock network interface configuration
  200. #
  201. check_if="$(printf "${adb_if}" | sed -n '/[^._0-9A-Za-z]/p')"
  202. banned_if="$(printf "${adb_if}" | sed -n '/.*lan.*\|.*wan.*\|.*switch.*\|main\|globals\|loopback\|px5g/p')"
  203. if [ -n "${check_if}" ] || [ -n "${banned_if}" ]
  204. then
  205. rc=540
  206. f_log "invalid adblock network interface input (${adb_if})" "${rc}"
  207. f_deltemp
  208. fi
  209. # check adblock ip address configuration
  210. #
  211. check_ip="$(printf "${adb_ip}" | sed -n '/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/p')"
  212. if [ -z "${check_ip}" ]
  213. then
  214. rc=545
  215. f_log "invalid adblock ip address input (${adb_ip})" "${rc}"
  216. f_deltemp
  217. fi
  218. # check adblock blacklist/whitelist configuration
  219. #
  220. if [ ! -r "${adb_blacklist}" ]
  221. then
  222. rc=550
  223. f_log "adblock blacklist not found" "${rc}"
  224. f_deltemp
  225. elif [ ! -r "${adb_whitelist}" ]
  226. then
  227. rc=555
  228. f_log "adblock whitelist not found" "${rc}"
  229. f_deltemp
  230. fi
  231. # check adblock temp directory
  232. #
  233. if [ -n "${adb_tmpdir}" ] && [ -d "${adb_tmpdir}" ]
  234. then
  235. f_space "${adb_tmpdir}"
  236. tmp_ok="true"
  237. else
  238. rc=560
  239. tmp_ok="false"
  240. f_log "temp directory not found" "${rc}"
  241. f_deltemp
  242. fi
  243. # check curl package dependency
  244. #
  245. check="$(printf "${pkg_list}" | grep "^curl -")"
  246. if [ -z "${check}" ]
  247. then
  248. rc=565
  249. f_log "curl package not found" "${rc}"
  250. f_deltemp
  251. fi
  252. # check wget package dependency
  253. #
  254. check="$(printf "${pkg_list}" | grep "^wget -")"
  255. if [ -z "${check}" ]
  256. then
  257. rc=570
  258. f_log "wget package not found" "${rc}"
  259. f_deltemp
  260. fi
  261. # check ca-certificates package and set wget/curl parms accordingly
  262. #
  263. check="$(printf "${pkg_list}" | grep "^ca-certificates -")"
  264. if [ -z "${check}" ]
  265. then
  266. curl_parm="-q --insecure"
  267. wget_parm="--no-config --no-check-certificate"
  268. else
  269. curl_parm="-q"
  270. wget_parm="--no-config"
  271. fi
  272. # check total and swap memory
  273. #
  274. mem_total="$(cat /proc/meminfo | grep "MemTotal" | grep -o "[0-9]*")"
  275. mem_free="$(cat /proc/meminfo | grep "MemFree" | grep -o "[0-9]*")"
  276. swap_total="$(cat /proc/meminfo | grep "SwapTotal" | grep -o "[0-9]*")"
  277. if [ $((mem_total)) -le 64000 ] && [ $((swap_total)) -eq 0 ]
  278. then
  279. f_log "please consider to add an external swap device to supersize your /tmp directory (total: ${mem_total}, free: ${mem_free}, swap: ${mem_swap})"
  280. fi
  281. # check backup configuration
  282. #
  283. adb_backupdir="${adb_backupfile%/*}"
  284. if [ -n "${adb_backupdir}" ] && [ -d "${adb_backupdir}" ]
  285. then
  286. f_space "${adb_backupdir}"
  287. backup_ok="true"
  288. else
  289. backup_ok="false"
  290. f_log "backup/restore will be disabled"
  291. fi
  292. # check dns query log configuration
  293. #
  294. adb_querydir="${adb_queryfile%/*}"
  295. adb_querypid="/var/run/adb_query.pid"
  296. if [ -n "${adb_querydir}" ] && [ -d "${adb_querydir}" ]
  297. then
  298. # check find capabilities
  299. #
  300. check="$(find --help 2>&1 | grep "mtime")"
  301. if [ -z "${check}" ]
  302. then
  303. query_ok="false"
  304. f_log "busybox without 'find/mtime' support (min. r47362), dns query logging will be disabled"
  305. else
  306. f_space "${adb_querydir}"
  307. query_ok="true"
  308. query_name="${adb_queryfile##*/}"
  309. query_ip="${adb_ip//./\\.}"
  310. fi
  311. else
  312. query_ok="false"
  313. f_log "dns query logging will be disabled"
  314. if [ -s "${adb_querypid}" ]
  315. then
  316. kill -9 "$(cat "${adb_querypid}")" >/dev/null 2>&1
  317. f_log "remove old dns query log background process (pid: $(cat "${adb_querypid}"))"
  318. > "${adb_querypid}"
  319. fi
  320. fi
  321. # check debug log configuration
  322. #
  323. adb_logdir="${adb_logfile%/*}"
  324. if [ -n "${adb_logdir}" ] && [ -d "${adb_logdir}" ]
  325. then
  326. f_space "${adb_logdir}"
  327. log_ok="true"
  328. else
  329. log_ok="false"
  330. f_log "debug logging will be disabled"
  331. fi
  332. # check wan update configuration
  333. #
  334. if [ -n "${adb_wandev}" ]
  335. then
  336. f_wancheck "${adb_maxloop}"
  337. else
  338. wan_ok="false"
  339. f_log "wan update check will be disabled"
  340. fi
  341. # check ntp sync configuration
  342. #
  343. if [ -n "${adb_ntpsrv}" ]
  344. then
  345. f_ntpcheck "${adb_maxloop}"
  346. else
  347. ntp_ok="false"
  348. f_log "ntp time sync will be disabled"
  349. fi
  350. # check dynamic/volatile adblock network interface configuration
  351. #
  352. rc="$(ifstatus "${adb_if}" >/dev/null 2>&1; printf ${?})"
  353. if [ $((rc)) -ne 0 ]
  354. then
  355. json_init
  356. json_add_string name "${adb_if}"
  357. json_add_string ifname "${adb_dev}"
  358. json_add_string proto "static"
  359. json_add_array ipaddr
  360. json_add_string "" "${adb_ip}"
  361. json_close_array
  362. json_close_object
  363. ubus call network add_dynamic "$(json_dump)"
  364. rc=${?}
  365. if [ $((rc)) -eq 0 ]
  366. then
  367. f_log "created new dynamic/volatile network interface (${adb_if}, ${adb_ip})"
  368. else
  369. f_log "failed to initialize new dynamic/volatile network interface (${adb_if}, ${adb_ip})" "${rc}"
  370. f_remove
  371. fi
  372. fi
  373. # check dynamic/volatile adblock uhttpd instance configuration
  374. #
  375. rc="$(ps | grep "[u]httpd.*\-r ${adb_if}" >/dev/null 2>&1; printf ${?})"
  376. if [ $((rc)) -ne 0 ]
  377. then
  378. uhttpd -h "/www/adblock" -r "${adb_if}" -E "/adblock.html" -p "${adb_ip}:80" >/dev/null 2>&1
  379. rc=${?}
  380. if [ $((rc)) -eq 0 ]
  381. then
  382. f_log "created new dynamic/volatile uhttpd instance (${adb_if}, ${adb_ip})"
  383. else
  384. f_log "failed to initialize new dynamic/volatile uhttpd instance (${adb_if}, ${adb_ip})" "${rc}"
  385. f_remove
  386. fi
  387. fi
  388. # remove no longer used environment variables
  389. #
  390. env_list="$(set | grep -o "CONFIG_[A-Za-z0-9_]*")"
  391. for var in ${env_list}
  392. do
  393. unset "${var}" 2>/dev/null
  394. done
  395. unset env_list 2>/dev/null
  396. unset pkg_list 2>/dev/null
  397. }
  398. ################################################
  399. # f_log: log messages to stdout, syslog, logfile
  400. #
  401. f_log()
  402. {
  403. local log_msg="${1}"
  404. local log_rc="${2}"
  405. local class="info "
  406. if [ -n "${log_msg}" ]
  407. then
  408. if [ $((log_rc)) -ne 0 ]
  409. then
  410. class="error"
  411. log_rc=", rc: ${log_rc}"
  412. fi
  413. /usr/bin/logger -s -t "adblock[${pid}] ${class}" "${log_msg}${log_rc}"
  414. if [ "${log_ok}" = "true" ] && [ "${ntp_ok}" = "true" ]
  415. then
  416. printf "%s\n" "$(/bin/date "+%d.%m.%Y %H:%M:%S") adblock[${pid}] ${class}: ${log_msg}${log_rc}" >> "${adb_logfile}"
  417. fi
  418. fi
  419. }
  420. ################################################
  421. # f_space: check mount points/space requirements
  422. #
  423. f_space()
  424. {
  425. local mp="${1}"
  426. if [ -d "${mp}" ]
  427. then
  428. df "${mp}" 2>/dev/null |\
  429. tail -n1 |\
  430. while read filesystem overall used available scrap
  431. do
  432. av_space="${available}"
  433. if [ $((av_space)) -eq 0 ]
  434. then
  435. rc=575
  436. f_log "no space left on device/not mounted (${mp})" "${rc}"
  437. exit ${rc}
  438. elif [ $((av_space)) -lt $((adb_minspace)) ]
  439. then
  440. rc=580
  441. f_log "not enough space left on device (${mp})" "${rc}"
  442. exit ${rc}
  443. fi
  444. done
  445. rc=${?}
  446. if [ $((rc)) -eq 0 ]
  447. then
  448. space_ok="true"
  449. else
  450. space_ok="false"
  451. f_deltemp
  452. fi
  453. fi
  454. }
  455. ####################################################
  456. # f_deltemp: delete temp files, directories and exit
  457. #
  458. f_deltemp()
  459. {
  460. if [ -f "${adb_tmpfile}" ]
  461. then
  462. rm -f "${adb_tmpfile}" >/dev/null 2>&1
  463. fi
  464. if [ -d "${adb_tmpdir}" ]
  465. then
  466. rm -rf "${adb_tmpdir}" >/dev/null 2>&1
  467. fi
  468. f_log "domain adblock processing finished (${adb_version}, ${openwrt_version})"
  469. exit ${rc}
  470. }
  471. ####################################################
  472. # f_remove: maintain and (re-)start domain query log
  473. #
  474. f_remove()
  475. {
  476. if [ "${query_ok}" = "true" ] && [ "${ntp_ok}" = "true" ]
  477. then
  478. query_date="$(date "+%Y%m%d")"
  479. if [ -s "${adb_querypid}" ] && [ ! -f "${adb_queryfile}.${query_date}" ]
  480. then
  481. kill -9 "$(cat "${adb_querypid}")" >/dev/null 2>&1
  482. find "${adb_backupdir}" -maxdepth 1 -type f -mtime +"${adb_queryhistory}" -name "${query_name}.*" -exec rm -f {} \; 2>/dev/null
  483. f_log "remove old dns query log background process (pid: $(cat "${adb_querypid}")) and do logfile housekeeping"
  484. > "${adb_querypid}"
  485. fi
  486. if [ ! -s "${adb_querypid}" ]
  487. then
  488. ( logread -f 2>/dev/null & printf ${!} > "${adb_querypid}" ) | egrep -o "(query\[A\].*)|([a-z0-9\.\-]* is ${query_ip}$)" >> "${adb_queryfile}.${query_date}" &
  489. f_log "new domain query log background process started (pid: $(cat "${adb_querypid}"))"
  490. fi
  491. fi
  492. f_deltemp
  493. }
  494. ################################################################
  495. # f_restore: restore last adblocklist backup and restart dnsmasq
  496. #
  497. f_restore()
  498. {
  499. if [ "${backup_ok}" = "true" ] && [ -f "${adb_backupfile}" ]
  500. then
  501. cp -f "${adb_backupfile}" "${adb_dnsfile}" >/dev/null 2>&1
  502. f_log "adblocklist backup restored"
  503. else
  504. > "${adb_dnsfile}"
  505. f_log="empty adblocklist generated"
  506. fi
  507. /etc/init.d/dnsmasq restart >/dev/null 2>&1
  508. f_remove
  509. }
  510. #######################################################
  511. # f_wancheck: check for usable adblock update interface
  512. #
  513. f_wancheck()
  514. {
  515. local cnt=0
  516. local cnt_max="${1}"
  517. local dev
  518. local dev_out
  519. while [ $((cnt)) -le $((cnt_max)) ]
  520. do
  521. for dev in ${adb_wandev}
  522. do
  523. if [ -d "/sys/class/net/${dev}" ]
  524. then
  525. dev_out="$(cat /sys/class/net/${dev}/operstate 2>/dev/null)"
  526. rc=${?}
  527. if [ "${dev_out}" = "up" ]
  528. then
  529. wan_ok="true"
  530. f_log "get wan/update interface (${dev}), after ${cnt} loops"
  531. break 2
  532. fi
  533. fi
  534. done
  535. sleep 1
  536. cnt=$((cnt + 1))
  537. done
  538. if [ -z "${wan_ok}" ]
  539. then
  540. rc=585
  541. wan_ok="false"
  542. f_log "no wan/update interface(s) found (${adb_wandev# })" "${rc}"
  543. f_restore
  544. fi
  545. }
  546. #####################################
  547. # f_ntpcheck: check/get ntp time sync
  548. #
  549. f_ntpcheck()
  550. {
  551. local cnt=0
  552. local cnt_max="${1}"
  553. local ntp_pool
  554. for srv in ${adb_ntpsrv}
  555. do
  556. ntp_pool="${ntp_pool} -p ${srv}"
  557. done
  558. while [ $((cnt)) -le $((cnt_max)) ]
  559. do
  560. /usr/sbin/ntpd -nq ${ntp_pool} >/dev/null 2>&1
  561. rc=${?}
  562. if [ $((rc)) -eq 0 ]
  563. then
  564. ntp_ok="true"
  565. f_log "get ntp time sync (${adb_ntpsrv# }), after ${cnt} loops"
  566. break
  567. fi
  568. sleep 1
  569. cnt=$((cnt + 1))
  570. done
  571. if [ -z "${ntp_ok}" ]
  572. then
  573. rc=590
  574. ntp_ok="false"
  575. f_log "ntp time sync failed (${adb_ntpsrv# })" "${rc}"
  576. f_restore
  577. fi
  578. }
  579. ####################################################################
  580. # f_dnscheck: dnsmasq health check with newly generated adblock list
  581. #
  582. f_dnscheck()
  583. {
  584. local dns_status
  585. dns_status="$(logread -l 20 -e "dnsmasq" -e "FAILED to start up")"
  586. rc=${?}
  587. if [ -z "${dns_status}" ]
  588. then
  589. dns_status="$(nslookup "${adb_domain}" 2>/dev/null | grep "${adb_ip}")"
  590. rc=${?}
  591. if [ -z "${dns_status}" ]
  592. then
  593. if [ "${backup_ok}" = "true" ]
  594. then
  595. cp -f "${adb_dnsfile}" "${adb_backupfile}" >/dev/null 2>&1
  596. f_log "new adblock list with ${adb_count} domains loaded, backup generated"
  597. else
  598. f_log "new adblock list with ${adb_count} domains loaded, no backup"
  599. fi
  600. else
  601. f_log "nslookup probe failed" "${rc}"
  602. f_restore
  603. fi
  604. else
  605. f_log "dnsmasq probe failed" "${rc}"
  606. f_restore
  607. fi
  608. }
  609. ##########################################################
  610. # f_footer: write footer with a few statistics to dns file
  611. #
  612. f_footer()
  613. {
  614. local url
  615. adb_count="$(wc -l < "${adb_dnsfile}")"
  616. printf "%s\n" "####################################################" >> "${adb_dnsfile}"
  617. printf "%s\n" "# last adblock list update: $(date +"%d.%m.%Y - %T")" >> "${adb_dnsfile}"
  618. printf "%s\n" "# ${0##*/} (${adb_version}) - ${adb_count} ad/abuse domains blocked" >> "${adb_dnsfile}"
  619. printf "%s\n" "# domain blacklist sources:" >> "${adb_dnsfile}"
  620. for src in ${adb_sources}
  621. do
  622. url="${src//\&ruleset=*/}"
  623. printf "%s\n" "# ${url}" >> "${adb_dnsfile}"
  624. done
  625. printf "%s\n" "#####" >> "${adb_dnsfile}"
  626. printf "%s\n" "# ${adb_whitelist}" >> "${adb_dnsfile}"
  627. printf "%s\n" "####################################################" >> "${adb_dnsfile}"
  628. }