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.

667 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
  133. elif [ "${config}" = "ntpcheck" ]
  134. then
  135. unset adb_ntpsrv
  136. elif [ "${config}" = "shalla" ]
  137. then
  138. unset adb_cat_shalla
  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 -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. # remove unused environment variables
  164. #
  165. env_list="$(set | grep -o "CONFIG_[A-Za-z_]*")"
  166. for var in ${env_list}
  167. do
  168. unset "${var}" 2>/dev/null
  169. done
  170. }
  171. #############################################
  172. # f_envcheck: check environment prerequisites
  173. #
  174. f_envcheck()
  175. {
  176. # check required config variables
  177. #
  178. adb_varlist="adb_ip adb_dev adb_if adb_domain adb_minspace adb_maxloop adb_maxtime adb_blacklist adb_whitelist"
  179. for var in ${adb_varlist}
  180. do
  181. if [ -z "$(eval printf \"\$"${var}"\")" ]
  182. then
  183. rc=525
  184. f_log "missing adblock config option (${var})" "${rc}"
  185. f_deltemp
  186. fi
  187. done
  188. # check main uhttpd configuration
  189. #
  190. check_uhttpd="$(uci get uhttpd.main.listen_http 2>/dev/null | grep -o "0.0.0.0")"
  191. if [ -n "${check_uhttpd}" ]
  192. then
  193. rc=530
  194. lan_ip="$(uci get network.lan.ipaddr 2>/dev/null)"
  195. f_log "main uhttpd instance listens to all network interfaces, please bind uhttpd to LAN only (${lan_ip})" "${rc}"
  196. f_deltemp
  197. fi
  198. # check adblock network device configuration
  199. #
  200. if [ ! -d "/sys/class/net/${adb_dev}" ]
  201. then
  202. rc=535
  203. f_log "invalid adblock network device input (${adb_dev})" "${rc}"
  204. f_deltemp
  205. fi
  206. # check adblock network interface configuration
  207. #
  208. check_if="$(printf "${adb_if}" | sed -n '/[^._0-9A-Za-z]/p')"
  209. banned_if="$(printf "${adb_if}" | sed -n '/.*lan.*\|.*wan.*\|.*switch.*\|main\|globals\|loopback\|px5g/p')"
  210. if [ -n "${check_if}" ] || [ -n "${banned_if}" ]
  211. then
  212. rc=540
  213. f_log "invalid adblock network interface input (${adb_if})" "${rc}"
  214. f_deltemp
  215. fi
  216. # check adblock ip address configuration
  217. #
  218. check_ip="$(printf "${adb_ip}" | sed -n '/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/p')"
  219. if [ -z "${check_ip}" ]
  220. then
  221. rc=545
  222. f_log "invalid adblock ip address input (${adb_ip})" "${rc}"
  223. f_deltemp
  224. fi
  225. # check adblock blacklist/whitelist configuration
  226. #
  227. if [ ! -r "${adb_blacklist}" ]
  228. then
  229. rc=550
  230. f_log "adblock blacklist not found" "${rc}"
  231. f_deltemp
  232. elif [ ! -r "${adb_whitelist}" ]
  233. then
  234. rc=555
  235. f_log "adblock whitelist not found" "${rc}"
  236. f_deltemp
  237. fi
  238. # check adblock temp directory
  239. #
  240. if [ -n "${adb_tmpdir}" ] && [ -d "${adb_tmpdir}" ]
  241. then
  242. f_space "${adb_tmpdir}"
  243. tmp_ok="true"
  244. else
  245. rc=560
  246. tmp_ok="false"
  247. f_log "temp directory not found" "${rc}"
  248. f_deltemp
  249. fi
  250. # check curl package dependency
  251. #
  252. check="$(printf "${pkg_list}" | grep "^curl -")"
  253. if [ -z "${check}" ]
  254. then
  255. rc=565
  256. f_log "curl package not found" "${rc}"
  257. f_deltemp
  258. fi
  259. # check wget package dependency
  260. #
  261. check="$(printf "${pkg_list}" | grep "^wget -")"
  262. if [ -z "${check}" ]
  263. then
  264. rc=570
  265. f_log "wget package not found" "${rc}"
  266. f_deltemp
  267. fi
  268. # check ca-certificates package and set wget/curl parms accordingly
  269. #
  270. check="$(printf "${pkg_list}" | grep "^ca-certificates -")"
  271. if [ -z "${check}" ]
  272. then
  273. curl_parm="--insecure"
  274. wget_parm="--no-check-certificate"
  275. else
  276. unset curl_parm
  277. unset wget_parm
  278. fi
  279. # check total and swap memory
  280. #
  281. mem_total="$(cat /proc/meminfo | grep "MemTotal" | grep -o "[0-9]*")"
  282. mem_free="$(cat /proc/meminfo | grep "MemFree" | grep -o "[0-9]*")"
  283. swap_total="$(cat /proc/meminfo | grep "SwapTotal" | grep -o "[0-9]*")"
  284. if [ $((mem_total)) -le 64000 ] && [ $((swap_total)) -eq 0 ]
  285. then
  286. f_log "please consider to add an external swap device to supersize your /tmp directory (total: ${mem_total}, free: ${mem_free}, swap: ${mem_swap})"
  287. fi
  288. # check backup configuration
  289. #
  290. adb_backupdir="${adb_backupfile%/*}"
  291. if [ -n "${adb_backupdir}" ] && [ -d "${adb_backupdir}" ]
  292. then
  293. f_space "${adb_backupdir}"
  294. backup_ok="true"
  295. else
  296. backup_ok="false"
  297. f_log "backup/restore will be disabled"
  298. fi
  299. # check dns query log configuration
  300. #
  301. adb_querydir="${adb_queryfile%/*}"
  302. adb_querypid="/var/run/adb_query.pid"
  303. if [ -n "${adb_querydir}" ] && [ -d "${adb_querydir}" ]
  304. then
  305. # check find capabilities
  306. #
  307. check="$(find --help 2>&1 | grep "mtime")"
  308. if [ -z "${check}" ]
  309. then
  310. query_ok="false"
  311. f_log "busybox without 'find/mtime' support (min. r47362), dns query logging will be disabled"
  312. else
  313. f_space "${adb_querydir}"
  314. query_ok="true"
  315. query_name="${adb_queryfile##*/}"
  316. query_ip="${adb_ip//./\\.}"
  317. fi
  318. else
  319. query_ok="false"
  320. f_log "dns query logging will be disabled"
  321. if [ -s "${adb_querypid}" ]
  322. then
  323. kill -9 "$(cat "${adb_querypid}")" >/dev/null 2>&1
  324. f_log "remove old dns query log background process (pid: $(cat "${adb_querypid}"))"
  325. > "${adb_querypid}"
  326. fi
  327. fi
  328. # check debug log configuration
  329. #
  330. adb_logdir="${adb_logfile%/*}"
  331. if [ -n "${adb_logdir}" ] && [ -d "${adb_logdir}" ]
  332. then
  333. f_space "${adb_logdir}"
  334. log_ok="true"
  335. else
  336. log_ok="false"
  337. f_log "debug logging will be disabled"
  338. fi
  339. # check wan update configuration
  340. #
  341. if [ -n "${adb_wandev}" ]
  342. then
  343. f_wancheck "${adb_maxloop}"
  344. else
  345. wan_ok="false"
  346. f_log "wan update check will be disabled"
  347. fi
  348. # check ntp sync configuration
  349. #
  350. if [ -n "${adb_ntpsrv}" ]
  351. then
  352. f_ntpcheck "${adb_maxloop}"
  353. else
  354. ntp_ok="false"
  355. f_log "ntp time sync will be disabled"
  356. fi
  357. # check dynamic/volatile adblock network interface configuration
  358. #
  359. rc="$(ifstatus "${adb_if}" >/dev/null 2>&1; printf ${?})"
  360. if [ $((rc)) -ne 0 ]
  361. then
  362. json_init
  363. json_add_string name "${adb_if}"
  364. json_add_string ifname "${adb_dev}"
  365. json_add_string proto "static"
  366. json_add_array ipaddr
  367. json_add_string "" "${adb_ip}"
  368. json_close_array
  369. json_close_object
  370. ubus call network add_dynamic "$(json_dump)"
  371. rc=${?}
  372. if [ $((rc)) -eq 0 ]
  373. then
  374. f_log "created new dynamic/volatile network interface (${adb_if}, ${adb_ip})"
  375. else
  376. f_log "failed to initialize new dynamic/volatile network interface (${adb_if}, ${adb_ip})" "${rc}"
  377. f_remove
  378. fi
  379. fi
  380. # check dynamic/volatile adblock uhttpd instance configuration
  381. #
  382. rc="$(ps | grep "[u]httpd.*\-r ${adb_if}" >/dev/null 2>&1; printf ${?})"
  383. if [ $((rc)) -ne 0 ]
  384. then
  385. uhttpd -h "/www/adblock" -r "${adb_if}" -E "/adblock.html" -p "${adb_ip}:80" >/dev/null 2>&1
  386. rc=${?}
  387. if [ $((rc)) -eq 0 ]
  388. then
  389. f_log "created new dynamic/volatile uhttpd instance (${adb_if}, ${adb_ip})"
  390. else
  391. f_log "failed to initialize new dynamic/volatile uhttpd instance (${adb_if}, ${adb_ip})" "${rc}"
  392. f_remove
  393. fi
  394. fi
  395. }
  396. ################################################
  397. # f_log: log messages to stdout, syslog, logfile
  398. #
  399. f_log()
  400. {
  401. local log_msg="${1}"
  402. local log_rc="${2}"
  403. local class="info "
  404. if [ -n "${log_msg}" ]
  405. then
  406. if [ $((log_rc)) -ne 0 ]
  407. then
  408. class="error"
  409. log_rc=", rc: ${log_rc}"
  410. fi
  411. /usr/bin/logger -s -t "adblock[${pid}] ${class}" "${log_msg}${log_rc}"
  412. if [ "${log_ok}" = "true" ] && [ "${ntp_ok}" = "true" ]
  413. then
  414. printf "%s\n" "$(/bin/date "+%d.%m.%Y %H:%M:%S") adblock[${pid}] ${class}: ${log_msg}${log_rc}" >> "${adb_logfile}"
  415. fi
  416. fi
  417. }
  418. ################################################
  419. # f_space: check mount points/space requirements
  420. #
  421. f_space()
  422. {
  423. local mp="${1}"
  424. if [ -d "${mp}" ]
  425. then
  426. df "${mp}" 2>/dev/null |\
  427. tail -n1 |\
  428. while read filesystem overall used available scrap
  429. do
  430. av_space="${available}"
  431. if [ $((av_space)) -eq 0 ]
  432. then
  433. rc=575
  434. f_log "no space left on device/not mounted (${mp})" "${rc}"
  435. exit ${rc}
  436. elif [ $((av_space)) -lt $((adb_minspace)) ]
  437. then
  438. rc=580
  439. f_log "not enough space left on device (${mp})" "${rc}"
  440. exit ${rc}
  441. fi
  442. done
  443. rc=${?}
  444. if [ $((rc)) -eq 0 ]
  445. then
  446. space_ok="true"
  447. else
  448. space_ok="false"
  449. f_deltemp
  450. fi
  451. fi
  452. }
  453. ####################################################
  454. # f_deltemp: delete temp files, directories and exit
  455. #
  456. f_deltemp()
  457. {
  458. if [ -f "${adb_tmpfile}" ]
  459. then
  460. rm -f "${adb_tmpfile}" >/dev/null 2>&1
  461. fi
  462. if [ -d "${adb_tmpdir}" ]
  463. then
  464. rm -rf "${adb_tmpdir}" >/dev/null 2>&1
  465. fi
  466. f_log "domain adblock processing finished (${adb_version})"
  467. exit ${rc}
  468. }
  469. ####################################################
  470. # f_remove: maintain and (re-)start domain query log
  471. #
  472. f_remove()
  473. {
  474. if [ "${query_ok}" = "true" ] && [ "${ntp_ok}" = "true" ]
  475. then
  476. query_date="$(date "+%Y%m%d")"
  477. if [ -s "${adb_querypid}" ] && [ ! -f "${adb_queryfile}.${query_date}" ]
  478. then
  479. kill -9 "$(cat "${adb_querypid}")" >/dev/null 2>&1
  480. find "${adb_backupdir}" -maxdepth 1 -type f -mtime +"${adb_queryhistory}" -name "${query_name}.*" -exec rm -f {} \; 2>/dev/null
  481. f_log "remove old dns query log background process (pid: $(cat "${adb_querypid}")) and do logfile housekeeping"
  482. > "${adb_querypid}"
  483. fi
  484. if [ ! -s "${adb_querypid}" ]
  485. then
  486. ( logread -f 2>/dev/null & printf ${!} > "${adb_querypid}" ) | egrep -o "(query\[A\].*)|([a-z0-9\.\-]* is ${query_ip}$)" >> "${adb_queryfile}.${query_date}" &
  487. f_log "new domain query log background process started (pid: $(cat "${adb_querypid}"))"
  488. fi
  489. fi
  490. f_deltemp
  491. }
  492. ################################################################
  493. # f_restore: restore last adblocklist backup and restart dnsmasq
  494. #
  495. f_restore()
  496. {
  497. if [ "${backup_ok}" = "true" ] && [ -f "${adb_backupfile}" ]
  498. then
  499. cp -f "${adb_backupfile}" "${adb_dnsfile}" >/dev/null 2>&1
  500. f_log "adblocklist backup restored"
  501. else
  502. > "${adb_dnsfile}"
  503. f_log="empty adblocklist generated"
  504. fi
  505. /etc/init.d/dnsmasq restart >/dev/null 2>&1
  506. f_remove
  507. }
  508. #######################################################
  509. # f_wancheck: check for usable adblock update interface
  510. #
  511. f_wancheck()
  512. {
  513. local cnt=0
  514. local cnt_max="${1}"
  515. local dev
  516. local dev_out
  517. while [ $((cnt)) -le $((cnt_max)) ]
  518. do
  519. for dev in ${adb_wandev}
  520. do
  521. if [ -d "/sys/class/net/${dev}" ]
  522. then
  523. dev_out="$(cat /sys/class/net/${dev}/operstate 2>/dev/null)"
  524. rc=${?}
  525. if [ "${dev_out}" = "up" ]
  526. then
  527. wan_ok="true"
  528. f_log "get wan/update interface (${dev}), after ${cnt} loops"
  529. break 2
  530. fi
  531. fi
  532. done
  533. sleep 1
  534. cnt=$((cnt + 1))
  535. done
  536. if [ -z "${wan_ok}" ]
  537. then
  538. rc=585
  539. wan_ok="false"
  540. f_log "no wan/update interface(s) found (${adb_wandev# })" "${rc}"
  541. f_restore
  542. fi
  543. }
  544. #####################################
  545. # f_ntpcheck: check/get ntp time sync
  546. #
  547. f_ntpcheck()
  548. {
  549. local cnt=0
  550. local cnt_max="${1}"
  551. local ntp_pool
  552. for srv in ${adb_ntpsrv}
  553. do
  554. ntp_pool="${ntp_pool} -p ${srv}"
  555. done
  556. while [ $((cnt)) -le $((cnt_max)) ]
  557. do
  558. /usr/sbin/ntpd -nq ${ntp_pool} >/dev/null 2>&1
  559. rc=${?}
  560. if [ $((rc)) -eq 0 ]
  561. then
  562. ntp_ok="true"
  563. f_log "get ntp time sync (${adb_ntpsrv# }), after ${cnt} loops"
  564. break
  565. fi
  566. sleep 1
  567. cnt=$((cnt + 1))
  568. done
  569. if [ -z "${ntp_ok}" ]
  570. then
  571. rc=590
  572. ntp_ok="false"
  573. f_log "ntp time sync failed (${adb_ntpsrv# })" "${rc}"
  574. f_restore
  575. fi
  576. }
  577. ####################################################################
  578. # f_dnscheck: dnsmasq health check with newly generated adblock list
  579. #
  580. f_dnscheck()
  581. {
  582. local dns_status
  583. dns_status="$(logread -l 20 -e "dnsmasq" -e "FAILED to start up")"
  584. rc=${?}
  585. if [ -z "${dns_status}" ]
  586. then
  587. dns_status="$(nslookup "${adb_domain}" 2>/dev/null | grep "${adb_ip}")"
  588. rc=${?}
  589. if [ -z "${dns_status}" ]
  590. then
  591. if [ "${backup_ok}" = "true" ]
  592. then
  593. cp -f "${adb_dnsfile}" "${adb_backupfile}" >/dev/null 2>&1
  594. f_log "new adblock list with ${adb_count} domains loaded, backup generated"
  595. else
  596. f_log "new adblock list with ${adb_count} domains loaded, no backup"
  597. fi
  598. else
  599. f_log "nslookup probe failed" "${rc}"
  600. f_restore
  601. fi
  602. else
  603. f_log "dnsmasq probe failed" "${rc}"
  604. f_restore
  605. fi
  606. }
  607. ##########################################################
  608. # f_footer: write footer with a few statistics to dns file
  609. #
  610. f_footer()
  611. {
  612. local url
  613. adb_count="$(wc -l < "${adb_dnsfile}")"
  614. printf "%s\n" "####################################################" >> "${adb_dnsfile}"
  615. printf "%s\n" "# last adblock list update: $(date +"%d.%m.%Y - %T")" >> "${adb_dnsfile}"
  616. printf "%s\n" "# ${0##*/} (${adb_version}) - ${adb_count} ad/abuse domains blocked" >> "${adb_dnsfile}"
  617. printf "%s\n" "# domain blacklist sources:" >> "${adb_dnsfile}"
  618. for src in ${adb_sources}
  619. do
  620. url="${src//\&ruleset=*/}"
  621. printf "%s\n" "# ${url}" >> "${adb_dnsfile}"
  622. done
  623. printf "%s\n" "#####" >> "${adb_dnsfile}"
  624. printf "%s\n" "# ${adb_whitelist}" >> "${adb_dnsfile}"
  625. printf "%s\n" "####################################################" >> "${adb_dnsfile}"
  626. }