unbound-adblock 0.5 errata 004, January 28, 2021:

This is a hotfix release to fix a performance regression introduced in patch 002 and address an issue with whitelisting as well as clean up some unwind related portability glue.

Issues fixed:

* RPZ whitelisting did not function correctly, woops!

* The IS_DOMAIN input santization function was unbearably slow on embedded devices and slow shells, so use a better solution.

* The unwind related code paths were given more doas permissions than necessary, so ratchet them down.

* Use unwindctl to interact with unwind, rather than rcctl

If you use unbound-adblock with unwind, you will need to adjust your doas.conf to read:
...
permit nopass _adblock cmd /usr/sbin/unwindctl args reload
...

Apply by doing: (Note: Provided file path is for OpenBSD, other platforms path may differ)

patch /usr/local/bin/unbound-adblock < p3.patch

NOTE: This patch is dependent on all previously released patches.
To check which patch/version of unbound-adblock you're running call unbound-adblock with the '-h' switch; the second line of output will show the version info:
$ unbound-adblock -h
...
# unbound-adblock 0.5p0 (Gaslight Republic)  Released on: 2021-01-10
...

'0.5p0' means you have the first patch installed, if there is no "p*" suffix, then that means you have no patches installed.


--- unbound-adblock.sh.orig3	Sat Jan 23 16:17:30 2021
+++ unbound-adblock.sh	Thu Jan 28 14:09:29 2021
@@ -23,7 +23,7 @@
 # Fetch, parse and generate domain blocklists data into format suitable 
 # for ingestion by RPZ compatible DNS servers and/or unbound/unwind.
 
-version='0.5p2'
+version='0.5p3'
 release_date='2021-01-10'
 release_name='Gaslight Republic'
 
@@ -159,7 +159,7 @@
 	cp -- "${oldconf}" "${confpath}" || WARN_ERR 'ERROR: Failed to to restore previous blocklist!'
 	if [ "${_ALT_UNWIND}" -eq 1 ]; then
 		# Unwind config restore
-		if ! "${getroot}" /sbin/unwind -n ; then
+		if ! unwind -n >/dev/null 2>&1; then
 			WARN_ERR 'ERROR: old unwind-adblock.db also has bad data!'
 			WARN_ERR "Clearing ${confpath} and bailing out..."
 			cp -- /dev/null "${confpath}" || WARN_ERR "ERROR: Failed to clear '${confpath}'"
@@ -282,15 +282,14 @@
 	{ find "${tmpdir_hosts}" -type f -exec gunzip -dcf -- {} + | tr -cd -- '[:alnum:][:blank:]%#.~\n_/\-' | FORMAT_HOSTS ;} > "${tmpfile_hosts}" || TMP_FILE_ABORT
 
 	# Merge and sort lists
-	cat -- "${tmpfile_domain}" "${tmpfile_hosts}" | while IFS= read -r _i ; do
-		IS_DOMAIN "${_i}" || true
-	done | WHITELIST_FILTER | mysort -u > "${rawout}" || TMP_FILE_ABORT
+	# Note: We use cat here because the mygrep func expects input from stdin
+	cat -- "${tmpfile_domain}" "${tmpfile_hosts}" | mygrep '^[[:alnum:]._-]*$' | mygrep -v '^\.|^-|\.$|-$' | tr '[:upper:]' '[:lower:]' | WHITELIST_FILTER | mysort -u > "${rawout}" || TMP_FILE_ABORT
 }
 
 
 
 LIST_INSTALL() {
-	typeset new_offset old_offset unbound_control
+	typeset new_offset old_offset unbound_control unwind unwindctl
 
 	# Backup old blocklist
 	cp -- "${confpath}" "${oldconf}" || TMP_FILE_ABORT
@@ -337,9 +336,11 @@
 
 	# Reload unbound/unwind IF needed (RPZ mode doesn't require unbound to be reloaded)
 	if [ "${_ALT_UNWIND}" -eq 1 ]; then
+		unwind="$(CHECK_CMD unwind)"
+		unwindctl="$(CHECK_CMD unwindctl)"
 		# Ensure proposed changes are valid before reloading unwind
-		if "${getroot}" /sbin/unwind -n ; then
-			"${getroot}" -- "${rcd}" "${rcdarg1}" unwind || ABORT
+		if "${unwind}" -n ; then
+			"${getroot}" -- "${unwindctl}" reload >/dev/null 2>&1 || ABORT
 		else
 			ABORT
 		fi
@@ -461,26 +462,6 @@
 	fi
 }
 
-IS_DOMAIN() {
-	typeset -l domain="${1}"
-	typeset prefix suffix
-	prefix="${domain%"${domain#?}"}"
-	suffix="${domain#"${domain%?}"}"
-
-	case "${prefix}" in
-	    .|-) WARNING "Skipping invalid domain: '${1}'" ; return 1 ;;
-	esac
-
-	case "${suffix}" in
-	    .|-) WARNING "Skipping invalid domain: '${1}'" ; return 1 ;;
-	esac
-
-	case "${domain}" in
-	    ''|*[!0-9A-Za-z._-]*) WARNING "Skipping invalid domain: '${1}'" ; return 1 ;;
-	    *) echo "${domain}" ; return 0 ;;
-	esac
-}
-
 IS_INT() {
 	case "$1" in
 	    ''|*[!0-9]*) return 1 ;;
@@ -494,7 +475,7 @@
 	# Make sure requisite utilities are installed
 	for _cmd in 'cmp' 'find' 'gunzip' "${getroot}" "${rcd}" "${netget}" ; do
 		CHECK_CMD "${_cmd}"
-	done > /dev/null
+	done >/dev/null
 
 	if [ "${_NO_UID_CHECK}" -ne 1 ]; then
 		CHECK_PRIVILEGE
@@ -503,9 +484,10 @@
 	# Make sure unbound/unwind is running
 	if [ "${_PRINT_ONLY}" -ne 1 ]; then
 		if [ "${_ALT_UNWIND}" -eq 1 ]; then
-			"${rcd}" check unwind >/dev/null 2>&1 || ERR 'unwind does not appear to be running!'
+			CHECK_CMD 'unwindctl' >/dev/null
+			unwindctl status >/dev/null 2>&1 || ERR 'unwind does not appear to be running!'
 		else
-			CHECK_CMD 'unbound-checkconf' > /dev/null
+			CHECK_CMD 'unbound-checkconf' >/dev/null
 			UNBOUND_STATUS_CHECK || ERR 'unbound does not appear to be running!'
 		fi
 		# Make sure 'unbound-control' is working
@@ -530,11 +512,11 @@
 	dragonflybsd)
 		"${rcd}" unbound onestatus >/dev/null 2>&1 ; return ;;
 	freebsd)
-		"${getroot}" "${rcd}" unbound onestatus >/dev/null 2>&1 ; return ;;
+		"${getroot}" -- "${rcd}" unbound onestatus >/dev/null 2>&1 ; return ;;
 	linux)
 		systemctl is-active --quiet unbound >/dev/null 2>&1 ; return ;;
 	netbsd)
-		"${getroot}" "${rcd}" unbound onestatus >/dev/null 2>&1 ; return ;;
+		"${getroot}" -- "${rcd}" unbound onestatus >/dev/null 2>&1 ; return ;;
 	openbsd)
 		"${rcd}" check unbound >/dev/null 2>&1 ; return ;;
 	*)
@@ -935,7 +917,7 @@
 	# Generate user whitelist rules
 	if [ "${_ALT_RPZ}" -eq 1 ] && [ "${#_user_rule[@]}" -ge 1 ]; then
 		for _i in "${_user_rule[@]}"; do
-			printf '%s CNAME passthru\n' "${_i}"
+			printf '%s CNAME rpz-passthru.\n' "${_i}"
 		done | mysort -u > "${user_rules}"
 	fi
 
