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.

919 lines
28 KiB

  1. #!/bin/sh /etc/rc.common
  2. # Copyright 2017-2019 Stan Grishin (stangri@melmac.net)
  3. # shellcheck disable=SC2039
  4. # shellcheck disable=SC1091
  5. PKG_VERSION=
  6. export START=94
  7. export USE_PROCD=1
  8. export LC_ALL=C
  9. export EXTRA_COMMANDS="check dl killcache status"
  10. export EXTRA_HELP=" check Checks if specified domain is found in current blacklist
  11. dl Force-redownloads all the list
  12. status Shows the service last-run status"
  13. readonly packageName="simple-adblock"
  14. readonly serviceName="$packageName $PKG_VERSION"
  15. readonly addnhostsFile="/var/run/${packageName}.addnhosts"
  16. readonly addnhostsCache="/var/run/${packageName}.addnhosts.cache"
  17. readonly addnhostsGzip="/etc/${packageName}.addnhosts.gz"
  18. readonly addnhostsOutputFilter='s|^|127.0.0.1 |;s|$||'
  19. readonly addnhostsOutputFilterIPv6='s|^|:: |;s|$||'
  20. readonly dnsmasqFile="/var/dnsmasq.d/${packageName}"
  21. readonly dnsmasqCache="/var/run/${packageName}.dnsmasq.cache"
  22. readonly dnsmasqGzip="/etc/${packageName}.dnsmasq.gz"
  23. readonly dnsmasqOutputFilter='s|^|local=/|;s|$|/|'
  24. readonly serversFile="/var/run/${packageName}.servers"
  25. readonly serversCache="/var/run/${packageName}.servers.cache"
  26. readonly serversGzip="/etc/${packageName}.servers.gz"
  27. readonly serversOutputFilter='s|^|server=/|;s|$|/|'
  28. readonly unboundFile="/var/lib/unbound/adb_list.${packageName}"
  29. readonly unboundCache="/var/run/${packageName}.unbound.cache"
  30. readonly unboundGzip="/etc/${packageName}.unbound.gz"
  31. readonly unboundOutputFilter='s|^|local-zone: "|;s|$|" static|'
  32. readonly A_TMP="/var/${packageName}.hosts.a.tmp"
  33. readonly B_TMP="/var/${packageName}.hosts.b.tmp"
  34. readonly PIDFile="/var/run/${packageName}.pid"
  35. readonly jsonFile="/var/run/${packageName}.json"
  36. readonly hostsFilter='/localhost/d;/^#/d;/^[^0-9]/d;s/^0\.0\.0\.0.//;s/^127\.0\.0\.1.//;s/[[:space:]]*#.*$//;s/[[:cntrl:]]$//;s/[[:space:]]//g;/[`~!@#\$%\^&\*()=+;:"'\'',<>?/\|[{}]/d;/]/d;/\./!d;/^$/d;/[^[:alnum:]_.-]/d;'
  37. readonly domainsFilter='/^#/d;s/[[:space:]]*#.*$//;s/[[:space:]]*$//;s/[[:cntrl:]]$//;/[[:space:]]/d;/[`~!@#\$%\^&\*()=+;:"'\'',<>?/\|[{}]/d;/]/d;/\./!d;/^$/d;/[^[:alnum:]_.-]/d;'
  38. readonly checkmark='\xe2\x9c\x93'
  39. readonly xmark='\xe2\x9c\x97'
  40. readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m'
  41. readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
  42. readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m'
  43. readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m'
  44. readonly _ERROR_='\033[0;31mERROR\033[0m'
  45. readonly statusSuccess='Success'
  46. readonly statusFail='Fail'
  47. readonly statusDownloading='Downloading'
  48. readonly statusReloading='Reloading'
  49. readonly statusRestarting='Restarting'
  50. readonly statusStarting='Starting'
  51. readonly statusForceReloading='Force-Reloading'
  52. readonly statusProcessing='Processing'
  53. readonly statusStopped='Stopped'
  54. readonly sharedMemoryError="/dev/shm/$packageName-error"
  55. create_lock() { [ -e "$PIDFile" ] && return 1; touch "$PIDFile"; }
  56. remove_lock() { [ -e "$PIDFile" ] && rm -f "$PIDFile"; }
  57. trap remove_lock EXIT
  58. output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; }
  59. output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; }
  60. output_fail() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; }
  61. output_failn() { output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; }
  62. str_replace() { echo "$1" | sed -e "s/$2/$3/g"; }
  63. str_contains() { [ "$1" != "$(str_replace "$1" "$2" "")" ]; }
  64. readonly sharedMemoryOutput="/dev/shm/$packageName-output"
  65. output() {
  66. # Can take a single parameter (text) to be output at any verbosity
  67. # Or target verbosity level and text to be output at specifc verbosity
  68. local msg memmsg
  69. if [ $# -ne 1 ]; then
  70. if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then shift; else return 0; fi
  71. fi
  72. [ -t 1 ] && printf "%b" "$1"
  73. msg="$(printf "%s" "$(str_replace "$1" "$serviceName " "service ")" | sed 's|\\033\[[0-9]\?;\?[0-9]\?[0-9]\?m||g')";
  74. if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
  75. [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
  76. logger -t "${packageName:-service} [$$]" "$(printf "%b" "${memmsg}${msg}")"
  77. rm -f "$sharedMemoryOutput"
  78. else
  79. printf "%b" "$msg" >> "$sharedMemoryOutput"
  80. fi
  81. }
  82. led_on(){ if [ -n "${1}" ] && [ -e "${1}/trigger" ]; then echo "default-on" > "${1}/trigger" 2>&1; fi; }
  83. led_off(){ if [ -n "${1}" ] && [ -e "${1}/trigger" ]; then echo "none" > "${1}/trigger" 2>&1; fi; }
  84. export serviceEnabled
  85. export forceDNS
  86. export parallelDL
  87. export debug
  88. export allowNonAscii
  89. export compressedCache
  90. export targetDNS
  91. export bootDelay
  92. export dlTimeout
  93. export curlRetry
  94. export verbosity
  95. export led
  96. export whitelist_domains
  97. export blacklist_domains
  98. export whitelist_domains_urls
  99. export blacklist_domains_urls
  100. export blacklist_hosts_urls
  101. export wan_if wan_gw wanphysdev dl_command serviceStatus dl_flag
  102. export outputFilter outputFilterIPv6 outputFile outputGzip outputCache ipv6Enabled
  103. load_package_config() {
  104. config_load "$packageName"
  105. config_get_bool serviceEnabled "config" "enabled" 1
  106. config_get_bool forceDNS "config" "force_dns" 1
  107. config_get_bool parallelDL "config" "parallel_downloads" 1
  108. config_get_bool debug "config" "debug" 0
  109. config_get_bool allowNonAscii "config" "allow_non_ascii" 0
  110. config_get_bool compressedCache "config" "compressed_cache" 0
  111. config_get_bool ipv6Enabled "config" "ipv6_enabled" 0
  112. config_get bootDelay "config" "boot_delay" "120"
  113. config_get dlTimeout "config" "download_timeout" "20"
  114. config_get curlRetry "config" "curl_retry" "3"
  115. config_get verbosity "config" "verbosity" "2"
  116. config_get led "config" "led"
  117. config_get targetDNS "config" "dns" "dnsmasq.servers"
  118. config_get whitelist_domains "config" "whitelist_domain"
  119. config_get blacklist_domains "config" "blacklist_domain"
  120. config_get whitelist_domains_urls "config" "whitelist_domains_url"
  121. config_get blacklist_domains_urls "config" "blacklist_domains_url"
  122. config_get blacklist_hosts_urls "config" "blacklist_hosts_url"
  123. if [ "$targetDNS" != "dnsmasq.addnhosts" ] && [ "$targetDNS" != "dnsmasq.conf" ] && \
  124. [ "$targetDNS" != "dnsmasq.servers" ] && [ "$targetDNS" != "unbound.adb_list" ]; then
  125. targetDNS="dnsmasq.servers"
  126. fi
  127. case "$targetDNS" in
  128. dnsmasq.addnhosts)
  129. outputFilter="$addnhostsOutputFilter"
  130. outputFile="$addnhostsFile"
  131. outputCache="$addnhostsCache"
  132. outputGzip="$addnhostsGzip"
  133. [ "$ipv6Enabled" -gt 0 ] && outputFilterIPv6="$addnhostsOutputFilterIPv6"
  134. rm -f "$dnsmasqFile" "$dnsmasqCache" "$dnsmasqGzip"
  135. rm -f "$serversFile" "$serversCache" "$serversGzip"
  136. rm -f "$unboundFile" "$unboundCache" "$unboundGzip"
  137. ;;
  138. dnsmasq.conf)
  139. outputFilter="$dnsmasqOutputFilter"
  140. outputFile="$dnsmasqFile"
  141. outputCache="$dnsmasqCache"
  142. outputGzip="$dnsmasqGzip"
  143. rm -f "$addnhostsFile" "$addnhostsCache" "$addnhostsGzip"
  144. rm -f "$serversFile" "$serversCache" "$serversGzip"
  145. rm -f "$unboundFile" "$unboundCache" "$unboundGzip"
  146. ;;
  147. dnsmasq.servers)
  148. outputFilter="$serversOutputFilter"
  149. outputFile="$serversFile"
  150. outputCache="$serversCache"
  151. outputGzip="$serversGzip"
  152. rm -f "$dnsmasqFile" "$dnsmasqCache" "$dnsmasqGzip"
  153. rm -f "$addnhostsFile" "$addnhostsCache" "$addnhostsGzip"
  154. rm -f "$unboundFile" "$unboundCache" "$unboundGzip"
  155. ;;
  156. unbound.adb_list)
  157. outputFilter="$unboundOutputFilter"
  158. outputFile="$unboundFile"
  159. outputCache="$unboundCache"
  160. outputGzip="$unboundGzip"
  161. rm -f "$dnsmasqFile" "$dnsmasqCache" "$dnsmasqGzip"
  162. rm -f "$addnhostsFile" "$addnhostsCache" "$addnhostsGzip"
  163. rm -f "$serversFile" "$serversCache" "$serversGzip"
  164. ;;
  165. esac
  166. if [ -z "${verbosity##*[!0-9]*}" ] || [ "$verbosity" -lt 0 ] || [ "$verbosity" -gt 2 ]; then
  167. verbosity=1
  168. fi
  169. . /lib/functions/network.sh
  170. . /usr/share/libubox/jshn.sh
  171. # Prefer curl because it supports the file: scheme.
  172. if [ -x /usr/bin/curl ] ; then
  173. dl_command="curl --insecure --retry $curlRetry --connect-timeout $dlTimeout --silent"
  174. dl_flag="-o"
  175. else
  176. dl_command="wget --no-check-certificate --timeout $dlTimeout -q"
  177. dl_flag="-O"
  178. fi
  179. led="${led:+/sys/class/leds/$led}"
  180. }
  181. is_enabled() {
  182. load_package_config
  183. if [ "$debug" -ne 0 ]; then
  184. exec 1>>/tmp/simple-adblock.log
  185. exec 2>&1
  186. set -x
  187. fi
  188. if [ "$serviceEnabled" -eq 0 ]; then
  189. case "$1" in
  190. on_start)
  191. output "$packageName is currently disabled.\\n"
  192. output "Run the following commands before starting service again:\\n"
  193. output "uci set ${packageName}.config.enabled='1'; uci commit $packageName;\\n"
  194. ;;
  195. esac
  196. return 1
  197. fi
  198. [ ! -d "${outputFile%/*}" ] && mkdir -p "${outputFile%/*}"
  199. [ ! -d "${outputCache%/*}" ] && mkdir -p "${outputFile%/*}"
  200. [ ! -d "${outputGzip%/*}" ] && mkdir -p "${outputFile%/*}"
  201. cacheOps 'testGzip' && return 0
  202. network_flush_cache; network_find_wan wan_if; network_get_gateway wan_gw "$wan_if";
  203. [ -n "$wan_gw" ] && return 0
  204. output "$_ERROR_: $serviceName failed to discover WAN gateway.\\n"; return 1;
  205. }
  206. dnsmasq_kill() { killall -q -HUP dnsmasq; }
  207. dnsmasq_restart() { /etc/init.d/dnsmasq restart >/dev/null 2>&1; }
  208. unbound_restart() { /etc/init.d/unbound restart >/dev/null 2>&1; }
  209. reload_resolver() {
  210. local param output_text
  211. case $1 in
  212. on_start)
  213. if [ ! -s "$outputFile" ]; then
  214. tmpfs set status "$statusFail"
  215. tmpfs add error "Error: Failed to create $outputFile file."
  216. output "$_ERROR_: $serviceName failed to create its data file!\\n"
  217. return 1
  218. fi
  219. case "$targetDNS" in
  220. dnsmasq.addnhosts)
  221. uci -q del_list dhcp.@dnsmasq[0].addnhosts="$addnhostsFile"
  222. uci add_list dhcp.@dnsmasq[0].addnhosts="$addnhostsFile"
  223. if [ -n "$(uci changes dhcp)" ]; then
  224. uci commit dhcp
  225. param=dnsmasq_restart
  226. output_text="Restarting DNSMASQ"
  227. else
  228. param=dnsmasq_kill
  229. output_text="Reloading DNSMASQ"
  230. fi
  231. ;;
  232. dnsmasq.conf)
  233. param=dnsmasq_restart
  234. output_text="Restarting DNSMASQ"
  235. ;;
  236. dnsmasq.servers)
  237. if [ "$(uci -q get dhcp.@dnsmasq[0].serversfile)" != "$serversFile" ]; then
  238. uci set dhcp.@dnsmasq[0].serversfile="$serversFile"
  239. uci commit dhcp
  240. param=dnsmasq_restart
  241. output_text="Restarting DNSMASQ"
  242. else
  243. param=dnsmasq_kill
  244. output_text="Reloading DNSMASQ"
  245. fi
  246. ;;
  247. unbound.adb_list)
  248. param=unbound_restart
  249. output_text="Restarting Unbound"
  250. ;;
  251. esac
  252. output 1 "$output_text "
  253. output 2 "$output_text "
  254. tmpfs set message "$output_text"
  255. if eval "$param"; then
  256. tmpfs set status "$statusSuccess"
  257. led_on "$led"
  258. output_okn
  259. else
  260. output_fail
  261. tmpfs set status "$statusFail"
  262. tmpfs add error "Error: $output_text error."
  263. output "$_ERROR_: $serviceName $output_text error!\\n"
  264. return 1
  265. fi
  266. ;;
  267. on_stop)
  268. cacheOps 'create'
  269. case "$targetDNS" in
  270. dnsmasq.addnhosts | dnsmasq.servers)
  271. if [ -n "$(uci changes dhcp)" ]; then
  272. uci -q commit dhcp
  273. param=dnsmasq_restart
  274. else
  275. param=dnsmasq_kill
  276. fi
  277. ;;
  278. dnsmasq.conf)
  279. param=dnsmasq_restart
  280. ;;
  281. unbound.adb_list)
  282. param=unbound_restart
  283. ;;
  284. esac
  285. eval "$param"
  286. return $?
  287. ;;
  288. quiet)
  289. case "$targetDNS" in
  290. dnsmasq.addnhosts | dnsmasq.servers | dnsmasq.conf)
  291. param=dnsmasq_restart
  292. ;;
  293. unbound.adb_list)
  294. param=unbound_restart
  295. ;;
  296. esac
  297. eval "$param"
  298. return $?
  299. ;;
  300. esac
  301. }
  302. tmpfs() {
  303. local action="$1" instance="$2" value="$3"
  304. local status message error stats
  305. local readReload readRestart curReload curRestart ret
  306. if [ -s "$jsonFile" ]; then
  307. status="$(jsonfilter -i $jsonFile -l1 -e "@['data']['status']")"
  308. message="$(jsonfilter -i $jsonFile -l1 -e "@['data']['message']")"
  309. error="$(jsonfilter -i $jsonFile -l1 -e "@['data']['error']")"
  310. stats="$(jsonfilter -i $jsonFile -l1 -e "@['data']['stats']")"
  311. readReload="$(jsonfilter -i $jsonFile -l1 -e "@['data']['reload']")"
  312. readRestart="$(jsonfilter -i $jsonFile -l1 -e "@['data']['restart']")"
  313. fi
  314. case "$action" in
  315. get)
  316. case "$instance" in
  317. status)
  318. echo "$status"; return;;
  319. message)
  320. echo "$message"; return;;
  321. error)
  322. echo "$error"; return;;
  323. stats)
  324. echo "$stats"; return;;
  325. triggers)
  326. curReload="$allowNonAscii $parallelDL $debug $dlTimeout $whitelist_domains $blacklist_domains $whitelist_domains_urls $blacklist_domains_urls $blacklist_hosts_urls $targetDNS"
  327. curRestart="$compressedCache $forceDNS $led"
  328. if [ "$curReload" != "$readReload" ]; then
  329. ret="download"
  330. elif [ "$curRestart" != "$readRestart" ]; then
  331. ret="restart"
  332. fi
  333. echo "$ret"
  334. return;;
  335. esac
  336. ;;
  337. add)
  338. case "$instance" in
  339. status)
  340. [ -n "$status" ] && status="$status $value" || status="$value";;
  341. message)
  342. [ -n "$message" ] && message="${message} ${value}" || message="$value";;
  343. error)
  344. [ -n "$error" ] && error="$error $value" || error="$value";;
  345. stats)
  346. [ -n "$stats" ] && stats="$stats $value" || stats="$value";;
  347. esac
  348. ;;
  349. del)
  350. case "$instance" in
  351. status)
  352. unset status;;
  353. message)
  354. unset message;;
  355. error)
  356. unset error;;
  357. stats)
  358. unset stats;;
  359. triggers)
  360. unset readReload; unset readRestart;;
  361. esac
  362. ;;
  363. set)
  364. case "$instance" in
  365. status)
  366. status="$value";;
  367. message)
  368. message="$value";;
  369. error)
  370. error="$value";;
  371. stats)
  372. stats="$value";;
  373. triggers)
  374. readReload="$allowNonAscii $parallelDL $debug $dlTimeout $whitelist_domains $blacklist_domains $whitelist_domains_urls $blacklist_domains_urls $blacklist_hosts_urls $targetDNS"
  375. readRestart="$compressedCache $forceDNS $led"
  376. ;;
  377. esac
  378. ;;
  379. esac
  380. json_init
  381. json_add_object "data"
  382. json_add_string version "$PKG_VERSION"
  383. json_add_string status "$status"
  384. json_add_string message "$message"
  385. json_add_string error "$error"
  386. json_add_string stats "$stats"
  387. json_add_string reload "$readReload"
  388. json_add_string restart "$readRestart"
  389. json_close_object
  390. json_dump > "$jsonFile"
  391. sync
  392. }
  393. cacheOps() {
  394. local R_TMP
  395. case "$1" in
  396. create|backup)
  397. [ -f "$outputFile" ] && mv "$outputFile" "$outputCache" >/dev/null 2>/dev/null
  398. return $?
  399. ;;
  400. restore|use)
  401. [ -f "$outputCache" ] && mv "$outputCache" "$outputFile" >/dev/null 2>/dev/null
  402. return $?
  403. ;;
  404. test)
  405. [ -s "$outputCache" ]
  406. return $?
  407. ;;
  408. testGzip)
  409. [ -s "$outputGzip" ] && gzip -t -c "$outputGzip"
  410. return $?
  411. ;;
  412. createGzip)
  413. R_TMP="$(mktemp -u -q -t ${packageName}_tmp.XXXXXXXX)"
  414. if gzip < "$outputFile" > "$R_TMP"; then
  415. if mv "$R_TMP" "$outputGzip"; then
  416. rm -f "$R_TMP"
  417. return 0
  418. else
  419. rm -f "$R_TMP"
  420. return 1
  421. fi
  422. else
  423. return 1
  424. fi
  425. ;;
  426. expand|unpack|expandGzip|unpackGzip)
  427. [ -s "$outputGzip" ] && gzip -dc < "$outputGzip" > "$outputCache"
  428. return $?
  429. ;;
  430. esac
  431. }
  432. is_chaos_calmer() { ubus -S call system board | grep -q "Chaos Calmer"; }
  433. remove_fw3_redirect() {
  434. local name
  435. config_get name "$1" "name"
  436. # shellcheck disable=SC2154
  437. if [ -n "$name" ] && str_contains "$name" "simple-adblock"; then
  438. uci -q del "firewall.$1"
  439. fi
  440. }
  441. fw3_setup() {
  442. config_load "firewall"
  443. config_foreach remove_fw3_redirect "redirect"
  444. if [ "$1" = "start" ]; then
  445. uci -q add firewall redirect >/dev/null 2>&1
  446. uci -q set firewall.@redirect[-1].name="simple_adblock_dns_hijack"
  447. uci -q set firewall.@redirect[-1].target="DNAT"
  448. uci -q set firewall.@redirect[-1].src="lan"
  449. uci -q set firewall.@redirect[-1].proto="tcpudp"
  450. uci -q set firewall.@redirect[-1].src_dport="53"
  451. uci -q set firewall.@redirect[-1].dest_port="53"
  452. uci -q set firewall.@redirect[-1].dest_ip="$2"
  453. uci -q set firewall.@redirect[-1].reflection="0"
  454. fi
  455. if [ -n "$(uci changes firewall)" ]; then
  456. uci -q commit firewall
  457. /etc/init.d/firewall restart >/dev/null 2>&1
  458. fi
  459. }
  460. process_url() {
  461. local label type D_TMP R_TMP
  462. if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then return 1; fi
  463. label="${1##*//}"; label="${label%%/*}";
  464. if [ "$2" = "hosts" ]; then
  465. label="Hosts: $label"; filter="$hostsFilter";
  466. else
  467. label="Domains: $label"; filter="$domainsFilter";
  468. fi
  469. if [ "$3" = "blocked" ]; then
  470. type="Blocked"; D_TMP="$B_TMP";
  471. else
  472. type="Allowed"; D_TMP="$A_TMP";
  473. fi
  474. while [ -z "$R_TMP" ] || [ -e "$R_TMP" ]; do
  475. R_TMP="$(mktemp -u -q -t ${packageName}_tmp.XXXXXXXX)"
  476. done
  477. if ! $dl_command "$1" $dl_flag "$R_TMP" 2>/dev/null || [ ! -s "$R_TMP" ]; then
  478. output 1 "$_FAIL_"
  479. output 2 "[DL] $type $label $__FAIL__\\n"
  480. printf "%b" "Error: downloading '${1}'.\\n" >> "$sharedMemoryError"
  481. else
  482. sed -i "$filter" "$R_TMP"
  483. if [ ! -s "$R_TMP" ]; then
  484. output 1 "$_FAIL_"
  485. output 2 "[DL] $type $label $__FAIL__\\n"
  486. printf "%b" "Error: parsing '${1}'.\\n" >> "$sharedMemoryError"
  487. else
  488. cat "${R_TMP}" >> "$D_TMP"
  489. output 1 "$_OK_"
  490. output 2 "[DL] $type $label $__OK__\\n"
  491. fi
  492. fi
  493. rm -f "$R_TMP"
  494. return 0
  495. }
  496. download_lists() {
  497. local hf w_filter j=0 R_TMP
  498. tmpfs set message "${statusDownloading}..."
  499. rm -f "$A_TMP" "$B_TMP" "$outputFile" "$outputCache" "$outputGzip"
  500. if [ "$(awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo")" -lt 32 ]; then
  501. output 3 "Low free memory, restarting resolver... "
  502. if reload_resolver 'quiet'; then
  503. output_okn
  504. else
  505. output_fail
  506. fi
  507. fi
  508. touch $A_TMP; touch $B_TMP;
  509. output 1 "Downloading lists "
  510. rm -f "$sharedMemoryError"
  511. if [ -n "$blacklist_hosts_urls" ]; then
  512. for hf in ${blacklist_hosts_urls}; do
  513. if [ "$parallelDL" -gt 0 ]; then
  514. process_url "$hf" "hosts" "blocked" &
  515. else
  516. process_url "$hf" "hosts" "blocked"
  517. fi
  518. done
  519. fi
  520. if [ -n "$blacklist_domains_urls" ]; then
  521. for hf in ${blacklist_domains_urls}; do
  522. if [ "$parallelDL" -gt 0 ]; then
  523. process_url "$hf" "domains" "blocked" &
  524. else
  525. process_url "$hf" "domains" "blocked"
  526. fi
  527. done
  528. fi
  529. if [ -n "$whitelist_domains_urls" ]; then
  530. for hf in ${whitelist_domains_urls}; do
  531. if [ "$parallelDL" -gt 0 ]; then
  532. process_url "$hf" "domains" "allowed" &
  533. else
  534. process_url "$hf" "domains" "allowed"
  535. fi
  536. done
  537. fi
  538. wait
  539. [ -s "$sharedMemoryError" ] && tmpfs add error "$(cat "$sharedMemoryError")"
  540. rm -f "$sharedMemoryError"
  541. output 1 "\\n"
  542. [ -n "$blacklist_domains" ] && for hf in ${blacklist_domains}; do echo "$hf" | sed "$domainsFilter" >> $B_TMP; done
  543. whitelist_domains="${whitelist_domains}
  544. $(cat $A_TMP)"
  545. [ -n "$whitelist_domains" ] && for hf in ${whitelist_domains}; do hf=$(echo "$hf" | sed 's/\./\\./g'); w_filter="$w_filter/^${hf}$/d;/\\.${hf}$/d;"; done
  546. [ ! -s "$B_TMP" ] && return 1
  547. output 1 "Processing downloads "
  548. output 2 "Sorting combined list "
  549. tmpfs set message "$statusProcessing: sorting combined list"
  550. if [ "$allowNonAscii" -gt 0 ]; then
  551. if sort "$B_TMP" | uniq > "$A_TMP"; then
  552. output_ok
  553. else
  554. output_failn
  555. tmpfs add error "Error: Sorting error."
  556. fi
  557. else
  558. if sort "$B_TMP" | uniq | grep -E -v '[^a-zA-Z0-9=/.-]' > "$A_TMP"; then
  559. output_ok
  560. else
  561. output_failn
  562. tmpfs add error "Error: Sorting error."
  563. fi
  564. fi
  565. if [ "$targetDNS" = "dnsmasq.conf" ] || \
  566. [ "$targetDNS" = "dnsmasq.servers" ] || \
  567. [ "$targetDNS" = "unbound.adb_list" ]; then
  568. # TLD optimization written by Dirk Brenken (dev@brenken.org)
  569. output 2 "Optimizing combined list "
  570. tmpfs set message "$statusProcessing: optimizing combined list"
  571. if awk -F "." '{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "$A_TMP" > "$B_TMP"; then
  572. if sort "$B_TMP" > "$A_TMP"; then
  573. if awk '{if(NR=1){tld=$NF};while(getline){if($NF!~tld"\\."){print tld;tld=$NF}}print tld}' "$A_TMP" > "$B_TMP"; then
  574. if awk -F "." '{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "$B_TMP" > "$A_TMP"; then
  575. if sort "$A_TMP" | uniq > "$B_TMP"; then
  576. output_ok
  577. else
  578. output_failn
  579. tmpfs add error "Error: Data file optimization."
  580. mv "$A_TMP" "$B_TMP"
  581. fi
  582. else
  583. output_failn
  584. tmpfs add error "Error: Data file optimization."
  585. fi
  586. else
  587. output_failn
  588. tmpfs add error "Error: Data file optimization."
  589. mv "$A_TMP" "$B_TMP"
  590. fi
  591. else
  592. output_failn
  593. tmpfs add error "Error: Data file optimization."
  594. fi
  595. else
  596. output_failn
  597. tmpfs add error "Error: Data file optimization."
  598. mv "$A_TMP" "$B_TMP"
  599. fi
  600. else
  601. mv "$A_TMP" "$B_TMP"
  602. fi
  603. output 2 "Whitelisting domains "
  604. tmpfs set message "$statusProcessing: whitelisting domains"
  605. if sed -i "$w_filter" "$B_TMP"; then
  606. output_ok
  607. else
  608. output_failn
  609. tmpfs add error "Error: Whitelist processing."
  610. fi
  611. output 2 "Formatting merged file "
  612. tmpfs set message "$statusProcessing: formatting merged file"
  613. if [ -z "$outputFilterIPv6" ]; then
  614. if sed "$outputFilter" "$B_TMP" > "$A_TMP"; then
  615. output_ok
  616. else
  617. output_failn
  618. tmpfs add error "Error: Data file formatting."
  619. fi
  620. else
  621. if sed "$outputFilter" "$B_TMP" > "$A_TMP" && \
  622. sed "$outputFilterIPv6" "$B_TMP" >> "$A_TMP"; then
  623. output_ok
  624. else
  625. output_failn
  626. tmpfs add error "Error: Data file formatting."
  627. fi
  628. fi
  629. case "$targetDNS" in
  630. dnsmasq.addnhosts)
  631. output 2 "Creating DNSMASQ addnhosts file "
  632. tmpfs set message "$statusProcessing: creating DNSMASQ addnhosts file"
  633. ;;
  634. dnsmasq.conf)
  635. output 2 "Creating DNSMASQ config file "
  636. tmpfs set message "$statusProcessing: creating DNSMASQ config file"
  637. ;;
  638. dnsmasq.servers)
  639. output 2 "Creating DNSMASQ servers file "
  640. tmpfs set message "$statusProcessing: creating DNSMASQ servers file"
  641. ;;
  642. unbound.adb_list)
  643. output 2 "Creating Unbound adb_list file "
  644. tmpfs set message "$statusProcessing: creating Unbound adb_list file"
  645. ;;
  646. esac
  647. if mv "$A_TMP" "$outputFile"; then
  648. output_ok
  649. else
  650. output_failn
  651. tmpfs add error "Error: moving data file '${A_TMP}' to '${outputFile}'."
  652. fi
  653. if [ "$compressedCache" -gt 0 ]; then
  654. output 2 "Creating compressed cache "
  655. tmpfs set message "$statusProcessing: creating compressed cache"
  656. if cacheOps 'createGzip'; then
  657. output_ok
  658. else
  659. output_failn
  660. tmpfs add error "Error: creating compressed cache."
  661. fi
  662. else
  663. rm -f "$outputGzip"
  664. fi
  665. output 2 "Removing temporary files "
  666. tmpfs set message "$statusProcessing: removing temporary files"
  667. rm -f "/tmp/${packageName}_tmp.*" "$A_TMP" "$B_TMP" "$outputCache" || j=1
  668. if [ $j -eq 0 ]; then
  669. output_ok
  670. else
  671. output_failn
  672. tmpfs add error "Error: removing temporary files."
  673. fi
  674. output 1 "\\n"
  675. }
  676. boot() {
  677. load_package_config
  678. if create_lock; then
  679. sleep "$bootDelay"
  680. remove_lock
  681. rc_procd start_service && rc_procd service_triggers
  682. fi
  683. }
  684. start_service() {
  685. is_enabled 'on_start' || return 1
  686. local ip action status error message stats
  687. if create_lock; then
  688. procd_open_instance "main"
  689. procd_set_param command /bin/true
  690. procd_set_param stdout 1
  691. procd_set_param stderr 1
  692. network_get_ipaddr ip "lan"
  693. # shellcheck disable=SC2154
  694. if [ "$forceDNS" -ne 0 ] && [ -n "$ip" ]; then
  695. if is_chaos_calmer; then
  696. fw3_setup "start" "$ip"
  697. else
  698. procd_open_data
  699. json_add_array firewall
  700. json_add_object ""
  701. json_add_string type redirect
  702. json_add_string target "DNAT"
  703. json_add_string src "lan"
  704. json_add_string dest "lan"
  705. json_add_string proto "tcpudp"
  706. json_add_string src_dport "53"
  707. json_add_string dest_port "53"
  708. json_add_string dest_ip "$ip"
  709. json_add_string name "simple-adblock-dns-hijack"
  710. json_add_string reflection "0"
  711. json_close_object
  712. json_close_array
  713. procd_close_data
  714. fi
  715. fi
  716. procd_close_instance
  717. status="$(tmpfs get status)"
  718. error="$(tmpfs get error)"
  719. message="$(tmpfs get message)"
  720. stats="$(tmpfs get stats)"
  721. action="$(tmpfs get triggers)"
  722. case "$1" in
  723. download) action="download";;
  724. restart|*)
  725. if [ "$1" != "restart" ] && [ -s "$outputFile" ] && [ -n "$status" ]; then
  726. status
  727. exit 0
  728. elif [ ! -s "$outputFile" ] && ! cacheOps 'test' && ! cacheOps 'testGzip'; then
  729. action="download"
  730. elif cacheOps 'test' || cacheOps 'testGzip'; then
  731. action="start"
  732. fi
  733. if [ -n "$error" ]; then
  734. action="download"
  735. fi
  736. action="${action:-$1}"
  737. ;;
  738. esac
  739. tmpfs del status
  740. tmpfs del error
  741. tmpfs del message
  742. tmpfs del stats
  743. tmpfs set triggers
  744. case $action in
  745. download)
  746. if [ -s "$outputFile" ] || cacheOps 'test' || cacheOps 'testGzip'; then
  747. output 0 "Force-reloading $serviceName... "
  748. output 3 "Force-reloading $serviceName...\\n"
  749. tmpfs set status "$statusForceReloading"
  750. else
  751. output 0 "Starting $serviceName... "
  752. output 3 "Starting $serviceName...\\n"
  753. tmpfs set status "$statusStarting"
  754. fi
  755. download_lists
  756. reload_resolver 'on_start'
  757. ;;
  758. restart|start)
  759. if [ "$action" = "restart" ]; then
  760. output 0 "Restarting $serviceName... "
  761. output 3 "Restarting $serviceName...\\n"
  762. tmpfs set status "$statusRestarting"
  763. else
  764. output 0 "Starting $serviceName... "
  765. output 3 "Starting $serviceName...\\n"
  766. tmpfs set status "$statusStarting"
  767. fi
  768. if cacheOps 'testGzip' && ! cacheOps 'test' && [ ! -s "$outputFile" ]; then
  769. output 3 "Found compressed cache file, unpacking it "
  770. tmpfs set message "found compressed cache file, unpacking it."
  771. if cacheOps 'unpackGzip'; then
  772. output_okn
  773. else
  774. output_fail
  775. output "$_ERROR_: $serviceName failed to unpack compressed cache!\\n"
  776. tmpfs add error "Error: Failed to unpack compressed cache."
  777. return 1
  778. fi
  779. fi
  780. if cacheOps 'test' && [ ! -s "$outputFile" ]; then
  781. output 3 "Found cache file, reusing it "
  782. tmpfs set message "found cache file, reusing it."
  783. if cacheOps 'restore'; then
  784. output_okn
  785. else
  786. output_fail
  787. tmpfs add error "Error: moving '$outputCache' to '$outputFile'."
  788. fi
  789. fi
  790. reload_resolver 'on_start'
  791. ;;
  792. esac
  793. if [ -s "$outputFile" ] && [ "$(tmpfs get status)" != "$statusFail" ]; then
  794. output 0 "$__OK__\\n";
  795. c="$(wc -l < "$outputFile")"
  796. output 3 "$serviceName is blocking $c domains "; output_okn
  797. tmpfs del message
  798. tmpfs set status "$statusSuccess: $c domains blocked (with ${targetDNS})."
  799. error="$(tmpfs get error)"
  800. if [ -n "$error" ]; then
  801. output "$(str_replace "$error" "Error:" "$_ERROR_:")\\n"
  802. fi
  803. else
  804. output 0 "$__FAIL__\\n";
  805. tmpfs set status "$statusFail"
  806. tmpfs add error "Error: Failed to create blocklist."
  807. fi
  808. remove_lock
  809. else
  810. output 3 "$serviceName: another instance is starting up "; output_fail
  811. return 0
  812. fi
  813. }
  814. service_started() { procd_set_config_changed firewall; }
  815. service_stopped() { procd_set_config_changed firewall; }
  816. restart_service() { rc_procd start_service "restart"; }
  817. reload_service() { restart_service; }
  818. restart() { restart_service; }
  819. reload() { restart_service; }
  820. dl() { rc_procd start_service "download"; }
  821. killcache() {
  822. rm -f "$addnhostsCache" "$addnhostsGzip"
  823. rm -f "$dnsmasqCache" "$dnsmasqGzip"
  824. rm -f "$serversCache" "$serversGzip"
  825. rm -f "$unboundCache" "$unboundGzip"
  826. return 0
  827. }
  828. status() {
  829. local status="$(tmpfs get status)" error="$(tmpfs get error)" message="$(tmpfs get message)"
  830. if [ -n "$status" ] && [ -n "$message" ]; then
  831. status="${status}: $message"
  832. fi
  833. [ -n "$status" ] && output "$serviceName $status\\n"
  834. [ -n "$error" ] && output "$error\\n"
  835. }
  836. stop_service() {
  837. load_package_config
  838. if is_chaos_calmer; then
  839. fw3_setup 'stop'
  840. fi
  841. if [ -s "$outputFile" ]; then
  842. output "Stopping $serviceName... "
  843. tmpfs del triggers
  844. if reload_resolver 'on_stop'; then
  845. led_off "$led"
  846. output 0 "$__OK__\\n"; output_okn
  847. tmpfs set status "$statusStopped"
  848. tmpfs del message
  849. else
  850. output 0 "$__FAIL__\\n"; output_fail
  851. tmpfs set status "$statusFail"
  852. tmpfs add error "Error: error stopping $serviceName."
  853. output "$_ERROR_: error stopping $serviceName!\\n"
  854. fi
  855. fi
  856. }
  857. check() {
  858. load_package_config
  859. local string="$1"
  860. if [ ! -f "$outputFile" ]; then
  861. echo "No blacklist ('$outputFile') found."
  862. elif [ -z "$string" ]; then
  863. echo "Usage: /etc/init.d/${packageName} check domain"
  864. elif grep -m1 -q "$string" "$outputFile"; then
  865. echo "Found $(grep -c "$string" "$outputFile") matches for '$string' in '$outputFile':"
  866. case "$targetDNS" in
  867. dnsmasq.addnhosts)
  868. grep "$string" "$outputFile" | sed 's|^127.0.0.1 ||;s|^:: ||;';;
  869. dnsmasq.conf)
  870. grep "$string" "$outputFile" | sed 's|local=/||;s|/$||;';;
  871. dnsmasq.servers)
  872. grep "$string" "$outputFile" | sed 's|server=/||;s|/$||;';;
  873. unbound.adb_list)
  874. grep "$string" "$outputFile" | sed 's|^local-zone: "||;s|" static$||;';;
  875. esac
  876. else
  877. echo "The $string is not found in current blacklist ('$outputFile')."
  878. fi
  879. }