adblock: release 4.5.0-1

* added firewall rules based on nftables in a separate isolated nftables table (inet adblock)
  and chains (prerouting), with MAC addresses stored in an nftables set.
  Implemented the following firewall‑integrated features:
  * external DNS Routing (unfiltered): routes DNS queries from selected devices or interfaces
    to an external unfiltered DNS resolver
  * external DNS Routing (filtered): routes DNS queries from selected devices or interfaces
    to an external filtered DNS resolver
  * force DNS: blocks or redirects all external DNS traffic from selected interfaces
    to ensure that clients use the local resolver
* removed the optional generation of an additional jail list (only supported bydnsmasq),
  use the new, resolver independent ext. DNS routing instead
* removed the pz-client-ip feature (only supported by bind),
  use the new, resolver independent ext. DNS routing instead
* removed the obsolete, hardcoded fw4 rules for DNS enforcement
  existing rules will be removed via uci-defaults script after adblock update
* changed the Jail mode to a simple allowlist-only mode
* fixed minor issues in the mail template
* readme update
* LuCI: added a new config tab "Firewall Settings"
* LuCI: fixed minor usability issues

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken
2026-01-18 23:34:19 +01:00
parent ae659deb40
commit 389baa9d00
6 changed files with 273 additions and 155 deletions

View File

@@ -1,13 +1,13 @@
# dns based ad/abuse domain blocking
# Copyright (c) 2015-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2015-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=adblock
PKG_VERSION:=4.4.5
PKG_RELEASE:=2
PKG_VERSION:=4.5.0
PKG_RELEASE:=1
PKG_LICENSE:=GPL-3.0-or-later
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
@@ -17,7 +17,7 @@ define Package/adblock
SECTION:=net
CATEGORY:=Network
TITLE:=adblock blocks ad/abuse domains by using DNS
DEPENDS:=+jshn +jsonfilter +coreutils +coreutils-sort +gawk +ca-bundle +rpcd +rpcd-mod-rpcsys
DEPENDS:=+jshn +jsonfilter +firewall4 +coreutils +coreutils-sort +gawk +ca-bundle +rpcd +rpcd-mod-rpcsys
PKGARCH:=all
endef

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (c) 2015-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2015-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions
@@ -11,7 +11,7 @@ export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
config="adblock"
old_options="adb_sources adb_forcedns adb_fetchutil adb_hag_sources adb_hst_sources adb_stb_sources adb_utc_sources \
adb_maxqueue adb_backup adb_dnsfilereset adb_tmpbase adb_mailcnt adb_safesearchmod adb_srcfile adb_srcarc adb_nice \
adb_hag_feed"
adb_hag_feed adb_jaildir adb_dnsdenyip adb_dnsallowip adb_zonelist adb_portlist adb_dnsforce"
for option in ${old_options}; do
inplace="0"
@@ -63,10 +63,30 @@ for option in ${old_options}; do
uci -q add_list ${config}.global.adb_hag_feed="wildcard/${value}"
fi
;;
"adb_dnsforce")
uci -q set ${config}.global.adb_nftforce="${value}"
;;
"adb_zonelist")
uci -q set ${config}.global.adb_nftdevforce="${value}"
;;
"adb_portlist")
uci -q set ${config}.global.adb_nftportforce="${value}"
;;
esac
done
[ "${inplace}" = "0" ] && uci -q delete ${config}.global.${option}
fi
done
[ -n "$(uci -q changes ${config})" ] && uci -q commit ${config}
# remove former adblock-related firewall zones
#
fwcfg="$(uci -qNX show "firewall" | awk 'BEGIN{FS="[.=]"};/adblock_/{if(zone==$2){next}else{ORS=" ";zone=$2;print zone}}')"
for section in ${fwcfg}; do
uci -q delete firewall."${section}"
done
if [ -n "$(uci -q changes firewall)" ]; then
uci -q commit firewall
/etc/init.d/firewall reload
fi
exit 0

View File

@@ -56,7 +56,6 @@ A lot of people already use adblocker plugins within their desktop browsers, but
* Supports six different DNS backend formats: dnsmasq, unbound, named (bind), kresd, smartdns or raw (e.g. used by dnscrypt-proxy)
* Supports three different SSL-enabled download utilities: uclient-fetch, full wget or curl
* Supports SafeSearch for google, bing, brave, duckduckgo, yandex, youtube and pixabay
* Supports RPZ-trigger 'RPZ-CLIENT-IP' to always allow/deny certain DNS clients based on their IP address (currently only supported by bind dns backend)
* Fast downloads & list processing as they are handled in parallel running background jobs with multicore support
* The download engine supports ETAG headers to download only updated feeds
* Supports a wide range of router modes, even AP modes are supported
@@ -75,7 +74,6 @@ A lot of people already use adblocker plugins within their desktop browsers, but
* Provides comprehensive runtime information
* Provides a detailed DNS Query Report with DNS related information about client requests, top (blocked) domains and more
* Provides a powerful query function to quickly find blocked (sub-)domains, e.g. to allow certain domains
* Includes an option to generate an additional, restrictive 'adb_list.jail' to block access to all domains except those listed in the allowlist file. You can use this restrictive blocklist manually e.g. for guest wifi or kidsafe configurations
* Contains an option to route DNS queries to the local resolver via corresponding firewall rules
* Automatic blocklist backup & restore, these backups will be used in case of download errors and during startup
* Send notification E-Mails, see example configuration below
@@ -148,13 +146,11 @@ Available commands:
| adb_debug | 0, disabled | set to 1 to enable the debug output |
| adb_nicelimit | 0, standard prio. | valid nice level range 0-19 of the adblock processes |
| adb_dnsshift | 0, disabled | shift the blocklist to the backup directory and only set a soft link to this file in memory |
| adb_dnsforce | 0, disabled | set to 1 to force DNS requests to the local resolver |
| adb_dnsdir | -, auto-detected | path for the generated blocklist file 'adb_list.overall' |
| adb_dnstimeout | 20 | timeout in seconds to wait for a successful DNS backend restart |
| adb_dnsinstance | 0, first instance | set to the relevant dns backend instance used by adblock (dnsmasq only) |
| adb_dnsinstance | 0, first instance | set the relevant dnsmasq backend instance used by adblock |
| adb_dnsflush | 0, disabled | set to 1 to flush the DNS Cache before & after adblock processing |
| adb_lookupdomain | localhost | domain to check for a successful DNS backend restart |
| adb_portlist | 53 853 5353 | space separated list of firewall ports which should be redirected locally |
| adb_report | 0, disabled | set to 1 to enable the background tcpdump gathering process for reporting |
| adb_map | 0, disabled | enable a GeoIP Map with blocked domains |
| adb_reportdir | /tmp/adblock-report | path for DNS related report files |
@@ -167,14 +163,26 @@ Available commands:
| adb_basedir | /tmp | path for all adblock related runtime operations, e.g. downloading, sorting, merging etc. |
| adb_backupdir | /tmp/adblock-backup | path for adblock backups |
| adb_safesearch | 0, disabled | enforce SafeSearch for google, bing, brave, duckduckgo, yandex, youtube and pixabay |
| adb_safesearchlist | -, not set | Limit SafeSearch to certain provider (see above) |
| adb_safesearchlist | -, not set | limit SafeSearch to certain provider (see above) |
| adb_mail | 0, disabled | set to 1 to enable notification E-Mails in case of a processing errors |
| adb_mailreceiver | -, not set | receiver address for adblock notification E-Mails |
| adb_mailsender | no-reply@adblock | sender address for adblock notification E-Mails |
| adb_mailtopic | adblock notification | topic for adblock notification E-Mails |
| adb_mailprofile | adb_notify | mail profile used in 'msmtp' for adblock notification E-Mails |
| adb_jail | 0 | create the additional restrictive 'adb_list.jail' |
| adb_jaildir | /tmp | path for the generated jail list |
| adb_jail | 0 | jail mode - only domains on the allowlist are permitted, all other DNS requests are rejected |
| adb_nftforce | 0, disabled | redirect all local DNS queries from specified LAN zones to the local DNS resolver |
| adb_nftdevforce | -, not set | firewall LAN Devices/VLANs that should be forced locally |
| adb_nftportforce | -, not set | firewall ports that should be forced locally |
| adb_nftallow | 0, disabled | routes MACs or interfaces to an unfiltered external DNS resolver, bypassing local adblock |
| adb_nftmacallow | -, not set | listed MAC addresses will always use the configured unfiltered DNS server |
| adb_nftdevallow | -, not set | entire interfaces or VLANs will be routed to the unfiltered DNS server |
| adb_allowdnsv4 | -, not set | IPv4 DNS resolver applied to MACs and interfaces using the unfiltered DNS policy |
| adb_allowdnsv6 | -, not set | IPv6 DNS resolver applied to MACs and interfaces using the unfiltered DNS policy |
| adb_nftblock | 0, disabled | routes MACs or interfaces to an filtered external DNS resolver, bypassing local adblock |
| adb_nftmacblock | -, not set | listed MAC addresses will always use the configured filtered DNS server |
| adb_nftdevblock | -, not set | entire interfaces or VLANs will be routed to the filtered DNS server |
| adb_blockdnsv4 | -, not set | IPv4 DNS resolver applied to MACs and interfaces using the filtered DNS policy |
| adb_blockdnsv6 | -, not set | IPv6 DNS resolver applied to MACs and interfaces using the filtered DNS policy |
<a id="examples"></a>
## Examples
@@ -215,16 +223,16 @@ To get the status in the CLI, just call _/etc/init.d/adblock status_ or _/etc/in
~# /etc/init.d/adblock status
::: adblock runtime information
+ adblock_status : enabled
+ frontend_ver : 4.4.5-r1
+ backend_ver : 4.4.5-r1
+ blocked_domains : 575 335
+ frontend_ver : 4.5.0-r1
+ backend_ver : 4.5.0-r1
+ blocked_domains : 582 457
+ active_feeds : 1hosts, adguard, adguard_tracking, bitcoin, certpl, doh_blocklist, hagezi, phishing_army, smarttv_tracking, stevenblack, winspy
+ dns_backend : unbound (1.24.2-r1), /mnt/data/adblock/backup, 232.20 MB
+ run_ifaces : trigger: wan , report: br-lan
+ run_directories : base: /mnt/data/adblock, dns: /var/lib/unbound, backup: /mnt/data/adblock/backup, report: /mnt/data/adblock/report, jail: /tmp
+ run_flags : shift: ✔, custom feed: ✘, force: ✔, flush: ✘, tld: ✔, search: , report: ✔, mail: ✔, jail: ✘
+ last_run : mode: reload, 2025-12-13T15:55:59+01:00, duration: 0m 46s, 1411.57 MB available
+ system_info : cores: 4, fetch: curl, Bananapi BPI-R3, mediatek/filogic, OpenWrt SNAPSHOT (r32305-52fa3728e5)
+ dns_backend : unbound (1.24.2-r1), /mnt/data/adblock/backup, 234.93 MB
+ run_ifaces : trigger: wan, report: br-lan
+ run_directories : base: /mnt/data/adblock, dns: /var/lib/unbound, backup: /mnt/data/adblock/backup, report: /mnt/data/adblock/report
+ run_flags : shift: ✔, custom feed: ✘, ext. DNS (std/prot): ✘/✘, force: ✔, flush: ✘, tld: ✔, search: , report: ✔, mail: ✔, jail: ✘
+ last_run : mode: restart, 2026-01-18T16:45:23+01:00, duration: 0m 19s, 1403.59 MB available
+ system_info : cores: 4, fetch: curl, Bananapi BPI-R3, mediatek/filogic, OpenWrt SNAPSHOT (r32670-66b6791abe)
```
<a id="best-practise-and-tweaks"></a>
@@ -259,12 +267,32 @@ To make this work, adblock uses the following external components:
**External adblock test**
In addition to the builtin DNS reporting and GeoIP map, adblock users can verify the effectiveness of their configuration with an external test page. The [Adblock Test](https://adblock.turtlecute.org/) provides a simple way to check whether your current adblock setup is working as expected. It loads a series of test elements (ads, trackers, and other resources) and reports whether they are successfully blocked by your configuration.
The test runs entirely in the browser and does not require additional configuration. For best results, open the page in the same environment where adblock is active and review the results displayed.
The test runs entirely in the browser and does not require additional configuration. For best results, open the page in the same environment where adblock is active and review the results displayed.
**Use the jail mode, a restrictive DNS blocklist:**
You can enable a restrictive 'adb_list.jail' to block access to all domains except those listed in the allowlist file. Usually this list will be generated as an additional list for guest or kidsafe configurations (for a separate dns server instance). If the jail directory points to your primary dns directory, the jail blocklist replaces your default blocklist.
**FirewallBased DNS Control**
adblock provides several advanced firewallintegrated features that allow you to enforce DNS policies directly at the network layer. These mechanisms operate independently of the local DNS resolver and ensure that DNS traffic follows your filtering rules, even when clients attempt to bypass them.
* unfiltered external DNS Routing: routes DNS queries from selected devices or interfaces to an external unfiltered DNS resolver
* filtered external DNS Routing: routes DNS queries from selected devices or interfaces to an external filtered DNS resolver
* force DNS: blocks or redirects all external DNS traffic to ensure that clients use the local resolver
**Enable E-Mail notification via 'msmtp':**
The DNS routing allows you to apply external DNS (unfiltered and/or filtered) to specific devices or entire network segments. DNS queries from these targets are transparently redirected to a chosen external resolver (IPv4 and/or IPv6):
* MACbased targeting for individual devices
* Interface/VLAN targeting for entire segments
* separate IPv4/IPv6 resolver selection
* transparent DNS redirection without clientside configuration
This mode is ideal for guest networks, IoT devices, or environments where certain clients require stricter/lesser DNS filtering.
force DNS ensures that all DNS traffic on your network by specific devices or entire network segments is processed by the local resolver. Any attempt to use external DNS servers is blocked or redirected.
* blocks external DNS on port 53 and redirects DNS queries to the local resolver when appropriate
* also prevents DNS bypassing by clients with hardcoded DNS settings on other ports, e.g. on port 853
This mode guarantees that adblocks filtering pipeline is always applied.
adblock's firewall rules are based on nftables in a separate isolated nftables table (inet adblock) and chains (prerouting), with MAC addresses stored in an nftables set. The configuration is carried out centrally in LuCI on the Firewall Settings tab in adblock.
**Jail mode (allowlist-only):**
Enforces a strict allowlistonly DNS policy in which only domains listed in the allowlist file are resolved, while every other query is rejected. This mode is intended for highly restrictive environments and depends on a carefully maintained allowlist, typically managed manually.
**Enable E-Mail notification via 'msmtp':**
To use the email notification you have to install & configure the package 'msmtp'.
Modify the file '/etc/msmtprc':
<pre><code>

View File

@@ -1,5 +1,5 @@
#!/bin/sh /etc/rc.common
# Copyright (c) 2015-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2015-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions
@@ -93,7 +93,7 @@ status_service() {
json_get_var value "${key}" >/dev/null 2>&1
if [ "${key}" = "active_feeds" ]; then
json_get_values values "${key}" >/dev/null 2>&1
value="${values// /, }"
value="${values}"
fi
printf " + %-15s : %s\n" "${key}" "${value:-"-"}"
done

View File

@@ -1,6 +1,6 @@
#!/bin/sh
# send mail script for adblock notifications
# Copyright (c) 2015-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2015-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# Please note: you have to manually install and configure the package 'msmtp' before using this script
@@ -16,7 +16,7 @@ adb_mailreceiver="$(uci_get adblock global adb_mailreceiver)"
adb_mailtopic="$(uci_get adblock global adb_mailtopic "adblock notification")"
adb_mailprofile="$(uci_get adblock global adb_mailprofile "adb_notify")"
[ -z "${adb_mailreceiver}" ] && f_log "err" "please set the mail receiver with the 'adb_mailreceiver' option"
[ -z "${adb_mailreceiver}" ] && f_log "info" "please set the mail receiver with the 'adb_mailreceiver' option"
[ "${adb_debug}" = "1" ] && debug="--debug"
adb_mailhead="From: ${adb_mailsender}\nTo: ${adb_mailreceiver}\nSubject: ${adb_mailtopic}\nReply-to: ${adb_mailsender}\nMime-Version: 1.0\nContent-Type: text/html;charset=utf-8\nContent-Disposition: inline\n\n"
@@ -48,8 +48,9 @@ if [ -x "${adb_mailcmd}" ]; then
if [ "${?}" = "0" ]; then
f_log "info" "mail successfully sent to '${adb_mailreceiver}'"
else
f_log "err" "failed to send mail to '${adb_mailreceiver}' with rc '${?}'"
f_log "info" "failed to send mail to '${adb_mailreceiver}' with rc '${?}'"
fi
else
f_log "err" "msmtp mail daemon not found"
f_log "info" "msmtp mail daemon not found"
fi
exit 0

View File

@@ -1,6 +1,6 @@
#!/bin/sh
# dns based ad/abuse domain blocking
# Copyright (c) 2015-2025 Dirk Brenken (dev@brenken.org)
# Copyright (c) 2015-2026 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the GNU General Public License v3.
# (s)hellcheck exceptions
@@ -13,7 +13,19 @@ export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
adb_enabled="0"
adb_debug="0"
adb_dnsforce="0"
adb_nftforce="0"
adb_nftdevforce=""
adb_nftportforce=""
adb_nftallow="0"
adb_nftmacallow=""
adb_nftdevallow=""
adb_nftblock="0"
adb_nftmacblock=""
adb_nftdevblock=""
adb_allowdnsv4=""
adb_allowdnsv6=""
adb_blockdnsv4=""
adb_blockdnsv6=""
adb_dnsshift="0"
adb_dnsflush="0"
adb_dnstimeout="20"
@@ -27,18 +39,16 @@ adb_map="0"
adb_tld="1"
adb_dns=""
adb_dnspid=""
adb_locallist="allowlist blocklist iplist"
adb_locallist="allowlist blocklist"
adb_basedir="/tmp"
adb_finaldir=""
adb_backupdir="/tmp/adblock-backup"
adb_reportdir="/tmp/adblock-report"
adb_jaildir="/tmp"
adb_pidfile="/var/run/adblock.pid"
adb_allowlist="/etc/adblock/adblock.allowlist"
adb_blocklist="/etc/adblock/adblock.blocklist"
adb_mailservice="/etc/adblock/adblock.mail"
adb_dnsfile="adb_list.overall"
adb_dnsjail="adb_list.jail"
adb_feedfile="/etc/adblock/adblock.feeds"
adb_customfeedfile="/etc/adblock/adblock.custom.feeds"
adb_rtfile="/var/run/adb_runtime.json"
@@ -104,6 +114,7 @@ f_load() {
if [ "${adb_enabled}" = "0" ]; then
f_extconf
f_temp
f_nftremove
f_rmdns
f_jsnup "disabled"
f_log "info" "adblock is currently disabled, please set the config option 'adb_enabled' to '1' to use this service"
@@ -161,9 +172,10 @@ f_load() {
f_env() {
adb_starttime="$(date "+%s")"
f_log "info" "adblock instance started ::: action: ${adb_action}, priority: ${adb_nicelimit:-"0"}, pid: ${$}"
f_jsnup "running"
f_jsnup "processing"
f_extconf
f_temp
f_nftadd
json_init
if [ -s "${adb_customfeedfile}" ]; then
if json_load_file "${adb_customfeedfile}" >/dev/null 2>&1; then
@@ -202,7 +214,11 @@ f_conf() {
;;
*)
eval "append=\"\${${option}}\""
eval "${option}=\"${append}${value} \""
if [ -n "${append}" ]; then
eval "${option}=\"${append} ${value}\""
else
eval "${option}=\"${value}\""
fi
;;
esac
}
@@ -361,8 +377,6 @@ f_dns() {
adb_dnsheader="${adb_dnsheader:-""}"
adb_dnsdeny="${adb_dnsdeny:-"${adb_awkcmd} '{print \"local-zone: \\042\"\$0\"\\042 always_nxdomain\"}'"}"
adb_dnsallow="${adb_dnsallow:-"${adb_awkcmd} '{print \"local-zone: \\042\"\$0\"\\042 always_transparent\"}'"}"
adb_dnsdenyip="${adb_dnsdenyip:-"0"}"
adb_dnsallowip="${adb_dnsallowip:-"0"}"
adb_dnssafesearch="${adb_dnssafesearch:-"${adb_awkcmd} -v item=\"\$item\" '{type=\"AAAA\";if(match(item,/^([0-9]{1,3}\.){3}[0-9]{1,3}$/)){type=\"A\"}}{print \"local-data: \\042\"\$0\" \"type\" \"item\"\\042\"}'"}"
adb_dnsstop="${adb_dnsstop:-"local-zone: \".\" always_nxdomain"}"
;;
@@ -374,8 +388,6 @@ f_dns() {
adb_dnsheader="${adb_dnsheader:-"\$TTL 2h\n@ IN SOA localhost. root.localhost. (1 6h 1h 1w 2h)\n IN NS localhost.\n"}"
adb_dnsdeny="${adb_dnsdeny:-"${adb_awkcmd} '{print \"\"\$0\" CNAME .\\n*.\"\$0\" CNAME .\"}'"}"
adb_dnsallow="${adb_dnsallow:-"${adb_awkcmd} '{print \"\"\$0\" CNAME rpz-passthru.\\n*.\"\$0\" CNAME rpz-passthru.\"}'"}"
adb_dnsdenyip="${adb_dnsdenyip:-"${adb_awkcmd} '{print \"\"\$0\".rpz-client-ip CNAME .\"}'"}"
adb_dnsallowip="${adb_dnsallowip:-"${adb_awkcmd} '{print \"\"\$0\".rpz-client-ip CNAME rpz-passthru.\"}'"}"
adb_dnssafesearch="${adb_dnssafesearch:-"${adb_awkcmd} -v item=\"\$item\" '{print \"\"\$0\" CNAME \"item\".\\n*.\"\$0\" CNAME \"item\".\"}'"}"
adb_dnsstop="${adb_dnsstop:-"* CNAME ."}"
;;
@@ -387,8 +399,6 @@ f_dns() {
adb_dnsheader="${adb_dnsheader:-"\$TTL 2h\n@ IN SOA localhost. root.localhost. (1 6h 1h 1w 2h)\n"}"
adb_dnsdeny="${adb_dnsdeny:-"${adb_awkcmd} '{print \"\"\$0\" CNAME .\\n*.\"\$0\" CNAME .\"}'"}"
adb_dnsallow="${adb_dnsallow:-"${adb_awkcmd} '{print \"\"\$0\" CNAME rpz-passthru.\\n*.\"\$0\" CNAME rpz-passthru.\"}'"}"
adb_dnsdenyip="${adb_dnsdenyip:-"0"}"
adb_dnsallowip="${adb_dnsallowip:-"0"}"
adb_dnssafesearch="${adb_dnssafesearch:-"${adb_awkcmd} -v item=\"\$item\" '{print \"\"\$0\" CNAME \"item\".\\n*.\"\$0\" CNAME \"item\".\"}'"}"
adb_dnsstop="${adb_dnsstop:-"* CNAME ."}"
;;
@@ -400,8 +410,6 @@ f_dns() {
adb_dnsheader="${adb_dnsheader:-""}"
adb_dnsdeny="${adb_dnsdeny:-"${adb_awkcmd} '{print \"address /\"\$0\"/#\"}'"}"
adb_dnsallow="${adb_dnsallow:-"${adb_awkcmd} '{print \"address /\"\$0\"/-\"}'"}"
adb_dnsdenyip="${adb_dnsdenyip:-"0"}"
adb_dnsallowip="${adb_dnsallowip:-"0"}"
adb_dnssafesearch="${adb_dnssafesearch:-"${adb_awkcmd} -v item=\"\$item\" '{print \"cname /\"\$0\"/\"item\"\"}'"}"
adb_dnsstop="${adb_dnsstop:-"address #"}"
;;
@@ -413,8 +421,6 @@ f_dns() {
adb_dnsheader="${adb_dnsheader:-""}"
adb_dnsdeny="${adb_dnsdeny:-"0"}"
adb_dnsallow="${adb_dnsallow:-"0"}"
adb_dnsdenyip="${adb_dnsdenyip:-"0"}"
adb_dnsallowip="${adb_dnsallowip:-"0"}"
adb_dnssafesearch="${adb_dnssafesearch:-"0"}"
adb_dnsstop="${adb_dnsstop:-"0"}"
;;
@@ -426,7 +432,7 @@ f_dns() {
adb_finaldir="${adb_backupdir}"
fi
if [ "${adb_action}" != "stop" ]; then
for dir in "${adb_dnsdir:-"/tmp"}" "${adb_backupdir:-"/tmp"}" "${adb_jaildir:-"/tmp"}"; do
for dir in "${adb_dnsdir:-"/tmp"}" "${adb_backupdir:-"/tmp"}"; do
[ ! -d "${dir}" ] && mkdir -p "${dir}"
done
if [ "${adb_dnsflush}" = "1" ] || [ "${free_mem}" -lt "64" ]; then
@@ -437,7 +443,7 @@ f_dns() {
fi
fi
f_log "debug" "f_dns ::: dns: ${adb_dns}, dns_instance: ${adb_dnsinstance}, dns_user: ${adb_dnsuser}, dns_dir: ${adb_dnsdir}, backup_dir: ${adb_backupdir}, final_dir: ${adb_finaldir}, jail_dir: ${adb_jaildir}"
f_log "debug" "f_dns ::: dns: ${adb_dns}, dns_instance: ${adb_dnsinstance}, dns_user: ${adb_dnsuser}, dns_dir: ${adb_dnsdir}, backup_dir: ${adb_backupdir}, final_dir: ${adb_finaldir}"
}
# load fetch utility
@@ -540,7 +546,7 @@ f_uci() {
"resolver")
printf "%b" "${adb_dnsheader}" >"${adb_finaldir}/${adb_dnsfile}"
adb_cnt="0"
f_jsnup "running"
f_jsnup "processing"
"/etc/init.d/${adb_dns}" reload >/dev/null 2>&1
;;
esac
@@ -576,7 +582,7 @@ f_count() {
# set external config options
#
f_extconf() {
local config section zone port fwcfg
local config section
case "${adb_dns}" in
"dnsmasq")
@@ -611,50 +617,6 @@ f_extconf() {
;;
esac
f_uci "${config}"
fwcfg="$(uci -qNX show "firewall" | "${adb_awkcmd}" 'BEGIN{FS="[.=]"};/adblock_/{if(zone==$2){next}else{ORS=" ";zone=$2;print zone}}')"
if [ "${adb_enabled}" = "1" ] && [ "${adb_dnsforce}" = "1" ] &&
/etc/init.d/firewall enabled; then
for zone in ${adb_zonelist}; do
for port in ${adb_portlist}; do
if ! printf "%s" "${fwcfg}" | "${adb_grepcmd}" -q "adblock_${zone}${port}"; then
config="firewall"
if "${adb_lookupcmd}" "localhost." "127.0.0.1:${port}" >/dev/null 2>&1; then
uci -q batch <<-EOC
set firewall."adblock_${zone}${port}"="redirect"
set firewall."adblock_${zone}${port}".name="Adblock DNS (${zone}, ${port})"
set firewall."adblock_${zone}${port}".src="${zone}"
set firewall."adblock_${zone}${port}".proto="tcp udp"
set firewall."adblock_${zone}${port}".src_dport="53"
set firewall."adblock_${zone}${port}".dest_port="${port}"
set firewall."adblock_${zone}${port}".target="DNAT"
set firewall."adblock_${zone}${port}".family="any"
EOC
else
uci -q batch <<-EOC
set firewall."adblock_${zone}${port}"="rule"
set firewall."adblock_${zone}${port}".name="Adblock DNS (${zone}, ${port})"
set firewall."adblock_${zone}${port}".src="${zone}"
set firewall."adblock_${zone}${port}".proto="tcp udp"
set firewall."adblock_${zone}${port}".dest_port="${port}"
set firewall."adblock_${zone}${port}".target="REJECT"
set firewall."adblock_${zone}${port}".dest="*"
EOC
fi
fi
fwcfg="${fwcfg/adblock_${zone}${port}[ |\$]/}"
done
done
fwcfg="${fwcfg#"${fwcfg%%[![:space:]]*}"}"
fwcfg="${fwcfg%"${fwcfg##*[![:space:]]}"}"
fi
if [ "${adb_enabled}" = "0" ] || [ "${adb_dnsforce}" = "0" ] || [ -n "${fwcfg}" ]; then
config="firewall"
for section in ${fwcfg}; do
uci_remove firewall "${section}"
done
fi
f_uci "${config}"
}
# restart dns backend
@@ -748,36 +710,132 @@ f_etag() {
return "${out_rc}"
}
# add adblock-related nft rules
#
f_nftadd() {
local devices device port file="${adb_tmpdir}/adb_nft.add"
# only proceed if at least one feature is enabled
#
if [ "${adb_nftallow}" = "0" ] && [ "${adb_nftblock}" = "0" ] && [ "${adb_nftforce}" = "0" ]; then
return
fi
{
# nft header (tables, sets, base and regular chains)
#
printf "%s\n\n" "#!${adb_nftcmd} -f"
if "${adb_nftcmd}" -t list table inet adblock >/dev/null 2>&1; then
printf "%s\n" "delete table inet adblock"
fi
printf "%s\n" "add table inet adblock"
if [ "${adb_nftallow}" = "1" ] && [ -n "${adb_nftmacallow}" ]; then
printf "%s\n" "add set inet adblock mac_allow { type ether_addr; flags interval; auto-merge; elements = { ${adb_nftmacallow// /, } }; }"
fi
if [ "${adb_nftblock}" = "1" ] && [ -n "${adb_nftmacblock}" ]; then
printf "%s\n" "add set inet adblock mac_block { type ether_addr; flags interval; auto-merge; elements = { ${adb_nftmacblock// /, } }; }"
fi
printf "%s\n" "add chain inet adblock pre-routing { type nat hook prerouting priority -150; policy accept; }"
printf "%s\n" "add chain inet adblock _reject"
# reject chain rules
#
printf "%s\n" "add rule inet adblock _reject meta l4proto tcp counter reject with tcp reset"
printf "%s\n" "add rule inet adblock _reject counter reject with icmpx host-unreachable"
# external allow rules
#
if [ "${adb_nftallow}" = "1" ]; then
if [ -n "${adb_nftmacallow}" ]; then
[ -n "${adb_allowdnsv4}" ] && printf "%s\n" "add rule inet adblock pre-routing meta nfproto ipv4 ether saddr @mac_allow meta l4proto { udp, tcp } th dport 53 counter dnat to ${adb_allowdnsv4}:53"
[ -n "${adb_allowdnsv6}" ] && printf "%s\n" "add rule inet adblock pre-routing meta nfproto ipv6 ether saddr @mac_allow meta l4proto { udp, tcp } th dport 53 counter dnat to [${adb_allowdnsv6}]:53"
fi
for device in ${adb_nftdevallow}; do
[ -n "${adb_allowdnsv4}" ] && printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" meta nfproto ipv4 meta l4proto { udp, tcp } th dport 53 counter dnat to ${adb_allowdnsv4}:53"
[ -n "${adb_allowdnsv6}" ] && printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" meta nfproto ipv6 meta l4proto { udp, tcp } th dport 53 counter dnat to [${adb_allowdnsv6}]:53"
done
fi
# external block rules
#
if [ "${adb_nftblock}" = "1" ]; then
if [ -n "${adb_nftmacblock}" ]; then
[ -n "${adb_blockdnsv4}" ] && printf "%s\n" "add rule inet adblock pre-routing meta nfproto ipv4 ether saddr @mac_block meta l4proto { udp, tcp } th dport 53 counter dnat to ${adb_blockdnsv4}:53"
[ -n "${adb_blockdnsv6}" ] && printf "%s\n" "add rule inet adblock pre-routing meta nfproto ipv6 ether saddr @mac_block meta l4proto { udp, tcp } th dport 53 counter dnat to [${adb_blockdnsv6}]:53"
fi
for device in ${adb_nftdevblock}; do
[ -n "${adb_blockdnsv4}" ] && printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" meta nfproto ipv4 meta l4proto { udp, tcp } th dport 53 counter dnat to ${adb_blockdnsv4}:53"
[ -n "${adb_blockdnsv6}" ] && printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" meta nfproto ipv6 meta l4proto { udp, tcp } th dport 53 counter dnat to [${adb_blockdnsv6}]:53"
done
fi
# local dns enforcement
#
if [ "${adb_nftforce}" = "1" ]; then
# device/vlan exceptions
#
for device in ${adb_nftdevallow} ${adb_nftdevblock}; do
case " ${devices} " in
*" ${device} "*)
;;
*) devices="${devices} ${device}"
printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" return"
;;
esac
done
# mac exceptions
#
for device in ${adb_nftdevforce}; do
if [ "${adb_nftallow}" = "1" ] && [ -n "${adb_nftmacallow}" ]; then
printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" ether saddr @mac_allow return"
fi
if [ "${adb_nftblock}" = "1" ] && [ -n "${adb_nftmacblock}" ]; then
printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" ether saddr @mac_block return"
fi
# dns enforce rules
#
for port in ${adb_nftportforce}; do
if [ "${port}" = "53" ]; then
printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" meta nfproto { ipv4, ipv6 } meta l4proto { udp, tcp } th dport ${port} counter redirect to :${port}"
else
printf "%s\n" "add rule inet adblock pre-routing iifname \"${device}\" meta nfproto { ipv4, ipv6 } meta l4proto { udp, tcp } th dport ${port} counter goto _reject"
fi
done
done
fi
} >"${file}"
if "${adb_nftcmd}" -f "${file}" >/dev/null 2>&1; then
f_log "info" "adblock-related nft rules added"
else
f_log "err" "failed to add adblock-related nft rules"
fi
}
# remove adblock-related nft rules
#
f_nftremove() {
local file="${adb_tmpdir}/adb_nft.remove"
if "${adb_nftcmd}" -t list table inet adblock >/dev/null 2>&1; then
{
printf "%s\n" "#!${adb_nftcmd} -f"
printf "%s\n" "delete table inet adblock"
} >"${file}"
if "${adb_nftcmd}" -f "${file}" >/dev/null 2>&1; then
f_log "info" "adblock-related nft rules removed"
else
f_log "err" "failed to remove adblock-related nft rules"
fi
fi
}
# backup/restore/remove blocklists
#
f_list() {
local file rset item array safe_url safe_ips safe_cname safe_domains ip out_rc file_name mode="${1}" src_name="${2:-"${src_name}"}" in_rc="${src_rc:-0}" use_cname="0" ffiles="-maxdepth 1 -name adb_list.*.gz"
case "${mode}" in
"iplist")
src_name="${mode}"
file_name="${adb_tmpdir}/tmp.add.${src_name}"
if [ "${adb_dnsallowip}" != "0" ] && [ "${adb_dnsdenyip}" != "0" ]; then
rset="BEGIN{FS=\"[.:]\";pfx=\"32\"}{if(match(\$0,/:/))pfx=\"128\"}{printf \"%s.\",pfx;for(seg=NF;seg>=1;seg--)if(seg==1)printf \"%s\n\",\$seg;else if(\$seg>=0)printf \"%s.\",\$seg; else printf \"%s.\",\"zz\"}"
if [ -n "${adb_allowip}" ]; then
: >"${adb_tmpdir}/tmp.raw.${src_name}"
for ip in ${adb_allowip}; do
printf "%s" "${ip}" | "${adb_awkcmd}" "${rset}" >>"${adb_tmpdir}/tmp.raw.${src_name}"
done
eval "${adb_dnsallowip}" "${adb_tmpdir}/tmp.raw.${src_name}" >"${file_name}"
out_rc="${?}"
fi
if [ -n "${adb_denyip}" ] && { [ -z "${out_rc}" ] || [ "${out_rc}" = "0" ]; }; then
: >"${adb_tmpdir}/tmp.raw.${src_name}"
for ip in ${adb_denyip}; do
printf "%s" "${ip}" | "${adb_awkcmd}" "${rset}" >>"${adb_tmpdir}/tmp.raw.${src_name}"
done
eval "${adb_dnsdenyip}" "${adb_tmpdir}/tmp.raw.${src_name}" >>"${file_name}"
out_rc="${?}"
fi
: >"${adb_tmpdir}/tmp.raw.${src_name}"
fi
;;
"blocklist" | "allowlist")
src_name="${mode}"
case "${src_name}" in
@@ -809,9 +867,9 @@ f_list() {
eval "${adb_dnsallow}" "${file_name}" >"${adb_tmpdir}/tmp.add.${src_name}"
out_rc="${?}"
if [ "${adb_jail}" = "1" ] && [ "${adb_dnsstop}" != "0" ]; then
printf "%b" "${adb_dnsheader}" >"${adb_tmpdir}/${adb_dnsjail}"
"${adb_catcmd}" "${adb_tmpdir}/tmp.add.${src_name}" >>"${adb_tmpdir}/${adb_dnsjail}"
printf "%b\n" "${adb_dnsstop}" >>"${adb_tmpdir}/${adb_dnsjail}"
printf "%b" "${adb_dnsheader}" >"${adb_tmpdir}/${adb_dnsfile}"
"${adb_catcmd}" "${adb_tmpdir}/tmp.add.${src_name}" >>"${adb_tmpdir}/${adb_dnsfile}"
printf "%b\n" "${adb_dnsstop}" >>"${adb_tmpdir}/${adb_dnsfile}"
fi
fi
;;
@@ -962,7 +1020,6 @@ f_list() {
file_name="${adb_finaldir}/${adb_dnsfile}"
rm -f "${file_name}"
[ -n "${adb_dnsheader}" ] && printf "%b" "${adb_dnsheader}" >>"${file_name}"
[ -s "${adb_tmpdir}/tmp.add.iplist" ] && "${adb_sortcmd}" ${adb_srtopts} -u "${adb_tmpdir}/tmp.add.iplist" >>"${file_name}"
[ -s "${adb_tmpdir}/tmp.add.allowlist" ] && "${adb_sortcmd}" ${adb_srtopts} -u "${adb_tmpdir}/tmp.add.allowlist" >>"${file_name}"
[ "${adb_safesearch}" = "1" ] && "${adb_catcmd}" "${adb_tmpdir}/tmp.safesearch."* 2>/dev/null >>"${file_name}"
if [ "${adb_dnsdeny}" != "0" ]; then
@@ -1135,6 +1192,7 @@ f_query() {
#
f_jsnup() {
local pids object feeds end_time runtime dns dns_ver dns_mem free_mem custom_feed="0" status="${1:-"enabled"}"
local duration jail="0" nft_unfiltered="0" nft_filtered="0" nft_force="0"
if [ -n "${adb_dnspid}" ]; then
pids="$("${adb_pgrepcmd}" -P "${adb_dnspid}" 2>/dev/null)"
@@ -1161,7 +1219,19 @@ f_jsnup() {
free_mem="$("${adb_awkcmd}" '/^MemAvailable/{printf "%.2f", $2/1024}' "/proc/meminfo" 2>/dev/null)"
adb_cnt="$("${adb_awkcmd}" -v cnt="${adb_cnt}" 'BEGIN{res="";pos=0;for(i=length(cnt);i>0;i--){res=substr(cnt,i,1)res;pos++;if(pos==3&&i>1){res=" "res;pos=0;}}; printf"%s",res}')"
[ -s "${adb_customfeedfile}" ] && custom_feed="1"
if [ "${adb_nftforce}" = "1" ] && [ -n "${adb_nftdevforce}" ] && [ -n "${adb_nftportforce}" ]; then
nft_force="1"
fi
if [ "${adb_nftallow}" = "1" ] \
&& { [ -n "${adb_nftmacallow}" ] || [ -n "${adb_nftdevallow}" ]; } \
&& { [ -n "${adb_allowdnsv4}" ] || [ -n "${adb_allowdnsv6}" ]; }; then
nft_unfiltered="1"
fi
if [ "${adb_nftblock}" = "1" ] \
&& { [ -n "${adb_nftmacblock}" ] || [ -n "${adb_nftdevblock}" ]; } \
&& { [ -n "${adb_blockdnsv4}" ] || [ -n "${adb_blockdnsv6}" ]; }; then
nft_filtered="1"
fi
case "${status}" in
"enabled")
if [ -n "${adb_starttime}" ] && [ "${adb_action}" != "boot" ]; then
@@ -1187,11 +1257,12 @@ f_jsnup() {
[ -z "${adb_cnt}" ] && json_get_var adb_cnt "blocked_domains"
[ -z "${runtime}" ] && json_get_var runtime "last_run"
if [ "${status}" = "enabled" ]; then
if [ "${adb_jail}" = "1" ] && [ "${adb_jaildir}" = "${adb_dnsdir}" ]; then
if [ "${adb_jail}" = "1" ] && [ "${adb_dnsstop}" != "0" ]; then
jail="1"
adb_cnt="0"
feeds="restrictive_jail"
feeds="restrictive jail (allowlist-only)"
else
feeds="$(printf "%s\n" ${adb_feed} | "${adb_sortcmd}" | "${adb_awkcmd}" '{ORS=" ";print $0}')"
feeds="$(printf "%s\n" ${adb_feed// /, } | ${adb_sortcmd} | xargs)"
fi
fi
fi
@@ -1209,8 +1280,8 @@ f_jsnup() {
json_close_array
json_add_string "dns_backend" "${adb_dns:-"-"} (${dns_ver:-"-"}), ${adb_finaldir:-"-"}, ${dns_mem:-"0"} MB"
json_add_string "run_ifaces" "trigger: ${adb_trigger:-"-"}, report: ${adb_repiface:-"-"}"
json_add_string "run_directories" "base: ${adb_basedir}, dns: ${adb_dnsdir}, backup: ${adb_backupdir}, report: ${adb_reportdir}, jail: ${adb_jaildir:-"-"}"
json_add_string "run_flags" "shift: $(f_char ${adb_dnsshift}), custom feed: $(f_char ${custom_feed}), force: $(f_char ${adb_dnsforce}), flush: $(f_char ${adb_dnsflush}), tld: $(f_char ${adb_tld}), search: $(f_char ${adb_safesearch}), report: $(f_char ${adb_report}), mail: $(f_char ${adb_mail}), jail: $(f_char ${adb_jail})"
json_add_string "run_directories" "base: ${adb_basedir}, dns: ${adb_dnsdir}, backup: ${adb_backupdir}, report: ${adb_reportdir}"
json_add_string "run_flags" "shift: $(f_char ${adb_dnsshift}), custom feed: $(f_char ${custom_feed}), ext. DNS (std/prot): $(f_char ${nft_unfiltered})/$(f_char ${nft_filtered}), force: $(f_char ${nft_force}), flush: $(f_char ${adb_dnsflush}), tld: $(f_char ${adb_tld}), search: $(f_char ${adb_safesearch}), report: $(f_char ${adb_report}), mail: $(f_char ${adb_mail}), jail: $(f_char ${jail})"
json_add_string "last_run" "${runtime:-"-"}"
json_add_string "system_info" "cores: ${adb_cores}, fetch: ${adb_fetchcmd##*/}, ${adb_sysver}"
json_dump >"${adb_rtfile}"
@@ -1256,29 +1327,23 @@ f_main() {
# jail mode preparation
#
if [ "${adb_jail}" = "1" ] && [ "${adb_dnsstop}" != "0" ]; then
if [ "${adb_jaildir}" = "${adb_dnsdir}" ]; then
"${adb_mvcmd}" -f "${adb_tmpdir}/${adb_dnsjail}" "${adb_finaldir}/${adb_dnsfile}"
chown "${adb_dnsuser}" "${adb_finaldir}/${adb_dnsfile}" 2>/dev/null
if [ "${adb_dnsshift}" = "1" ] && [ ! -L "${adb_dnsdir}/${adb_dnsfile}" ]; then
ln -fs "${adb_finaldir}/${adb_dnsfile}" "${adb_dnsdir}/${adb_dnsfile}"
elif [ "${adb_dnsshift}" = "0" ] && [ -s "${adb_backupdir}/${adb_dnsfile}" ]; then
rm -f "${adb_backupdir}/${adb_dnsfile}"
fi
if f_dnsup; then
if [ "${adb_action}" != "resume" ]; then
f_jsnup "enabled"
fi
f_log "info" "restrictive jail mode enabled successfully (${adb_sysver})"
else
f_log "err" "dns backend restart in jail mode failed"
fi
f_rmtemp
return
else
"${adb_mvcmd}" -f "${adb_tmpdir}/${adb_dnsjail}" "${adb_jaildir}/${adb_dnsjail}"
chown "${adb_dnsuser}" "${adb_jaildir}/${adb_dnsjail}" 2>/dev/null
f_log "info" "additional restrictive jail blocklist placed in ${adb_jaildir}"
"${adb_mvcmd}" -f "${adb_tmpdir}/${adb_dnsfile}" "${adb_finaldir}/${adb_dnsfile}"
chown "${adb_dnsuser}" "${adb_finaldir}/${adb_dnsfile}" 2>/dev/null
if [ "${adb_dnsshift}" = "1" ] && [ ! -L "${adb_dnsdir}/${adb_dnsfile}" ]; then
ln -fs "${adb_finaldir}/${adb_dnsfile}" "${adb_dnsdir}/${adb_dnsfile}"
elif [ "${adb_dnsshift}" = "0" ] && [ -s "${adb_backupdir}/${adb_dnsfile}" ]; then
rm -f "${adb_backupdir}/${adb_dnsfile}"
fi
if f_dnsup; then
if [ "${adb_action}" != "resume" ]; then
f_jsnup "enabled"
fi
f_log "info" "restrictive jail mode enabled successfully (${adb_sysver})"
else
f_log "err" "dns backend restart in jail mode failed"
fi
f_rmtemp
return
fi
# safe search preparation
@@ -1689,13 +1754,16 @@ adb_lookupcmd="$(f_cmd nslookup)"
adb_dumpcmd="$(f_cmd tcpdump optional)"
adb_mailcmd="$(f_cmd msmtp optional)"
adb_logreadcmd="$(f_cmd logread optional)"
adb_nftcmd="$(f_cmd nft)"
# handle different adblock actions
#
f_load
case "${adb_action}" in
"stop")
f_temp
f_jsnup "stopped"
f_nftremove
f_rmdns
;;
"suspend")
@@ -1715,7 +1783,8 @@ case "${adb_action}" in
f_main
;;
"restart")
f_jsnup "running"
f_jsnup "processing"
f_nftremove
f_rmdns
f_env
f_main