* Overall duplicate removal in generated blocklist file 'adb_list.overall'
* Additional local allowlist for manual overrides, located in '/etc/adblock/adblock.allowlist' (only exact matches).
* Additional local blocklist for manual overrides, located in '/etc/adblock/adblock.blocklist'
-* Implements Firewall‑Based DNS Control to force DNS interfaces/ports and to redirect to external unfiltered/filtered DNS server
+* Implements firewall‑based DNS Control to force DNS interfaces/ports and to redirect to external unfiltered/filtered DNS server
+* Includes firewall‑based Remote DNS Allow, a CGI-Interface to allow certain MACs temporary bypass the local adblock DNS
+* Supports firewall‑based temporary DNS Bridging, to ensure a Zero‑Downtime during adblock-related DNS Restarts
* Connection 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', 'enable', 'disable', 'running', 'status', 'suspend', 'resume', 'query', 'report')
* 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
-* Contains an option to route DNS queries to the local resolver via corresponding firewall rules
* Implements a jail mode - only domains on the allowlist are permitted, all other DNS requests are rejected
* 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
| adb_enabled | 1, enabled | set to 0 to disable the adblock service |
| adb_feedfile | /etc/adblock/adblock.feeds | full path to the used adblock feed file |
| adb_dns | -, auto-detected | 'dnsmasq', 'unbound', 'named', 'kresd', 'smartdns' or 'raw' |
+| adb_cores | -, auto-detected | limit the cpu cores used by adblock to save RAM |
| adb_fetchcmd | -, auto-detected | 'uclient-fetch', 'wget' or 'curl' |
| adb_fetchparm | -, auto-detected | manually override the config options for the selected download utility |
| adb_fetchinsecure | 0, disabled | don't check SSL server certificates during download |
| 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_allowdnsv4 | -, not set | external IPv4 DNS resolver applied to MACs and interfaces using the unfiltered DNS policy |
+| adb_allowdnsv6 | -, not set | external IPv6 DNS resolver applied to MACs and interfaces using the unfiltered DNS policy |
| adb_nftremote | 0, disabled | routes MACs to an unfiltered external DNS resolver, bypassing local adblock |
| adb_nftmacremote | -, not set | Allows listed MACs to remotely access an unfiltered external DNS resolver, bypassing local adblock |
| adb_nftremotetimeout | 15 | Time limit in minutes for remote DNS access of the listed MAC addresses |
-| adb_remotednsv4 | -, not set | IPv4 DNS resolver applied to MACs using the unfiltered remote DNS policy |
-| adb_remotednsv6 | -, not set | IPv6 DNS resolver applied to MACs using the unfiltered remote DNS policy |
+| adb_remotednsv4 | -, not set | external IPv4 DNS resolver applied to MACs using the unfiltered remote DNS policy |
+| adb_remotednsv6 | -, not set | external IPv6 DNS resolver applied to MACs using the unfiltered remote DNS policy |
| adb_nftblock | 0, disabled | routes MACs or interfaces to a 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 |
+| adb_blockdnsv4 | -, not set | external IPv4 DNS resolver applied to MACs and interfaces using the filtered DNS policy |
+| adb_blockdnsv6 | -, not set | external IPv6 DNS resolver applied to MACs and interfaces using the filtered DNS policy |
+| adb_nftbridge | -, not set | enables a temporary DNS bridge to an external DNS resolver during local DNS restarts |
+| adb_bridgednsv4 | -, not set | external IPv4 DNS resolver used during bridging |
+| adb_bridgednsv6 | -, not set | external IPv6 DNS resolver used during bridging |
<a id="examples"></a>
## Examples
~# /etc/init.d/adblock status
::: adblock runtime information
+ adblock_status : enabled
- + 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, 234.93 MB
+ + frontend_ver : 4.5.2-r1
+ + backend_ver : 4.5.2-r1
+ + blocked_domains : 753 951
+ + active_feeds : 1hosts, adguard, adguard_tracking, bitcoin, certpl, doh_blocklist, hagezi, ipfire_dbl, phishing_army, smarttv_tracking, stevenblack, winspy
+ + dns_backend : unbound (1.24.2-r1), /mnt/data/adblock/backup, 297.66 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)
+ + run_information : base: /mnt/data/adblock, dns: /var/lib/unbound, backup: /mnt/data/adblock/backup, report: /mnt/data/adblock/report, error: /mnt/data/adblock/adb_error.log
+ + run_flags : shift: ✔, custom feed: ✘, ext. DNS (std/prot/remote/bridge): ✘/✔/✔/✔, force: ✔, flush: ✘, tld: ✔, search: ✘, report: ✔, mail: ✔, jail: ✘
+ + last_run : mode: restart, 2026-03-01T06:20:27+01:00, duration: 0m 24s, 1342.71 MB available
+ + system_info : cores: 4, fetch: curl, Bananapi BPI-R3, mediatek/filogic, OpenWrt SNAPSHOT (r33197-cf4cd07777)
```
<a id="best-practise-and-tweaks"></a>
* use external storage: point 'adb_basedir', 'adb_backupdir' and 'adb_reportdir' to an USB drive or SSD
* limit CPU processing to one core: set 'adb_cores' to '1' to reduce peak memory usage during feed processing
-* enable blocklist shifting: activate 'adb_dnsshift' to store the blocklist in the backup directory and expose it via a symlink in RAM.
+* enable blocklist shifting: activate 'adb_dnsshift' to store the blocklist in the backup directory on a USB stick and only create a symlink in RAM.
* Firewall DNS redirection: use nftables based DNS routing to external filtered DNS serves and only use a minimal set of local blocklists
**Sensible choice of blocklists**
The CGI interface is mobile‑friendly and includes a LuCI‑style loading spinner during the renew process, giving immediate visual feedback while the nftables entry is created. All operations are atomic and safe even when multiple devices renew access in parallel.
+**Temporary DNS Bridging (Zero‑Downtime during DNS Restarts)**
+Adblock can optionally enable a temporary DNS bridging mode to avoid DNS downtime during DNS backend restarts.
+When this feature is enabled, all DNS queries from LAN clients are briefly redirected to an external fallback resolver until the local DNS backend becomes available again. This ensures that DNS resolution continues to work seamlessly for all clients, even while adblock reloads blocklists or restarts the DNS service. Just set the options 'adb_nftbridging', 'adb_bridgednsv4' and 'adb_bridgednsv6' accordingly.
+
**Jail mode (allowlist-only):**
Enforces a strict allowlist‑only 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.
3. column: the domain column within the feed file, e.g. '2' (required)
4. separator: an optional field separator, default is the character class '[[:space:]]'
+**Enable debug mode**
+Adblock provides an optional debug mode that writes diagnostic information to the system log and captures internal error output in a dedicated error logfile - by default located in the adblock base directory as '/tmp/adb_error.log'. The log file is automatically cleared at the beginning of each run. Under normal conditions, all error messages are discarded to keep regular runs clean and silent. To enable debug mode, set the option 'adb_debug' to '1'. When enabled, the script produces significantly more log output to assist with troubleshooting.
+
## 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>
adb_nftremote="0"
adb_nftremotetimeout="15"
adb_nftmacremote=""
+adb_nftbridge="0"
adb_allowdnsv4=""
adb_allowdnsv6=""
adb_remotednsv4=""
adb_remotednsv6=""
adb_blockdnsv4=""
adb_blockdnsv6=""
+adb_bridgednsv4=""
+adb_bridgednsv6=""
adb_dnsshift="0"
adb_dnsflush="0"
adb_dnstimeout="20"
adb_feedfile="/etc/adblock/adblock.feeds"
adb_customfeedfile="/etc/adblock/adblock.custom.feeds"
adb_rtfile="/var/run/adb_runtime.json"
+adb_errorlog="/dev/null"
adb_fetchcmd=""
adb_fetchinsecure=""
adb_fetchparm=""
f_load() {
local bg_pid port filter tcpdump_filter cpu core
- adb_packages="$("${adb_ubuscmd}" -S call rpc-sys packagelist '{ "all": true }' 2>/dev/null)"
+ # load adblock config and set debug log file
+ #
+ f_conf
+ if [ "${adb_debug}" = "1" ]; then
+ adb_errorlog="${adb_basedir}/adb_error.log"
+ : > "${adb_errorlog}"
+ else
+ rm -f "${adb_errorlog}"
+ fi
+
+ # fetch installed packages amd system information
+ #
+ adb_packages="$("${adb_ubuscmd}" -S call rpc-sys packagelist '{ "all": true }' 2>>"${adb_errorlog}")"
adb_bver="$(printf "%s" "${adb_packages}" | "${adb_jsoncmd}" -ql1 -e '@.packages.adblock')"
adb_fver="$(printf "%s" "${adb_packages}" | "${adb_jsoncmd}" -ql1 -e '@.packages["luci-app-adblock"]')"
- adb_sysver="$("${adb_ubuscmd}" -S call system board 2>/dev/null |
+ adb_sysver="$("${adb_ubuscmd}" -S call system board 2>>"${adb_errorlog}" |
"${adb_jsoncmd}" -ql1 -e '@.model' -e '@.release.target' -e '@.release.distribution' -e '@.release.version' -e '@.release.revision' |
"${adb_awkcmd}" 'BEGIN{RS="";FS="\n"}{printf "%s, %s, %s %s (%s)",$1,$2,$3,$4,$5}')"
- f_conf
+ # detect cpu cores for parallel processing
+ #
if [ -z "${adb_cores}" ]; then
- cpu="$("${adb_grepcmd}" -c '^processor' /proc/cpuinfo 2>/dev/null)"
- core="$("${adb_grepcmd}" -cm1 '^core id' /proc/cpuinfo 2>/dev/null)"
+ cpu="$("${adb_grepcmd}" -c '^processor' /proc/cpuinfo 2>>"${adb_errorlog}")"
+ core="$("${adb_grepcmd}" -cm1 '^core id' /proc/cpuinfo 2>>"${adb_errorlog}")"
[ "${cpu}" = "0" ] && cpu="1"
[ "${core}" = "0" ] && core="1"
adb_cores="$((cpu * core))"
[ "${adb_cores}" -gt "16" ] && adb_cores="16"
fi
+ # check if adblock is enabled
+ #
if [ "${adb_enabled}" = "0" ]; then
f_extconf
f_temp
exit 0
fi
+ # load dns backend and fetch utility
+ #
if [ "${adb_action}" != "report" ] && [ "${adb_action}" != "mail" ]; then
f_dns
f_fetch
fi
+ # check if reporting is enabled and tcpdump is available
+ #
if [ "${adb_report}" = "1" ] && [ ! -x "${adb_dumpcmd}" ]; then
f_log "info" "please install the package 'tcpdump' or 'tcpdump-mini' to use the reporting feature"
elif [ -x "${adb_dumpcmd}" ]; then
bg_pid="$("${adb_pgrepcmd}" -nf "${adb_reportdir}/adb_report.pcap")"
if [ -n "${bg_pid}" ] && { [ "${adb_report}" = "0" ] || [ "${adb_action}" = "stop" ] || [ "${adb_action}" = "restart" ]; }; then
- if kill -HUP "${bg_pid}" 2>/dev/null; then
+ if kill -HUP "${bg_pid}" 2>>"${adb_errorlog}"; then
for cnt in 1 2 3; do
kill -0 "${bg_pid}" >/dev/null 2>&1 || break
sleep 1
)
sleep 1
bg_pid="$("${adb_pgrepcmd}" -nf "${adb_reportdir}/adb_report.pcap")"
- f_log "info" "tcpdump backgound process started (interface: ${adb_repiface}, port: ${adb_repport}, dir: ${adb_reportdir}, pid: ${bg_pid})"
+ f_log "info" "tcpdump backgound process started for interface: ${adb_repiface}, port: ${adb_repport}, dir: ${adb_reportdir}, pid: ${bg_pid}"
else
f_log "info" "please set the reporting interface 'adb_repiface' and reporting directory 'adb_reportdir' manually"
fi
f_jsnup "processing"
f_extconf
f_temp
+ [ "${action}" = "restart" ] && f_nftremove
f_nftadd
json_init
if [ -s "${adb_customfeedfile}" ]; then
f_dns() {
local dns dns_list dns_section dns_info free_mem dir
- free_mem="$("${adb_awkcmd}" '/^MemAvailable/{printf "%s",int($2/1000)}' "/proc/meminfo" 2>/dev/null)"
+ free_mem="$("${adb_awkcmd}" '/^MemAvailable/{printf "%s",int($2/1000)}' "/proc/meminfo" 2>>"${adb_errorlog}")"
if [ "${adb_action}" = "boot" ] && [ -z "${adb_trigger}" ]; then
sleep ${adb_triggerdelay:-"5"}
fi
adb_dnssafesearch="${adb_dnssafesearch:-"${adb_awkcmd} -v item=\"\$item\" '{print \"address=/\"\$0\"/\"item\"\";print \"local=/\"\$0\"/\"}'"}"
adb_dnsstop="${adb_dnsstop:-"address=/#/\nlocal=/#/"}"
if [ -z "${adb_dnsdir}" ]; then
- dns_section="$("${adb_ubuscmd}" -S call uci get "{\"config\":\"dhcp\", \"section\":\"@dnsmasq[${adb_dnsinstance}]\", \"type\":\"dnsmasq\"}" 2>/dev/null)"
+ dns_section="$("${adb_ubuscmd}" -S call uci get "{\"config\":\"dhcp\", \"section\":\"@dnsmasq[${adb_dnsinstance}]\", \"type\":\"dnsmasq\"}" 2>>"${adb_errorlog}")"
dns_info="$(printf "%s" "${dns_section}" | "${adb_jsoncmd}" -l1 -e '@.values["confdir"]')"
if [ -n "${dns_info}" ]; then
adb_dnsdir="${dns_info}"
# remove temporary files and directories
#
f_rmtemp() {
+ [ -f "${adb_errorlog}" ] && [ ! -s "${adb_errorlog}" ] && rm -f "${adb_errorlog}"
rm -rf "${adb_tmpdir}"
: >"${adb_pidfile}"
}
adb_cnt="0"
if [ -s "${file}" ]; then
- adb_cnt="$("${adb_wccmd}" -l 2>/dev/null <"${file}")"
+ adb_cnt="$("${adb_wccmd}" -l 2>>"${adb_errorlog}" <"${file}")"
if [ -n "${var}" ]; then
printf "%s" "${adb_cnt}"
else
if [ "${mode}" = "final" ]; then
if [ -s "${adb_tmpdir}/tmp.add.allowlist" ]; then
- adb_cnt="$((adb_cnt - $("${adb_wccmd}" -l 2>/dev/null <"${adb_tmpdir}/tmp.add.allowlist")))"
+ adb_cnt="$((adb_cnt - $("${adb_wccmd}" -l 2>>"${adb_errorlog}" <"${adb_tmpdir}/tmp.add.allowlist")))"
fi
for file in "${adb_tmpdir}/tmp.safesearch".*; do
if [ -r "${file}" ]; then
- adb_cnt="$((adb_cnt - $("${adb_wccmd}" -l 2>/dev/null <"${file}")))"
+ adb_cnt="$((adb_cnt - $("${adb_wccmd}" -l 2>>"${adb_errorlog}" <"${file}")))"
fi
done
[ -n "${adb_dnsheader}" ] && adb_cnt="$(((adb_cnt - $(printf "%b" "${adb_dnsheader}" | "${adb_grepcmd}" -c "^")) / 2))"
# restart dns backend
#
f_dnsup() {
- local restart_rc cnt="0" out_rc="4"
+ local restart_rc nft_rc cnt="0" out_rc="4"
adb_dnspid=""
if [ "${adb_dns}" = "raw" ] || [ -z "${adb_dns}" ]; then
out_rc="0"
else
+ # load external dns bridge
+ #
+ if { [ -n "${adb_bridgednsv4}" ] || [ -n "${adb_bridgednsv6}" ]; } && [ "${adb_nftbridge}" = "1" ]; then
+ if "${adb_nftcmd}" list chain inet adblock dns-bridge >/dev/null 2>&1; then
+ if [ -n "${adb_bridgednsv4}" ]; then
+ "${adb_nftcmd}" add rule inet adblock dns-bridge meta nfproto ipv4 meta l4proto { udp, tcp } th dport 53 counter dnat to ${adb_bridgednsv4}:53 2>>"${adb_errorlog}"
+ nft_rc="${?}"
+ fi
+ if [ -n "${adb_bridgednsv6}" ]; then
+ "${adb_nftcmd}" add rule inet adblock dns-bridge meta nfproto ipv6 meta l4proto { udp, tcp } th dport 53 counter dnat to [${adb_bridgednsv6}]:53 2>>"${adb_errorlog}"
+ nft_rc="$(( nft_rc + $? ))"
+ fi
+ if [ "${nft_rc}" = "0" ]; then
+ f_log "info" "external DNS bridge loaded: ${adb_bridgednsv4:-"-"} / ${adb_bridgednsv6:-"-"}"
+ else
+ f_log "err" "failed to load external DNS bridge: ${adb_bridgednsv4:-"-"} / ${adb_bridgednsv6:-"-"}"
+ fi
+ fi
+ fi
+ # restart dns backend
+ #
if [ "${adb_dnsflush}" = "0" ]; then
case "${adb_dns}" in
"unbound")
if [ -x "${adb_dnscachecmd}" ] && [ -d "${adb_tmpdir}" ] && [ -f "${adb_dnsdir}/unbound.conf" ]; then
- "${adb_dnscachecmd}" -c "${adb_dnsdir}/unbound.conf" dump_cache >"${adb_tmpdir}/adb_cache.dump" 2>/dev/null
+ "${adb_dnscachecmd}" -c "${adb_dnsdir}/unbound.conf" dump_cache >"${adb_tmpdir}/adb_cache.dump" 2>>"${adb_errorlog}"
fi
"/etc/init.d/${adb_dns}" restart >/dev/null 2>&1
restart_rc="${?}"
restart_rc="${?}"
fi
fi
+
+ # check if dns backend is responsive, restore dns cache for unbound and get dns backend pid
+ #
if [ "${restart_rc}" = "0" ]; then
while [ "${cnt}" -le "${adb_dnstimeout}" ]; do
if "${adb_lookupcmd}" "${adb_lookupdomain}." >/dev/null 2>&1; then
fi
fi
fi
- adb_dnspid="$("${adb_ubuscmd}" -S call service list 2>/dev/null | "${adb_jsoncmd}" -l1 -e "@[\"${adb_dns}\"].instances.*.pid")"
+ adb_dnspid="$("${adb_ubuscmd}" -S call service list 2>>"${adb_errorlog}" | "${adb_jsoncmd}" -l1 -e "@[\"${adb_dns}\"].instances.*.pid")"
- f_log "debug" "f_dnsup ::: dns: ${adb_dns}, cache_cmd: ${adb_dnscachecmd:-"-"}, lookup_domain: ${adb_lookupdomain:-"-"}, restart_rc: ${restart_rc:-"-"}, dns_flush: ${adb_dnsflush}, dns_timeout: ${adb_dnstimeout}, dns_pid: ${adb_dnspid}, dns_cnt: ${cnt}, rc: ${out_rc}"
+ # remove external dns bridge
+ #
+ if [ "${adb_nftbridge}" = "1" ] && "${adb_nftcmd}" list chain inet adblock dns-bridge >/dev/null 2>&1; then
+ "${adb_nftcmd}" flush chain inet adblock dns-bridge 2>>"${adb_errorlog}"
+ nft_rc="${?}"
+ if [ "${nft_rc}" = "0" ]; then
+ f_log "info" "external DNS bridge removed"
+ else
+ f_log "err" "failed to remove external DNS bridge"
+ fi
+ fi
+
+ f_log "debug" "f_dnsup ::: dns: ${adb_dns}, cache_cmd: ${adb_dnscachecmd:-"-"}, lookup_domain: ${adb_lookupdomain:-"-"}, restart_rc: ${restart_rc:-"-"}, dns_flush: ${adb_dnsflush}, dns_timeout: ${adb_dnstimeout}, dns_pid: ${adb_dnspid}, dns_cnt: ${cnt}, nft_rc: ${nft_rc:-"-"}, rc: ${out_rc}"
return "${out_rc}"
}
# only proceed if at least one feature is enabled
#
- if [ "${adb_nftallow}" = "0" ] && [ "${adb_nftblock}" = "0" ] && [ "${adb_nftremote}" = "0" ] && [ "${adb_nftforce}" = "0" ]; then
+ if [ "${adb_nftallow}" = "0" ] && [ "${adb_nftblock}" = "0" ] \
+ && [ "${adb_nftremote}" = "0" ] && [ "${adb_nftforce}" = "0" ] \
+ && [ "${adb_nftbridging}" = "0" ]; then
return
fi
printf "%s\n" "delete table inet adblock"
fi
printf "%s\n" "add table inet adblock"
+
# allow Set
#
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
+
# remote allow Set with timeout, for MACs that should be temporary allowed to bypass dns blocking
#
if [ "${adb_nftremote}" = "1" ] && [ -n "${adb_nftmacremote}" ]; then
printf "%s\n" "add set inet adblock mac_remote { type ether_addr; flags timeout; timeout ${adb_nftremotetimeout}m; }"
fi
- # block Set
+
+ # adblock pre-routing chain for allow/block rules
#
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// /, } }; }"
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"
+ # dns-bridge base chain
+ #
+ printf "%s\n" "add chain inet adblock dns-bridge { type nat hook prerouting priority -160; policy accept; }"
+
# reject chain rules
#
printf "%s\n" "add rule inet adblock _reject meta l4proto tcp counter reject with tcp reset"
[ -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
+ f_log "info" "adblock-related nft allow rules prepared for external DNS ${adb_allowdnsv4:-"-"} / ${adb_allowdnsv6:-"-"}"
fi
# external remote allow rules
if [ "${adb_nftremote}" = "1" ]; then
[ -n "${adb_remotednsv4}" ] && printf "%s\n" "add rule inet adblock pre-routing meta nfproto ipv4 ether saddr @mac_remote meta l4proto { udp, tcp } th dport 53 counter dnat to ${adb_remotednsv4}:53"
[ -n "${adb_remotednsv6}" ] && printf "%s\n" "add rule inet adblock pre-routing meta nfproto ipv6 ether saddr @mac_remote meta l4proto { udp, tcp } th dport 53 counter dnat to [${adb_remotednsv6}]:53"
+ f_log "info" "adblock-related nft remote allow rules prepared for external DNS ${adb_remotednsv4:-"-"} / ${adb_remotednsv6:-"-"} with timeout of ${adb_nftremotetimeout} minutes"
fi
# external block rules
[ -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
+ f_log "info" "adblock-related nft block rules prepared for external DNS ${adb_blockdnsv4:-"-"} / ${adb_blockdnsv6:-"-"}"
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}"
+ *) [ -n "${devices}" ] && devices="${devices} ${device}" || 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_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
fi
done
done
+ f_log "info" "adblock-related nft local DNS enforcement rules prepared for devices: ${adb_nftdevforce// /, } and ports: ${adb_nftportforce// /, }"
fi
} >"${file}"
if "${adb_nftcmd}" -f "${file}" >/dev/null 2>&1; then
- f_log "info" "adblock-related nft rules added"
+ f_log "info" "adblock-related nft rules loaded"
else
- f_log "err" "failed to add adblock-related nft rules"
+ f_log "err" "failed to load adblock-related nft rules"
fi
}
"${adb_sortcmd}" ${adb_srtopts} -u >"${file_name}"
out_rc="${?}"
else
- "${adb_sortcmd}" ${adb_srtopts} -u "${adb_tmpdir}/tmp.deduplicate.${src_name}" 2>/dev/null >"${file_name}"
+ "${adb_sortcmd}" ${adb_srtopts} -u "${adb_tmpdir}/tmp.deduplicate.${src_name}" 2>>"${adb_errorlog}" >"${file_name}"
out_rc="${?}"
fi
fi
if [ -s "${adb_backupdir}/safesearch.${src_name}.gz" ]; then
"${adb_zcatcmd}" "${adb_backupdir}/safesearch.${src_name}.gz" >"${adb_tmpdir}/tmp.load.safesearch.${src_name}"
else
- "${adb_fetchcmd}" ${adb_fetchparm} "${adb_tmpdir}/tmp.load.safesearch.${src_name}" "${safe_url}" 2>/dev/null
+ "${adb_fetchcmd}" ${adb_fetchparm} "${adb_tmpdir}/tmp.load.safesearch.${src_name}" "${safe_url}" 2>>"${adb_errorlog}"
if [ -s "${adb_tmpdir}/tmp.load.safesearch.${src_name}" ]; then
"${adb_gzipcmd}" -cf "${adb_tmpdir}/tmp.load.safesearch.${src_name}" >"${adb_backupdir}/safesearch.${src_name}.gz"
fi
esac
if [ -n "${safe_domains}" ] && [ -n "${safe_cname}" ]; then
if [ "${use_cname}" = "0" ]; then
- safe_ips="$("${adb_lookupcmd}" "${safe_cname}" 2>/dev/null | "${adb_awkcmd}" '/^Address[ 0-9]*: /{ORS=" ";print $NF}')"
+ safe_ips="$("${adb_lookupcmd}" "${safe_cname}" 2>>"${adb_errorlog}" | "${adb_awkcmd}" '/^Address[ 0-9]*: /{ORS=" ";print $NF}')"
fi
if [ -n "${safe_ips}" ] || [ "${use_cname}" = "1" ]; then
printf "%s\n" ${safe_domains} >"${adb_tmpdir}/tmp.raw.safesearch.${src_name}"
if [ "${adb_tld}" = "1" ]; then
f_chkdom ${src_rset} < "${src_tmpload}" |
"${adb_awkcmd}" 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' |
- "${adb_sortcmd}" ${adb_srtopts} -u >"${src_tmpfile}" 2>/dev/null
+ "${adb_sortcmd}" ${adb_srtopts} -u >"${src_tmpfile}" 2>>"${adb_errorlog}"
else
f_chkdom ${src_rset} < "${src_tmpload}" |
- "${adb_sortcmd}" ${adb_srtopts} -u >"${src_tmpfile}" 2>/dev/null
+ "${adb_sortcmd}" ${adb_srtopts} -u >"${src_tmpfile}" 2>>"${adb_errorlog}"
fi
out_rc="${?}"
if [ "${out_rc}" = "0" ] && [ -s "${src_tmpfile}" ]; then
fi
;;
"remove")
- rm "${adb_backupdir}/adb_list.${src_name}.gz" 2>/dev/null
+ rm "${adb_backupdir}/adb_list.${src_name}.gz" 2>>"${adb_errorlog}"
out_rc="${?}"
adb_feed="${adb_feed/${src_name}/}"
;;
if [ "${adb_safesearch}" = "1" ] && [ "${adb_dnssafesearch}" != "0" ]; then
files="${files} ! -name safesearch.google.gz"
fi
- "${adb_findcmd}" "${adb_backupdir}" ${files} -print0 2>/dev/null | xargs -0r rm -f 2>/dev/null
+ "${adb_findcmd}" "${adb_backupdir}" ${files} -print0 2>>"${adb_errorlog}" | xargs -0r rm -f
# merge files
#
: > "${file_name}"
out_rc="4"
else
- "${adb_sortcmd}" ${adb_srtopts} -mu ${files} > "${file_name}"
+ "${adb_sortcmd}" ${adb_srtopts} -mu ${files} 2>>"${adb_errorlog}" > "${file_name}"
out_rc="${?}"
fi
- rm -f "${adb_tmpfile}".* 2>/dev/null
+ rm -f "${adb_tmpfile}".*
;;
"final")
src_name=""
rm -f "${file_name}"
[ -n "${adb_dnsheader}" ] && printf "%b" "${adb_dnsheader}" >>"${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}"
+ [ "${adb_safesearch}" = "1" ] && "${adb_catcmd}" "${adb_tmpdir}/tmp.safesearch."* 2>>"${adb_errorlog}" >>"${file_name}"
if [ "${adb_dnsdeny}" != "0" ]; then
eval "${adb_dnsdeny}" "${adb_tmpdir}/${adb_dnsfile}" >>"${file_name}"
else
suffix="${file##*.}"
if [ "${suffix}" = "gz" ]; then
if [ "${adb_tld}" = "1" ]; then
- "${adb_zcatcmd}" "${file}" 2>/dev/null |
+ "${adb_zcatcmd}" "${file}" 2>>"${adb_errorlog}" |
"${adb_awkcmd}" 'BEGIN{FS="."}{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' |
"${adb_awkcmd}" -v f="${file##*/}" "BEGIN{rc=1};/^($search|.*\\.${search})$/{i++;if(i<=3){printf \" + %-30s%s\n\",f,\$1;rc=0}else if(i==4){printf \" + %-30s%s\n\",f,\"[...]\"}};END{exit rc}"
else
- "${adb_zcatcmd}" "${file}" 2>/dev/null |
+ "${adb_zcatcmd}" "${file}" 2>>"${adb_errorlog}" |
"${adb_awkcmd}" -v f="${file##*/}" "BEGIN{rc=1};/^($search|.*\\.${search})$/{i++;if(i<=3){printf \" + %-30s%s\n\",f,\$1;rc=0}else if(i==4){printf \" + %-30s%s\n\",f,\"[...]\"}};END{exit rc}"
fi
rc="${?}"
#
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_remote="0" nft_force="0"
+ local duration jail="0" nft_unfiltered="0" nft_filtered="0" nft_remote="0" nft_bridge="0" nft_force="0"
if [ -n "${adb_dnspid}" ]; then
- pids="$("${adb_pgrepcmd}" -P "${adb_dnspid}" 2>/dev/null)"
+ pids="$("${adb_pgrepcmd}" -P "${adb_dnspid}" 2>>"${adb_errorlog}")"
for pid in ${adb_dnspid} ${pids}; do
- dns_mem="$((dns_mem + $("${adb_awkcmd}" '/^VmSize/{printf "%s", $2}' "/proc/${pid}/status" 2>/dev/null)))"
+ dns_mem="$((dns_mem + $("${adb_awkcmd}" '/^VmSize/{printf "%s", $2}' "/proc/${pid}/status" 2>>"${adb_errorlog}")))"
done
case "${adb_dns}" in
"kresd")
;;
esac
dns_ver="$(printf "%s" "${adb_packages}" | "${adb_jsoncmd}" -ql1 -e "@.packages[\"${dns:-"${adb_dns}"}\"]")"
- dns_mem="$("${adb_awkcmd}" -v mem="${dns_mem}" 'BEGIN{printf "%.2f", mem/1024}' 2>/dev/null)"
+ dns_mem="$("${adb_awkcmd}" -v mem="${dns_mem}" 'BEGIN{printf "%.2f", mem/1024}' 2>>"${adb_errorlog}")"
fi
- free_mem="$("${adb_awkcmd}" '/^MemAvailable/{printf "%.2f", $2/1024}' "/proc/meminfo" 2>/dev/null)"
+ free_mem="$("${adb_awkcmd}" '/^MemAvailable/{printf "%.2f", $2/1024}' "/proc/meminfo" 2>>"${adb_errorlog}")"
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
&& { [ -n "${adb_remotednsv4}" ] || [ -n "${adb_remotednsv6}" ]; }; then
nft_remote="1"
fi
+ if [ "${adb_nftbridge}" = "1" ] \
+ && { [ -n "${adb_bridgednsv4}" ] || [ -n "${adb_bridgednsv6}" ]; }; then
+ nft_bridge="1"
+ fi
case "${status}" in
"enabled")
if [ -n "${adb_starttime}" ] && [ "${adb_action}" != "boot" ]; then
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}"
- json_add_string "run_flags" "shift: $(f_char ${adb_dnsshift}), custom feed: $(f_char ${custom_feed}), ext. DNS (std/prot/remote): $(f_char ${nft_unfiltered})/$(f_char ${nft_filtered})/$(f_char ${nft_remote}), 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 "run_information" "base: ${adb_basedir}, dns: ${adb_dnsdir}, backup: ${adb_backupdir}, report: ${adb_reportdir}, error: ${adb_errorlog}"
+ json_add_string "run_flags" "shift: $(f_char ${adb_dnsshift}), custom feed: $(f_char ${custom_feed}), ext. DNS (std/prot/remote/bridge): $(f_char ${nft_unfiltered})/$(f_char ${nft_filtered})/$(f_char ${nft_remote})/$(f_char ${nft_bridge}), 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}"
#
if [ "${adb_jail}" = "1" ] && [ "${adb_dnsstop}" != "0" ]; then
"${adb_mvcmd}" -f "${adb_tmpdir}/${adb_dnsfile}" "${adb_finaldir}/${adb_dnsfile}"
- chown "${adb_dnsuser}" "${adb_finaldir}/${adb_dnsfile}" 2>/dev/null
+ chown "${adb_dnsuser}" "${adb_finaldir}/${adb_dnsfile}" 2>>"${adb_errorlog}"
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
continue
fi
fi
+
# etag handling on reload
#
if [ -n "${adb_etagparm}" ] && [ "${adb_action}" = "reload" ]; then
fi
fi
fi
+
# normal download
#
for suffix in ${src_cat}; do
else
(
[ "${src_name}" = "utcapitole" ] && src_cat="${adb_utc_feed}"
+
# restore handling on boot, resume or (re-)start
#
if [ "${adb_action}" = "boot" ] || [ "${adb_action}" = "start" ] || [ "${adb_action}" = "restart" ] || [ "${adb_action}" = "resume" ]; then
continue
fi
fi
+
# etag handling on reload
#
if [ -n "${adb_etagparm}" ] && [ "${adb_action}" = "reload" ]; then
fi
fi
fi
+
# normal download
#
if [ "${src_name}" = "utcapitole" ]; then
src_rc="${?}"
if [ "${src_rc}" = "0" ] && [ -s "${src_tmparchive}" ]; then
src_suffix="$(eval printf "%s" \"\$\{adb_src_suffix_${src_name}:-\"domains\"\}\")"
- src_list="$(tar -tzf "${src_tmparchive}" 2>/dev/null)"
+ src_list="$(tar -tzf "${src_tmparchive}" 2>>"${adb_errorlog}")"
for src_item in ${src_cat}; do
src_entries="${src_entries} $(printf "%s" "${src_list}" | "${adb_grepcmd}" -E "${src_item}/${src_suffix}$")"
done
if [ -n "${src_entries}" ]; then
- tar -xOzf "${src_tmparchive}" ${src_entries} 2>/dev/null >"${src_tmpload}"
+ tar -xOzf "${src_tmparchive}" ${src_entries} 2>>"${adb_errorlog}" >"${src_tmpload}"
src_rc="${?}"
fi
: >"${src_tmparchive}"
printf "%b" "${adb_dnsheader}" >"${adb_finaldir}/${adb_dnsfile}"
f_log "info" "no merge input, only header written to ${adb_finaldir}/${adb_dnsfile}"
fi
- chown "${adb_dnsuser}" "${adb_finaldir}/${adb_dnsfile}" 2>/dev/null
+ chown "${adb_dnsuser}" "${adb_finaldir}/${adb_dnsfile}" 2>>"${adb_errorlog}"
if f_dnsup; then
[ "${adb_action}" != "resume" ] && f_jsnup "enabled"
f_log "info" "blocklist with overall ${adb_cnt} blocked domains loaded successfully (${adb_sysver})"
[ "${adb_represolve}" = "1" ] && resolve=""
for file in "${adb_reportdir}/adb_report.pcap"*; do
(
- "${adb_dumpcmd}" ${resolve} --immediate-mode -tttt -T domain -r "${file}" 2>/dev/null |
+ "${adb_dumpcmd}" ${resolve} --immediate-mode -tttt -T domain -r "${file}" 2>>"${adb_errorlog}" |
"${adb_awkcmd}" -v repiface="${adb_repiface}" '
BEGIN {
pending = 0
fi
for ip in ${ip_v4} ${ip_v6}; do
(
- "${adb_fetchcmd}" ${adb_geoparm} "${adb_geourl}/${ip}" 2>/dev/null |
+ "${adb_fetchcmd}" ${adb_geoparm} "${adb_geourl}/${ip}" 2>>"${adb_errorlog}" |
"${adb_awkcmd}" -v feed="homeIP" '{printf ",{\"%s\": %s}\n",feed,$0}' >>"${map_jsn}"
) &
[ "${cnt}" -gt "${adb_cores}" ] && wait -n
json_get_var domain "domain" >/dev/null 2>&1
if [ "${rc}" = "NX" ] && ! "${adb_grepcmd}" -q "\"${domain}\":" "${map_jsn}"; then
(
- "${adb_fetchcmd}" ${adb_geoparm} "${adb_geourl}/${domain}" 2>/dev/null |
+ "${adb_fetchcmd}" ${adb_geoparm} "${adb_geourl}/${domain}" 2>>"${adb_errorlog}" |
"${adb_awkcmd}" -v feed="${domain}" '{printf ",{\"%s\": %s}\n",feed,$0}' >>"${map_jsn}"
) &
[ "${cnt}" -gt "${adb_cores}" ] && wait -n
fi
json_select ".."
done
- content="$("${adb_catcmd}" "${report_txt}" 2>/dev/null)"
+ content="$("${adb_catcmd}" "${report_txt}" 2>>"${adb_errorlog}")"
rm -f "${report_txt}"
fi
;;
"json")
if [ "${adb_map}" = "1" ] && [ -s "${map_jsn}" ]; then
- jsn="$("${adb_catcmd}" ${report_jsn} ${map_jsn} 2>/dev/null)"
+ jsn="$("${adb_catcmd}" ${report_jsn} ${map_jsn} 2>>"${adb_errorlog}")"
[ -n "${jsn}" ] && printf "[%s]]\n" "${jsn}"
else
- jsn="$("${adb_catcmd}" ${report_jsn} 2>/dev/null)"
+ jsn="$("${adb_catcmd}" ${report_jsn} 2>>"${adb_errorlog}")"
[ -n "${jsn}" ] && printf "[%s]\n" "${jsn}"
fi
;;
"restart")
f_temp
f_jsnup "processing"
- f_nftremove
f_rmdns
f_env
f_main