simple-adblock: options to filter non-ASCII domains, local compressed storage 9395/head
authorStan Grishin <stangri@melmac.net>
Thu, 4 Jul 2019 22:38:58 +0000 (15:38 -0700)
committerStan Grishin <stangri@melmac.net>
Thu, 4 Jul 2019 22:38:58 +0000 (15:38 -0700)
Signed-off-by: Stan Grishin <stangri@melmac.net>
net/simple-adblock/Makefile
net/simple-adblock/files/README.md
net/simple-adblock/files/simple-adblock.conf
net/simple-adblock/files/simple-adblock.hotplug
net/simple-adblock/files/simple-adblock.init

index 0ef43b23a0f680d2a0d6ff6a18dd45f0a234b5a6..81081ab4fc21737a8ad68a1ee8cfe4d22ca0bc38 100644 (file)
@@ -5,10 +5,10 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=simple-adblock
-PKG_VERSION:=1.6.3
-PKG_RELEASE:=5
-PKG_LICENSE:=GPL-3.0+
+PKG_VERSION:=1.7.0
+PKG_RELEASE:=1
 PKG_MAINTAINER:=Stan Grishin <stangri@melmac.net>
+PKG_LICENSE:=GPL-3.0-or-later
 
 include $(INCLUDE_DIR)/package.mk
 
index fd3dd7f28303bac830b97a022afc1a711cf262de..605e30a1ec49c92bc921f0049c96a4eb9052610c 100644 (file)
@@ -1,7 +1,9 @@
 # Simple AdBlock
+
 A simple DNSMASQ-based AdBlocking service for OpenWrt/LEDE Project. Loosely based on [bole5's](https://forum.openwrt.org/profile.php?id=45571) idea with major performance improvements, added features and Web UI (as a separate package); inspired by @dibdot's innovation.
 
 ## Features
+
 - Supports OpenWrt Designated Driver and LEDE Project.
 - Super-fast due to the nature of supported block lists and backgrounding of already downloaded data while next list is downloading.
 - Supports both hosts files and domains lists for blocking (to keep it lean and fast).
@@ -18,62 +20,72 @@ A simple DNSMASQ-based AdBlocking service for OpenWrt/LEDE Project. Loosely base
 - Blocks ads served over https.
 - Proudly made in Canada, using locally-sourced electrons.
 
-If you want a more robust AdBlocking, supporting free memory detection and complex block lists, check out [@dibdot's adblock](https://github.com/openwrt/packages/tree/master/net/adblock/files).
-
+If you want a more robust AdBlocking, supporting free memory detection and complex block lists, supporting IDN, check out [@dibdot's adblock](https://github.com/openwrt/packages/tree/master/net/adblock/files).
 
 ## Screenshot (luci-app-simple-adblock)
-![screenshot](https://raw.githubusercontent.com/stangri/openwrt_packages/master/screenshots/simple-adblock/screenshot06.png "screenshot")
 
+![screenshot](https://raw.githubusercontent.com/stangri/openwrt_packages/master/screenshots/simple-adblock/screenshot06.png "screenshot")
 
 ## Requirements
+
 This service requires the following packages to be installed on your router: ```dnsmasq``` or ```dnsmasq-full``` and either ```ca-certificates```, ```wget``` and ```libopenssl``` (for OpenWrt 15.05.1) or ```uclient-fetch``` and ```libustream-mbedtls``` (for OpenWrt DD trunk and all LEDE Project builds). Additionally installation of ```coreutils-sort``` is highly recommended as it speeds up blocklist processing.
 
 To satisfy the requirements for connect to your router via ssh and run the following commands:
-###### OpenWrt 15.05.1
+
+### OpenWrt 15.05.1 Requirements
+
 ```sh
 opkg update; opkg install ca-certificates wget libopenssl coreutils-sort dnsmasq
 ```
 
-###### LEDE Project 17.01.x and OpenWrt 18.xx or later
+### LEDE Project 17.01.x and OpenWrt 18.xx or later Requirements
+
 ```sh
 opkg update; opkg install uclient-fetch libustream-mbedtls coreutils-sort dnsmasq
 ```
 
-###### IPv6 Support
+### IPv6 Support
+
 For IPv6 support additionally install ```ip6tables-mod-nat``` and ```kmod-ipt-nat6``` packages from Web UI or run the following in the command line:
+
 ```sh
 opkg update; opkg install ip6tables-mod-nat kmod-ipt-nat6
 ```
 
-###### Speed up blocklist processing with coreutils-sort
+### Speed up blocklist processing with coreutils-sort
+
 The ```coreutils-sort``` is an optional, but recommended package as it speeds up sorting and removing duplicates from the merged list dramatically. If opkg complains that it can't install ```coreutils-sort``` because /usr/bin/sort is already provided by busybox, you can run ```opkg --force-overwrite install coreutils-sort```.
 
+## Unmet dependencies
 
-#### Unmet dependencies
 If you are running a development (trunk/snapshot) build of OpenWrt/LEDE Project on your router and your build is outdated (meaning that packages of the same revision/commit hash are no longer available and when you try to satisfy the [requirements](#requirements) you get errors), please flash either current LEDE release image or current development/snapshot image.
 
-
 ## How to install
+
 Install ```simple-adblock``` and ```luci-app-simple-adblock``` packages from Web UI or run the following in the command line:
+
 ```sh
 opkg update; opkg install simple-adblock luci-app-simple-adblock
 ```
 
 If ```simple-adblock``` and ```luci-app-simple-adblock``` packages are not found in the official feed/repo for your version of OpenWrt/LEDE Project, you will need to [add a custom repo to your router](#add-custom-repo-to-your-router) first.
 
+### Add custom repo to your router
 
-#### Add custom repo to your router
 If your router is not set up with the access to repository containing these packages you will need to add custom repository to your router by connecting to your router via ssh and running the following commands:
 
-###### OpenWrt 15.05.1
+#### OpenWrt 15.05.1 Instructions
+
 ```sh
 opkg update; opkg install ca-certificates wget libopenssl
 echo -e -n 'untrusted comment: LEDE usign key of Stan Grishin\nRWR//HUXxMwMVnx7fESOKO7x8XoW4/dRidJPjt91hAAU2L59mYvHy0Fa\n' > /tmp/stangri-repo.pub && opkg-key add /tmp/stangri-repo.pub
 ! grep -q 'stangri_repo' /etc/opkg/customfeeds.conf && echo 'src/gz stangri_repo https://raw.githubusercontent.com/stangri/openwrt-repo/master' >> /etc/opkg/customfeeds.conf
 opkg update
+opkg install simple-adblock luci-app-simple-adblock
 ```
 
-###### LEDE Project and OpenWrt 18.xx or later
+#### LEDE Project 17.01.x and OpenWrt 18.06.x Instructions
+
 ```sh
 opkg update
 opkg list-installed | grep -q uclient-fetch || opkg install uclient-fetch
@@ -81,26 +93,37 @@ opkg list-installed | grep -q libustream || opkg install libustream-mbedtls
 echo -e -n 'untrusted comment: LEDE usign key of Stan Grishin\nRWR//HUXxMwMVnx7fESOKO7x8XoW4/dRidJPjt91hAAU2L59mYvHy0Fa\n' > /tmp/stangri-repo.pub && opkg-key add /tmp/stangri-repo.pub
 ! grep -q 'stangri_repo' /etc/opkg/customfeeds.conf && echo 'src/gz stangri_repo https://raw.githubusercontent.com/stangri/openwrt-repo/master' >> /etc/opkg/customfeeds.conf
 opkg update
+opkg install simple-adblock luci-app-simple-adblock
 ```
 
+## Default Settings
 
-#### Default Settings
 Default configuration has service disabled (use Web UI to enable/start service or run ```uci set simple-adblock.config.enabled=1```) and selected ad/malware lists suitable for routers with 64Mb RAM. The configuration file has lists in descending order starting with biggest ones, comment out or delete the lists you don't want or your router can't handle.
 
-
 ## How to customize
+
 You can use Web UI (found in Services/Simple AdBlock) to add/remove/edit links to:
+
 - hosts files (127.0.0.1 or 0.0.0.0 followed by space and domain name per line) to be blocked.
 - domains lists (one domain name per line) to be blocked.
 - domains lists (one domain name per line) to be whitelisted. It is useful if you want to run simple-adblock on multiple routers and maintain one centralized whitelist which you can publish on a web-server.
 
-Please note that these lists **have** to include either ```http://``` or ```https://``` prefix. Some of the top block lists (both hosts files and domains lists) suitable for routers with at least 8MB RAM are used in the default simple-adblock installation.
+Please note that these lists **have** to include either ```http://``` or ```https://``` (or, if ```curl``` is installed the ```file://```) prefix. Some of the top block lists (both hosts files and domains lists) suitable for routers with at least 8MB RAM are used in the default simple-adblock installation.
 
 You can also use Web UI to add individual domains to be blocked or whitelisted.
 
 If you want to use CLI to customize simple-adblock config, you can probably figure out how to do it by looking at the contents of ```/etc/config/simple-adblock``` or output of the ```uci show simple-adblock``` command.
 
+## How to use
+
+Once the service is enabled in the [config file](#default-settings), run ```/etc/init.d/simple-adblock start``` to start the service. Either ```/etc/init.d/simple-adblock restart``` or ```/etc/init.d/simple-adblock reload``` will only restart the service and/or re-donwload the lists if there were relevant changes in the config file since the last successful start. Had the previous start resulted in any error, either ```/etc/init.d/simple-adblock start```, ```/etc/init.d/simple-adblock restart``` or ```/etc/init.d/simple-adblock reload``` will attempt to re-download the lists.
+
+If you want to force simple-adblock to re-download the lists, run ```/etc/init.d/simple-adblock download```.
+
+If you want to check if the specific domain (or part of the domain name) is being blocked, run ```/etc/init.d/simple-adblock check test-domain.com```.
+
 ## How does it work
+
 This service downloads (and processes in the background, removing comments and other useless data) lists of hosts and domains to be blocked, combines those lists into one big block list, removes duplicates and sorts it and then removes your whitelisted domains from the block list before converting to to dnsmasq-compatible file and restarting dnsmasq. The result of the process is that dnsmasq returns "domain not found" for the blocked domains.
 
 If you specify ```google.com``` as a domain to be whitelisted, you will have access to ```google.com```, ```www.google.com```, ```analytics.google.com```, but not fake domains like ```email-google.com``` or ```drive.google.com.verify.signin.normandeassociation.com``` for example. If you only want to allow ```www.google.com``` while blocking all other ```google.com``` subdomains, just specify ```www.google.com``` as domain to be whitelisted.
@@ -108,23 +131,9 @@ If you specify ```google.com``` as a domain to be whitelisted, you will have acc
 In general, whatever domain is specified to be whitelisted; it, along with with its subdomains will be whitelisted, but not any fake domains containing it.
 
 ## Documentation / Discussion
+
 Please head [LEDE Project Forum](https://forum.lede-project.org/t/simple-adblock-fast-lean-and-fully-uci-luci-configurable-adblocking/1327/) for discussion of this package.
 
-## What's New
-1.5.8:
-- Better start/stop/reload logic.
-- Better uninstall logic.
-- Better start/stop/reload from Web UI.
-- New command-line ```check``` command.
-
-1.5.7:
-- Much stricter filters for hosts and domains lists resulting in better garbage removal.
-- Better handling of service start/enable from Web UI and enabled flag management.
-- Implemented support to set one of the router LEDs on/off based on the AdBlocking status.
-- Fixed the output bug when verbosity=1.
-- No longer using enabled in config file, Simple AdBlocking Web UI now enables/disables service directly.
-- Reworked console/system log output logic and formatting.
-- Processes already downloaded lists in the background while downloading next list from config, dramatically increasing overall speed.
-
-1.0.0:
-- Initial release
+## Thanks
+
+I'd like to thank everyone who helped create, test and troubleshoot this service. Special thanks to [@hnyman](https://github.com/hnyman) for general package/luci guidance, [@dibdot](https://github.com/dibdot) for general guidance and block-list optimization code and [@ckuethe](https://github.com/ckuethe) for the curl support, non-ASCII filtering and compressed cache code.
\ No newline at end of file
index ee151594edef1e9be352dee05aa0f961d3107a0f..27a2a52fb2e8e4f8765d0a68fa29bda20455af16 100644 (file)
@@ -2,25 +2,31 @@ config simple-adblock 'config'
        option enabled '0'
        option verbosity '2'
        option force_dns '1'
-       option hosts_file '/var/dnsmasq.d/simple-adblock'
+       option led 'none'
+       option boot_delay '120'
+       option download_timeout '10'
+       option parallel_downloads '1'
+       option debug '0'
+       option allow_non_ascii '0'
+       option compressed_cache '0'
   list whitelist_domain 'raw.githubusercontent.com'
 #      list blacklist_hosts_url 'http://support.it-mate.co.uk/downloads/hosts.txt'
-#      list blacklist_hosts_url 'http://hostsfile.mine.nu/Hosts'
-#      list blacklist_hosts_url 'http://hosts-file.net/.\ad_servers.txt'
-#      list blacklist_hosts_url 'http://sysctl.org/cameleon/hosts.win'
+#      list blacklist_hosts_url 'https://hostsfile.mine.nu/Hosts'
+#      list blacklist_hosts_url 'https://hosts-file.net/ad_servers.txt'
+#      list blacklist_hosts_url 'http://sysctl.org/cameleon/hosts'
        list blacklist_hosts_url 'http://www.mvps.org/winhelp2002/hosts.txt'
-       list blacklist_hosts_url 'http://pgl.yoyo.org/as/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext'
-       list blacklist_hosts_url 'http://www.malwaredomainlist.com/hostslist/hosts.txt'
+       list blacklist_hosts_url 'https://pgl.yoyo.org/as/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext'
+       list blacklist_hosts_url 'https://www.malwaredomainlist.com/hostslist/hosts.txt'
        list blacklist_hosts_url 'https://adaway.org/hosts.txt'
-       list blacklist_hosts_url 'http://someonewhocares.org/hosts/hosts'
+       list blacklist_hosts_url 'https://someonewhocares.org/hosts/hosts'
        list blacklist_hosts_url 'https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/hosts.txt'
        list blacklist_hosts_url 'https://zeustracker.abuse.ch/blocklist.php?download=hostfile'
-       list blacklist_domains_url 'http://mirror1.malwaredomains.com/files/justdomains'
+       list blacklist_domains_url 'https://mirror1.malwaredomains.com/files/justdomains'
        list blacklist_domains_url 'https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt'
        list blacklist_domains_url 'https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt'
        list blacklist_domains_url 'https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt'
        list blacklist_domains_url 'https://ransomwaretracker.abuse.ch/downloads/RW_DOMBL.txt'
        list blacklist_domains_url 'https://ssl.bblck.me/blacklists/domain-list.txt'
-       list blacklist_domains_url 'http://dshield.org/feeds/suspiciousdomains_High.txt'
-#      list blacklist_domains_url 'http://dshield.org/feeds/suspiciousdomains_Medium.txt'
-#      list blacklist_domains_url 'http://dshield.org/feeds/suspiciousdomains_Low.txt'
+       list blacklist_domains_url 'https://dshield.org/feeds/suspiciousdomains_High.txt'
+#      list blacklist_domains_url 'https://dshield.org/feeds/suspiciousdomains_Medium.txt'
+#      list blacklist_domains_url 'https://dshield.org/feeds/suspiciousdomains_Low.txt'
index 53062460d9911f6da7870e6d882e97772a7cedb9..a21673a68b62c63f99a727ab32dd724086b1bfbe 100644 (file)
@@ -1,5 +1,5 @@
 #!/bin/sh
 
-if [[ "$ACTION" == "ifup" ]]; then
+if [ "$ACTION" = "ifup" ]; then
   sleep 10 && /etc/init.d/simple-adblock start &
 fi
index 799ee44677c7b2ec7b690e8680d27e82fb985e68..78cb6f4c61437e92c132bc8a98fe10db4b355bc8 100644 (file)
@@ -1,22 +1,26 @@
 #!/bin/sh /etc/rc.common
-# TLD optimization written by Dirk Brenken (dev@brenken.org)
 PKG_VERSION=
 
 export START=94
 export USE_PROCD=1
+export LC_ALL=C
+
+export EXTRA_COMMANDS="check dl killcache status"
+export EXTRA_HELP="    check   Checks if specified domain is found in current blacklist
+       dl              Force-redownloads all the lists, even if the last download was successful and no config changes were made
+       status    Shows the service last-run status"
 
-readonly packageName='simple-adblock'
+readonly packageName="simple-adblock"
 readonly serviceName="$packageName $PKG_VERSION"
-readonly PID="/var/run/${packageName}.pid"
 readonly dnsmasqFile="/var/dnsmasq.d/${packageName}"
-export EXTRA_COMMANDS="check killcache"
-export EXTRA_HELP="    check   Checks if specified domain is found in current blacklist"
-
-readonly A_TMP='/var/simple-adblock.hosts.a.tmp'
-readonly B_TMP='/var/simple-adblock.hosts.b.tmp'
-readonly CACHE_TMP='/var/simple-adblock.cache'
-readonly h_filter='/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;'
-readonly d_filter='/^#/d;s/[[:space:]]*#.*$//;s/[[:space:]]*$//;s/[[:cntrl:]]$//;/[[:space:]]/d;/[`~!@#\$%\^&\*()=+;:"'\'',<>?/\|[{}]/d;/]/d;/\./!d;/^$/d;'
+readonly compressedCacheFile="/etc/${packageName}.gz"
+readonly A_TMP="/var/simple-adblock.hosts.a.tmp"
+readonly B_TMP="/var/simple-adblock.hosts.b.tmp"
+readonly cacheFile="/var/run/${packageName}.cache"
+readonly PIDFile="/var/run/${packageName}.pid"
+readonly JsonFile="/var/run/${packageName}.json"
+readonly h_filter='/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;'
+readonly d_filter='/^#/d;s/[[:space:]]*#.*$//;s/[[:space:]]*$//;s/[[:cntrl:]]$//;/[[:space:]]/d;/[`~!@#\$%\^&\*()=+;:"'\'',<>?/\|[{}]/d;/]/d;/\./!d;/^$/d;/[^[:alnum:]_.-]/d;'
 readonly f_filter='s|^|local=/|;s|$|/|'
 readonly checkmark='\xe2\x9c\x93'
 readonly xmark='\xe2\x9c\x97'
@@ -25,56 +29,97 @@ readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
 readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m'
 readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m'
 readonly _ERROR_='\033[0;31mERROR\033[0m'
+readonly statusSuccess='Success'
+readonly statusFail='Fail'
+readonly statusDownloading='Downloading'
+readonly statusReloading='Reloading'
+readonly statusRestarting='Restarting'
+readonly statusStarting='Starting'
+readonly statusForceReloading='Force-Reloading'
+readonly statusProcessing='Processing'
+readonly statusStopped='Stopped'
 
-create_lock() { [ -e "$PID" ] && return 1; touch "$PID"; }
-remove_lock() { [ -e "$PID" ] && rm -f "$PID"; rm -f /var/simple-adblock_tmp_* >/dev/null 2>&1; }
+create_lock() { [ -e "$PIDFile" ] && return 1; touch "$PIDFile"; }
+remove_lock() { [ -e "$PIDFile" ] && rm -f "$PIDFile"; } # rm -f /var/simple-adblock_tmp_* >/dev/null 2>&1; }
 trap remove_lock EXIT
-output_ok() { case $verbosity in 1) output 1 "$_OK_";; 2) output 2 "$__OK__\n";; esac; }
-output_okn() { case $verbosity in 1) output 1 "$_OK_\n";; 2) output 2 "$__OK__\n";; esac; }
-output_fail() { case $verbosity in 1) output 1 "$_FAIL_";; 2) output 2 "$__FAIL__\n";; esac; }
-output_failn() { case $verbosity in 1) output 1 "$_FAIL_\n";; 2) output 2 "$__FAIL__\n";; esac; }
+output_ok() { case $verbosity in 1) output 1 "$_OK_";; 2) output 2 "$__OK__\\n";; esac; }
+output_okn() { case $verbosity in 1) output 1 "$_OK_\\n";; 2) output 2 "$__OK__\\n";; esac; }
+output_fail() { case $verbosity in 1) output 1 "$_FAIL_";; 2) output 2 "$__FAIL__\\n";; esac; }
+output_failn() { case $verbosity in 1) output 1 "$_FAIL_\\n";; 2) output 2 "$__FAIL__\\n";; esac; }
 export logmsg
 output() {
 # Can take a single parameter (text) to be output at any verbosity
 # Or target verbosity level and text to be output at specifc verbosity
-       if [[ $# -ne 1 ]]; then
-               [[ ! $((verbosity & $1)) -gt 0 ]] && return 0 || shift
+       if [ $# -ne 1 ]; then
+               if [ ! $((verbosity & $1)) -gt 0 ]; then return 0; else shift; fi
        fi
-       [[ -t 1 ]] && echo -e -n "$1" # if we're running in console, echo text
-       # strip text of ASCII control characters and send completed lines to log
+       [ -t 1 ] && echo -e -n "$1"
        local msg=$(echo -n "${1/$serviceName /service }" | sed 's|\\033\[[0-9]\?;\?[0-9]\?[0-9]\?m||g');
-       if [[ $(echo -e -n "$msg" | wc -l) -gt 0 ]]; then
-               logger -t "${packageName:-service} [$$]" "$(echo -e -n ${logmsg}${msg})"
-               logmsg=''
+       if [ "$(echo -e -n "$msg" | wc -l)" -gt 0 ]; then
+               logger -t "${packageName:-service} [$$]" "$(echo -e -n "${logmsg}${msg}")"
+               logmsg=""
        else
-               logmsg=${logmsg}${msg}
+               logmsg="${logmsg}${msg}"
        fi
 }
-led_on(){ [[ -n "${1}" && -e "${1}/trigger" ]] && echo "default-on" > "${1}/trigger" 2>&1; }
-led_off(){ [[ -n "${1}" && -e "${1}/trigger" ]] && echo "none" > "${1}/trigger" 2>&1; }
-boot() { load_package_config; ( sleep $bootDelay && rc_procd start_service && rc_procd service_triggers | cat & ); }
+led_on(){ if [ -n "${1}" ] && [ -e "${1}/trigger" ]; then echo "default-on" > "${1}/trigger" 2>&1; fi; }
+led_off(){ if [ -n "${1}" ] &&  [ -e "${1}/trigger" ]; then echo "none" > "${1}/trigger" 2>&1; fi; }
+testCompressedCache(){ [ "$compressedCache" -gt 0 ] && gzip -t -c $compressedCacheFile; }
+boot() { load_package_config; ( sleep "$bootDelay" && rc_procd start_service && rc_procd service_triggers | cat & ); }
 
-export serviceEnabled verbosity forceDNS debug led wan_if wan_gw wanphysdev bootDelay dl_command serviceStatus
+export serviceEnabled
+export forceDNS
+export parallelDL
+export debug
+export allowNonAscii
+export compressedCache     
+export bootDelay
+export dlTimeout
+export verbosity
+export led
+export whitelist_domains
+export blacklist_domains
+export whitelist_domains_urls
+export blacklist_domains_urls
+export blacklist_hosts_urls
+export wan_if wan_gw wanphysdev dl_command serviceStatus dl_flag
+export dlStatus
 
 load_package_config() {
        config_load "$packageName"
-       config_get_bool serviceEnabled 'config' 'enabled' 1
-       config_get_bool forceDNS       'config' 'force_dns' 1
-       config_get_bool debug          'config' 'debug' 0
-       config_get bootDelay           'config' 'boot_delay' '120'
-       config_get dlTimeout           'config' 'download_timeout' '20'
-       config_get verbosity           'config' 'verbosity' '2'
-       config_get led                 'config' 'led'
-       if [ -z "${verbosity##*[!0-9]*}" ] || [ $verbosity -lt 0 ] || [ $verbosity -gt 2 ]; then
+       config_get_bool serviceEnabled        "config" "enabled" 1
+       config_get_bool forceDNS              "config" "force_dns" 1
+       config_get_bool parallelDL            "config" "parallel_downloads" 1
+       config_get_bool debug                 "config" "debug" 0
+       config_get_bool allowNonAscii         "config" "allow_non_ascii" 0
+       config_get_bool compressedCache       "config" "compressed_cache" 0
+       config_get bootDelay                  "config" "boot_delay" "120"
+       config_get dlTimeout                  "config" "download_timeout" "20"
+       config_get verbosity                  "config" "verbosity" "2"
+       config_get led                        "config" "led"
+       config_get whitelist_domains          "config" "whitelist_domain"
+       config_get blacklist_domains          "config" "blacklist_domain"
+       config_get whitelist_domains_urls     "config" "whitelist_domains_url"
+       config_get blacklist_domains_urls     "config" "blacklist_domains_url"
+       config_get blacklist_hosts_urls       "config" "blacklist_hosts_url"
+
+       if [ -z "${verbosity##*[!0-9]*}" ] || [ "$verbosity" -lt 0 ] || [ "$verbosity" -gt 2 ]; then
                verbosity=1
        fi
-       source /lib/functions/network.sh
-       dl_command="wget --no-check-certificate --timeout $dlTimeout -qO-"
+       . /lib/functions/network.sh
+       . /usr/share/libubox/jshn.sh
+       # Prefer curl because it supports the file: scheme.
+       if [ -x /usr/bin/curl ] ; then
+               dl_command="curl --insecure --connect-timeout $dlTimeout --silent"
+               dl_flag="-o"
+       else
+               dl_command="wget --no-check-certificate --timeout $dlTimeout -q"
+               dl_flag="-O"
+       fi
        led="${led:+/sys/class/leds/$led}"
 }
 
 is_enabled() {
-       local sleepCount=1
        load_package_config
 
        if [ "$debug" -ne 0 ]; then
@@ -83,17 +128,19 @@ is_enabled() {
                set -x
        fi
 
-       if [ $serviceEnabled -eq 0 ]; then
-               if [ "$1" == "on_start" ]; then
-                       output "$packageName is currently disabled.\n"
-                       output "Run the following commands before starting service again:\n"
-                       output "uci set $packageName.config.enabled='1'; uci commit;\n"
+       if [ "$serviceEnabled" -eq 0 ]; then
+               if [ "$1" = "on_start" ]; then
+                       output "$packageName is currently disabled.\\n"
+                       output "Run the following commands before starting service again:\\n"
+                       output "uci set $packageName.config.enabled='1'; uci commit;\\n"
                fi
                return 1
        fi
-       network_flush_cache; network_find_wan wan_if;   network_get_gateway wan_gw $wan_if;
+       [ ! -d ${dnsmasqFile%/*} ] && mkdir -p ${dnsmasqFile%/*}
+       testCompressedCache && return 0
+       network_flush_cache; network_find_wan wan_if; network_get_gateway wan_gw "$wan_if";
        [ -n "$wan_gw" ] && return 0
-       output "$_ERROR_: $serviceName failed to discover WAN gateway.\n"; return 1;
+       output "$_ERROR_: $serviceName failed to discover WAN gateway.\\n"; return 1;
 }
 
 dnsmasq_kill() { killall -q -HUP dnsmasq; }
@@ -101,34 +148,43 @@ dnsmasq_restart() { /etc/init.d/dnsmasq restart >/dev/null 2>&1; }
 reload_dnsmasq() {
        case $1 in
                on_start)
-                       if [ -s $dnsmasqFile ]; then
-                               output 3 'Restarting dnsmasq '
+                       if [ -s "$dnsmasqFile" ]; then
+                               output 3 "Restarting DNSMASQ "
+                               tmpfs set message "restarting DNSMASQ"
                                if dnsmasq_restart; then
+                                       tmpfs set status "$statusSuccess"
                                        led_on "$led"
                                        output_okn
-                               else
+                               else 
                                        output_failn
-                                       output "$_ERROR_: $serviceName failed to restart dnsmasq!\n"
-                                       serviceStatus="${serviceStatus:-'DNSMASQ restart error'}"
+                                       tmpfs set status "$statusFail"
+                                       tmpfs add error "DNSMASQ restart error"
+                                       output "$_ERROR_: $serviceName failed to restart DNSMASQ!\\n"
                                        return 1
                                fi
                        else
-                               output "$_ERROR_: $serviceName failed to create its data file!\n"
-                               serviceStatus="${serviceStatus:-'Failed to create data file'}"
+                               tmpfs set status "$statusFail"
+                               tmpfs add error "Failed to create $dnsmasqFile file."
+                               output "$_ERROR_: $serviceName failed to create its data file!\\n"
                                return 1
                        fi
                        ;;
                on_stop)
-                       [ -f $dnsmasqFile ] && mv $dnsmasqFile $CACHE_TMP
-                       output 3 'Restarting dnsmasq '
+                       [ -f $dnsmasqFile ] && mv $dnsmasqFile $cacheFile
+                       output 3 "Restarting dnsmasq "
                        if dnsmasq_restart; then
                                led_off "$led"
                                output_okn
-                               output "$serviceName stopped.\n"
+                               output "$serviceName stopped.\\n"
+                               tmpfs set status "$statusStopped"
+                               tmpfs del message
+                               tmpfs del error
                                return 0
                        else
                                output_failn;
-                               output "$_ERROR_: $serviceName failed to restart dnsmasq!\n"
+                               tmpfs set status "$statusFail"
+                               tmpfs add error "DNSMASQ restart error on stop"
+                               output "$_ERROR_: $serviceName failed to restart DNSMASQ on stop !\\n"
                                return 1
                        fi
                        ;;
@@ -138,45 +194,122 @@ reload_dnsmasq() {
        esac
 }
 
-ubus_status(){
-       case "$1" in
+tmpfs(){
+       local action="$1" instance="$2" value="$3" 
+       local status message error stats 
+       local readReload readRestart curReload curRestart ret
+       if [ -s "$JsonFile" ]; then
+               status="$(jsonfilter -i $JsonFile -l1 -e "@['data']['status']")"
+               message="$(jsonfilter -i $JsonFile -l1 -e "@['data']['message']")"
+               error="$(jsonfilter -i $JsonFile -l1 -e "@['data']['error']")"
+               stats="$(jsonfilter -i $JsonFile -l1 -e "@['data']['stats']")"
+               readReload="$(jsonfilter -i $JsonFile -l1 -e "@['data']['reload']")"
+               readRestart="$(jsonfilter -i $JsonFile -l1 -e "@['data']['restart']")"
+       fi
+       case "$action" in
+               get)
+                       case "$instance" in
+                               status)
+                                       echo "$status"; return;;
+                               message) 
+                                       echo "$message"; return;;
+                               error) 
+                                       echo "$error"; return;;
+                               stats) 
+                                       echo "$stats"; return;;
+                               triggers)
+                                       curReload="$allowNonAscii $parallelDL $debug $dlTimeout $whitelist_domains $blacklist_domains $whitelist_domains_urls $blacklist_domains_urls $blacklist_hosts_urls"
+                                       curRestart="$compressedCache $forceDNS $led"
+                                       if [ "$curReload" != "$readReload" ]; then
+                                               ret="download"
+                                       elif [ "$curRestart" != "$readRestart" ]; then
+                                               ret="restart"
+                                       fi
+                                       echo "$ret"
+                                       return;;
+                       esac
+                       ;;
                add)
-                       ubus_status set "$(ubus_status get)${2}"
+                       case "$instance" in
+                               status)
+                                       [ -n "$status" ] && status="$status $value" || status="$value";;
+                               message) 
+                                       [ -n "$message" ] && message="${message} ${value}" || message="$value";;
+                               error) 
+                                       [ -n "$error" ] && error="$error $value" || error="$value";;
+                               stats) 
+                                       [ -n "$stats" ] && stats="$stats $value" || stats="$value";;
+                       esac
                        ;;
-               del | set)
-                       ubus call service set "{ \"name\": \"${packageName}\", \"instances\": { \"status\": { \"command\": [ \"\" ],  \"data\": { \"status\": \"${2}\" }}}}"
-                       # ubus call service set "{ \"name\": \"${packageName}\", \"instances\": { \"status\": { \"data\": { \"status\": \"${2}\" }}}}"
+               del)
+                       case "$instance" in
+                               status)
+                                       unset status;;
+                               message) 
+                                       unset message;;
+                               error) 
+                                       unset error;;
+                               stats) 
+                                       unset stats;;
+                               triggers) 
+                                       unset readReload; unset readRestart;;
+                       esac
                        ;;
-               get)
-                       echo "$(ubus call service list "{\"name\": \"${packageName}\"}" | jsonfilter -l1 -e "@['${packageName}']['instances']['status']['data']['status']")"
+               set)
+                       case "$instance" in
+                               status)
+                                       status="$value";;
+                               message) 
+                                       message="$value";;
+                               error) 
+                                       error="$value";;
+                               stats) 
+                                       stats="$value";;
+                               triggers) 
+                                       readReload="$allowNonAscii $parallelDL $debug $dlTimeout $whitelist_domains $blacklist_domains $whitelist_domains_urls $blacklist_domains_urls $blacklist_hosts_urls"
+                                       readRestart="$compressedCache $forceDNS $led"
+                                       ;;
+                       esac
                        ;;
        esac
+  json_init
+  json_add_object "data"
+  json_add_string version "$PKG_VERSION"
+  json_add_string status "$status"
+  json_add_string message "$message"
+  json_add_string error "$error"
+  json_add_string stats "$stats"
+  json_add_string reload "$readReload"
+  json_add_string restart "$readRestart"
+  json_close_object
+  json_dump > "$JsonFile"
+       sync
 }
 
-is_chaos_calmer() { ubus -S call system board | grep -q 'Chaos Calmer'; }
+is_chaos_calmer() { ubus -S call system board | grep -q "Chaos Calmer"; }
 
 remove_fw3_redirect() {
-       config_get name "$1" 'name'
-       if [[ -n "$name" && "$name" != "${name//simple_adblock}" ]]; then
+       local name
+       config_get name "$1" "name"
+       if [ -n "$name" ] && [ "$name" != "${name//simple_adblock}" ]; then
                uci -q del "firewall.$1"
        fi
 }
 
 fw3_setup() {
-       config_load 'firewall'
-       config_foreach remove_fw3_redirect 'redirect'
-       if [ "$1" == "start" ]; then
+       config_load "firewall"
+       config_foreach remove_fw3_redirect "redirect"
+       if [ "$1" = "start" ]; then
                uci -q add firewall redirect >/dev/null 2>&1
-               uci -q set firewall.@redirect[-1].name='simple_adblock_dns_hijack'
-               uci -q set firewall.@redirect[-1].target='DNAT'
-               uci -q set firewall.@redirect[-1].src='lan'
-               uci -q set firewall.@redirect[-1].proto='tcpudp'
-               uci -q set firewall.@redirect[-1].src_dport='53'
-               uci -q set firewall.@redirect[-1].dest_port='53'
+               uci -q set firewall.@redirect[-1].name="simple_adblock_dns_hijack"
+               uci -q set firewall.@redirect[-1].target="DNAT"
+               uci -q set firewall.@redirect[-1].src="lan"
+               uci -q set firewall.@redirect[-1].proto="tcpudp"
+               uci -q set firewall.@redirect[-1].src_dport="53"
+               uci -q set firewall.@redirect[-1].dest_port="53"
                uci -q set firewall.@redirect[-1].dest_ip="$ip"
-               uci -q set firewall.@redirect[-1].reflection='0'
+               uci -q set firewall.@redirect[-1].reflection="0"
        fi
-
        if [ -n "$(uci changes firewall)" ]; then
                uci -q commit firewall
                /etc/init.d/firewall restart >/dev/null 2>&1
@@ -185,210 +318,307 @@ fw3_setup() {
 
 process_url() {
        local label type D_TMP R_TMP
-       [[ -n "$1" && -n "$2" && -n "$3" ]] || return 1
-#      ping -W5 -c1 "$(echo $1 | awk -F '/' '{print $3}')" 1>/dev/null 2>/dev/null || { output_fail; return 1; }
-       if [ "$2" == "hosts" ]; then
-               label="Hosts: $(echo $1 | cut -d'/' -f3)" filter="$h_filter"
+       if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then return 1; fi
+       label="${1##*//}"; label="${label%%/*}";
+       if [ "$2" = "hosts" ]; then
+               label="Hosts: $label"; filter="$h_filter";
        else
-               label="Domains: $(echo $1 | cut -d'/' -f3)" filter="$d_filter"
+               label="Domains: $label"; filter="$d_filter";
        fi
-       if [ "$3" == "blocked" ]; then
-               type='Blocked'; D_TMP="$B_TMP";
+       if [ "$3" = "blocked" ]; then
+               type="Blocked"; D_TMP="$B_TMP";
        else
-               type='Allowed'; D_TMP="$A_TMP";
+               type="Allowed"; D_TMP="$A_TMP";
        fi
-       while [[ -z "$R_TMP" || -e "$R_TMP" ]]; do
-               R_TMP="/var/${packageName}_tmp_$(head -c40 /dev/urandom 2>/dev/null | tr -dc 'A-Za-z0-9' 2>/dev/null)"
+       while [ -z "$R_TMP" ] || [ -e "$R_TMP" ]; do
+               R_TMP="$(mktemp -u -q -t ${packageName}_tmp.XXXXXXXX)"
        done
-       touch "$R_TMP"
-       if ! $dl_command "$1" > "$R_TMP" 2>/dev/null; then
-               output 2 "[DL] $type $label $__FAIL__\n"
+       if ! $dl_command "$1" $dl_flag "$R_TMP" 2>/dev/null || [ ! -s "$R_TMP" ]; then
+               output 2 "[DL] $type $label $__FAIL__\\n"
                output 1 "$_FAIL_"
-               ubus_status add '-'
-               return 1
+#              tmpfs add message "-"
+               dlStatus="${dlStatus}-"
+               tmpfs add error "Error downloading ${1}."
+               return 0
        fi
        sed -i "$filter" "$R_TMP"
-       cat "$R_TMP" >> "$D_TMP"
-       rm -f "$R_TMP" >/dev/null 2>/dev/null
-       output 2 "[DL] $type $label $__OK__\n"
+       cat "${R_TMP}" >> "$D_TMP"
+       rm -f "${R_TMP}" >/dev/null 2>/dev/null
+       output 2 "[DL] $type $label $__OK__\\n"
        output 1 "$_OK_"
-       ubus_status add '+'
+#      tmpfs add message "+"
+       dlStatus="${dlStatus}+"
        return 0
 }
 
 download_lists() {
-       local i hf w_filter whitelist_domains blacklist_domains whitelist_domains_urls blacklist_domains_urls blacklist_hosts_urls j=0
-       config_get whitelist_domains          'config' 'whitelist_domain'
-       config_get blacklist_domains          'config' 'blacklist_domain'
-       config_get whitelist_domains_urls     'config' 'whitelist_domains_url'
-       config_get blacklist_domains_urls     'config' 'blacklist_domains_url'
-       config_get blacklist_hosts_urls       'config' 'blacklist_hosts_url'
+       local i hf w_filter j=0 R_TMP
 
-       ubus_status set 'Reloading '
-       [ ! -d ${dnsmasqFile%/*} ] && mkdir -p ${dnsmasqFile%/*}
-       for i in $A_TMP $B_TMP $CACHE_TMP $dnsmasqFile; do [ -f $i ] && rm -f $i; done
+       tmpfs set message "${statusDownloading}..."
+       for i in $A_TMP $B_TMP $cacheFile $dnsmasqFile; do [ -f $i ] && rm -f $i; done
        if [ "$(awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo")" -lt 32 ]; then
-               output 3 'Low free memory, restarting dnsmasq...'
-               reload_dnsmasq 'quiet' && output_okn || output_failn
+               output 3 "Low free memory, restarting dnsmasq..."
+               if reload_dnsmasq "quiet"; then output_okn; else output_failn; fi
        fi
        touch $A_TMP; touch $B_TMP;
-       output 1 'Downloading lists '
+       output 1 "Downloading lists "
+       unset dlStatus
        if [ -n "$blacklist_hosts_urls" ]; then
                for hf in ${blacklist_hosts_urls}; do
-                       process_url "$hf" 'hosts' 'blocked' &
+                       if [ "$parallelDL" -gt 0 ]; then
+                               process_url "$hf" "hosts" "blocked" &
+                       else
+                               process_url "$hf" "hosts" "blocked"
+                       fi
                done
        fi
        if [ -n "$blacklist_domains_urls" ]; then
                for hf in ${blacklist_domains_urls}; do
-                       process_url "$hf" 'domains' 'blocked' &
+                       if [ "$parallelDL" -gt 0 ]; then
+                               process_url "$hf" "domains" "blocked" &
+                       else
+                               process_url "$hf" "domains" "blocked"
+                       fi
                done
        fi
        if [ -n "$whitelist_domains_urls" ]; then
                for hf in ${whitelist_domains_urls}; do
-                       process_url "$hf" 'domains' 'allowed' &
+                       if [ "$parallelDL" -gt 0 ]; then
+                               process_url "$hf" "domains" "allowed" &
+                       else
+                               process_url "$hf" "domains" "allowed"
+                       fi
                done
        fi
        wait
-       i="$(ubus_status get)"
-       [ "${i//-}" != "$i" ] && serviceStatus="${serviceStatus:-'Download error'}" || unset serviceStatus
-       i="${i//Reloading }"
-       i="${i//-/$xmark}"
-       i="${i//+/$checkmark}"
-       [ "$verbosity" == "1" ] && logmsg="${logmsg}${i}"
-       output 1 '\n'
+       dlStatus="${dlStatus//-/$xmark}"
+       dlStatus="${dlStatus//+/$checkmark}"
+       [ "$verbosity" = "1" ] && logmsg="${logmsg}${dlStatus}"
+       output 1 "\\n"
 
        [ -n "$blacklist_domains" ] && for hf in ${blacklist_domains}; do echo "$hf" | sed "$d_filter" >> $B_TMP; done
-       whitelist_domains="${whitelist_domains}"$'\n'"$(cat $A_TMP)"
-       [ -n "$whitelist_domains" ] && for hf in ${whitelist_domains}; do hf=$(echo $hf | sed 's/\./\\./g'); w_filter="$w_filter/^${hf}$/d;/\\.${hf}$/d;"; done
+       whitelist_domains="${whitelist_domains}
+$(cat $A_TMP)"
+       [ -n "$whitelist_domains" ] && for hf in ${whitelist_domains}; do hf=$(echo "$hf" | sed 's/\./\\./g'); w_filter="$w_filter/^${hf}$/d;/\\.${hf}$/d;"; done
        if [ -s $B_TMP ]; then
-                       output 1 'Processing downloads '
-                       output 2 'Sorting combined list '
-                       if sort $B_TMP | uniq > $A_TMP; then
-                               output_ok
-                       else
-                               output_fail
-                               serviceStatus="${serviceStatus:-'Sorting error'}"
-                       fi
-                       output 2 'Optimizing combined list '
-                       if awk -F "." '{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "$A_TMP" > "$B_TMP"; then
-                               if sort "$B_TMP" > "$A_TMP"; then
-                                       if awk '{if(NR==1){tld=$NF};while(getline){if($NF!~tld"\\."){print tld;tld=$NF}}print tld}' "$A_TMP" > "$B_TMP"; then
-                                               if awk -F "." '{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "$B_TMP" > "$A_TMP"; then
-                                                       if sort "$A_TMP" | uniq > "$B_TMP"; then
-                                                               output_ok
-                                                       else
-                                                               output_fail
-                                                               serviceStatus="${serviceStatus:-'Data file optimization error'}"
-                                                               mv $A_TMP $B_TMP
-                                                       fi
+               output 1 "Processing downloads "
+               output 2 "Sorting combined list "
+               tmpfs set message "$statusProcessing: sorting combined list"
+               if sort $B_TMP | uniq > $A_TMP; then
+                       output_ok
+               else
+                       output_fail
+                       tmpfs add error "Sorting error."
+               fi
+
+# TLD optimization written by Dirk Brenken (dev@brenken.org)
+               output 2 "Optimizing combined list "
+               tmpfs set message "$statusProcessing: optimizing combined list"
+               if awk -F "." '{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "$A_TMP" > "$B_TMP"; then
+                       if sort "$B_TMP" > "$A_TMP"; then
+                               if awk '{if(NR==1){tld=$NF};while(getline){if($NF!~tld"\\."){print tld;tld=$NF}}print tld}' "$A_TMP" > "$B_TMP"; then
+                                       if awk -F "." '{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "$B_TMP" > "$A_TMP"; then
+                                               if sort "$A_TMP" | uniq > "$B_TMP"; then
+                                                       output_ok
                                                else
                                                        output_fail
-                                                       serviceStatus="${serviceStatus:-'Data file optimization error'}"
+                                                       tmpfs add error "Data file optimization error."
+                                                       mv $A_TMP $B_TMP
                                                fi
                                        else
                                                output_fail
-                                               serviceStatus="${serviceStatus:-'Data file optimization error'}"
-                                               mv $A_TMP $B_TMP
+                                               tmpfs add error "Data file optimization error."
                                        fi
                                else
                                        output_fail
-                                       serviceStatus="${serviceStatus:-'Data file optimization error'}"
+                                       tmpfs add error "Data file optimization error."
+                                       mv $A_TMP $B_TMP
                                fi
                        else
                                output_fail
-                               serviceStatus="${serviceStatus:-'Data file optimization error'}"
-                               mv $A_TMP $B_TMP
-                       fi
-                       output 2 'Whitelisting domains '
-                       if sed -i "$w_filter" $B_TMP; then
-                               output_ok
-                       else
-                               output_fail
-                               serviceStatus="${serviceStatus:-'Whitelist processing error'}"
+                               tmpfs add error "Data file optimization error."
                        fi
-                       output 2 'Formatting merged file '
+               else
+                       output_fail
+                       tmpfs add error "Data file optimization error."
+                       mv $A_TMP $B_TMP
+               fi
+
+               output 2 "Whitelisting domains "
+               tmpfs set message "$statusProcessing: whitelisting domains"
+               if sed -i "$w_filter" $B_TMP; then
+                       output_ok
+               else
+                       output_fail
+                       tmpfs add error "Whitelist processing error."
+               fi
+               output 2 "Formatting merged file "
+               tmpfs set message "$statusProcessing: formatting merged file"
+               if [ "$allowNonAscii" -gt 0 ]; then
                        if sed "$f_filter" $B_TMP > $A_TMP; then
                                output_ok
                        else
                                output_fail
-                               serviceStatus="${serviceStatus:-'Data file formatting error'}"
+                               tmpfs add error "Data file formatting error."
                        fi
-                       output 2 'Creating dnsmasq config '
-                       if mv $A_TMP $dnsmasqFile; then
+               else
+                       if sed "$f_filter" $B_TMP | grep -E -v '[^a-zA-Z0-9=/.-]' > $A_TMP; then
                                output_ok
                        else
                                output_fail
-                               serviceStatus="${serviceStatus:-'Error moving data file'}"
+                               tmpfs add error "Data file formatting error."
                        fi
-                       output 2 'Removing temporary files '
-                       rm -f /var/simple-adblock_tmp_* >/dev/null 2>&1;
-                       for i in $A_TMP $B_TMP $CACHE_TMP; do if [ -s $i ]; then rm -f $i || j=1; fi; done
-                       if [ $j -eq 0 ]; then
+               fi
+
+               output 2 "Creating DNSMASQ config "
+               tmpfs set message "$statusProcessing: creating DNSMASQ blocklist"
+               if mv $A_TMP $dnsmasqFile; then
+                       output_ok
+               else
+                       output_fail
+                       tmpfs add error "Error moving data file ${A_TMP} to ${dnsmasqFile}."
+               fi
+
+               if [ "$compressedCache" -gt 0 ]; then
+                       output 2 "Creating compressed cache "
+                       tmpfs set message "$statusProcessing: creating compressed cache"
+                       R_TMP="$(mktemp -u -q -t ${packageName}_tmp.XXXXXXXX)"
+                       if gzip < "$dnsmasqFile" > "$R_TMP"; then
+                               mv "$R_TMP" "$compressedCacheFile"
                                output_ok
                        else
                                output_fail
-                               serviceStatus="${serviceStatus:-'Error removing temporary files'}"
+                               rm -f "$R_TMP"
+                               tmpfs add error "Error creating compressed cache."
                        fi
-                       output 1 '\n'
+               else
+                       rm -f "$compressedCacheFile" >/dev/null 2>&1
+               fi
+
+               output 2 "Removing temporary files "
+               tmpfs set message "$statusProcessing: removing temporary files"
+               rm -f "/tmp/${packageName}_tmp.*" >/dev/null 2>&1
+               for i in $A_TMP $B_TMP $cacheFile; do if [ -s $i ]; then rm -f $i || j=1; fi; done
+               if [ $j -eq 0 ]; then
+                       output_ok
+               else
+                       output_fail
+                       tmpfs add error "Error removing temporary files."
+               fi
+               output 1 "\\n"
        fi
 }
 
 start_service() {
-       local ip status
+       is_enabled "on_start" || return 1
+       local ip status error action="$(tmpfs get triggers)"
        if create_lock; then
-               is_enabled 'on_start' || return 1
-               procd_open_instance
+               tmpfs set triggers
+               procd_open_instance "main"
                procd_set_param command /bin/true
                procd_set_param stdout 1
                procd_set_param stderr 1
-               network_get_ipaddr ip 'lan'
-               if [[ $forceDNS -ne 0 && -n "$ip" ]]; then
+               network_get_ipaddr ip "lan"
+               if [ "$forceDNS" -ne 0 ] && [ -n "$ip" ]; then
                        if is_chaos_calmer; then
-                               fw3_setup 'start'
+                               fw3_setup "start"
                        else
                                procd_open_data
                                json_add_array firewall
                                json_add_object ""
                                json_add_string type redirect
-                               json_add_string target 'DNAT'
-                               json_add_string src 'lan'
-                               json_add_string proto 'tcpudp'
-                               json_add_string src_dport '53'
-                               json_add_string dest_port '53'
+                               json_add_string target "DNAT"
+                               json_add_string src "lan"
+                               json_add_string dest "lan"
+                               json_add_string proto "tcpudp"
+                               json_add_string src_dport "53"
+                               json_add_string dest_port "53"
                                json_add_string dest_ip "$ip"
-                               json_add_string name 'simple_adblock_dns_hijack'
-                               json_add_string reflection '0'
+                               json_add_string name "simple-adblock-dns-hijack"
+                               json_add_string reflection "0"
                                json_close_object
                                json_close_array
                                procd_close_data
                        fi
                fi
                procd_close_instance
-               status="$(ubus_status get)"
-               if [ -s "$CACHE_TMP" ] && [ "$1" != "reload" ]; then
-                       output "Starting $serviceName...\n"
-                       output 3 'Found existing data file, reusing it '
-                       mv $CACHE_TMP $dnsmasqFile && output_okn || output_failn
-                       reload_dnsmasq 'on_start' || serviceStatus="${serviceStatus:-'DNSMASQ restart error'}"
-               elif [ "$1" == "reload" ] || [ "$status" == "${status//Success}" ]; then
-                       output "Reloading $serviceName...\n"
-                       download_lists
-                       reload_dnsmasq 'on_start' || serviceStatus="${serviceStatus:-'DNSMASQ restart error'}"
-               elif [ ! -s "$dnsmasqFile" ]; then
-                       output "Starting $serviceName...\n"
-                       download_lists
-                       reload_dnsmasq 'on_start' || serviceStatus="${serviceStatus:-'DNSMASQ restart error'}"
-               fi
-               if [ -s "$dnsmasqFile" ]; then
-                       if [ -z "$serviceStatus" ]; then
-                               output "$serviceName is blocking $(wc -l < $dnsmasqFile) domains "; output_okn;
-                               serviceStatus="Success: $(wc -l < $dnsmasqFile) domains blocked"
-                       else
-                               output "$serviceName is blocking $(wc -l < $dnsmasqFile) domains with error: $serviceStatus "; output_failn;
-                               serviceStatus="$(wc -l < $dnsmasqFile) domains blocked with error: $serviceStatus"
+               status="$(tmpfs get status)"
+               error="$(tmpfs get error)"
+               tmpfs del status
+               tmpfs del message
+               tmpfs del error
+               tmpfs del stats
+
+               case "$1" in
+                       download) action="download";;
+                       restart|*)
+                               if [ ! -s "$dnsmasqFile" ] && [ ! -s "$cacheFile" ] && ! testCompressedCache; then
+                                       action="download"
+                               fi
+                               if [ -n "$error" ]; then 
+                                       action="download"
+                               fi
+                               action="${action:-$1}"
+                       ;;
+               esac
+
+               case $action in
+                       download)
+                               if [ -s "$dnsmasqFile" ] || [ -s "$cacheFile" ] || testCompressedCache; then
+                                       output "Force-reloading $serviceName...\\n"
+                                       tmpfs set status "$statusForceReloading"
+                               else
+                                       output "Starting $serviceName...\\n"
+                                       tmpfs set status "$statusStarting"
+                               fi
+                               download_lists
+                               reload_dnsmasq "on_start"
+                       ;;
+                       restart|*)
+                               if [ "$action" == "restart" ]; then
+                                       output "Retarting $serviceName...\\n"
+                                       tmpfs set status "$statusRestarting"
+                               else
+                                       output "Starting $serviceName...\\n"
+                                       tmpfs set status "$statusStarting"
+                               fi
+                               if testCompressedCache && [ ! -s "$cacheFile" ] && [ ! -s "$dnsmasqFile" ]; then
+                                       output 3 "Found compressed cache file, unpacking it "
+                                       tmpfs set message "found compressed cache file, unpacking it."
+                                       if gzip -dc < "${compressedCacheFile}" > "$cacheFile"; then
+                                               output_okn
+                                       else
+                                               output_failn
+                                               output "$_ERROR_: $serviceName failed to unpack compressed cache!\\n"
+                                               tmpfs add error "failed to unpack compressed cache!"
+                                               return 1
+                                       fi
+                               fi
+                               if [ -s "$cacheFile" ] &&  [ ! -s "$dnsmasqFile" ]; then
+                                       output 3 "Found cache file, reusing it "
+                                       tmpfs set message "found cache file, reusing it."
+                                       if mv "$cacheFile" "$dnsmasqFile"; then 
+                                               output_okn
+                                       else 
+                                               output_failn
+                                               tmpfs add error "Error moving $cacheFile to $dnsmasqFile."
+                                       fi
+                               fi
+                               reload_dnsmasq "on_start"
+                       ;;
+               esac
+
+               if [ -s "$dnsmasqFile" ] && [ "$(tmpfs get status)" != "$statusFail" ]; then
+                       output "$serviceName is blocking $(wc -l < $dnsmasqFile) domains "; output_okn;
+                       tmpfs del message
+                       tmpfs set status "$statusSuccess: $(wc -l < $dnsmasqFile) domains blocked."
+                       if [ -n "$(tmpfs get error)" ]; then
+                               output "$_ERROR_: $(tmpfs get error)\\n"
                        fi
+               else
+                       tmpfs set status "$statusFail"
+                       tmpfs add error "Failed to create DNSMASQ blocklist."
                fi
-               [ -n "$serviceStatus" ] && ubus_status set "$serviceStatus"
                remove_lock
        else
                output "$serviceName: another instance is starting up "; output_failn;
@@ -397,31 +627,53 @@ start_service() {
 }
 
 service_started() { procd_set_config_changed firewall; }
-reload_service() { start_service 'reload'; }
-killcache() { [ -s $CACHE_TMP ] && rm -f $CACHE_TMP >/dev/null 2>/dev/null; }
+service_stopped() { procd_set_config_changed firewall; }
+restart_service() { rc_procd stop_service "restart"; rc_procd start_service "restart"; }
+reload_service() { restart_service; }
+restart() { restart_service; }
+reload() { restart_service; }
+dl() { rc_procd stop_service "restart"; rc_procd start_service "download"; }
+killcache() { [ -s $cacheFile ] && rm -f $cacheFile >/dev/null 2>/dev/null; [ -s $compressedCacheFile ] && rm -f $compressedCacheFile >/dev/null 2>/dev/null; }
+status() {
+       local status
+       if [ -n "$(tmpfs get status)" ]; then 
+               status="$(tmpfs get status)"
+       fi
+       if [ -n "$status" ] && [ -n "$(tmpfs get message)" ]; then 
+               status="${status}: $(tmpfs get message)"
+       fi
+       [ -n "$status" ] && output "$serviceName $status\\n"
+       [ -n "$(tmpfs get error)" ] && output "$_ERROR_: $(tmpfs get error)\\n"
+}
 
 stop_service() {
        load_package_config
-       if [ $serviceEnabled -gt 0 ]; then
-               output "Stopping $serviceName...\n"
-               reload_dnsmasq 'on_stop'
+       if [ "$serviceEnabled" -gt 0 ]; then
+               if [ -z "$1" ] && [ -s "$dnsmasqFile" ]; then
+                       [ -s "$dnsmasqFile" ] && mv "$dnsmasqFile" "$cacheFile" >/dev/null 2>/dev/null
+                       output "Stopping $serviceName...\\n"
+                       tmpfs del triggers
+                       reload_dnsmasq "on_stop"
+               fi
        else
-               reload_dnsmasq 'quiet'
+               [ -s "$dnsmasqFile" ] && mv "$dnsmasqFile" "$cacheFile" >/dev/null 2>/dev/null
+               reload_dnsmasq "quiet"
+       fi
+       if is_chaos_calmer; then
+               fw3_setup "stop"
        fi
-       ubus_status set 'Stopped'
-       procd_set_config_changed firewall
 }
 
 check() {
        load_package_config
        local string="$1"
-       if [ ! -f $dnsmasqFile ]; then
+       if [ ! -f "$dnsmasqFile" ]; then
                echo "No local blacklist ($dnsmasqFile) found."
        elif [ -z "$string" ]; then
-               echo "Usage: /etc/init.d/${packageName} check 'domain'"
-       elif grep -m1 -q $string $dnsmasqFile; then
-               echo "Found $(grep $string $dnsmasqFile | wc -l) matches for $string in $dnsmasqFile:"
-               grep $string $dnsmasqFile | sed 's|local=/||;s|/$||;'
+               echo "Usage: /etc/init.d/${packageName} check domain"
+       elif grep -m1 -q "$string" "$dnsmasqFile"; then
+               echo "Found $(grep -c "$string" "$dnsmasqFile") matches for $string in $dnsmasqFile:"
+               grep "$string" "$dnsmasqFile" | sed 's|local=/||;s|/$||;'
        else
                echo "The $string is not found in current blacklist."
        fi