]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix #1477: respip + dns64: dns64 uses A records modified by
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 24 Jul 2026 07:29:17 +0000 (09:29 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 24 Jul 2026 07:29:17 +0000 (09:29 +0200)
  respip instead of original A records. Adds local-zone types
  block_a_wdata and block_aaaa_wdata, that are like block_a
  and block_aaaa, and uses local-data if present.

doc/Changelog
doc/example.conf.in
doc/unbound.conf.rst
services/localzone.c
services/localzone.h
testdata/local_block_a.rpl
util/configparser.y

index 57296b3311bc90a1db99ab33320a9d2e06e3b079..25fd018e004cff67d8e27d73029225a52332e804 100644 (file)
@@ -2,6 +2,10 @@
        - Merge #1433 from jisakiel: Add new static zone type
          block_aaaa to suppress AAAA queries.
        - Unit test for block_a and block_aaaa.
+       - Fix #1477: respip + dns64: dns64 uses A records modified by
+         respip instead of original A records. Adds local-zone types
+         block_a_wdata and block_aaaa_wdata, that are like block_a
+         and block_aaaa, and uses local-data if present.
 
 23 July 2026: Wouter
        - Updated credits for Xuanchao Xie in 22 july changelog.
index f1e1e412bc983d204fff717dbaf4ec7189ff12e6..c5e4e242e8d776d0703a03f7d50e45e679e28a65 100644 (file)
@@ -901,6 +901,8 @@ server:
        #   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 block_a_wdata like block_a but uses local data if present.
+       # o block_aaaa_wdata like block_aaaa but uses local data if present.
        # 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 71259afd952b287486b12056fcdf573f977121ee..e341c516ff84e1328e43694cba44a52a7095e2f8 100644 (file)
@@ -2593,6 +2593,8 @@ These options are part of the ``server:`` section.
     :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:`block_a_wdata<unbound.conf.local-zone.type.block_a_wdata>`,
+    :ref:`block_aaaa_wdata<unbound.conf.local-zone.type.block_aaaa_wdata>`,
     :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>`,
@@ -2750,6 +2752,18 @@ These options are part of the ``server:`` section.
         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@block_a_wdata@@
+        Like :ref:`block_a<unbound.conf.local-zone.type.block_a>`, but
+        uses local data if present.
+        If there is local data that is returned, and it acts like transparent.
+        For A queries it returns NODATA.
+
+    @@UAHL@unbound.conf.local-zone.type@block_aaaa_wdata@@
+        Like :ref:`block_aaaa<unbound.conf.local-zone.type.block_aaaa>`, but
+        uses local data if present.
+        If there is local data that is returned, and it acts like transparent.
+        For AAAA queries it returns NODATA.
+
     @@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 5d376cb156f0eb30b7efe5f6bb202afa62105afa..5de7801277d9cc7b9da0ac32824d32c199dd6ace 100644 (file)
@@ -1679,7 +1679,9 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
        key.namelen = qinfo->qname_len;
        key.namelabs = labs;
        ld = (struct local_data*)rbtree_search(&z->data, &key.node);
-       if(z->type == local_zone_transparent || z->type == local_zone_inform)
+       if(z->type == local_zone_transparent || z->type == local_zone_inform
+               || z->type == local_zone_block_a_wdata
+               || z->type == local_zone_block_aaaa_wdata)
                return (ld == NULL);
        if(ld)
                lr = local_data_find_type(ld, qinfo->qtype, 1);
@@ -1745,7 +1747,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                || lz_type == local_zone_always_transparent) {
                /* no NODATA or NXDOMAINS for this zone type */
                return 0;
-       } else if(lz_type == local_zone_block_a) {
+       } else if(lz_type == local_zone_block_a ||
+               lz_type == local_zone_block_a_wdata) {
                /* Return NODATA for all A queries */
                if(qinfo->qtype == LDNS_RR_TYPE_A) {
                        local_error_encode(qinfo, env, edns, repinfo, buf, temp,
@@ -1755,7 +1758,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                }
 
                return 0;
-       } else if(lz_type == local_zone_block_aaaa) {
+       } else if(lz_type == local_zone_block_aaaa ||
+               lz_type == local_zone_block_aaaa_wdata) {
                /* Return NODATA for all AAAA queries */
                if(qinfo->qtype == LDNS_RR_TYPE_AAAA) {
                        local_error_encode(qinfo, env, edns, repinfo, buf, temp,
@@ -1933,7 +1937,9 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
                        lzt == local_zone_inform ||
                        lzt == local_zone_always_transparent ||
                        lzt == local_zone_block_a ||
-                       lzt == local_zone_block_aaaa) &&
+                       lzt == local_zone_block_aaaa ||
+                       lzt == local_zone_block_a_wdata ||
+                       lzt == local_zone_block_aaaa_wdata) &&
                        local_zone_does_not_cover(z, qinfo, labs)) {
                        lock_rw_unlock(&z->lock);
                        z = NULL;
@@ -2015,6 +2021,8 @@ const char* local_zone_type2str(enum localzone_type t)
                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_block_a_wdata: return "block_a_wdata";
+               case local_zone_block_aaaa_wdata: return "block_aaaa_wdata";
                case local_zone_always_refuse: return "always_refuse";
                case local_zone_always_nxdomain: return "always_nxdomain";
                case local_zone_always_nodata: return "always_nodata";
@@ -2053,6 +2061,10 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
                *t = local_zone_block_a;
        else if(strcmp(type, "block_aaaa") == 0)
                *t = local_zone_block_aaaa;
+       else if(strcmp(type, "block_a_wdata") == 0)
+               *t = local_zone_block_a_wdata;
+       else if(strcmp(type, "block_aaaa_wdata") == 0)
+               *t = local_zone_block_aaaa_wdata;
        else if(strcmp(type, "always_refuse") == 0)
                *t = local_zone_always_refuse;
        else if(strcmp(type, "always_nxdomain") == 0)
index de263348615c0d12c0d192539693ab2fdbe34baa..436874e0faa3ebcdbc3409fd94dc16d9f6dca43f 100644 (file)
@@ -95,6 +95,10 @@ enum localzone_type {
        local_zone_block_a,
        /** resolve normally, even when there is local data, but return NODATA for AAAA queries */
        local_zone_block_aaaa,
+       /** resolve normally, use local data, else return NODATA for A queries */
+       local_zone_block_a_wdata,
+       /** resolve normally, use local data, else return NODATA for AAAA queries */
+       local_zone_block_aaaa_wdata,
        /** answer with error, even when there is local data */ 
        local_zone_always_refuse,
        /** answer with nxdomain, even when there is local data */
index 4e3c9c3abd966d340c7bbe8a8b804a8d95e6fc68..6db5cb20042fc863cfe7fb7b0d80c92b911e4c55 100644 (file)
@@ -4,6 +4,12 @@ server:
        qname-minimisation: no
        local-zone: "example1.com." block_a
        local-zone: "example2.com." block_aaaa
+       local-zone: "example3.com." block_a_wdata
+       local-data: "b.example3.com. A 1.2.3.5"
+       local-data: "b.example3.com. AAAA 1:2:3::5"
+       local-zone: "example4.com." block_aaaa_wdata
+       local-data: "b.example4.com. A 1.2.3.5"
+       local-data: "b.example4.com. AAAA 1:2:3::5"
 
 stub-zone:
        name: "."
@@ -13,7 +19,7 @@ CONFIG_END
 SCENARIO_BEGIN test local data with block_a and block_aaaa
 
 ; K.ROOT-SERVERS.NET.
-RANGE_BEGIN 0 100
+RANGE_BEGIN 0 400
        ADDRESS 193.0.14.129
 ENTRY_BEGIN
 MATCH opcode qtype qname
@@ -66,6 +72,46 @@ a.example2.com. IN AAAA
 SECTION ANSWER
 a.example2.com. IN AAAA 1:2:3::4
 ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.example3.com. IN A
+SECTION ANSWER
+a.example3.com. IN A 1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.example3.com. IN AAAA
+SECTION ANSWER
+a.example3.com. IN AAAA 1:2:3::4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.example4.com. IN A
+SECTION ANSWER
+a.example4.com. IN A 1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+a.example4.com. IN AAAA
+SECTION ANSWER
+a.example4.com. IN AAAA 1:2:3::4
+ENTRY_END
 RANGE_END
 
 ; block_a for example1.com
@@ -141,4 +187,148 @@ a.example2.com. IN AAAA
 SECTION ANSWER
 ENTRY_END
 
+; block_a_wdata for example3.com
+STEP 80 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+a.example3.com. IN A
+ENTRY_END
+
+; block_a_wdata blocks A
+STEP 90 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA DO NOERROR
+SECTION QUESTION
+a.example3.com. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 100 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+a.example3.com. IN AAAA
+ENTRY_END
+
+; block_a_wdata allows AAAA from upstream
+STEP 110 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+a.example3.com. IN AAAA
+SECTION ANSWER
+a.example3.com. IN AAAA 1:2:3::4
+ENTRY_END
+
+STEP 120 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+b.example3.com. IN A
+ENTRY_END
+
+; block_a_wdata allows local-data A
+STEP 130 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA DO NOERROR
+SECTION QUESTION
+b.example3.com. IN A
+SECTION ANSWER
+b.example3.com. A 1.2.3.5
+ENTRY_END
+
+STEP 140 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+b.example3.com. IN AAAA
+ENTRY_END
+
+; block_a_wdata allows local-data AAAA
+STEP 150 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA DO NOERROR
+SECTION QUESTION
+b.example3.com. IN AAAA
+SECTION ANSWER
+b.example3.com. AAAA 1:2:3::5
+ENTRY_END
+
+; block_aaaa_wdata for example4.com
+STEP 160 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+a.example4.com. IN A
+ENTRY_END
+
+; block_aaaa_wdata allows A from upstream
+STEP 170 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+a.example4.com. IN A
+SECTION ANSWER
+a.example4.com. IN A 1.2.3.4
+ENTRY_END
+
+STEP 180 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+a.example4.com. IN AAAA
+ENTRY_END
+
+; block_aaaa_wdata blocks AAAA
+STEP 190 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA DO NOERROR
+SECTION QUESTION
+a.example4.com. IN AAAA
+SECTION ANSWER
+ENTRY_END
+
+STEP 200 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+b.example4.com. IN A
+ENTRY_END
+
+; block_aaaa_wdata allows local-data A
+STEP 210 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA DO NOERROR
+SECTION QUESTION
+b.example4.com. IN A
+SECTION ANSWER
+b.example4.com. A 1.2.3.5
+ENTRY_END
+
+STEP 220 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+b.example4.com. IN AAAA
+ENTRY_END
+
+; block_aaaa_wdata allows local-data AAAA
+STEP 230 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR AA RD RA DO NOERROR
+SECTION QUESTION
+b.example4.com. IN AAAA
+SECTION ANSWER
+b.example4.com. AAAA 1:2:3::5
+ENTRY_END
+
 SCENARIO_END
index 64fdfc41e2846db3a59b08bba78f964c313eab70..490bba0ffaa43c2f661d036281e8c975de50ba0f 100644 (file)
@@ -2396,6 +2396,8 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
                   && strcmp($3, "always_transparent")!=0
                   && strcmp($3, "block_a")!=0
                   && strcmp($3, "block_aaaa")!=0
+                  && strcmp($3, "block_a_wdata")!=0
+                  && strcmp($3, "block_aaaa_wdata")!=0
                   && strcmp($3, "always_refuse")!=0
                   && strcmp($3, "always_nxdomain")!=0
                   && strcmp($3, "always_nodata")!=0
@@ -2410,6 +2412,7 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
                                "typetransparent, inform, inform_deny, "
                                "inform_redirect, always_transparent, "
                                "block_a, block_aaaa, "
+                               "block_a_wdata, block_aaaa_wdata, "
                                "always_refuse, always_nxdomain, "
                                "always_nodata, always_deny, always_null, "
                                "noview, nodefault or ipset");