]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Add new static zone type block_aaaa to suppress AAAA queries (#1433)
authorJisakiel <471530+jisakiel@users.noreply.github.com>
Fri, 24 Jul 2026 06:52:20 +0000 (07:52 +0100)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2026 06:52:20 +0000 (08:52 +0200)
Following d5b9a790f lead for block_a - this would allow suppressing AAAA queries instead for sticking to IPV4.

Co-authored-by: Jisakiel <jisakiel@users.noreply.github.com>
doc/example.conf.in
doc/unbound.conf.5.in
doc/unbound.conf.rst
services/localzone.c
services/localzone.h
util/configparser.y

index 5250ef456e1e805930cfb560f1853c92c7259df4..f1e1e412bc983d204fff717dbaf4ec7189ff12e6 100644 (file)
@@ -899,6 +899,8 @@ server:
        #   that name
        # o block_a resolves all records normally but returns
        #   NODATA for A queries and ignores local data for that name
+       # o block_aaaa similarly to block_a, resolves all records normally but
+       #   returns NODATA for AAAA queries and ignores local data for that name
        # o always_null returns 0.0.0.0 or ::0 for any name in the zone.
        # o noview breaks out of that view towards global local-zones.
        #
index 25fcca373a9ea22f747112d2932b7abd0730528f..ae1dc851941477c31b53b782f2d8f06ec64fb602 100644 (file)
@@ -2910,6 +2910,7 @@ The types are
 \fI\%inform_redirect\fP,
 \fI\%always_transparent\fP,
 \fI\%block_a\fP,
+\fI\%block_aaaa\fP,
 \fI\%always_refuse\fP,
 \fI\%always_nxdomain\fP,
 \fI\%always_null\fP,
@@ -3100,6 +3101,15 @@ use IPv6 protocol and avoid any queries to IPv4.
 .UNINDENT
 .INDENT 7.0
 .TP
+.B block_aaaa 
+Like \fI\%transparent\fP or \fI\%block_a\fP, but
+ignores local data and resolves normally all query types excluding AAAA.
+For AAAA queries it unconditionally returns NODATA.
+Useful in cases when there is a need to explicitly force all apps to
+use IPv4 protocol and avoid any queries to IPv6.
+.UNINDENT
+.INDENT 7.0
+.TP
 .B always_refuse 
 Like \fI\%refuse\fP, but ignores
 local data and refuses the query.
index 649bd2ab81904bee693498bec183af322c6fa6a4..71259afd952b287486b12056fcdf573f977121ee 100644 (file)
@@ -2592,6 +2592,7 @@ These options are part of the ``server:`` section.
     :ref:`inform_redirect<unbound.conf.local-zone.type.inform_redirect>`,
     :ref:`always_transparent<unbound.conf.local-zone.type.always_transparent>`,
     :ref:`block_a<unbound.conf.local-zone.type.block_a>`,
+    :ref:`block_aaaa<unbound.conf.local-zone.type.block_aaaa>`,
     :ref:`always_refuse<unbound.conf.local-zone.type.always_refuse>`,
     :ref:`always_nxdomain<unbound.conf.local-zone.type.always_nxdomain>`,
     :ref:`always_null<unbound.conf.local-zone.type.always_null>`,
@@ -2741,6 +2742,14 @@ These options are part of the ``server:`` section.
         Useful in cases when there is a need to explicitly force all apps to
         use IPv6 protocol and avoid any queries to IPv4.
 
+    @@UAHL@unbound.conf.local-zone.type@block_aaaa@@
+        Like :ref:`transparent<unbound.conf.local-zone.type.transparent>` or
+        :ref:`block_a<unbound.conf.local-zone.type.block_a>`, but
+        ignores local data and resolves normally all query types excluding AAAA.
+        For AAAA queries it unconditionally returns NODATA.
+        Useful in cases when there is a need to explicitly force all apps to
+        use IPv4 protocol and avoid any queries to IPv6.
+
     @@UAHL@unbound.conf.local-zone.type@always_refuse@@
         Like :ref:`refuse<unbound.conf.local-zone.type.refuse>`, but ignores
         local data and refuses the query.
index 77fc5b6b907a97906823f1b85e9b5c52c8d5a626..5d376cb156f0eb30b7efe5f6bb202afa62105afa 100644 (file)
@@ -1668,7 +1668,7 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
        struct local_data key;
        struct local_data* ld = NULL;
        struct local_rrset* lr = NULL;
-       if(z->type == local_zone_always_transparent || z->type == local_zone_block_a)
+       if(z->type == local_zone_always_transparent || z->type == local_zone_block_a || z->type == local_zone_block_aaaa)
                return 1;
        if(z->type != local_zone_transparent
                && z->type != local_zone_typetransparent
@@ -1754,6 +1754,16 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                                return 1;
                }
 
+               return 0;
+       } else if(lz_type == local_zone_block_aaaa) {
+               /* Return NODATA for all AAAA queries */
+               if(qinfo->qtype == LDNS_RR_TYPE_AAAA) {
+                       local_error_encode(qinfo, env, edns, repinfo, buf, temp,
+                               LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA),
+                               LDNS_EDE_NONE, NULL);
+                               return 1;
+               }
+
                return 0;
        } else if(lz_type == local_zone_always_null) {
                /* 0.0.0.0 or ::0 or noerror/nodata for this zone type,
@@ -1922,7 +1932,8 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
                        lzt == local_zone_typetransparent ||
                        lzt == local_zone_inform ||
                        lzt == local_zone_always_transparent ||
-                       lzt == local_zone_block_a) &&
+                       lzt == local_zone_block_a ||
+                       lzt == local_zone_block_aaaa) &&
                        local_zone_does_not_cover(z, qinfo, labs)) {
                        lock_rw_unlock(&z->lock);
                        z = NULL;
@@ -1971,6 +1982,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
        if(lzt != local_zone_always_refuse
                && lzt != local_zone_always_transparent
                && lzt != local_zone_block_a
+               && lzt != local_zone_block_aaaa
                && lzt != local_zone_always_nxdomain
                && lzt != local_zone_always_nodata
                && lzt != local_zone_always_deny
@@ -2002,6 +2014,7 @@ const char* local_zone_type2str(enum localzone_type t)
                case local_zone_inform_redirect: return "inform_redirect";
                case local_zone_always_transparent: return "always_transparent";
                case local_zone_block_a: return "block_a";
+               case local_zone_block_aaaa: return "block_aaaa";
                case local_zone_always_refuse: return "always_refuse";
                case local_zone_always_nxdomain: return "always_nxdomain";
                case local_zone_always_nodata: return "always_nodata";
@@ -2038,6 +2051,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
                *t = local_zone_always_transparent;
        else if(strcmp(type, "block_a") == 0)
                *t = local_zone_block_a;
+       else if(strcmp(type, "block_aaaa") == 0)
+               *t = local_zone_block_aaaa;
        else if(strcmp(type, "always_refuse") == 0)
                *t = local_zone_always_refuse;
        else if(strcmp(type, "always_nxdomain") == 0)
index e3fb0afe3e4a247abfd952d62ac77608d14e74c6..de263348615c0d12c0d192539693ab2fdbe34baa 100644 (file)
@@ -93,6 +93,8 @@ enum localzone_type {
        local_zone_always_transparent,
        /** resolve normally, even when there is local data but return NODATA for A queries */
        local_zone_block_a,
+       /** resolve normally, even when there is local data, but return NODATA for AAAA queries */
+       local_zone_block_aaaa,
        /** answer with error, even when there is local data */ 
        local_zone_always_refuse,
        /** answer with nxdomain, even when there is local data */
index 9e1cd611b79c83d54b91282d859de68e02dad1c4..64fdfc41e2846db3a59b08bba78f964c313eab70 100644 (file)
@@ -2395,6 +2395,7 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
                   && strcmp($3, "typetransparent")!=0
                   && strcmp($3, "always_transparent")!=0
                   && strcmp($3, "block_a")!=0
+                  && strcmp($3, "block_aaaa")!=0
                   && strcmp($3, "always_refuse")!=0
                   && strcmp($3, "always_nxdomain")!=0
                   && strcmp($3, "always_nodata")!=0
@@ -2407,7 +2408,8 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
                        yyerror("local-zone type: expected static, deny, "
                                "refuse, redirect, transparent, "
                                "typetransparent, inform, inform_deny, "
-                               "inform_redirect, always_transparent, block_a, "
+                               "inform_redirect, always_transparent, "
+                               "block_a, block_aaaa, "
                                "always_refuse, always_nxdomain, "
                                "always_nodata, always_deny, always_null, "
                                "noview, nodefault or ipset");