Package: pdns-recursor
Version: 4.8.8-1+deb12u1
Severity: normal
Tags: patch fixed-upstream

With export-etc-hosts enabled, the recursor in bookworm only serves the
first line of /etc/hosts for a name. If a name is listed with an IPv4 and
an IPv6 address on two lines, only one of the two record types is
answered.

Steps to reproduce (Debian 12 based system, pdns-recursor 4.8.8-1+deb12u1,
export-etc-hosts=yes):

  /etc/hosts:
    192.0.2.77     plain.test
    2001:db8::77   plain.test

  rec_control reload-zones
  dig +short @127.0.0.1 plain.test A      -> 192.0.2.77
  dig +short @127.0.0.1 plain.test AAAA   -> (empty)

With the two lines in the opposite order only the AAAA record is
answered. In 4.8.8 makeNameToIPZone() in reczones-helpers.cc creates a
new zone for each line and addToDomainMap() refuses to replace an
existing one ("Will not overwrite already loaded zone").

Upstream fixed this in 4.9.0, PowerDNS pull request 12203, commit
a867410a2183e64d6abe212c5abcac7cf8a95b6b "Allow multiple records with
same name for etc/hosts processing" (15 lines added, 2 removed, one
file). With upstream 5.4.7 both records of the example are answered.
Debian 13 should not be affected, because the fix is in all releases
since 4.9.0, but I have not tested the trixie package.

The patch applies cleanly to the 4.8.8 source. I checked this with
"patch --dry-run" against the rec-4.8.8 tag and did not build or run a
patched package. A patch in DEP-3 format is attached.

I know that 4.x is end of life upstream, so a fix has to come from
Debian. Could this be considered for a bookworm point release? I noticed
it in VyOS (a Debian 12 based router distribution), where DHCP and static
host mappings for the same name use different address families and only
one of them resolves. I am happy to test a patched package.
Description: Allow multiple records with the same name for /etc/hosts processing
 With export-etc-hosts enabled, the recursor only served the first line of
 /etc/hosts for a name. A name listed with an IPv4 and an IPv6 address on two
 lines got only the first one, so either the A or the AAAA record was missing.
 The records of the same name are now added to the same zone.
Author: Sten Spans <[email protected]>
Origin: upstream, https://github.com/PowerDNS/pdns/commit/a867410a2183e64d6abe212c5abcac7cf8a95b6b
Applied-Upstream: 4.9.0, https://github.com/PowerDNS/pdns/pull/12203
Forwarded: not-needed
Last-Update: 2026-10-20

 pdns/recursordist/reczones-helpers.cc | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/pdns/recursordist/reczones-helpers.cc b/pdns/recursordist/reczones-helpers.cc
index 8f613ac92fed..daee88e6ffd8 100644
--- a/pdns/recursordist/reczones-helpers.cc
+++ b/pdns/recursordist/reczones-helpers.cc
@@ -75,17 +75,30 @@ static void makeNameToIPZone(SyncRes::domainmap_t& newMap,
                              const ComboAddress& address,
                              Logr::log_t log)
 {
+  SyncRes::AuthDomain ad;
   DNSRecord dr;
+
   dr.d_name = hostname;
 
-  SyncRes::AuthDomain ad = makeSOAAndNSNodes(dr, "localhost.");
+  if (newMap.count(hostname) != 0) {
+    ad = newMap[hostname];
+  }
+  else {
+    ad = makeSOAAndNSNodes(dr, "localhost.");
+  }
 
   auto recType = address.isIPv6() ? QType::AAAA : QType::A;
   dr.d_type = recType;
+  dr.d_ttl = 86400;
   dr.d_content = DNSRecordContent::mastermake(recType, 1, address.toStringNoInterface());
   ad.d_records.insert(dr);
 
-  addToDomainMap(newMap, ad, dr.d_name, log);
+  if (newMap.count(hostname) != 0) {
+    newMap[ad.d_name] = ad;
+  }
+  else {
+    addToDomainMap(newMap, ad, dr.d_name, log);
+  }
 }
 
 static void makeIPToNamesZone(SyncRes::domainmap_t& newMap,

Reply via email to