adblock: release 3.8.0
authorDirk Brenken <dev@brenken.org>
Thu, 15 Aug 2019 12:02:30 +0000 (14:02 +0200)
committerDirk Brenken <dev@brenken.org>
Fri, 23 Aug 2019 04:46:51 +0000 (06:46 +0200)
* add support for 'DNS File Reset', where the final DNS blockfile
  will be purged after DNS backend loading (save storage space).
  A small background service will be started to trace/handle
  dns backend reloads/restarts
* add support for the 'null' blocking variant in dnsmasq
  (via addn-hosts), which may provide better response times
  in dnsmasq
* enhance the report & search engine to support
  the new blocking variants. Search now includes
  backups & black-/whitelist as well
* compressed source list backups are now mandatory (default to '/tmp')
* speed up TLD compression
* E-Mail notification setup is now integrated in UCI/LuCI
* update the LuCI frontend to reflect all changes (separate PR)
* drop preliminary dnscrypt-proxy-support (use dnsmasq instead)
* drop additional 'dnsjail' blocklist support (not used by anyone)
* procd cleanups in init
* various shellcheck cleanups
* update readme

Signed-off-by: Dirk Brenken <dev@brenken.org>
(cherry picked from commit 504412ccdbe9e6f1f65b34cf28641ec9aa9b7c22)

net/adblock/Makefile
net/adblock/files/README.md
net/adblock/files/adblock.conf
net/adblock/files/adblock.init
net/adblock/files/adblock.mail [new file with mode: 0755]
net/adblock/files/adblock.notify [deleted file]
net/adblock/files/adblock.service [new file with mode: 0755]
net/adblock/files/adblock.sh

index 79ffea4a083aa7535e563046eba60a45dd6cb7d1..a195490d39de27715030e60bb36dcdf96006b628 100644 (file)
@@ -6,8 +6,8 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=adblock
-PKG_VERSION:=3.6.5
-PKG_RELEASE:=2
+PKG_VERSION:=3.8.0
+PKG_RELEASE:=1
 PKG_LICENSE:=GPL-3.0+
 PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
 
@@ -22,7 +22,7 @@ define Package/adblock
 endef
 
 define Package/adblock/description
-Powerful adblock script to block ad/abuse domains via dnsmasq, unbound, named, kresd or dnscrypt-proxy.
+Powerful adblock script to block ad/abuse domains via dnsmasq, unbound, named or kresd.
 The script supports many domain blacklist sites plus manual black- and whitelist overrides.
 Please see https://github.com/openwrt/packages/blob/master/net/adblock/files/README.md for further information.
 
@@ -45,7 +45,7 @@ endef
 
 define Package/adblock/install
        $(INSTALL_DIR) $(1)/usr/bin
-       $(INSTALL_BIN) ./files/adblock.sh $(1)/usr/bin/
+       $(INSTALL_BIN) ./files/adblock.sh $(1)/usr/bin
 
        $(INSTALL_DIR) $(1)/etc/init.d
        $(INSTALL_BIN) ./files/adblock.init $(1)/etc/init.d/adblock
@@ -54,9 +54,10 @@ define Package/adblock/install
        $(INSTALL_CONF) ./files/adblock.conf $(1)/etc/config/adblock
 
        $(INSTALL_DIR) $(1)/etc/adblock
-       $(INSTALL_CONF) ./files/adblock.notify $(1)/etc/adblock/
-       $(INSTALL_CONF) ./files/adblock.blacklist $(1)/etc/adblock/
-       $(INSTALL_CONF) ./files/adblock.whitelist $(1)/etc/adblock/
+       $(INSTALL_BIN) ./files/adblock.mail $(1)/etc/adblock
+       $(INSTALL_BIN) ./files/adblock.service $(1)/etc/adblock
+       $(INSTALL_CONF) ./files/adblock.blacklist $(1)/etc/adblock
+       $(INSTALL_CONF) ./files/adblock.whitelist $(1)/etc/adblock
 endef
 
 $(eval $(call BuildPackage,adblock))
index 36eeee4129381854b615c1101af4f516c922ba3e..1e26b015c03b5cb33c2aebcc00fb67f1d26315fb 100644 (file)
@@ -61,44 +61,43 @@ A lot of people already use adblocker plugins within their desktop browsers, but
     * => weekly updates, approx. 2.500 entries (enabled by default)
 * zero-conf like automatic installation & setup, usually no manual changes needed
 * simple but yet powerful adblock engine: adblock does not use error prone external iptables rulesets, http pixel server instances and things like that
-* supports five different dns backends / blocklist formats: dnsmasq, unbound, named (bind), kresd and dnscrypt-proxy
-* supports six different download utilities: uclient-fetch, wget, curl, aria2c, wget-nossl, busybox-wget
-* Really fast downloads & list processing as they are handled in parallel as background jobs in a configurable 'Download Queue'
-* provides 'http only' mode without installed ssl library for all non-SSL blocklist sources
-* supports a wide range of router modes, even AP modes are supported
+* support four different dns backends: dnsmasq, unbound, named (bind) and kresd
+* support two different dns blocking variants: 'nxdomain' (default, supported by all backends), 'null' (supported only by dnsmasq)
+* support six different download utilities: uclient-fetch, wget, curl, aria2c, wget-nossl, busybox-wget
+* fast downloads & list processing as they are handled in parallel running background jobs (see 'Download Queue')
+* provide 'http only' mode without installed ssl library for all non-SSL blocklist sources
+* support a wide range of router modes, even AP modes are supported
 * full IPv4 and IPv6 support
-* provides top level domain compression ('tld compression'), this feature removes thousands of needless host entries from the blocklist and lowers the memory footprint for the dns backend
+* provide top level domain compression ('tld compression'), this feature removes thousands of needless host entries from the blocklist and lowers the memory footprint for the dns backend
+* provide a 'DNS File Reset', where the final DNS blockfile will be purged after DNS backend loading to save storage space
 * blocklist source parsing by fast & flexible regex rulesets
 * overall duplicate removal in central blocklist 'adb_list.overall'
-* additional whitelist for manual overrides, located by default in /etc/adblock/adblock.whitelist
+* additional blacklist for manual overrides, located by default in /etc/adblock/adblock.blacklist or in LuCI
+* additional whitelist for manual overrides, located by default in /etc/adblock/adblock.whitelist or in LuCI
 * quality checks during blocklist update to ensure a reliable dns backend service
 * minimal status & error logging to syslog, enable debug logging to receive more output
 * procd based init system support (start/stop/restart/reload/suspend/resume/query/status)
 * procd network interface trigger support or classic time based startup
 * keep the dns cache intact after adblock processing (currently supported by unbound, named and kresd)
-* conditional dns backend restarts by old/new blocklist comparison with sha256sum (default) or md5sum
 * suspend & resume adblock actions temporarily without blocklist reloading
 * provide comprehensive runtime information via LuCI or via 'status' init command
 * provide a detailed DNS Query Report with dns related information about client requests, top (blocked) domains and more
-* provide a query function to quickly identify blocked (sub-)domains, e.g. for whitelisting. This function is also able to search in adblock backups, to get back the set of blocking lists sources for a certain domain
-* force dns requests to local resolver
-* force overall sort / duplicate removal for low memory devices (handle with care!)
-* automatic blocklist backup & restore, they will be used in case of download errors or during startup in backup mode
-* 'backup mode' to re-use blocklist backups during startup, get fresh lists only via reload or restart action
-* 'Jail' blocklist generation which builds an additional list (/tmp/adb_list.jail) to block access to all domains except those listed in the whitelist file. You can use this restrictive blocklist manually e.g. for guest wifi or kidsafe configurations
-* send notification emails in case of a processing error or if the overall domain count is &le; 0
+* provide a query function to quickly identify blocked (sub-)domains, e.g. for whitelisting. This function is also able to search in adblock backups and black-/whitelist, to get back the set of blocking lists sources for a certain domain
+* option to force dns requests to the local resolver
+* automatic blocklist backup & restore, these backups will be used in case of download errors and during startup
+* send notification E-Mails in case of a processing error or if the overall domain count is &le; 0
 * add new adblock sources on your own, see example below
-* strong LuCI support
+* strong LuCI support for all options
 
 ## Prerequisites
-* [OpenWrt](https://openwrt.org), tested with the stable release series (18.06) and with the latest snapshot
+* [OpenWrt](https://openwrt.org), tested with the stable release series (19.07) and with the latest snapshot
 * a usual setup with an enabled dns backend at minimum - dump AP modes without a working dns backend are _not_ supported
 * a download utility:
     * to support all blocklist sources a full version (with ssl support) of 'wget', 'uclient-fetch' with one of the 'libustream-*' ssl libraries, 'aria2c' or 'curl' is required
     * for limited devices with real memory constraints, adblock provides also a 'http only' option and supports wget-nossl and uclient-fetch (without libustream-ssl) as well
     * for more configuration options see examples below
-* email notification (optional): for email notification support you need to install and configure the additional 'msmtp' package
-* DNS Query Report (optional): for this detailed report you need to install the additional package 'tcpdump' or 'tcpdump-mini'
+* E-Mail notification (optional): for E-Mail notification support you need the additional 'msmtp' package
+* DNS Query Report (optional): for this detailed report you need the additional package 'tcpdump' or 'tcpdump-mini'
 
 ## Installation & Usage
 * install 'adblock' (_opkg install adblock_)
@@ -108,56 +107,59 @@ A lot of people already use adblocker plugins within their desktop browsers, but
 ## LuCI adblock companion package
 * it's strongly recommended to use the LuCI frontend to easily configure all powerful aspects of adblock
 * install 'luci-app-adblock' (_opkg install luci-app-adblock_)
-* the application is located in LuCI under 'Services' menu
+* the application is located in LuCI under the 'Services' menu
 
 ## Tweaks
 * **runtime information:** the adblock status is available via _/etc/init.d/adblock status_ (see example below)
 * **debug logging:** for script debugging please set the config option 'adb\_debug' to '1' and check the runtime output with _logread -e "adblock"_
-* **storage expansion:** to process and store all blocklist sources at once it might helpful to enlarge your temp directory with a swap partition => see [OpenWrt Wiki](https://wiki.openwrt.org/doc/uci/fstab) for further details
-* **add white- / blacklist entries:** add domain white- or blacklist entries to always-allow or -deny certain (sub) domains, by default both lists are empty and located in _/etc/adblock_. Please add one domain per line - ip addresses, wildcards & regex are _not_ allowed (see example below)
-* **backup & restore blocklists:** enable this feature, to restore automatically the latest compressed backup of your blocklists in case of any processing error (e.g. a single blocklist source is not available during update). Please use an (external) solid partition and _not_ your volatile router temp directory for this
+* **storage expansion:** to process and store all blocklist sources at once it might be helpful to enlarge your temp directory with a swap partition => see [OpenWrt Wiki](https://openwrt.org/docs/guide-user/storage/fstab) for further details
+* **add white- / blacklist entries:** add domain black- or whitelist entries to always-deny or -allow certain (sub) domains, by default both lists are empty and located in _/etc/adblock_. Please add one domain per line - ip addresses, wildcards & regex are _not_ allowed (see example below). You need to refresh your blocklists after changes to these static lists.
 * **download queue size:** for further download & list processing performance improvements you can raise the 'adb\_maxqueue' value, e.g. '8' or '16' should be safe
 * **scheduled list updates:** for a scheduled call of the adblock service add an appropriate crontab entry (see example below)
 * **change startup behaviour:** by default the startup will be triggered by the 'wan' procd interface trigger. Choose 'none' to disable automatic startups, 'timed' to use a classic timeout (default 30 sec.) or select another trigger interface
 * **suspend & resume adblocking:** to quickly switch the adblock service 'on' or 'off', simply use _/etc/init.d/adblock [suspend|resume]_
 * **domain query:** to query the active blocklist for a certain domain, please use the LuCI frontend or run _/etc/init.d/adblock query `<DOMAIN>`_ (see example below)
 * **add new list sources:** you could add new blocklist sources on your own via uci config, all you need is a source url and an awk one-liner (see example below)
-* **disable active dns probing in windows 10:** to prevent a yellow exclamation mark on your internet connection icon (which wrongly means connected, but no internet), please change the following registry key/value from "1" to "0" _HKLM\SYSTEM\CurrentControlSet\Services\NlaSvc\Parameters\Internet\EnableActiveProbing_
 
 ## Further adblock config options
 * usually the pre-configured adblock setup works quite well and no manual overrides are needed
 * the following options apply to the 'global' config section:
     * adb\_enabled => main switch to enable/disable adblock service (default: '0', disabled)
-    * adb\_debug => enable/disable adblock debug output (default: '0', disabled)
+    * adb\_dns => select the dns backend for your environment: 'dnsmasq', 'unbound', 'named' or 'kresd' (default: 'dnsmasq')
+    * adb\_dnsvariant => select the blocking variant: 'nxdomain' (default, supported by all backends), 'null (IPv4)' and 'null (IPv4/IPv6)' both options are only supported by dnsmasq
     * adb\_fetchutil => name of the used download utility: 'uclient-fetch', 'wget', 'curl', 'aria2c', 'wget-nossl'. 'busybox' (default: 'uclient-fetch')
     * adb\_fetchparm => special config options for the download utility (default: not set)
-    * adb\_dns => select the dns backend for your environment: 'dnsmasq', 'unbound', 'named', 'kresd' or 'dnscrypt-proxy' (default: 'dnsmasq')
-    * adb\_dnsdir => target directory for the generated blocklist 'adb_list.overall' (default: not set, use dns backend default)
     * adb\_trigger => set the startup trigger to a certain interface, to 'timed' or to 'none' (default: 'wan')
-
 * the following options apply to the 'extra' config section:
+    * adb\_debug => enable/disable adblock debug output (default: '0', disabled)
     * adb\_nice => set the nice level of the adblock process and all sub-processes (int/default: '0', standard priority)
-    * adb\_triggerdelay => additional trigger delay in seconds before adblock processing begins (int/default: '2')
     * adb\_forcedns => force dns requests to local resolver (bool/default: '0', disabled)
-    * adb\_backup => create compressed blocklist backups, they will be used in case of download errors or during startup in backup mode (bool/default: '0', disabled)
-    * adb\_backupdir => target directory for adblock backups (default: not set)
-    * adb\_backup_mode => do not automatically update blocklists during startup, use backups instead (bool/default: '0', disabled)
+    * adb\_maxqueue => size of the download queue to handle downloads & list processing in parallel (int/default: '8')
+    * adb\_dnsfilereset => the final DNS blockfile will be purged after DNS backend loading to save storage space (bool/default: 'false', disabled)
     * adb\_report => enable the background tcpdump gathering process to provide a detailed DNS Query Report (bool/default: '0', disabled)
     * adb\_repdir => target directory for dns related report files generated by tcpdump (default: '/tmp')
+    * adb\_backupdir => target directory for adblock backups (default: '/tmp')
+    * adb\_mail => send notification E-Mails in case of a processing errors or if the overall domain count is &le; 0 (bool/default: '0', disabled)
+    * adb\_mreceiver => receiver address for adblock notification E-Mails (default: not set)
+* the following options could be added via "Additional Field" in LuCI and apply to the 'extra' config section as well:
+    * adb\_dnsdir => target directory for the generated blocklist 'adb_list.overall' (default: not set, use dns backend default)
+    * adb\_blacklist => full path to the static blacklist file (default: '/etc/adblock/adblock.blacklist')
+    * adb\_whitelist => full path to the static whitelist file (default: '/etc/adblock/adblock.whitelist')
+    * adb\_triggerdelay => additional trigger delay in seconds before adblock processing begins (int/default: '2')
+    * adb\_dnsflush => flush DNS cache after adblock processing, i.e. enable the old restart behavior (bool/default: '0', disabled)
     * adb\_repiface => reporting interface used by tcpdump, set to 'any' for multiple interfaces (default: 'br-lan')
     * adb\_replisten => space separated list of reporting port(s) used by tcpdump (default: '53')
-    * adb\_repchunksize => report chunk size used by tcpdump in MB (int/default: '1')
     * adb\_repchunkcnt => report chunk count used by tcpdump (default: '5')
-    * adb\_maxqueue => size of the download queue to handle downloads & list processing in parallel (int/default: '8')
-    * adb\_jail => builds an additional 'Jail' list (/tmp/adb_list.jail) to block access to all domains except those listed in the whitelist file (bool/default: '0', disabled)
-    * adb\_dnsflush => flush DNS cache after adblock processing, i.e. enable the old restart behavior (bool/default: '0', disabled)
-    * adb\_notify => send notification emails in case of a processing error or if the overall domain count is &le; 0 (bool/default: '0', disabled)
-    * adb\_notifycnt => Raise minimum domain count email notification trigger (int/default: '0')
+    * adb\_repchunksize => report chunk size used by tcpdump in MB (int/default: '1')
+    * adb\_msender => sender address for adblock notification E-Mails (default: 'no-reply@adblock')
+    * adb\_mtopic => topic for adblock notification E-Mails (default: 'adblock notification')
+    * adb\_mprofile => mail profile used in 'msmtp' for adblock notification E-Mails (default: 'adb_notify')
+    * adb\_mcnt => raise the minimum domain count E-Mmail notification trigger (int/default: '0')
 
 ## Examples
 **change default dns backend to 'unbound':**
 
-Adblock deposits the final blocklist 'adb_list.overall' in '/var/lib/unbound' where unbound can find them in its jail.  
+Adblock deposits the final blocklist 'adb_list.overall' in '/var/lib/unbound' where unbound can find them in its jail, no further configuration needed.  
 To preserve the DNS cache after adblock processing you need to install 'unbound-control'.  
   
 **change default dns backend to 'named' (bind):**
@@ -183,25 +185,7 @@ and at the end of the file add:
 The knot-resolver (kresd) is only available on Turris Omnia devices.  
 Adblock deposits the final blocklist 'adb_list.overall' in '/etc/kresd', no further configuration needed.
   
-**change default dns backend to 'dnscrypt-proxy':**
-
-The required 'blacklist' option of dnscrypt-proxy is not enabled by default, because the package will be compiled without plugins support.  
-Take a custom OpenWrt build with plugins support to use this feature. Adblock deposits the final blocklist 'adb_list.overall' in '/tmp'.  
-To use the blocklist please modify '/etc/config/dnscrypt-proxy' per instance:
-<pre><code>
-  list blacklist 'domains:/tmp/adb_list.overall'
-</code></pre>
-  
-**reference the jail block list manually in a 'kidsafe' dhcp config:**
-
-The additional 'Jail' blocklist (by default in /tmp/adb_list.jail) block access to all domains except those listed in the whitelist file.
-<pre><code>
-config dnsmasq 'kidsafe'
-        [...]
-        option serversfile '/tmp/adb_list.jail'
-</code></pre>
-  
-**enable email notification via msmtp:**
+**enable E-Mail notification via msmtp:**
 
 To use the email notification you have to install & configure the package 'msmtp'.  
 Modify the file '/etc/msmtprc':
@@ -221,8 +205,7 @@ from            dev.adblock@gmail.com
 user            dev.adblock
 password        xxx
 </code></pre>
-Edit the file '/etc/adblock/adblock.notify' and change at least the 'mail_receiver'.  
-Finally make this file executable via 'chmod' and test it directly. If no more errors come up you can comment 'mail_debug', too.
+Finally enable E-Mail support and add a valid E-Mail address in LuCI.
   
 **receive adblock runtime information:**
 
@@ -230,12 +213,14 @@ Finally make this file executable via 'chmod' and test it directly. If no more e
 /etc/init.d/adblock status
 ::: adblock runtime information
   + adblock_status  : enabled
-  + adblock_version : 3.6.0
-  + overall_domains : 30267 (backup mode)
+  + adblock_version : 3.8.0
+  + overall_domains : 48359
   + fetch_utility   : /bin/uclient-fetch (libustream-ssl)
-  + dns_backend     : dnsmasq (/tmp)
-  + last_rundate    : 19.12.2018 16:29:25
-  + system_release  : GL-AR750S, OpenWrt SNAPSHOT r8814-6835c13e5a
+  + dns_backend     : dnsmasq, /tmp
+  + dns_variant     : null (IPv4/IPv6), true
+  + backup_dir      : /mnt/data/adblock
+  + last_rundate    : 15.08.2019 08:43:16
+  + system_release  : GL.iNet GL-AR750S, OpenWrt SNAPSHOT r10720-ccb4b96b8a
 </code></pre>
   
 **receive adblock DNS Query Report information:**
@@ -272,6 +257,7 @@ Finally make this file executable via 'chmod' and test it directly. If no more e
   + 2        ::: v10.events.data.microsoft.com
   + 2        ::: settings-win.data.microsoft.com
   + 2        ::: nexusrules.officeapps.live.com
+[...]
 </code></pre>
   
 **cronjob for a regular block list update (/etc/crontabs/root):**
@@ -309,23 +295,28 @@ This entry does not remove:
   www.adwhere.com
 </code></pre>
   
-**query the active blocklist for a certain (sub-)domain, e.g. for whitelisting:**
+**query the active blocklist, the backups and black-/whitelist for a certain (sub-)domain, e.g. for whitelisting:**
 
 The query function checks against the submitted (sub-)domain and recurses automatically to the upper top level domain. For every (sub-)domain it returns the first ten relevant results.
 <pre><code>
 /etc/init.d/adblock query google.com
 :::
-::: results for domain 'google.com'
+::: results for domain 'google.com' in active blocklist
 :::
+  + adservice.google.com
+  + adservice.google.com.au
+  + adservice.google.com.vn
+  + adservices.google.com
   + analytics.google.com
   + googleadapis.l.google.com
   + pagead.l.google.com
   + partnerad.l.google.com
   + ssl-google-analytics.l.google.com
-  + www-google-analytics.l.google.com
   + video-stats.video.google.com
+  + [...]
+
 :::
-::: results for domain 'google.com' in backups
+::: results for domain 'google.com' in backups and black-/whitelist
 :::
   + adb_list.adguard.gz           partnerad.l.google.com
   + adb_list.adguard.gz           googleadapis.l.google.com
@@ -335,9 +326,13 @@ The query function checks against the submitted (sub-)domain and recurses automa
   + adb_list.disconnect.gz        partnerad.l.google.com
   + adb_list.disconnect.gz        video-stats.video.google.com
   + adb_list.disconnect.gz        [...]
+  + adb_list.whocares.gz          video-stats.video.google.com
+  + adb_list.whocares.gz          adservice.google.com
+  + adb_list.whocares.gz          adservice.google.com.au
+  + adb_list.whocares.gz          [...]
+  + adb_list.yoyo.gz              adservice.google.com
   + adb_list.yoyo.gz              analytics.google.com
   + adb_list.yoyo.gz              pagead.l.google.com
-  + adb_list.yoyo.gz              partnerad.l.google.com
   + adb_list.yoyo.gz              [...]
 </code></pre>
   
@@ -361,9 +356,5 @@ To add a really new source with different domain/host format you have to write a
 ## Support
 Please join the adblock discussion in this [forum thread](https://forum.openwrt.org/t/adblock-support-thread/507) or contact me by mail <dev@brenken.org>  
 
-## Removal
-* stop all adblock related services with _/etc/init.d/adblock stop_
-* optional: remove the adblock package (_opkg remove adblock_)
-
 Have fun!  
 Dirk  
index 8b47627d4179a3240f8004a31b01f123d5868a01..fad665ba49209ec6a0132291440f75887e71ed02 100644 (file)
@@ -1,16 +1,17 @@
 
 config adblock 'global'
+       option adb_basever '3.8'
        option adb_enabled '0'
        option adb_dns 'dnsmasq'
+       option adb_dnsvariant 'nxdomain'
        option adb_fetchutil 'uclient-fetch'
        option adb_trigger 'wan'
 
 config adblock 'extra'
        option adb_debug '0'
        option adb_forcedns '0'
-       option adb_backup '0'
        option adb_report '0'
-       option adb_maxqueue '8'
+       option adb_maxqueue '4'
 
 config source 'adaway'
        option adb_src 'https://adaway.org/hosts.txt'
@@ -30,12 +31,6 @@ config source 'bitcoin'
        option adb_src_desc 'focus on malicious bitcoin mining sites, infrequent updates, approx. 80 entries'
        option enabled '0'
 
-config source 'blacklist'
-       option adb_src '/etc/adblock/adblock.blacklist'
-       option adb_src_rset '/^([[:alnum:]_-]+\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}'
-       option adb_src_desc 'static local domain blacklist, always deny these domains'
-       option enabled '1'
-
 config source 'disconnect'
        option adb_src 'https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt'
        option adb_src_rset '/^([[:alnum:]_-]+\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}'
index 74cbf01bb38446ba510b3f4fb720280e7b743316..b5369230ae751bfef6d2e40dd8f930bf6329ddd2 100755 (executable)
@@ -52,7 +52,6 @@ reload_service()
 stop_service()
 {
        rc_procd "${adb_script}" stop
-       rc_procd start_service
 }
 
 restart()
@@ -63,13 +62,13 @@ restart()
 suspend()
 {
        [ -s "${adb_pidfile}" ] && return 1
-       rc_procd "${adb_script}" suspend
+       rc_procd start_service suspend
 }
 
 resume()
 {
        [ -s "${adb_pidfile}" ] && return 1
-       rc_procd "${adb_script}" resume
+       rc_procd start_service resume
 }
 
 query()
@@ -91,17 +90,17 @@ status()
        rtfile="${rtfile:-"/tmp/adb_runtime.json"}"
        if [ -s "${rtfile}" ]
        then
-               printf "%s\n" "::: adblock runtime information"
+               printf "%s\\n" "::: adblock runtime information"
                json_load_file "${rtfile}"
                json_select data
                json_get_keys keylist
                for key in ${keylist}
                do
                        json_get_var value "${key}"
-                       printf "  + %-15s : %s\n" "${key}" "${value}"
+                       printf "  + %-15s : %s\\n" "${key}" "${value}"
                done
        else
-               printf "%s\n" "::: no adblock runtime information available"
+               printf "%s\\n" "::: no adblock runtime information available"
        fi
 }
 
diff --git a/net/adblock/files/adblock.mail b/net/adblock/files/adblock.mail
new file mode 100755 (executable)
index 0000000..3b4d69c
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+#
+# send mail script for adblock notifications
+# written by Dirk Brenken (dev@brenken.org)
+# Please note: you have to manually install and configure the package 'msmtp' before using this script
+
+# This is free software, licensed under the GNU General Public License v3.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+LC_ALL=C
+PATH="/usr/sbin:/usr/bin:/sbin:/bin"
+
+if [ -r "/lib/functions.sh" ]
+then
+       . "/lib/functions.sh"
+       adb_basever="$(uci_get adblock global adb_basever)"
+       adb_debug="$(uci_get adblock extra adb_debug "0")"
+       adb_msender="$(uci_get adblock extra adb_msender "no-reply@adblock")"
+       adb_mreceiver="$(uci_get adblock extra adb_mreceiver)"
+       adb_mtopic="$(uci_get adblock extra adb_mtopic "adblock notification")"
+       adb_mprofile="$(uci_get adblock extra adb_mprofile "adb_notify")"
+fi
+adb_mail="$(command -v msmtp)"
+adb_rc=1
+
+if [ "${adb_debug}" -eq 1 ]
+then
+       debug="--debug"
+fi
+
+# mail header & receiver check
+#
+if [ -z "${adb_mreceiver}" ]
+then
+       logger -p "err" -t "adblock-${adb_basever}  [${$}]" "please set the mail receiver with the 'adb_mreceiver' option"
+       exit ${adb_rc}
+fi
+adb_mhead="From: ${adb_msender}\\nTo: ${adb_mreceiver}\\nSubject: ${adb_mtopic}\\nReply-to: ${adb_msender}\\nMime-Version: 1.0\\nContent-Type: text/html\\nContent-Disposition: inline\\n\\n"
+
+# info preparation
+#
+sys_info="$(strings /etc/banner 2>/dev/null; ubus call system board | sed -e 's/\"release\": {//' | sed -e 's/^[ \t]*//' | sed -e 's/[{}\",]//g' | sed -e 's/[ ]/  \t/' | sed '/^$/d' 2>/dev/null)"
+adb_info="$(/etc/init.d/adblock status 2>/dev/null)"
+if [ -f "/var/log/messages" ]
+then
+       log_info="$(awk '/adblock-/{NR=1;max=79;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max),"&#8629;"} else {print " ",substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}' /var/log/messages)"
+else
+       log_info="$(logread -e "adblock-" | awk '{NR=1;max=79;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max),"&#8629;"} else {print " ",substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')"
+fi
+
+# mail body
+#
+adb_mtext="<html><body><pre style='display:block;font-family:monospace;font-size:1rem;padding:20;background-color:#f3eee5;white-space:pre'>"
+adb_mtext="${adb_mtext}\\n<strong>++\\n++ System Information ++\\n++</strong>\\n${sys_info}"
+adb_mtext="${adb_mtext}\\n\\n<strong>++\\n++ Adblock Information ++\\n++</strong>\\n${adb_info}"
+adb_mtext="${adb_mtext}\\n\\n<strong>++\\n++ Logfile Information ++\\n++</strong>\\n${log_info}"
+adb_mtext="${adb_mtext}</pre></body></html>"
+
+# send mail
+#
+if [ -x "${adb_mail}" ]
+then
+       printf "%b" "${adb_mhead}${adb_mtext}" 2>/dev/null | "${adb_mail}" ${debug} -a "${adb_mprofile}" "${adb_mreceiver}" >/dev/null 2>&1
+       adb_rc=${?}
+       logger -p "info" -t "adblock-${adb_basever}  [${$}]" "mail sent to '${adb_mreceiver}' with rc '${adb_rc}'"
+else
+       logger -p "err" -t "adblock-${adb_basever}  [${$}]" "msmtp mail daemon not found"
+fi
+
+exit ${adb_rc}
diff --git a/net/adblock/files/adblock.notify b/net/adblock/files/adblock.notify
deleted file mode 100644 (file)
index 54f0288..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/sh
-#
-# adblock send mail script for msmtp
-# written by Dirk Brenken (dev@brenken.org)
-# Please note: you have to install and configure the package 'msmtp' before using this script.
-
-# This is free software, licensed under the GNU General Public License v3.
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-LC_ALL=C
-PATH="/usr/sbin:/usr/bin:/sbin:/bin"
-mail_ver="1.0.4"
-mail_daemon="$(command -v msmtp)"
-mail_profile="adb_notify"
-#mail_debug="--debug"
-mail_rc=1
-
-# mail header & mail receiver check
-#
-mail_receiver=""
-mail_sender="no-reply@adblock"
-mail_topic="${HOSTNAME}: adblock notification"
-mail_head="From: ${mail_sender}\nTo: ${mail_receiver}\nSubject: ${mail_topic}\nReply-to: ${mail_sender}\nMime-Version: 1.0\nContent-Type: text/html\nContent-Disposition: inline\n\n"
-
-if [ -z "${mail_receiver}" ]
-then
-       logger -p "err" -t "adblock-notify-${mail_ver}[${$}]" "please supply/customize the 'mail_receiver' in '/etc/adblock/adblock.notify'"
-       exit ${mail_rc}
-fi
-
-# mail daemon check
-#
-if [ ! -x "${mail_daemon}" ]
-then
-       mail_daemon="$(command -v sendmail)"
-fi
-
-# info preparation
-#
-sys_info="$(strings /etc/banner 2>/dev/null; ubus call system board | sed -e 's/\"release\": {//' | sed -e 's/^[ \t]*//' | sed -e 's/[{}\",]//g' | sed -e 's/[ ]/  \t/' | sed '/^$/d' 2>/dev/null)"
-adb_info="$(/etc/init.d/adblock status 2>/dev/null)"
-if [ -f "/var/log/messages" ]
-then
-       log_info="$(awk '/adblock-/{NR=1;max=79;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max),"&#8629;"} else {print " ",substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}' /var/log/messages)"
-else
-       log_info="$(logread -e "adblock-" | awk '{NR=1;max=79;if(length($0)>max+1)while($0){if(NR==1){print substr($0,1,max),"&#8629;"} else {print " ",substr($0,1,max)}{$0=substr($0,max+1);NR=NR+1}}else print}')"
-fi
-
-# mail body
-#
-mail_text="<html><body><pre style='display:block;font-family:monospace;font-size:1rem;padding:20;background-color:#f3eee5;white-space:pre'>"
-mail_text="${mail_text}\n<strong>++\n++ System Information ++\n++</strong>\n${sys_info}"
-mail_text="${mail_text}\n\n<strong>++\n++ Adblock Information ++\n++</strong>\n${adb_info}"
-mail_text="${mail_text}\n\n<strong>++\n++ Logfile Information ++\n++</strong>\n${log_info}"
-mail_text="${mail_text}</pre></body></html>"
-
-# send mail
-#
-if [ -x "${mail_daemon}" ]
-then
-       printf "%b" "${mail_head}${mail_text}" 2>/dev/null | "${mail_daemon}" ${mail_debug} -a "${mail_profile}" "${mail_receiver}" >/dev/null 2>&1
-       mail_rc=${?}
-       logger -p "info" -t "adblock-notify-${mail_ver}[${$}]" "mail sent to '${mail_receiver}' with rc '${mail_rc}'"
-else
-       logger -p "err" -t "adblock-notify-${mail_ver}[${$}]" "msmtp mail daemon not found"
-fi
-
-exit ${mail_rc}
diff --git a/net/adblock/files/adblock.service b/net/adblock/files/adblock.service
new file mode 100755 (executable)
index 0000000..1265c13
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+# ubus monitor to trace dns backend events and conditionally restart adblock
+# written by Dirk Brenken (dev@brenken.org)
+
+# This is free software, licensed under the GNU General Public License v3.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+LC_ALL=C
+PATH="/usr/sbin:/usr/bin:/sbin:/bin"
+
+if [ -r "/lib/functions.sh" ]
+then
+       . "/lib/functions.sh"
+       adb_basever="$(uci_get adblock global adb_basever)"
+       adb_dns="$(uci_get adblock global adb_dns)"
+fi
+adb_ubus="$(command -v ubus)"
+
+if [ -x "${adb_ubus}" ] && [ -n "${adb_dns}" ]
+then
+       logger -p "info" -t "adblock-${adb_basever}  [${$}]" "ubus/adblock service started"
+       "${adb_ubus}" -S -M r -m invoke monitor | \
+               { grep -qF "\"method\":\"set\",\"data\":{\"name\":\"${adb_dns}\""; [ $? -eq 0 ] && /etc/init.d/adblock start; }
+else
+       logger -p "err" -t "adblock-${adb_basever}  [${$}]" "can't start ubus/adblock service"
+fi
index 24e58b28f383e329105258f11188b841790c380b..e4bba187a4b716b0c0104e56418c5d3cab4d3d25 100755 (executable)
 #
 LC_ALL=C
 PATH="/usr/sbin:/usr/bin:/sbin:/bin"
-adb_ver="3.6.5-2"
+adb_ver="3.8.0"
 adb_sysver="unknown"
 adb_enabled=0
 adb_debug=0
 adb_forcedns=0
-adb_jail=0
-adb_maxqueue=8
-adb_notify=0
-adb_notifycnt=0
+adb_maxqueue=4
+adb_mail=0
+adb_mcnt=0
+adb_trigger="wan"
 adb_triggerdelay=0
-adb_backup=0
-adb_backup_mode=0
-adb_backupdir="/mnt"
+adb_backupdir="/tmp"
 adb_fetchutil="uclient-fetch"
 adb_dns="dnsmasq"
+adb_dnsvariant="nxdomain"
 adb_dnsprefix="adb_list"
 adb_dnsfile="${adb_dnsprefix}.overall"
-adb_dnsjail="${adb_dnsprefix}.jail"
+adb_dnsfilereset="false"
 adb_dnsflush=0
+adb_blacklist="/etc/adblock/adblock.blacklist"
 adb_whitelist="/etc/adblock/adblock.whitelist"
 adb_rtfile="/tmp/adb_runtime.json"
-adb_hashutil="$(command -v sha256sum)"
-adb_hashold=""
-adb_hashnew=""
 adb_report=0
 adb_repiface="br-lan"
 adb_replisten="53"
@@ -45,10 +42,13 @@ adb_cnt=""
 adb_rc=0
 adb_action="${1:-"start"}"
 adb_pidfile="/var/run/adblock.pid"
+adb_ubusservice="/etc/adblock/adblock.service"
+adb_mailservice="/etc/adblock/adblock.mail"
+adb_sources=""
 
 # load adblock environment
 #
-f_envload()
+f_load()
 {
        local dns_up sys_call sys_desc sys_model cnt=0
 
@@ -57,18 +57,11 @@ f_envload()
        sys_call="$(ubus -S call system board 2>/dev/null)"
        if [ -n "${sys_call}" ]
        then
-               sys_desc="$(printf '%s' "${sys_call}" | jsonfilter -e '@.release.description')"
-               sys_model="$(printf '%s' "${sys_call}" | jsonfilter -e '@.model')"
+               sys_desc="$(printf "%s" "${sys_call}" | jsonfilter -e '@.release.description')"
+               sys_model="$(printf "%s" "${sys_call}" | jsonfilter -e '@.model')"
                adb_sysver="${sys_model}, ${sys_desc}"
        fi
 
-       # check hash utility
-       #
-       if [ ! -x "${adb_hashutil}" ]
-       then
-               adb_hashutil="$(command -v md5sum)"
-       fi
-
        # parse 'global' and 'extra' section by callback
        #
        config_cb()
@@ -108,71 +101,78 @@ f_envload()
        config_load adblock
        config_foreach parse_config source
 
-       # check dns backend
+       # version check
+       #
+       if [ -z "${adb_basever}" ] || [ "${adb_ver%.*}" != "${adb_basever}" ]
+       then
+               f_log "info" "your adblock config seems to be too old, please update your config with the '--force-maintainer' opkg option"
+               exit 0
+       fi
+
+       # set dns backend
        #
        case "${adb_dns}" in
-               dnsmasq)
+               "dnsmasq")
                        adb_dnsinstance="${adb_dnsinstance:-"0"}"
                        adb_dnsuser="${adb_dnsuser:-"dnsmasq"}"
                        adb_dnsdir="${adb_dnsdir:-"/tmp"}"
                        adb_dnsheader=""
-                       adb_dnsdeny="awk '{print \"server=/\"\$0\"/\"}'"
-                       adb_dnsallow="awk '{print \"server=/\"\$0\"/#\"}'"
-                       adb_dnshalt="server=/#/"
+                       if [ "${adb_dnsvariant}" = "nxdomain" ]
+                       then
+                               adb_dnsdeny="awk '{print \"server=/\"\$0\"/\"}'"
+                               adb_dnsallow="awk '{print \"server=/\"\$0\"/#\"}'"
+                       elif [ "${adb_dnsvariant}" = "null (IPv4)" ]
+                       then
+                               adb_dnsdeny="awk '{print \"0.0.0.0\\t\"\$0\"\"}'"
+                       elif [ "${adb_dnsvariant}" = "null (IPv4/IPv6)" ]
+                       then
+                               adb_dnsdeny="awk '{print \"0.0.0.0\\t\"\$0\"\\n::\\t\"\$0\"\"}'"
+                       fi
+                       adb_dnsallow=""
                ;;
-               unbound)
+               "unbound")
                        adb_dnsinstance="${adb_dnsinstance:-"0"}"
                        adb_dnsuser="${adb_dnsuser:-"unbound"}"
                        adb_dnsdir="${adb_dnsdir:-"/var/lib/unbound"}"
                        adb_dnsheader=""
-                       adb_dnsdeny="awk '{print \"local-zone: \042\"\$0\"\042 static\"}'"
-                       adb_dnsallow="awk '{print \"local-zone: \042\"\$0\"\042 transparent\"}'"
-                       adb_dnshalt="local-zone: \".\" static"
+                       adb_dnsdeny="awk '{print \"local-zone: \\042\"\$0\"\\042 static\"}'"
+                       adb_dnsallow="awk '{print \"local-zone: \\042\"\$0\"\\042 transparent\"}'"
                ;;
-               named)
+               "named")
                        adb_dnsinstance="${adb_dnsinstance:-"0"}"
                        adb_dnsuser="${adb_dnsuser:-"bind"}"
                        adb_dnsdir="${adb_dnsdir:-"/var/lib/bind"}"
                        adb_dnsheader="\$TTL 2h"$'\n'"@ IN SOA localhost. root.localhost. (1 6h 1h 1w 2h)"$'\n'"  IN NS localhost."
-                       adb_dnsdeny="awk '{print \"\"\$0\" CNAME .\n*.\"\$0\" CNAME .\"}'"
-                       adb_dnsallow="awk '{print \"\"\$0\" CNAME rpz-passthru.\n*.\"\$0\" CNAME rpz-passthru.\"}'"
-                       adb_dnshalt="* CNAME ."
+                       adb_dnsdeny="awk '{print \"\"\$0\" CNAME .\\n*.\"\$0\" CNAME .\"}'"
+                       adb_dnsallow="awk '{print \"\"\$0\" CNAME rpz-passthru.\\n*.\"\$0\" CNAME rpz-passthru.\"}'"
                ;;
-               kresd)
+               "kresd")
                        adb_dnsinstance="${adb_dnsinstance:-"0"}"
                        adb_dnsuser="${adb_dnsuser:-"root"}"
                        adb_dnsdir="${adb_dnsdir:-"/etc/kresd"}"
                        adb_dnsheader="\$TTL 2h"$'\n'"@ IN SOA localhost. root.localhost. (1 6h 1h 1w 2h)"$'\n'"  IN NS  localhost."
-                       adb_dnsdeny="awk '{print \"\"\$0\" CNAME .\n*.\"\$0\" CNAME .\"}'"
-                       adb_dnsallow="awk '{print \"\"\$0\" CNAME rpz-passthru.\n*.\"\$0\" CNAME rpz-passthru.\"}'"
-                       adb_dnshalt="* CNAME ."
-               ;;
-               dnscrypt-proxy)
-                       adb_dnsinstance="${adb_dnsinstance:-"0"}"
-                       adb_dnsuser="${adb_dnsuser:-"nobody"}"
-                       adb_dnsdir="${adb_dnsdir:-"/tmp"}"
-                       adb_dnsheader=""
-                       adb_dnsdeny="awk '{print \$0}'"
-                       adb_dnsallow=""
-                       adb_dnshalt=""
+                       adb_dnsdeny="awk '{print \"\"\$0\" CNAME .\\n*.\"\$0\" CNAME .\"}'"
+                       adb_dnsallow="awk '{print \"\"\$0\" CNAME rpz-passthru.\\n*.\"\$0\" CNAME rpz-passthru.\"}'"
                ;;
        esac
 
-       # check adblock status
+       # status check
        #
-       if [ ${adb_enabled} -eq 0 ]
+       if [ "${adb_enabled}" -eq 0 ]
        then
                f_extconf
                f_temp
                f_rmdns
                f_jsnup "disabled"
-               f_log "info" "adblock is currently disabled, please set adb_enabled to '1' to use this service"
+               f_log "info" "adblock is currently disabled, please set the config option 'adb_enabled' to '1' to use this service"
                exit 0
        fi
 
+       # dns backend check
+       #
        if [ -d "${adb_dnsdir}" ] && [ ! -f "${adb_dnsdir}/${adb_dnsfile}" ]
        then
-               printf '%s\n' "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
+               printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
        fi
 
        if [ "${adb_action}" = "start" ] && [ "${adb_trigger}" = "timed" ]
@@ -180,7 +180,7 @@ f_envload()
                sleep ${adb_triggerdelay}
        fi
 
-       while [ ${cnt} -le 30 ]
+       while [ "${cnt}" -le 30 ]
        do
                dns_up="$(ubus -S call service list "{\"name\":\"${adb_dns}\"}" 2>/dev/null | jsonfilter -l1 -e "@[\"${adb_dns}\"].instances.*.running" 2>/dev/null)"
                if [ "${dns_up}" = "true" ]
@@ -193,27 +193,29 @@ f_envload()
 
        if [ "${dns_up}" != "true" ] || [ -z "${adb_dns}" ] || [ ! -x "$(command -v ${adb_dns})" ]
        then
-               f_log "err" "'${adb_dns}' not running or not executable"
+               f_log "err" "'${adb_dns}' not running or executable"
        elif [ ! -d "${adb_dnsdir}" ]
        then
                f_log "err" "'${adb_dnsdir}' backend directory not found"
        fi
 }
 
-# check environment
+# check & set environment
 #
-f_envcheck()
+f_env()
 {
        local ssl_lib
 
-       # startup message
-       #
        f_log "info" "adblock instance started ::: action: ${adb_action}, priority: ${adb_nice:-"0"}, pid: ${$}"
        f_jsnup "running"
+       f_extconf
 
-       # check external uci config files
+       # check backup directory
        #
-       f_extconf
+       if [ ! -d "${adb_backupdir}" ]
+       then
+               f_log "err" "the backup directory '${adb_backupdir}' does not exist/is not mounted yet, please create the directory or raise the 'adb_triggerdelay' to defer the adblock start"
+       fi
 
        # check fetch utility
        #
@@ -260,15 +262,18 @@ f_envcheck()
 #
 f_temp()
 {
-       if [ -z "${adb_tmpdir}" ]
+       if [ -d "/tmp" ] && [ -z "${adb_tmpdir}" ]
        then
                adb_tmpdir="$(mktemp -p /tmp -d)"
-               adb_tmpload="$(mktemp -p ${adb_tmpdir} -tu)"
-               adb_tmpfile="$(mktemp -p ${adb_tmpdir} -tu)"
+               adb_tmpload="$(mktemp -p "${adb_tmpdir}" -tu)"
+               adb_tmpfile="$(mktemp -p "${adb_tmpdir}" -tu)"
+       elif [ ! -d "/tmp" ]
+       then
+               f_log "err" "the temp directory '/tmp' does not exist/is not mounted yet, please create the directory or raise the 'adb_triggerdelay' to defer the adblock start"
        fi
        if [ ! -s "${adb_pidfile}" ]
        then
-               printf '%s' "${$}" > "${adb_pidfile}"
+               printf "%s" "${$}" > "${adb_pidfile}"
        fi
 }
 
@@ -283,22 +288,16 @@ f_rmtemp()
        > "${adb_pidfile}"
 }
 
-# remove dns related files and directories
+# remove dns related files, services and directories
 #
 f_rmdns()
 {
        if [ -n "${adb_dns}" ]
        then
-               f_hash
-               printf '%s\n' "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
-               > "${adb_dnsdir}/.${adb_dnsfile}"
+               printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}"/"${adb_dnsfile}"
                > "${adb_rtfile}"
-               rm -f "${adb_backupdir}/${adb_dnsprefix}"*.gz
-               f_hash
-               if [ ${?} -eq 1 ]
-               then
-                       f_dnsup
-               fi
+               rm -f "${adb_backupdir}"/"${adb_dnsprefix}"*".gz"
+               f_dnsup
                f_rmtemp
        fi
        f_log "debug" "f_rmdns  ::: dns: ${adb_dns}, dns_dir: ${adb_dnsdir}, dns_prefix: ${adb_dnsprefix}, dns_file: ${adb_dnsfile}, rt_file: ${adb_rtfile}, backup_dir: ${adb_backupdir}"
@@ -317,7 +316,7 @@ f_uci()
                then
                        uci_commit "${config}"
                        case "${config}" in
-                               firewall)
+                               "firewall")
                                        /etc/init.d/firewall reload >/dev/null 2>&1
                                ;;
                                *)
@@ -336,17 +335,23 @@ f_count()
        local mode="${1}"
 
        adb_cnt=0
-       if [ -s "${adb_dnsdir}/${adb_dnsfile}" ] && ([ -z "${mode}" ] || [ "${mode}" = "final" ])
+       if [ -s "${adb_dnsdir}/${adb_dnsfile}" ] && { [ -z "${mode}" ] || [ "${mode}" = "final" ]; }
        then
                adb_cnt="$(wc -l 2>/dev/null < "${adb_dnsdir}/${adb_dnsfile}")"
-               if [ -s "${adb_tmpdir}/tmp.add_whitelist" ]
+               if [ -s "${adb_tmpdir}/tmp.add.whitelist" ]
                then
-                       adb_cnt="$(( ${adb_cnt} - $(wc -l 2>/dev/null < "${adb_tmpdir}/tmp.add_whitelist") ))"
+                       adb_cnt="$((adb_cnt-$(wc -l 2>/dev/null < "${adb_tmpdir}/tmp.add.whitelist")))"
                fi
-               if [ "${adb_dns}" = "named" ] || [ "${adb_dns}" = "kresd" ]
+               if [ "${adb_dns}" = "named" ] || [ "${adb_dns}" = "kresd" ] || { [ "${adb_dns}" = "dnsmasq" ] && [ "${adb_dnsvariant}" = "null (IPv4/IPv6)" ]; }
                then
-                       adb_cnt="$(( (${adb_cnt} - $(printf '%s' "${adb_dnsheader}" | grep -c "^")) / 2 ))"
+                       adb_cnt="$(((adb_cnt-$(printf "%s" "${adb_dnsheader}" | grep -c "^"))/2))"
                fi
+       elif [ "${mode}" = "blacklist" ] && [ -s "${adb_tmpfile}.blacklist" ]
+       then
+               adb_cnt="$(wc -l 2>/dev/null < "${adb_tmpfile}.blacklist")"
+       elif [ "${mode}" = "whitelist" ] && [ -s "${adb_tmpdir}/tmp.raw.whitelist" ]
+       then
+               adb_cnt="$(wc -l 2>/dev/null < "${adb_tmpdir}/tmp.raw.whitelist")"
        elif [ -s "${adb_tmpfile}" ]
        then
                adb_cnt="$(wc -l 2>/dev/null < "${adb_tmpfile}")"
@@ -360,31 +365,49 @@ f_extconf()
        local uci_config port port_list="53 853 5353"
 
        case "${adb_dns}" in
-               dnsmasq)
+               "dnsmasq")
                        uci_config="dhcp"
-                       if [ ${adb_enabled} -eq 1 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]")" ] && \
-                               [ -z "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ] && \
-                               [ -z "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsjail}")" ]
+                       if [ "${adb_dnsvariant}" = "nxdomain" ]
                        then
-                               uci_set dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile "${adb_dnsdir}/${adb_dnsfile}"
-                       elif [ ${adb_enabled} -eq 0 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                               if [ "${adb_enabled}" -eq 1 ] && [ -z "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                               then
+                                       uci_set dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile "${adb_dnsdir}/${adb_dnsfile}"
+                                       if [ "${adb_enabled}" -eq 1 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                                       then
+                                               uci -q del_list dhcp.@dnsmasq[${adb_dnsinstance}].addnhosts="${adb_dnsdir}/${adb_dnsfile}"
+                                       fi
+                               elif [ "${adb_enabled}" -eq 0 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                               then
+                                       uci_remove dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile
+                               fi
+                       elif [ "${adb_dnsvariant% *}" = "null" ]
                        then
-                               uci_remove dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile
+                               if [ "${adb_enabled}" -eq 1 ] && [ -z "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                               then
+                                       uci -q add_list dhcp.@dnsmasq[${adb_dnsinstance}].addnhosts="${adb_dnsdir}/${adb_dnsfile}"
+                                       if [ "${adb_enabled}" -eq 1 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                                       then
+                                               uci_remove dhcp "@dnsmasq[${adb_dnsinstance}]" serversfile
+                                       fi
+                               elif [ "${adb_enabled}" -eq 0 ] && [ -n "$(uci_get dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                               then
+                                       uci_remove dhcp "@dnsmasq[${adb_dnsinstance}]" addnhosts
+                               fi
                        fi
                ;;
-               kresd)
+               "kresd")
                        uci_config="resolver"
-                       if [ ${adb_enabled} -eq 1 ] && [ -z "$(uci_get resolver kresd rpz_file | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                       if [ "${adb_enabled}" -eq 1 ] && [ -z "$(uci_get resolver kresd rpz_file | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
                        then
                                uci -q add_list resolver.kresd.rpz_file="${adb_dnsdir}/${adb_dnsfile}"
-                       elif [ ${adb_enabled} -eq 0 ] && [ -n "$(uci_get resolver kresd rpz_file | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
+                       elif [ "${adb_enabled}" -eq 0 ] && [ -n "$(uci_get resolver kresd rpz_file | grep -Fo "${adb_dnsdir}/${adb_dnsfile}")" ]
                        then
                                uci -q del_list resolver.kresd.rpz_file="${adb_dnsdir}/${adb_dnsfile}"
                        fi
-                       if [ ${adb_enabled} -eq 1 ] && [ ${adb_dnsflush} -eq 0 ] && [ "$(uci_get resolver kresd keep_cache)" != "1" ]
+                       if [ "${adb_enabled}" -eq 1 ] && [ "${adb_dnsflush}" -eq 0 ] && [ "$(uci_get resolver kresd keep_cache)" != "1" ]
                        then
                                uci_set resolver kresd keep_cache "1"
-                       elif [ ${adb_enabled} -eq 0 ] || ([ ${adb_dnsflush} -eq 1 ] && [ "$(uci_get resolver kresd keep_cache)" = "1" ])
+                       elif [ "${adb_enabled}" -eq 0 ] || { [ "${adb_dnsflush}" -eq 1 ] && [ "$(uci_get resolver kresd keep_cache)" = "1" ]; }
                        then
                                uci_set resolver kresd keep_cache "0"
                        fi
@@ -393,8 +416,8 @@ f_extconf()
        f_uci "${uci_config}"
 
        uci_config="firewall"
-       if [ ${adb_enabled} -eq 1 ] && [ ${adb_forcedns} -eq 1 ] && \
-               [ -z "$(uci_get firewall adblock_dns_53)" ] && [ $(/etc/init.d/firewall enabled; printf '%u' ${?}) -eq 0 ]
+       if [ "${adb_enabled}" -eq 1 ] && [ "${adb_forcedns}" -eq 1 ] && \
+               [ -z "$(uci_get firewall adblock_dns_53)" ] && [ "$(/etc/init.d/firewall enabled; printf "%u" ${?})" -eq 0 ]
        then
                for port in ${port_list}
                do
@@ -406,7 +429,7 @@ f_extconf()
                        uci_set firewall "adblock_dns_${port}" "dest_port" "${port}"
                        uci_set firewall "adblock_dns_${port}" "target" "DNAT"
                done
-       elif [ -n "$(uci_get firewall adblock_dns_53)" ] && ([ ${adb_enabled} -eq 0 ] || [ ${adb_forcedns} -eq 0 ])
+       elif [ -n "$(uci_get firewall adblock_dns_53)" ] && { [ "${adb_enabled}" -eq 0 ] || [ "${adb_forcedns}" -eq 0 ]; }
        then
                for port in ${port_list}
                do
@@ -422,14 +445,20 @@ f_dnsup()
 {
        local dns_up cache_util cache_rc cnt=0
 
-       if [ ${adb_dnsflush} -eq 0 ] && [ ${adb_enabled} -eq 1 ] && [ "${adb_rc}" -eq 0 ]
+       if [ "${adb_dnsflush}" -eq 0 ] && [ "${adb_enabled}" -eq 1 ] && [ "${adb_rc}" -eq 0 ]
        then
                case "${adb_dns}" in
-                       dnsmasq)
-                               killall -q -HUP "${adb_dns}"
-                               cache_rc=${?}
+                       "dnsmasq")
+                               if [ "${adb_dnsvariant}" = "nxdomain" ]
+                               then
+                                       killall -q -HUP "${adb_dns}"
+                                       cache_rc=${?}
+                               elif [ "${adb_dnsvariant% *}" = "null" ]
+                               then
+                                       "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
+                               fi
                        ;;
-                       unbound)
+                       "unbound")
                                cache_util="$(command -v unbound-control)"
                                if [ -x "${cache_util}" ] && [ -d "${adb_tmpdir}" ] && [ -f "${adb_dnsdir}"/unbound.conf ]
                                then
@@ -437,12 +466,12 @@ f_dnsup()
                                fi
                                "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
                        ;;
-                       kresd)
+                       "kresd")
                                cache_util="keep_cache"
                                "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
                                cache_rc=${?}
                        ;;
-                       named)
+                       "named")
                                cache_util="$(command -v rndc)"
                                if [ -x "${cache_util}" ] && [ -f /etc/bind/rndc.conf ]
                                then
@@ -452,30 +481,25 @@ f_dnsup()
                                        "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
                                fi
                        ;;
-                       *)
-                               "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
-                       ;;
                esac
-       else
-               "/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
        fi
 
        adb_rc=1
-       while [ ${cnt} -le 10 ]
+       while [ "${cnt}" -le 10 ]
        do
                dns_up="$(ubus -S call service list "{\"name\":\"${adb_dns}\"}" | jsonfilter -l1 -e "@[\"${adb_dns}\"].instances.*.running")"
                if [ "${dns_up}" = "true" ]
                then
                        case "${adb_dns}" in
-                               unbound)
+                               "unbound")
                                        cache_util="$(command -v unbound-control)"
                                        if [ -x "${cache_util}" ] && [ -d "${adb_tmpdir}" ] && [ -s "${adb_tmpdir}"/adb_cache.dump ]
                                        then
-                                               while [ ${cnt} -le 10 ]
+                                               while [ "${cnt}" -le 10 ]
                                                do
                                                        "${cache_util}" -c "${adb_dnsdir}"/unbound.conf load_cache < "${adb_tmpdir}"/adb_cache.dump >/dev/null 2>&1
                                                        cache_rc=${?}
-                                                       if [ ${cache_rc} -eq 0 ]
+                                                       if [ "${cache_rc}" -eq 0 ]
                                                        then
                                                                break
                                                        fi
@@ -485,6 +509,7 @@ f_dnsup()
                                        fi
                                ;;
                        esac
+                       sleep 1
                        adb_rc=0
                        break
                fi
@@ -499,35 +524,69 @@ f_dnsup()
 #
 f_list()
 {
-       local file mode="${1}" in_rc="${adb_rc}"
+       local file name tmp_file="${adb_tmpfile}" mode="${1}" in_rc="${adb_rc}"
 
        case "${mode}" in
-               backup)
+               "blacklist")
+                       if [ -s "${adb_blacklist}" ]
+                       then
+                               src_name="${mode}"
+                               adb_blacklist_rset="/^([[:alnum:]_-]+\\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}"
+                               awk "${adb_blacklist_rset}" "${adb_blacklist}" > "${adb_tmpfile}"."${src_name}"
+                       fi
+               ;;
+               "whitelist")
+                       if [ -s "${adb_whitelist}" ]
+                       then
+                               src_name="${mode}"
+                               adb_whitelist_rset="/^([[:alnum:]_-]+\\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}"
+                               awk "${adb_whitelist_rset}" "${adb_whitelist}" > "${adb_tmpdir}"/tmp.raw."${src_name}"
+                               
+                               adb_whitelist_rset="/^([[:alnum:]_-]+\\.)+[[:alpha:]]+([[:space:]]|$)/{gsub(\"\\\.\",\"\\\.\",\$1);print tolower(\"^\"\$1\"\\\|\\\.\"\$1)}"
+                               awk "${adb_whitelist_rset}" "${adb_tmpdir}"/tmp.raw."${src_name}" > "${adb_tmpdir}"/tmp.rem."${src_name}"
+
+                               if [ -n "${adb_dnsallow}" ]
+                               then
+                                       eval "${adb_dnsallow}" "${adb_tmpdir}"/tmp.raw."${src_name}" > "${adb_tmpdir}"/tmp.add."${src_name}"
+                               fi
+                       fi
+               ;;
+               "backup")
                        if [ -d "${adb_backupdir}" ]
                        then
                                gzip -cf "${adb_tmpfile}" 2>/dev/null > "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz"
                                adb_rc=${?}
                        fi
                ;;
-               restore)
-                       if [ -d "${adb_backupdir}" ] && [ -f "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz" ]
+               "restore")
+                       if [ -d "${adb_backupdir}" ]
                        then
-                               gunzip -cf "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz" 2>/dev/null > "${adb_tmpfile}"
+                               if [ -n "${src_name}" ] && [ -f "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz" ]
+                               then
+                                       zcat "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz" 2>/dev/null > "${adb_tmpfile}"
+                               else
+                                       for file in "${adb_backupdir}/${adb_dnsprefix}."*".gz"
+                                       do
+                                               name="${file##*/}"
+                                               name="${name%.*}"
+                                               zcat "${file}" 2>/dev/null > "${adb_tmpfile}"."${name}"
+                                       done
+                               fi
                                adb_rc=${?}
                        fi
                ;;
-               remove)
+               "remove")
                        if [ -d "${adb_backupdir}" ]
                        then
                                rm -f "${adb_backupdir}/${adb_dnsprefix}.${src_name}.gz"
                        fi
                        adb_rc=${?}
                ;;
-               merge)
+               "merge")
                        for file in "${adb_tmpfile}".*
                        do
                                cat "${file}" 2>/dev/null >> "${adb_tmpdir}/${adb_dnsfile}"
-                               if [ ${?} -ne 0 ]
+                               if [ "${?}" -ne 0 ]
                                then
                                        adb_rc=${?}
                                        break
@@ -536,24 +595,24 @@ f_list()
                        done
                        adb_tmpfile="${adb_tmpdir}/${adb_dnsfile}"
                ;;
-               final)
+               "final")
                        > "${adb_dnsdir}/${adb_dnsfile}"
 
-                       if [ -s "${adb_tmpdir}/tmp.add_whitelist" ]
+                       if [ -s "${adb_tmpdir}/tmp.add.whitelist" ]
                        then
-                               cat "${adb_tmpdir}/tmp.add_whitelist" >> "${adb_dnsdir}/${adb_dnsfile}"
+                               cat "${adb_tmpdir}/tmp.add.whitelist" >> "${adb_dnsdir}/${adb_dnsfile}"
                        fi
 
-                       if [ -s "${adb_tmpdir}/tmp.rem_whitelist" ]
+                       if [ -s "${adb_tmpdir}/tmp.rem.whitelist" ]
                        then
-                               grep -vf "${adb_tmpdir}/tmp.rem_whitelist" "${adb_tmpdir}/${adb_dnsfile}" | eval "${adb_dnsdeny}" >> "${adb_dnsdir}/${adb_dnsfile}"
+                               grep -vf "${adb_tmpdir}/tmp.rem.whitelist" "${adb_tmpdir}/${adb_dnsfile}" | eval "${adb_dnsdeny}" >> "${adb_dnsdir}/${adb_dnsfile}"
                        else
                                eval "${adb_dnsdeny}" "${adb_tmpdir}/${adb_dnsfile}" >> "${adb_dnsdir}/${adb_dnsfile}"
                        fi
 
-                       if [ ${?} -eq 0 ] && [ -n "${adb_dnsheader}" ]
+                       if [ "${?}" -eq 0 ] && [ -n "${adb_dnsheader}" ]
                        then
-                               printf '%s\n' "${adb_dnsheader}" | cat - "${adb_dnsdir}/${adb_dnsfile}" > "${adb_tmpdir}/${adb_dnsfile}"
+                               printf "%s\\n" "${adb_dnsheader}" | cat - "${adb_dnsdir}/${adb_dnsfile}" > "${adb_tmpdir}/${adb_dnsfile}"
                                mv -f "${adb_tmpdir}/${adb_dnsfile}" "${adb_dnsdir}/${adb_dnsfile}"
                        fi
                        adb_rc=${?}
@@ -567,24 +626,23 @@ f_list()
 #
 f_tld()
 {
-       local cnt cnt_srt cnt_tld source="${1}" temp_src="${1}.src.gz" temp_tld="${1}.tld" tld_ok="false"
+       local cnt cnt_srt cnt_tld source="${1}" temp_tld="${1}.tld" tld_ok="false"
 
-       gzip -cf "${source}" 2>/dev/null > "${temp_src}"
-       if [ ${?} -eq 0 ]
-       then    
-               cnt="$(wc -l 2>/dev/null < "${source}")"
+       cnt="$(wc -l 2>/dev/null < "${source}")"
+       if [ "${adb_dns}" != "dnsmasq" ] && [ "${adb_dnsvariant% *}" != "null" ]
+       then
                awk 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "${source}" > "${temp_tld}"
-               if [ ${?} -eq 0 ]
+               if [ "${?}" -eq 0 ]
                then
                        sort -u "${temp_tld}" > "${source}"
-                       if [ ${?} -eq 0 ]
+                       if [ "${?}" -eq 0 ]
                        then
                                cnt_srt="$(wc -l 2>/dev/null < "${source}")"
                                awk '{if(NR==1){tld=$NF};while(getline){if($NF!~tld"\\."){print tld;tld=$NF}}print tld}' "${source}" > "${temp_tld}"
-                               if [ ${?} -eq 0 ]
+                               if [ "${?}" -eq 0 ]
                                then
                                        awk 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "${temp_tld}" > "${source}"
-                                       if [ ${?} -eq 0 ]
+                                       if [ "${?}" -eq 0 ]
                                        then
                                                rm -f "${temp_src}" "${temp_tld}"
                                                cnt_tld="$(wc -l 2>/dev/null < "${source}")"
@@ -593,90 +651,72 @@ f_tld()
                                fi
                        fi
                fi
+       else
+               sort -u "${source}" > "${temp_tld}"
+               if [ "${?}" -eq 0 ]
+               then
+                       mv -f "${temp_tld}" "${source}"
+                       cnt_srt="$(wc -l 2>/dev/null < "${source}")"
+                       tld_ok="true"
+               fi
        fi
-
        if [ "${tld_ok}" = "false" ]
        then
+               unset cnt_srt cnt_tld
                rm -f "${temp_tld}"
-               gunzip -cf "${temp_src}" 2>/dev/null > "${source}"
-               if [ ${?} -ne 0 ]
-               then
-                       rm -f "${temp_src}"
-                       > "${source}"
-               fi
+               f_list blacklist
+               f_list whitelist
+               f_list restore
+               f_list merge
+               f_list final
+               cnt="$(wc -l 2>/dev/null < "${adb_tmpdir}"/"${adb_dnsfile}")"
        fi
        f_log "debug" "f_tld    ::: source: ${source}, cnt: ${cnt:-"-"}, cnt_srt: ${cnt_srt:-"-"}, cnt_tld: ${cnt_tld:-"-"}, tld_ok: ${tld_ok}"
 }
 
-# blocklist hash compare
-#
-f_hash()
-{
-       local hash hash_rc=1
-
-       if [ -x "${adb_hashutil}" ] && [ -f "${adb_dnsdir}/${adb_dnsfile}" ]
-       then
-               hash="$(${adb_hashutil} "${adb_dnsdir}/${adb_dnsfile}" 2>/dev/null | awk '{print $1}')"
-               if [ -z "${adb_hashold}" ] && [ -n "${hash}" ]
-               then
-                       adb_hashold="${hash}"
-               elif [ -z "${adb_hashnew}" ] && [ -n "${hash}" ]
-               then
-                       adb_hashnew="${hash}"
-               fi
-               if [ -n "${adb_hashold}" ] && [ -n "${adb_hashnew}" ]
-               then
-                       if [ "${adb_hashold}" = "${adb_hashnew}" ]
-                       then
-                               hash_rc=0
-                       fi
-                       adb_hashold=""
-                       adb_hashnew=""
-               fi
-       fi
-       f_log "debug" "f_hash   ::: hash_util: ${adb_hashutil}, hash: ${hash}, out_rc: ${hash_rc}"
-       return ${hash_rc}
-}
-
 # suspend/resume adblock processing
 #
 f_switch()
 {
-       local status cnt mode="${1}"
+       local status done="false" mode="${1}"
 
        json_load_file "${adb_rtfile}" >/dev/null 2>&1
-       json_select "data"
+       json_select "data" >/dev/null 2>&1
        json_get_var status "adblock_status"
-       json_get_var cnt "overall_domains"
-
+       f_temp
        if [ "${mode}" = "suspend" ] && [ "${status}" = "enabled" ]
        then
-               if [ ${cnt%% *} -gt 0 ] && [ -s "${adb_dnsdir}/${adb_dnsfile}" ]
+               > "${adb_dnsdir}/${adb_dnsfile}"
+               if [ -n "${adb_dnsheader}" ]
                then
-                       f_hash
-                       cat "${adb_dnsdir}/${adb_dnsfile}" > "${adb_dnsdir}/.${adb_dnsfile}"
-                       printf '%s\n' "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
-                       f_hash
+                       printf "%s\\n" "${adb_dnsheader}" > "${adb_dnsdir}/${adb_dnsfile}"
                fi
+               done="true"
        elif [ "${mode}" = "resume" ] && [ "${status}" = "paused" ]
        then
-               if [ ${cnt%% *} -gt 0 ] && [ -s "${adb_dnsdir}/.${adb_dnsfile}" ]
-               then
-                       f_hash
-                       cat "${adb_dnsdir}/.${adb_dnsfile}" > "${adb_dnsdir}/${adb_dnsfile}"
-                       > "${adb_dnsdir}/.${adb_dnsfile}"
-                       f_hash
-               fi
+               f_list blacklist
+               f_list whitelist
+               f_list restore
+               f_list merge
+               f_tld "${adb_tmpdir}"/"${adb_dnsfile}"
+               f_list final
+               done="true"
        fi
-       if [ ${?} -eq 1 ]
+       if [ "${done}" = "true" ]
        then
-               f_temp
+               if [ "${mode}" = "suspend" ]
+               then
+                       f_bgserv "stop"
+               fi
                f_dnsup
+               if [ "${mode}" = "resume" ]
+               then
+                       f_bgserv "start"
+               fi
                f_jsnup "${mode}"
                f_log "info" "${mode} adblock processing"
-               f_rmtemp
-               exit 0
        fi
+       f_rmtemp
 }
 
 # query blocklist for certain (sub-)domains
@@ -687,54 +727,65 @@ f_query()
 
        if [ -z "${domain}" ] || [ "${domain}" = "${tld}" ]
        then
-               printf '%s\n' "::: invalid domain input, please submit a single domain, e.g. 'doubleclick.net'"
+               printf "%s\\n" "::: invalid domain input, please submit a single domain, e.g. 'doubleclick.net'"
        else
                case "${adb_dns}" in
-                       dnsmasq)
-                               prefix=".*[\/\.]"
-                               suffix="(\/)"
-                               field=2
+                       "dnsmasq")
+                               if [ "${adb_dnsvariant}" = "nxdomain" ]
+                               then
+                                       prefix=".*[\\/\\.]"
+                                       suffix="(\\/)"
+                                       field=2
+                               elif [ "${adb_dnsvariant% *}" = "null" ]
+                               then
+                                       prefix=".*[\\t\\.]"
+                                       suffix=""
+                                       field=2
+                               fi
                        ;;
-                       unbound)
-                               prefix=".*[\"\.]"
+                       "unbound")
+                               prefix=".*[\"\\.]"
                                suffix="(static)"
                                field=3
                        ;;
-                       named)
-                               prefix="[^\*].*[\.]"
-                               suffix="( \.)"
+                       "named")
+                               prefix="[^\\*].*[\\.]"
+                               suffix="( \\.)"
                                field=1
                        ;;
-                       kresd)
-                               prefix="[^\*].*[\.]"
-                               suffix="( \.)"
-                               field=1
-                       ;;
-                       dnscrypt-proxy)
-                               prefix=".*[\.]"
-                               suffix=""
+                       "kresd")
+                               prefix="[^\\*].*[\\.]"
+                               suffix="( \\.)"
                                field=1
                        ;;
                esac
-               while [ "${domain}" != "${tld}" ]
-               do
-                       search="${domain//./\\.}"
-                       search="${search//[+*~%\$&\"\']/}"
-                       result="$(awk -F '/|\"| ' "/^(${search}|${prefix}+${search}.*${suffix}$)/{i++;{printf(\"  + %s\n\",\$${field})};if(i>9){printf(\"  + %s\n\",\"[...]\");exit}}" "${adb_dnsdir}/${adb_dnsfile}")"
-                       printf '%s\n%s\n%s\n' ":::" "::: results for domain '${domain}'" ":::"
-                       printf '%s\n' "${result:-"  - no match"}"
-                       domain="${tld}"
-                       tld="${domain#*.}"
-               done
-
-               if [ ${adb_backup} -eq 1 ] && [ -d "${adb_backupdir}" ]
+               if [ "${adb_dnsfilereset}" = "false" ]
+               then
+                       while [ "${domain}" != "${tld}" ]
+                       do
+                               search="${domain//./\\.}"
+                               search="${search//[+*~%\$&\"\']/}"
+                               result="$(awk -F '/|\"|\t| ' "/^(${prefix}+${search}.*${suffix}$)/{i++;{printf(\"  + %s\\n\",\$${field})};if(i>9){printf(\"  + %s\\n\",\"[...]\");exit}}" "${adb_dnsdir}/${adb_dnsfile}")"
+                               printf "%s\\n%s\\n%s\\n" ":::" "::: results for domain '${domain}' in active blocklist" ":::"
+                               printf "%s\n\n" "${result:-"  - no match"}"
+                               domain="${tld}"
+                               tld="${domain#*.}"
+                       done
+               fi
+               if [ -d "${adb_backupdir}" ]
                then
                        search="${1//./\\.}"
                        search="${search//[+*~%\$&\"\']/}"
-                       printf '%s\n%s\n%s\n' ":::" "::: results for domain '${1}' in backups" ":::"
-                       for file in ${adb_backupdir}/${adb_dnsprefix}.*.gz
+                       printf "%s\\n%s\\n%s\\n" ":::" "::: results for domain '${1}' in backups and black-/whitelist" ":::"
+                       for file in "${adb_backupdir}"/"${adb_dnsprefix}".*.gz "${adb_blacklist}" "${adb_whitelist}"
                        do
-                               zcat "${file}" 2>/dev/null | awk -v f="${file##*/}" "/^($search|.*\.${search})/{i++;{printf(\"  + %-30s%s\n\",f,\$1)};if(i>=3){printf(\"  + %-30s%s\n\",f,\"[...]\");exit}}"
+                               suffix="${file##*.}"
+                               if [ "${suffix}" = "gz" ]
+                               then
+                                       zcat "${file}" 2>/dev/null | awk -v f="${file##*/}" "/^($search|.*\\.${search})/{i++;{printf(\"  + %-30s%s\\n\",f,\$1)};if(i>=3){printf(\"  + %-30s%s\\n\",f,\"[...]\");exit}}"
+                               else
+                                       cat "${file}" 2>/dev/null | awk -v f="${file##*/}" "/^($search|.*\\.${search})/{i++;{printf(\"  + %-30s%s\\n\",f,\$1)};if(i>=3){printf(\"  + %-30s%s\\n\",f,\"[...]\");exit}}"
+                               fi
                        done
                fi
        fi
@@ -744,9 +795,9 @@ f_query()
 #
 f_jsnup()
 {
-       local run_time bg_pid status="${1:-"enabled"}" mode="normal mode"
+       local run_time bg_pid status="${1:-"enabled"}"
 
-       if [ ${adb_rc} -gt 0 ]
+       if [ "${adb_rc}" -gt 0 ]
        then
                status="error"
                run_time="$(/bin/date "+%d.%m.%Y %H:%M:%S")"
@@ -763,14 +814,10 @@ f_jsnup()
        then
                status=""
        fi
-       if [ ${adb_backup_mode} -eq 1 ]
-       then
-               mode="backup mode"
-       fi
 
        json_load_file "${adb_rtfile}" >/dev/null 2>&1
        json_select "data" >/dev/null 2>&1
-       if [ ${?} -eq 0 ]
+       if [ "${?}" -eq 0 ]
        then
                if [ -z "${adb_fetchinfo}" ]
                then
@@ -793,21 +840,23 @@ f_jsnup()
        json_add_object "data"
        json_add_string "adblock_status" "${status:-"enabled"}"
        json_add_string "adblock_version" "${adb_ver}"
-       json_add_string "overall_domains" "${adb_cnt:-0} (${mode})"
+       json_add_string "overall_domains" "${adb_cnt:-0}"
        json_add_string "fetch_utility" "${adb_fetchinfo:-"-"}"
-       json_add_string "dns_backend" "${adb_dns} (${adb_dnsdir})"
+       json_add_string "dns_backend" "${adb_dns}, ${adb_dnsdir}"
+       json_add_string "dns_variant" "${adb_dnsvariant}, ${adb_dnsfilereset:-"false"}"
+       json_add_string "backup_dir" "${adb_backupdir}"
        json_add_string "last_rundate" "${run_time:-"-"}"
        json_add_string "system_release" "${adb_sysver}"
        json_close_object
        json_dump > "${adb_rtfile}"
 
-       if [ ${adb_notify} -eq 1 ] && [ -x /etc/adblock/adblock.notify ] && \
-               ([ "${status}" = "error" ] || ([ "${status}" = "enabled" ] && [ ${adb_cnt} -le ${adb_notifycnt} ]))
+       if [ ${adb_mail} -eq 1 ] && [ -x "${adb_mailservice}" ] && \
+               { [ "${status}" = "error" ] || { [ "${status}" = "enabled" ] && [ "${adb_cnt}" -le "${adb_mcnt}" ]; } }
        then
-               (/etc/adblock/adblock.notify >/dev/null 2>&1)&
+               ("${adb_mailservice}" >/dev/null 2>&1)&
                bg_pid=${!}
        fi
-       f_log "debug" "f_jsnup  ::: status: ${status:-"-"}, mode: ${mode}, cnt: ${adb_cnt}, notify: ${adb_notify}, notify_cnt: ${adb_notifycnt}, notify_pid: ${bg_pid:-"-"}"
+       f_log "debug" "f_jsnup  ::: status: ${status:-"-"}, cnt: ${adb_cnt}, mail: ${adb_mail}, mail_service: ${adb_mailservice}, mail_cnt: ${adb_mcnt}, mail_pid: ${bg_pid:-"-"}"
 }
 
 # write to syslog
@@ -816,7 +865,7 @@ f_log()
 {
        local class="${1}" log_msg="${2}"
 
-       if [ -n "${log_msg}" ] && ([ "${class}" != "debug" ] || [ ${adb_debug} -eq 1 ])
+       if [ -n "${log_msg}" ] && { [ "${class}" != "debug" ] || [ ${adb_debug} -eq 1 ]; }
        then
                logger -p "${class}" -t "adblock-${adb_ver}[${$}]" "${log_msg}"
                if [ "${class}" = "err" ]
@@ -829,6 +878,24 @@ f_log()
        fi
 }
 
+# start ubus monitor service to trace dns backend events
+#
+f_bgserv()
+{
+       local bg_pid status="${1}"
+
+       bg_pid="$(pgrep -f "^/bin/sh ${adb_ubusservice}|^/bin/ubus -S -M r -m invoke monitor|^grep -qF \"method\":\"set\",\"data\":\\{\"name\":\"${adb_dns}\"" | awk '{ORS=" "; print $1}')"
+       if [ -z "${bg_pid}" ] && [ "${status}" = "start" ] \
+               && [ -x "${adb_ubusservice}" ] && [ "${adb_dnsfilereset}" = "true" ]
+       then
+               ( "${adb_ubusservice}" &)
+       elif [ -n "${bg_pid}" ] && [ "${status}" = "stop" ] 
+       then
+               kill -HUP ${bg_pid}
+       fi
+       f_log "debug" "f_bgserv ::: status: ${status:-"-"}, bg_pid: ${bg_pid:-"-"}, dns_filereset: ${adb_dnsfilereset:-"-"}, ubus_service: ${adb_ubusservice:-"-"}"
+}
+
 # main function for blocklist processing
 #
 f_main()
@@ -839,57 +906,25 @@ f_main()
        mem_free="$(awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
        tmp_load="${adb_tmpload}"
        tmp_file="${adb_tmpfile}"
-       > "${adb_dnsdir}/.${adb_dnsfile}"
-       > "${adb_tmpdir}/tmp.raw_whitelist"
-       > "${adb_tmpdir}/tmp.add_whitelist"
-       > "${adb_tmpdir}/tmp.rem_whitelist"
-       f_log "debug" "f_main   ::: dns: ${adb_dns}, fetch_util: ${adb_fetchinfo}, backup: ${adb_backup}, backup_mode: ${adb_backup_mode}, dns_jail: ${adb_jail}, force_dns: ${adb_forcedns}, mem_total: ${mem_total:-0}, mem_free: ${mem_free:-0}, max_queue: ${adb_maxqueue}"
-
-       # prepare whitelist entries
-       #
-       if [ -s "${adb_whitelist}" ]
-       then
-               adb_whitelist_rset="/^([[:alnum:]_-]+\.)+[[:alpha:]]+([[:space:]]|$)/{print tolower(\$1)}"
-               awk "${adb_whitelist_rset}" "${adb_whitelist}" > "${adb_tmpdir}/tmp.raw_whitelist"
-               f_tld "${adb_tmpdir}/tmp.raw_whitelist"
-
-               adb_whitelist_rset="/^([[:alnum:]_-]+\.)+[[:alpha:]]+([[:space:]]|$)/{gsub(\"\\\.\",\"\\\.\",\$1);print tolower(\"^\"\$1\"\\\|\\\.\"\$1)}"
-               awk "${adb_whitelist_rset}" "${adb_tmpdir}/tmp.raw_whitelist" > "${adb_tmpdir}/tmp.rem_whitelist"
-
-               if [ -n "${adb_dnsallow}" ]
-               then
-                       eval "${adb_dnsallow}" "${adb_tmpdir}/tmp.raw_whitelist" > "${adb_tmpdir}/tmp.add_whitelist"
-               fi
-       fi
-
-       # build 'dnsjail' list
-       #
-       if [ ${adb_jail} -eq 1 ]
-       then
-               cat "${adb_tmpdir}/tmp.add_whitelist" > "/tmp/${adb_dnsjail}"
-               printf '%s\n' "${adb_dnshalt}" >> "/tmp/${adb_dnsjail}"
-               if [ -n "${adb_dnsheader}" ]
-               then
-                       printf '%s\n' "${adb_dnsheader}" | cat - "/tmp/${adb_dnsjail}" > "${adb_tmpdir}/tmp.dnsjail"
-                       cat "${adb_tmpdir}/tmp.dnsjail" > "/tmp/${adb_dnsjail}"
-               fi
-       fi
-
+       f_log "debug" "f_main   ::: dns: ${adb_dns}, fetch_util: ${adb_fetchinfo}, force_dns: ${adb_forcedns}, mem_total: ${mem_total:-0}, mem_free: ${mem_free:-0}, max_queue: ${adb_maxqueue}"
+       
        # main loop
        #
+       f_list blacklist
+       f_list whitelist
        for src_name in ${adb_sources}
        do
-               enabled="$(eval printf '%s' \"\${enabled_${src_name}\}\")"
-               src_url="$(eval printf '%s' \"\${adb_src_${src_name}\}\")"
-               src_rset="$(eval printf '%s' \"\${adb_src_rset_${src_name}\}\")"
-               src_cat="$(eval printf '%s' \"\${adb_src_cat_${src_name}\}\")"
-               adb_tmpload="${tmp_load}.${src_name}"
-               adb_tmpfile="${tmp_file}.${src_name}"
+               enabled="$(eval printf "%s" \"\$\{enabled_${src_name}\}\")"
+               src_url="$(eval printf "%s" \"\$\{adb_src_${src_name}\}\")"
+               src_rset="$(eval printf "%s" \"\$\{adb_src_rset_${src_name}\}\")"
+               src_cat="$(eval printf "%s" \"\$\{adb_src_cat_${src_name}\}\")"
+               adb_tmpload="${tmp_load}"."${src_name}"
+               adb_tmpfile="${tmp_file}"."${src_name}"
 
                # basic pre-checks
                #
                f_log "debug" "f_main   ::: name: ${src_name}, enabled: ${enabled}"
-               if [ "${enabled}" != "1" ] || [ -z "${src_url}" ] || [ -z "${src_rset}" ]
+               if [ "${enabled}" != "1" ] || [ -f "${src_url}" ] || [ -z "${src_url}" ] || [ -z "${src_rset}" ]
                then
                        f_list remove
                        continue
@@ -897,10 +932,10 @@ f_main()
 
                # backup mode
                #
-               if [ ${adb_backup_mode} -eq 1 ] && [ "${adb_action}" = "start" ] && [ "${src_name}" != "blacklist" ]
+               if [ "${adb_action}" = "start" ]
                then
                        f_list restore
-                       if [ ${adb_rc} -eq 0 ] && [ -s "${adb_tmpfile}" ]
+                       if [ "${adb_rc}" -eq 0 ] && [ -s "${adb_tmpfile}" ]
                        then
                                continue
                        fi
@@ -908,76 +943,47 @@ f_main()
 
                # download queue processing
                #
-               if [ "${src_name}" = "blacklist" ]
-               then
-                       if [ -s "${src_url}" ]
-                       then
-                               (
-                                       src_log="$(cat "${src_url}" > "${adb_tmpload}" 2>&1)"
-                                       adb_rc=${?}
-                                       if [ ${adb_rc} -eq 0 ] && [ -s "${adb_tmpload}" ]
-                                       then
-                                               awk "${src_rset}" "${adb_tmpload}" 2>/dev/null > "${adb_tmpfile}"
-                                               adb_rc=${?}
-                                               if [ ${adb_rc} -eq 0 ] && [ -s "${adb_tmpfile}" ]
-                                               then
-                                                       rm -f "${adb_tmpload}"
-                                                       f_list download
-                                               fi
-                                       else
-                                               src_log="$(printf '%s' "${src_log}" | awk '{ORS=" ";print $0}')"
-                                               f_log "debug" "f_main   ::: name: ${src_name}, url: ${src_url}, rc: ${adb_rc}, log: ${src_log:-"-"}"
-                                       fi
-                               ) &
-                       else
-                               continue
-                       fi
-               elif [ -n "${src_cat}" ]
+               if [ -n "${src_cat}" ]
                then
                        (
-                               src_arc="${adb_tmpdir}/${src_url##*/}"
+                               src_arc="${adb_tmpdir}"/"${src_url##*/}"
                                src_log="$("${adb_fetchutil}" ${adb_fetchparm} "${src_arc}" "${src_url}" 2>&1)"
                                adb_rc=${?}
-                               if [ ${adb_rc} -eq 0 ] && [ -s "${src_arc}" ]
+                               if [ "${adb_rc}" -eq 0 ] && [ -s "${src_arc}" ]
                                then
                                        list="$(tar -tzf "${src_arc}")"
-                                       suffix="$(eval printf '%s' \"\${adb_src_suffix_${src_name}:-\"domains\"\}\")"
+                                       suffix="$(eval printf "%s" \"\$\{adb_src_suffix_${src_name}:-\"domains\"\}\")"
                                        for cat in ${src_cat}
                                        do
-                                               entry="$(printf '%s' "${list}" | grep -E "[\^/]+${cat}/${suffix}")"
+                                               entry="$(printf "%s" "${list}" | grep -E "[\\^/]+${cat}/${suffix}")"
                                                if [ -n "${entry}" ]
                                                then
                                                        tar -xOzf "${src_arc}" "${entry}" >> "${adb_tmpload}"
                                                        adb_rc=${?}
-                                                       if [ ${adb_rc} -ne 0 ]
+                                                       if [ "${adb_rc}" -ne 0 ]
                                                        then
                                                                break
                                                        fi
                                                fi
                                        done
                                else
-                                       src_log="$(printf '%s' "${src_log}" | awk '{ORS=" ";print $0}')"
+                                       src_log="$(printf "%s" "${src_log}" | awk '{ORS=" ";print $0}')"
                                        f_log "debug" "f_main   ::: name: ${src_name}, url: ${src_url}, rc: ${adb_rc}, log: ${src_log:-"-"}"
                                fi
-                               if [ ${adb_rc} -eq 0 ] && [ -s "${adb_tmpload}" ]
+                               if [ "${adb_rc}" -eq 0 ] && [ -s "${adb_tmpload}" ]
                                then
                                        rm -f "${src_arc}"
                                        awk "${src_rset}" "${adb_tmpload}" 2>/dev/null > "${adb_tmpfile}"
                                        adb_rc=${?}
-                                       if [ ${adb_rc} -eq 0 ] && [ -s "${adb_tmpfile}" ]
+                                       if [ "${adb_rc}" -eq 0 ] && [ -s "${adb_tmpfile}" ]
                                        then
                                                rm -f "${adb_tmpload}"
                                                f_list download
-                                               if [ ${adb_backup} -eq 1 ]
-                                               then
-                                                       f_list backup
-                                               fi
-                                       elif [ ${adb_backup} -eq 1 ]
-                                       then
+                                               f_list backup
+                                       else
                                                f_list restore
                                        fi
-                               elif [ ${adb_backup} -eq 1 ]
-                               then
+                               else
                                        f_list restore
                                fi
                        ) &
@@ -989,34 +995,27 @@ f_main()
                                then
                                        awk "${src_rset}" "${adb_tmpload}" 2>/dev/null > "${adb_tmpfile}"
                                        adb_rc=${?}
-                                       if [ ${adb_rc} -eq 0 ] && [ -s "${adb_tmpfile}" ]
+                                       if [ "${adb_rc}" -eq 0 ] && [ -s "${adb_tmpfile}" ]
                                        then
                                                rm -f "${adb_tmpload}"
                                                f_list download
-                                               if [ ${adb_backup} -eq 1 ]
-                                               then
-                                                       f_list backup
-                                               fi
-                                       elif [ ${adb_backup} -eq 1 ]
-                                       then
+                                               f_list backup
+                                       else
                                                f_list restore
                                        fi
                                else
-                                       src_log="$(printf '%s' "${src_log}" | awk '{ORS=" ";print $0}')"
+                                       src_log="$(printf "%s" "${src_log}" | awk '{ORS=" ";print $0}')"
                                        f_log "debug" "f_main   ::: name: ${src_name}, url: ${src_url}, rc: ${adb_rc}, log: ${src_log:-"-"}"
-                                       if [ ${adb_backup} -eq 1 ]
-                                       then
-                                               f_list restore
-                                       fi
+                                       f_list restore
                                fi
                        ) &
                fi
-               hold=$(( cnt % adb_maxqueue ))
-               if [ ${hold} -eq 0 ]
+               hold=$((cnt%adb_maxqueue))
+               if [ "${hold}" -eq 0 ]
                then
                        wait
                fi
-               cnt=$(( cnt + 1 ))
+               cnt=$((cnt+1))
        done
 
        # list merge
@@ -1026,26 +1025,28 @@ f_main()
        adb_tmpfile="${tmp_file}"
        f_list merge
 
-       # overall sort and conditional dns restart
+       # overall sort and dns restart
        #
-       f_hash
-       if [ -s "${adb_tmpdir}/${adb_dnsfile}" ]
+       if [ -s "${adb_tmpdir}"/"${adb_dnsfile}" ]
        then
-               f_tld "${adb_tmpdir}/${adb_dnsfile}"
+               f_tld "${adb_tmpdir}"/"${adb_dnsfile}"
                f_list final
        else
-               > "${adb_dnsdir}/${adb_dnsfile}"
-       fi
-       chown "${adb_dnsuser}" "${adb_dnsdir}/${adb_dnsfile}" 2>/dev/null
-       f_hash
-       if [ ${?} -eq 1 ]
-       then
-               f_dnsup
+               > "${adb_dnsdir}"/"${adb_dnsfile}"
        fi
+       chown "${adb_dnsuser}" "${adb_dnsdir}"/"${adb_dnsfile}" 2>/dev/null
+       f_dnsup
        f_jsnup
-       if [ ${?} -eq 0 ]
+       if [ "${?}" -eq 0 ]
        then
-               f_log "info" "blocklist with overall ${adb_cnt} domains loaded successfully (${adb_sysver})"
+               if [ "${adb_dnsfilereset}" = "true" ]
+               then
+                       f_bgserv "start"
+                       > "${adb_dnsdir}"/"${adb_dnsfile}"
+                       f_log "info" "blocklist with overall ${adb_cnt} domains loaded successfully and reset afterwards (${adb_sysver})"
+               else
+                       f_log "info" "blocklist with overall ${adb_cnt} domains loaded successfully (${adb_sysver})"
+               fi
        else
                f_log "err" "dns backend restart with active blocklist failed"
        fi
@@ -1057,20 +1058,20 @@ f_main()
 #
 f_report()
 {
-       local bg_pid total blocked percent rep_clients rep_domains rep_blocked index hold ports cnt=0 search="${1}" count="${2}" filter="${3}" print="${4}"
+       local bg_pid status total blocked percent rep_clients rep_domains rep_blocked index hold ports cnt=0 search="${1}" count="${2}" filter="${3}" print="${4}"
 
-       if [ ${adb_report} -eq 1 ] && [ ! -x "${adb_reputil}" ]
+       if [ "${adb_report}" -eq 1 ] && [ ! -x "${adb_reputil}" ]
        then
                f_log "info" "Please install the package 'tcpdump' or 'tcpdump-mini' to use the adblock reporting feature!"
-       elif [ ${adb_report} -eq 0 ] && [ "${adb_action}" = "report" ]
+       elif [ "${adb_report}" -eq 0 ] && [ "${adb_action}" = "report" ]
        then
                f_log "info" "Please enable the extra option 'adb_report' to use the adblock reporting feature!"
        fi
 
        if [ -x "${adb_reputil}" ]
        then
-               bg_pid="$(pgrep -f "^${adb_reputil}.*adb_report\.pcap$" | awk '{ORS=" "; print $1}')"
-               if [ ${adb_report} -eq 0 ] || ([ -n "${bg_pid}" ] && ([ "${adb_action}" = "stop" ] || [ "${adb_action}" = "restart" ]))
+               bg_pid="$(pgrep -f "^${adb_reputil}.*adb_report\\.pcap$" | awk '{ORS=" "; print $1}')"
+               if [ "${adb_report}" -eq 0 ] || { [ -n "${bg_pid}" ] && { [ "${adb_action}" = "stop" ] || [ "${adb_action}" = "restart" ]; } }
                then
                        if [ -n "${bg_pid}" ]
                        then
@@ -1084,7 +1085,7 @@ f_report()
                fi
        fi
 
-       if [ -x "${adb_reputil}" ] && [ ${adb_report} -eq 1 ]
+       if [ -x "${adb_reputil}" ] && [ "${adb_report}" -eq 1 ]
        then
                if [ -z "${bg_pid}" ] && [ "${adb_action}" != "report" ] && [ "${adb_action}" != "stop" ]
                then
@@ -1097,53 +1098,53 @@ f_report()
                                        ports="${ports} or port ${port}"
                                fi
                        done
-                       ("${adb_reputil}" -nn -s0 -l -i ${adb_repiface} ${ports} -C${adb_repchunksize} -W${adb_repchunkcnt} -w "${adb_repdir}/adb_report.pcap" >/dev/null 2>&1 &)
-                       bg_pid="$(pgrep -f "^${adb_reputil}.*adb_report\.pcap$" | awk '{ORS=" "; print $1}')"
+                       ( "${adb_reputil}" -nn -s0 -l -i ${adb_repiface} ${ports} -C${adb_repchunksize} -W${adb_repchunkcnt} -w "${adb_repdir}"/adb_report.pcap >/dev/null 2>&1 & )
+                       bg_pid="$(pgrep -f "^${adb_reputil}.*adb_report\\.pcap$" | awk '{ORS=" "; print $1}')"
                fi
 
                if [ "${adb_action}" = "report" ] && [ "${filter}" = "false" ]
                then
-                       > "${adb_repdir}/adb_report.raw"
+                       > "${adb_repdir}"/adb_report.raw
                        for file in "${adb_repdir}"/adb_report.pcap*
                        do
                                (
-                                       "${adb_reputil}" -tttt -r $file 2>/dev/null | \
-                                               awk -v cnt=${cnt} '!/\.lan\. /&&/ A[\? ]+|NXDomain/{a=$1;b=substr($2,0,8);c=$4;sub(/\.[0-9]+$/,"",c); \
-                                               d=cnt $7;e=$(NF-1);sub(/[0-9]\/[0-9]\/[0-9]/,"NX",e);sub(/\.$/,"",e);sub(/([0-9]{1,3}\.){3}[0-9]{1,3}/,"OK",e);printf("%s\t%s\t%s\t%s\t%s\n", a,b,c,d,e)}' >> "${adb_repdir}/adb_report.raw"
+                                       "${adb_reputil}" -tttt -r "${file}" 2>/dev/null | \
+                                               awk -v cnt=${cnt} '!/\.lan\. /&&/ A[\? ]+|NXDomain|0\.0\.0\.0/{a=$1;b=substr($2,0,8);c=$4;sub(/\.[0-9]+$/,"",c); \
+                                               d=cnt $7;sub(/\*$/,"",d);e=$(NF-1);sub(/[0-9]\/[0-9]\/[0-9]|0\.0\.0\.0/,"NX",e);sub(/\.$/,"",e);sub(/([0-9]{1,3}\.){3}[0-9]{1,3}/,"OK",e);printf("%s\t%s\t%s\t%s\t%s\n", a,b,c,d,e)}' >> "${adb_repdir}/adb_report.raw"
                                )&
-                               hold=$(( cnt % adb_maxqueue ))
-                               if [ ${hold} -eq 0 ]
+                               hold=$((cnt%adb_maxqueue))
+                               if [ "${hold}" -eq 0 ]
                                then
                                        wait
                                fi
-                               cnt=$(( cnt + 1 ))
+                               cnt=$((cnt+1))
                        done
                        wait
 
-                       if [ -s "${adb_repdir}/adb_report.raw" ]
+                       if [ -s "${adb_repdir}"/adb_report.raw ]
                        then
                                awk '{printf("%s\t%s\t%s\t%s\t%s\t%s\n", $4,$5,$1,$2,$3,$4)}' "${adb_repdir}/adb_report.raw" | \
                                        sort -ur | uniq -uf2 | awk '{currA=($6+0);currB=$6;currC=substr($6,length($6),1); \
                                        if(reqA==currB){reqA=0;printf("%s\t%s\n",d,$2)}else if(currC=="+"){reqA=currA;d=$3"\t"$4"\t"$5"\t"$2}}' | sort -ur > "${adb_repdir}/adb_report"
                        fi
 
-                       if [ -s "${adb_repdir}/adb_report" ]
+                       if [ -s "${adb_repdir}"/adb_report ]
                        then
-                               total="$(wc -l < ${adb_repdir}/adb_report)"
-                               blocked="$(awk '{if($5=="NX")print $4}' ${adb_repdir}/adb_report | wc -l)"
-                               percent="$(awk -v t=${total} -v b=${blocked} 'BEGIN{printf("%.2f %s\n",b/t*100, "%")}')"
-                               rep_clients="$(awk '{print $3}' ${adb_repdir}/adb_report | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10) printf("%s_%s ",$1,$2)}')"
-                               rep_domains="$(awk '{if($5!="NX")print $4}' ${adb_repdir}/adb_report | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10)printf("%s_%s ",$1,$2)}')"
-                               rep_blocked="$(awk '{if($5=="NX")print $4}' ${adb_repdir}/adb_report | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10)printf("%s_%s ",$1,$2)}')"
-
-                               > "${adb_repdir}/adb_report.json"
-                               json_load_file "${adb_repdir}/adb_report.json" >/dev/null 2>&1
+                               total="$(wc -l < "${adb_repdir}"/adb_report)"
+                               blocked="$(awk '{if($5=="NX")print $4}' "${adb_repdir}"/adb_report | wc -l)"
+                               percent="$(awk -v t="${total}" -v b="${blocked}" 'BEGIN{printf("%.2f %s\n",b/t*100, "%")}')"
+                               rep_clients="$(awk '{print $3}' "${adb_repdir}"/adb_report | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10) printf("%s_%s ",$1,$2)}')"
+                               rep_domains="$(awk '{if($5!="NX")print $4}' "${adb_repdir}"/adb_report | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10)printf("%s_%s ",$1,$2)}')"
+                               rep_blocked="$(awk '{if($5=="NX")print $4}' "${adb_repdir}"/adb_report | sort | uniq -c | sort -r | awk '{ORS=" ";if(NR<=10)printf("%s_%s ",$1,$2)}')"
+
+                               > "${adb_repdir}"/adb_report.json
+                               json_load_file "${adb_repdir}"/adb_report.json >/dev/null 2>&1
                                json_init
                                json_add_object "data"
-                               json_add_string "start_date" "$(awk 'END{printf("%s",$1)}' ${adb_repdir}/adb_report)"
-                               json_add_string "start_time" "$(awk 'END{printf("%s",$2)}' ${adb_repdir}/adb_report)"
-                               json_add_string "end_date" "$(awk 'NR==1{printf("%s",$1)}' ${adb_repdir}/adb_report)"
-                               json_add_string "end_time" "$(awk 'NR==1{printf("%s",$2)}' ${adb_repdir}/adb_report)"
+                               json_add_string "start_date" "$(awk 'END{printf("%s",$1)}' "${adb_repdir}"/adb_report)"
+                               json_add_string "start_time" "$(awk 'END{printf("%s",$2)}' "${adb_repdir}"/adb_report)"
+                               json_add_string "end_date" "$(awk 'NR==1{printf("%s",$1)}' "${adb_repdir}"/adb_report)"
+                               json_add_string "end_time" "$(awk 'NR==1{printf("%s",$2)}' "${adb_repdir}"/adb_report)"
                                json_add_string "total" "${total}"
                                json_add_string "blocked" "${blocked}"
                                json_add_string "percent" "${percent}"
@@ -1175,29 +1176,29 @@ f_report()
                                        json_close_object
                                done
                                json_close_object
-                               json_dump > "${adb_repdir}/adb_report.json"
+                               json_dump > "${adb_repdir}"/adb_report.json
                        fi
-                       rm -f "${adb_repdir}/adb_report.raw"
+                       rm -f "${adb_repdir}"/adb_report.raw
                fi
 
-               if [ -s "${adb_repdir}/adb_report" ]
+               if [ -s "${adb_repdir}"/adb_report ]
                then
                        search="${search//./\\.}"
                        search="${search//[+*~%\$&\"\' ]/}"
-                       > "${adb_repdir}/adb_report.final"
-                       awk "BEGIN{i=0}/(${search})/{i++;if(i<=${count}){printf \"%s\t%s\t%s\t%s\t%s\n\",\$1,\$2,\$3,\$4,\$5}}" "${adb_repdir}/adb_report" > "${adb_repdir}/adb_report.final"
-                       if [ ! -s "${adb_repdir}/adb_report.final" ]
+                       > "${adb_repdir}"/adb_report.final
+                       awk "BEGIN{i=0}/(${search})/{i++;if(i<=${count}){printf \"%s\\t%s\\t%s\\t%s\\t%s\\n\",\$1,\$2,\$3,\$4,\$5}}" "${adb_repdir}"/adb_report > "${adb_repdir}"/adb_report.final
+                       if [ ! -s "${adb_repdir}"/adb_report.final ]
                        then
-                               printf "%s\t%s\t%s\t%s\t%s\n" "-" "-" "-" "-" "-" > "${adb_repdir}/adb_report.final"
+                               printf "%s\\t%s\\t%s\\t%s\\t%s\\n" "-" "-" "-" "-" "-" > "${adb_repdir}"/adb_report.final
                        fi
                fi
 
                if [ "${print}" = "true" ]
                then
-                       if [ -s "${adb_repdir}/adb_report.json" ]
+                       if [ -s "${adb_repdir}"/adb_report.json ]
                        then
-                               printf "%s\n%s\n%s\n" ":::" "::: Adblock DNS-Query Report" ":::"
-                               json_load_file "${adb_repdir}/adb_report.json"
+                               printf "%s\\n%s\\n%s\\n" ":::" "::: Adblock DNS-Query Report" ":::"
+                               json_load_file "${adb_repdir}"/adb_report.json
                                json_select "data"
                                json_get_keys keylist
                                for key in ${keylist}
@@ -1205,55 +1206,55 @@ f_report()
                                        json_get_var value "${key}"
                                        eval "${key}=\"${value}\""
                                done
-                               printf "  + %s\n  + %s\n" "Start    ::: ${start_date}, ${start_time}" "End      ::: ${end_date}, ${end_time}"
-                               printf "  + %s\n  + %s %s\n" "Total    ::: ${total}" "Blocked  ::: ${blocked}" "(${percent})"
+                               printf "  + %s\\n  + %s\\n" "Start    ::: ${start_date}, ${start_time}" "End      ::: ${end_date}, ${end_time}"
+                               printf "  + %s\\n  + %s %s\\n" "Total    ::: ${total}" "Blocked  ::: ${blocked}" "(${percent})"
                                json_select ".."
-                               if json_get_type Status "top_clients" && [ "${Status}" = "array" ]
+                               if json_get_type status "top_clients" && [ "${status}" = "array" ]
                                then
-                                       printf "%s\n%s\n%s\n" ":::" "::: Top 10 Clients" ":::"
+                                       printf "%s\\n%s\\n%s\\n" ":::" "::: Top 10 Clients" ":::"
                                        json_select "top_clients"
                                        index=1
-                                       while json_get_type Status ${index} && [ "${Status}" = "object" ]
+                                       while json_get_type status "${index}" && [ "${status}" = "object" ]
                                        do
-                                               json_get_values client ${index}
-                                               printf "  + %-9s::: %s\n" ${client}
-                                               index=$((index + 1))
+                                               json_get_values client "${index}"
+                                               printf "  + %-9s::: %s\\n" ${client}
+                                               index=$((index+1))
                                        done
                                fi
                                json_select ".."
-                               if json_get_type Status "top_domains" && [ "${Status}" = "array" ]
+                               if json_get_type status "top_domains" && [ "${status}" = "array" ]
                                then
-                                       printf "%s\n%s\n%s\n" ":::" "::: Top 10 Domains" ":::"
+                                       printf "%s\\n%s\\n%s\\n" ":::" "::: Top 10 Domains" ":::"
                                        json_select "top_domains"
                                        index=1
-                                       while json_get_type Status ${index} && [ "${Status}" = "object" ]
+                                       while json_get_type status "${index}" && [ "${status}" = "object" ]
                                        do
-                                               json_get_values domain ${index}
-                                               printf "  + %-9s::: %s\n" ${domain}
-                                               index=$((index + 1))
+                                               json_get_values domain "${index}"
+                                               printf "  + %-9s::: %s\\n" ${domain}
+                                               index=$((index+1))
                                        done
                                fi
                                json_select ".."
-                               if json_get_type Status "top_blocked" && [ "${Status}" = "array" ]
+                               if json_get_type status "top_blocked" && [ "${status}" = "array" ]
                                then
-                                       printf "%s\n%s\n%s\n" ":::" "::: Top 10 Blocked Domains" ":::"
+                                       printf "%s\\n%s\\n%s\\n" ":::" "::: Top 10 Blocked Domains" ":::"
                                        json_select "top_blocked"
                                        index=1
-                                       while json_get_type Status ${index} && [ "${Status}" = "object" ]
+                                       while json_get_type status "${index}" && [ "${status}" = "object" ]
                                        do
-                                               json_get_values blocked ${index}
-                                               printf "  + %-9s::: %s\n" ${blocked}
-                                               index=$((index + 1))
+                                               json_get_values blocked "${index}"
+                                               printf "  + %-9s::: %s\\n" ${blocked}
+                                               index=$((index+1))
                                        done
                                fi
-                               if [ -s "${adb_repdir}/adb_report.final" ]
+                               if [ -s "${adb_repdir}"/adb_report.final ]
                                then
-                                       printf "%s\n%s\n%s\n" ":::" "::: Latest DNS Queries" ":::"
-                                       printf "%-15s%-15s%-45s%-50s%s\n" "Date" "Time" "Client" "Domain" "Answer"
-                                       awk '{printf "%-15s%-15s%-45s%-50s%s\n",$1,$2,$3,$4,$5}' "${adb_repdir}/adb_report.final"
+                                       printf "%s\\n%s\\n%s\\n" ":::" "::: Latest DNS Queries" ":::"
+                                       printf "%-15s%-15s%-45s%-50s%s\\n" "Date" "Time" "Client" "Domain" "Answer"
+                                       awk '{printf "%-15s%-15s%-45s%-50s%s\n",$1,$2,$3,$4,$5}' "${adb_repdir}"/adb_report.final
                                fi
                        else
-                               printf "%s\n%s\n%s\n" ":::" "::: no reporting data available yet" ":::"
+                               printf "%s\\n%s\\n%s\\n" ":::" "::: no reporting data available yet" ":::"
                        fi
                fi
        fi
@@ -1272,16 +1273,18 @@ fi
 
 # handle different adblock actions
 #
-f_envload
+f_load
 case "${adb_action}" in
        stop)
+               f_bgserv "stop"
                f_report "+" "50" "false" "false"
                f_rmdns
        ;;
        restart)
+               f_bgserv "stop"
                f_report "+" "50" "false" "false"
                f_rmdns
-               f_envcheck
+               f_env
                f_main
        ;;
        suspend)
@@ -1297,8 +1300,9 @@ case "${adb_action}" in
                f_query "${2}"
        ;;
        start|reload)
+               f_bgserv "stop"
                f_report "+" "50" "false" "false"
-               f_envcheck
+               f_env
                f_main
        ;;
 esac