]> git.99rst.org Git - openwrt-packages.git/commitdiff
https-dns-proxy: update to 2026.05.06-1
authorStan Grishin <redacted>
Fri, 17 Jul 2026 18:24:22 +0000 (18:24 +0000)
committerStan Grishin <redacted>
Sun, 19 Jul 2026 00:26:36 +0000 (17:26 -0700)
Maintainer: me
Compile tested: x86_64, Dell EMC Edge620, OpenWrt 25.12.4
Run tested: x86_64, Dell EMC Edge620, OpenWrt 25.12.4

Description:
Update to 2026.05.06 and add IP family option

  - Update PKG_VERSION to 2026.05.06
  - Update PKG_RELEASE to 1
  - Add PKG_CPE_ID for CVE tracking
  - Update PKG_MIRROR_HASH and PKG_SOURCE_VERSION

files/etc/config/https-dns-proxy:
  - Add comments for default options
  - Add new 'force_ip_family' option to control IP family for resolvers
  - Update default 'bootstrap_dns' to include IPv6 addresses

files/etc/init.d/https-dns-proxy:
  - Add DEFAULT_BOOTSTRAP4 and DEFAULT_BOOTSTRAP6 for family fallbacks
  - Change 'global_force_ipv6' to 'global_force_ip_family' for new option
  - Modify append_boot to filter bootstrap DNS by 'force_ip_family'
  - Implement fallback bootstrap DNS for forced IP families with no
    compatible configured servers
  - Change 'start_instance' to use 'force_ip_family' instead of
    'force_ipv6'
  - Ensure 'service_started' and 'service_stopped' always return 0 to
    prevent incorrect failure reports for `start`/`reload`/`restart`
    commands

files/etc/uci-defaults/50-https-dns-proxy-migrate-options.sh:
  - Migrate 'force_ipv6_resolvers' option to 'force_ip_family' option
  - Remove old 'force_ipv6_resolvers' option after migration

Signed-off-by: Stan Grishin <redacted>
net/https-dns-proxy/Makefile
net/https-dns-proxy/files/etc/config/https-dns-proxy
net/https-dns-proxy/files/etc/init.d/https-dns-proxy
net/https-dns-proxy/files/etc/uci-defaults/50-https-dns-proxy-migrate-options.sh
net/https-dns-proxy/tests/run_tests.sh

index 11db37807f90417affa03cb2fa6fd4d15f396e43..3695d469c7d216ee6c20b2f081bf2e72cab3324b 100644 (file)
@@ -2,13 +2,14 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=https-dns-proxy
-PKG_VERSION:=2026.03.18
-PKG_RELEASE:=4
+PKG_VERSION:=2026.05.06
+PKG_RELEASE:=1
+PKG_CPE_ID:=cpe:/a:mossdef:https-dns-proxy
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL:=https://github.com/aarond10/https_dns_proxy/
-PKG_MIRROR_HASH:=4c356c19b62fc7bdef3a67fd678e48f3659d709da10517c2eadef76e3409f5ce
-PKG_SOURCE_VERSION:=801881210ba8215dc9cd577222d8c10372423360
+PKG_MIRROR_HASH:=345f14e0a05e032754cea440f5e8798c6896cf5bc7cc12b3c7ed1c8d34e4daad
+PKG_SOURCE_VERSION:=0ba0525fa7c10115cc7c92e99621bfe484ae96e7
 
 PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
 PKG_LICENSE:=MIT
index 62555f8873cc9f95db2d7a48547f95735ea45d01..2198b5af10bfaabe9b2e922f16aa6feada9bb53a 100644 (file)
@@ -1,9 +1,15 @@
 config main 'config'
+# Answer iCloud Private Relay canary domains so DNS-based filtering keeps working
        option canary_domains_icloud '1'
+# Answer Mozilla canary domain so Firefox does not auto-enable its own DoH
        option canary_domains_mozilla '1'
+# dnsmasq instances to point at the proxy ('*' = all, or space-separated indexes/names)
        option dnsmasq_config_update '*'
+# Force LAN clients onto the proxy by redirecting/rejecting their outbound DNS
        option force_dns '1'
+# Add nftables notrack rules for the proxy's loopback DNS traffic
        option notrack_dns '1'
+# Destination ports intercepted by force_dns (53 = DNS, 853 = DoT)
        list force_dns_port '53'
        list force_dns_port '853'
 # ports listed below are used by some
@@ -14,21 +20,37 @@ config main 'config'
 #      list force_dns_port '4434'
 #      list force_dns_port '5443'
 #      list force_dns_port '8443'
+# Interface(s) whose outbound DNS is forced to the proxy
        list force_dns_src_interface 'lan'
+# Also (re)start instances on wan6 interface events
        option procd_trigger_wan6 '0'
+# Domain resolved to confirm the resolver works after start ('-' disables the check)
        option heartbeat_domain 'heartbeat.mossdef.org'
+# Seconds to wait before running the heartbeat check
        option heartbeat_sleep_timeout '10'
+# Seconds to wait for the heartbeat domain to resolve
        option heartbeat_wait_timeout '10'
+# User the proxy drops privileges to
        option user 'nobody'
+# Group the proxy drops privileges to
        option group 'nogroup'
+# Default local address instances bind to
        option listen_addr '127.0.0.1'
+# IP family for resolvers: 'auto' (dual-stack, default), 'ipv4' (IPv4 only + -4), 'ipv6' (IPv6 only)
+       option force_ip_family 'auto'
 
 config https-dns-proxy
-       option bootstrap_dns '1.1.1.1,1.0.0.1'
+# Plain DNS servers used to resolve the DoH resolver hostname at startup
+       option bootstrap_dns '1.1.1.1,1.0.0.1,2606:4700:4700::1111,2606:4700:4700::1001'
+# DoH resolver endpoint (RFC 8484)
        option resolver_url 'https://cloudflare-dns.com/dns-query'
+# Local port this instance listens on
        option listen_port '5053'
 
 config https-dns-proxy
-       option bootstrap_dns '8.8.8.8,8.8.4.4'
+# Plain DNS servers used to resolve the DoH resolver hostname at startup
+       option bootstrap_dns '8.8.8.8,8.8.4.4,2001:4860:4860::8888,2001:4860:4860::8844'
+# DoH resolver endpoint (RFC 8484)
        option resolver_url 'https://dns.google/dns-query'
+# Local port this instance listens on
        option listen_port '5054'
index c81de1dafc4cd2e98d9ea2172f448e3b1ae7e9c5..5803318f5f9756be319dabf6398827cad587df65 100755 (executable)
@@ -25,6 +25,10 @@ readonly PROG=/usr/sbin/https-dns-proxy
 readonly BOOTSTRAP_CF='1.1.1.1,1.0.0.1,2606:4700:4700::1111,2606:4700:4700::1001'
 readonly BOOTSTRAP_GOOGLE='8.8.8.8,8.8.4.4,2001:4860:4860::8888,2001:4860:4860::8844'
 readonly DEFAULT_BOOTSTRAP="${BOOTSTRAP_CF},${BOOTSTRAP_GOOGLE}"
+# Cloudflare/Google servers by family, used as bootstrap fallback when a forced
+# IP family has no compatible server in the instance's configured bootstrap_dns.
+readonly DEFAULT_BOOTSTRAP4='1.1.1.1,1.0.0.1,8.8.8.8,8.8.4.4'
+readonly DEFAULT_BOOTSTRAP6='2606:4700:4700::1111,2606:4700:4700::1001,2001:4860:4860::8888,2001:4860:4860::8844'
 readonly canaryDomainsMozilla='use-application-dns.net'
 readonly canaryDomainsiCloud='mask.icloud.com mask-h2.icloud.com'
 readonly NOTRACK_NFT_FILE='/usr/share/nftables.d/ruleset-post/20-https-dns-proxy-notrack.nft'
@@ -57,7 +61,7 @@ global_polling_interval=
 global_proxy_server=
 global_force_http1=
 global_force_http3=
-global_force_ipv6=
+global_force_ip_family=
 global_max_idle_time=
 global_conn_loss_time=
 global_ca_certs_file=
@@ -223,14 +227,24 @@ append_boot() {
        [ -z "$_loctmp" ] && return 0
        IFS=" ,"
        for i in $_loctmp; do
-               if { [ -z "$force_ipv6" ] && is_ipv4 "$i"; } || \
-                       { [ -n "$force_ipv6" ] && is_ipv6 "$i"; }; then
-                       [ -z "$_newtmp" ] && _newtmp="$i" || _newtmp="${_newtmp},${i}"
-               fi
+               case "$force_ip_family" in
+                       ipv4) is_ipv4 "$i" || continue;;
+                       ipv6) is_ipv6 "$i" || continue;;
+               esac
+               [ -z "$_newtmp" ] && _newtmp="$i" || _newtmp="${_newtmp},${i}"
        done
        IFS="$_old_ifs"
+       # A forced family with no compatible bootstrap server configured would leave the
+       # proxy unable to resolve the resolver host; fall back to the Cloudflare/Google
+       # servers of the forced family so bootstrap still works.
+       if [ -z "$_newtmp" ]; then
+               case "$force_ip_family" in
+                       ipv4) _newtmp="$DEFAULT_BOOTSTRAP4";;
+                       ipv6) _newtmp="$DEFAULT_BOOTSTRAP6";;
+               esac
+       fi
        [ -n "$_newtmp" ] && xappend "$switch $_newtmp"
-       [ -z "$force_ipv6" ] && xappend '-4'
+       [ "$force_ip_family" = 'ipv4' ] && xappend '-4'
 }
 
 boot() {
@@ -248,7 +262,7 @@ load_package_config() {
        config_get_bool procd_trigger_wan6     'config' 'procd_trigger_wan6' '0'
        config_get_bool global_force_http1     'config' 'force_http1' '0'
        config_get_bool global_force_http3     'config' 'force_http3' '0'
-       config_get_bool global_force_ipv6      'config' 'force_ipv6_resolvers' '0'
+       config_get global_force_ip_family      'config' 'force_ip_family' 'auto'
        config_get dnsmasq_config_update       'config' 'dnsmasq_config_update' '*'
        config_get force_dns_port              'config' 'force_dns_port' '53 853'
        config_get force_dns_src_interface     'config' 'force_dns_src_interface' 'lan'
@@ -276,13 +290,12 @@ load_package_config() {
 start_instance() {
        local cfg="$1" param="$2"
        local PROG_param
-       local listen_addr listen_port force_ipv6 p url iface
+       local listen_addr listen_port force_ip_family p url iface
 
        config_get url             "$cfg" 'resolver_url'
        config_get listen_addr     "$cfg" 'listen_addr' "$global_listen_addr"
        config_get listen_port     "$cfg" 'listen_port' "$port"
-       config_get_bool force_ipv6 "$cfg" 'force_ipv6_resolvers' "$global_force_ipv6"
-       [ "$force_ipv6" = '1' ] || unset force_ipv6
+       config_get force_ip_family "$cfg" 'force_ip_family' "$global_force_ip_family"
 
        append_parm "$cfg" 'resolver_url'       '-r'
        append_parm "$cfg" 'listen_addr'        '-a' "$global_listen_addr"        '127.0.0.1'
@@ -460,8 +473,12 @@ service_triggers() {
        fi
 }
 
-service_started() { { [ -n "$force_dns" ] || [ -n "$notrack_dns" ]; } && procd_set_config_changed firewall; }
-service_stopped() { { [ -n "$force_dns" ] || [ -n "$notrack_dns" ]; } && procd_set_config_changed firewall; }
+# These run for their side effect only (flag the firewall for reconfig). Force a
+# 0 return so a falsy test doesn't become the exit code of start/reload/restart —
+# force_dns/notrack_dns are empty in this scope, so without this restart exits 1
+# even on a successful start. See issue #11.
+service_started() { { [ -n "$force_dns" ] || [ -n "$notrack_dns" ]; } && procd_set_config_changed firewall; return 0; }
+service_stopped() { { [ -n "$force_dns" ] || [ -n "$notrack_dns" ]; } && procd_set_config_changed firewall; return 0; }
 restart() { reload "$@"; }
 
 dnsmasq_instance_append_force_dns_port() {
index 6716bd7105afa11dafafc7a5f9c0f2e621a052a9..b46bab3730478a6b0b46e2d0d80f4dc2b2bb43ec 100644 (file)
@@ -6,3 +6,5 @@ sed -i "s|wan6_trigger|procd_trigger_wan6|" "/etc/config/https-dns-proxy"
 sed -i "s|procd_fw_src_interfaces|force_dns_src_interface|" "/etc/config/https-dns-proxy"
 sed -i "s|use_http1|force_http1|" "/etc/config/https-dns-proxy"
 sed -i "s|use_ipv6_resolvers_only|force_ipv6_resolvers|" "/etc/config/https-dns-proxy"
+sed -i "s|option force_ipv6_resolvers '1'|option force_ip_family 'ipv6'|" "/etc/config/https-dns-proxy"
+sed -i "/option force_ipv6_resolvers/d" "/etc/config/https-dns-proxy"
index 2074071608d594ddeba0bdbc8d44045ae0a8f31f..9bf4bee5bb4390c35dd4883c8d6967080d7473cc 100644 (file)
@@ -529,6 +529,44 @@ assert_eq "xappend adds parameter" " -r https://dns.google/dns-query" "$PROG_par
 xappend "-p 5053"
 assert_eq "xappend appends parameter" " -r https://dns.google/dns-query -p 5053" "$PROG_param"
 
+printf "\n##\n## 07b: append_boot (force_ip_family)\n##\n\n"
+
+rm -f "$__uci_store"/*
+__cfg_package="https-dns-proxy"
+uci_set "https-dns-proxy" "inst" "bootstrap_dns" "1.1.1.1,2606:4700:4700::1111"
+
+# auto: keep both families, no -4
+PROG_param=""; force_ip_family="auto"
+append_boot "inst" 'bootstrap_dns' '-b' "$DEFAULT_BOOTSTRAP"
+assert_eq "append_boot auto keeps both families, no -4" " -b 1.1.1.1,2606:4700:4700::1111" "$PROG_param"
+
+# ipv4: v4 only + -4
+PROG_param=""; force_ip_family="ipv4"
+append_boot "inst" 'bootstrap_dns' '-b' "$DEFAULT_BOOTSTRAP"
+assert_eq "append_boot ipv4 keeps v4 and adds -4" " -b 1.1.1.1 -4" "$PROG_param"
+
+# ipv6: v6 only, no -4
+PROG_param=""; force_ip_family="ipv6"
+append_boot "inst" 'bootstrap_dns' '-b' "$DEFAULT_BOOTSTRAP"
+assert_eq "append_boot ipv6 keeps v6, no -4" " -b 2606:4700:4700::1111" "$PROG_param"
+
+# forced ipv6 but config bootstrap has only v4 → fall back to CF/Google v6
+uci_set "https-dns-proxy" "v4only" "bootstrap_dns" "1.1.1.1,8.8.8.8"
+PROG_param=""; force_ip_family="ipv6"
+append_boot "v4only" 'bootstrap_dns' '-b' "$DEFAULT_BOOTSTRAP"
+assert_eq "append_boot ipv6 falls back to CF/Google v6" \
+       " -b 2606:4700:4700::1111,2606:4700:4700::1001,2001:4860:4860::8888,2001:4860:4860::8844" "$PROG_param"
+
+# forced ipv4 but config bootstrap has only v6 → fall back to CF/Google v4 + -4
+uci_set "https-dns-proxy" "v6only" "bootstrap_dns" "2606:4700:4700::1111"
+PROG_param=""; force_ip_family="ipv4"
+append_boot "v6only" 'bootstrap_dns' '-b' "$DEFAULT_BOOTSTRAP"
+assert_eq "append_boot ipv4 falls back to CF/Google v4 and adds -4" \
+       " -b 1.1.1.1,1.0.0.1,8.8.8.8,8.8.4.4 -4" "$PROG_param"
+
+unset force_ip_family
+rm -f "$__uci_store"/*
+
 printf "\n##\n## 08: UCI migration script\n##\n\n"
 
 MIGRATION_SCRIPT="./files/etc/uci-defaults/50-https-dns-proxy-migrate-options.sh"
@@ -541,7 +579,10 @@ config main 'config'
        option wan6_trigger '0'
        option procd_fw_src_interfaces 'lan'
        option use_http1 '0'
-       option use_ipv6_resolvers_only '0'
+       option use_ipv6_resolvers_only '1'
+
+config https-dns-proxy 'disabled_family'
+       option force_ipv6_resolvers '0'
 CONF
 
        # Run the migration sed commands against our test file
@@ -550,6 +591,8 @@ CONF
        sed -i "s|procd_fw_src_interfaces|force_dns_src_interface|" "$MIGRATE_CONF"
        sed -i "s|use_http1|force_http1|" "$MIGRATE_CONF"
        sed -i "s|use_ipv6_resolvers_only|force_ipv6_resolvers|" "$MIGRATE_CONF"
+       sed -i "s|option force_ipv6_resolvers '1'|option force_ip_family 'ipv6'|" "$MIGRATE_CONF"
+       sed -i "/option force_ipv6_resolvers/d" "$MIGRATE_CONF"
 
        grep -q "dnsmasq_config_update" "$MIGRATE_CONF"
        assert_rc "migration: update_dnsmasq_config → dnsmasq_config_update" 0 $?
@@ -563,8 +606,17 @@ CONF
        grep -q "force_http1" "$MIGRATE_CONF"
        assert_rc "migration: use_http1 → force_http1" 0 $?
 
+       grep -q "option force_ip_family 'ipv6'" "$MIGRATE_CONF"
+       assert_rc "migration: enabled force_ipv6_resolvers → force_ip_family=ipv6" 0 $?
+
        grep -q "force_ipv6_resolvers" "$MIGRATE_CONF"
-       assert_rc "migration: use_ipv6_resolvers_only → force_ipv6_resolvers" 0 $?
+       assert_rc "migration: force_ipv6_resolvers option retired" 1 $?
+
+       grep -qw "use_ipv6_resolvers_only" "$MIGRATE_CONF"
+       assert_rc "migration: old name use_ipv6_resolvers_only removed" 1 $?
+
+       [ "$(grep -c 'option force_ip_family' "$MIGRATE_CONF")" = "1" ]
+       assert_rc "migration: disabled force_ipv6_resolvers dropped (defaults to auto)" 0 $?
 
        # Verify old names are gone
        grep -q "update_dnsmasq_config" "$MIGRATE_CONF"
@@ -595,7 +647,7 @@ uci_set "https-dns-proxy" "config" "force_dns" "1"
 uci_set "https-dns-proxy" "config" "procd_trigger_wan6" "0"
 uci_set "https-dns-proxy" "config" "force_http1" "0"
 uci_set "https-dns-proxy" "config" "force_http3" "0"
-uci_set "https-dns-proxy" "config" "force_ipv6_resolvers" "0"
+uci_set "https-dns-proxy" "config" "force_ip_family" "auto"
 
 # Reset globals before load
 canary_domains_icloud=""
@@ -611,6 +663,7 @@ assert_eq "load_package_config: force_dns=1" "1" "$force_dns"
 assert_eq "load_package_config: global_user defaults to nobody" "nobody" "$global_user"
 assert_eq "load_package_config: global_group defaults to nogroup" "nogroup" "$global_group"
 assert_eq "load_package_config: global_listen_addr defaults to 127.0.0.1" "127.0.0.1" "$global_listen_addr"
+assert_eq "load_package_config: global_force_ip_family=auto" "auto" "$global_force_ip_family"
 
 # Canary domains should be populated
 echo "$canaryDomains" | grep -q "mask.icloud.com"
@@ -626,7 +679,7 @@ uci_set "https-dns-proxy" "config" "force_dns" "0"
 uci_set "https-dns-proxy" "config" "procd_trigger_wan6" "0"
 uci_set "https-dns-proxy" "config" "force_http1" "0"
 uci_set "https-dns-proxy" "config" "force_http3" "0"
-uci_set "https-dns-proxy" "config" "force_ipv6_resolvers" "0"
+uci_set "https-dns-proxy" "config" "force_ip_family" "auto"
 
 canaryDomains=""
 load_package_config
@@ -634,6 +687,18 @@ load_package_config
 assert_eq "load_package_config: canary disabled → canaryDomains empty" "" "$canaryDomains"
 assert_eq "load_package_config: force_dns=0 → unset" "" "$force_dns"
 
+printf "\n##\n## 9b: service_started/service_stopped exit code (issue #11)\n##\n\n"
+
+# These run only for the procd_set_config_changed side effect. When force_dns and
+# notrack_dns are both empty the guard test is false; without an explicit
+# 'return 0' the function's exit status (1) becomes the exit code of
+# start/reload/restart, so a successful restart wrongly reports failure.
+force_dns='' notrack_dns=''
+service_started; assert_rc "service_started returns 0 when force_dns/notrack_dns empty" 0 $?
+service_stopped; assert_rc "service_stopped returns 0 when force_dns/notrack_dns empty" 0 $?
+force_dns='1' notrack_dns=''
+service_started; assert_rc "service_started returns 0 when force_dns set" 0 $?
+
 printf "\n##\n## 10: notrack_nft (regression: missing nftables.d/ruleset-post dir)\n##\n\n"
 
 # Reset state — ensure parent dir does NOT exist (this is the apk-install
git clone https://git.99rst.org/PROJECT