]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
fix(ixfrdist): Allow 64K AXFR chunks 17729/head
authorPieter Lexis <pieter.lexis@powerdns.com>
Fri, 10 Jul 2026 08:54:31 +0000 (10:54 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Tue, 14 Jul 2026 07:44:53 +0000 (09:44 +0200)
This was changed in #8051 for performance (compression) reasons. But
this would limit each AXFR chunk to 16K, so *large* TXT records (over
16K) could not be transferred out by ixfrdist.

This commit uses a 64K limit once when a chunk was truncated twice (once
can happen after any number of records, the second time would mean
truncation on a single record, when the second happens, we error).

Discovered by Haruto Kimura (Stella), thanks!

pdns/ixfrdist.cc

index 9eab14178dd9c1557ab71ec9d8f4c5970c542284..56e56c70c9663e8d583f8f82ce64436edb93deed 100644 (file)
@@ -809,12 +809,13 @@ static bool sendPacketOverTCP(int fd, const std::vector<uint8_t>& packet)
   return true;
 }
 
-static bool addRecordToWriter(DNSPacketWriter& pw, const DNSName& zoneName, const DNSRecord& record, bool compress)
+static bool addRecordToWriter(DNSPacketWriter& pwr, const DNSName& zoneName, const DNSRecord& record, bool compress, bool ignoreLimit=false)
 {
-  pw.startRecord(record.d_name + zoneName, record.d_type, record.d_ttl, QClass::IN, DNSResourceRecord::ANSWER, compress);
-  record.getContent()->toPacket(pw);
-  if (pw.size() > 16384) {
-    pw.rollback();
+  pwr.startRecord(record.d_name + zoneName, record.d_type, record.d_ttl, QClass::IN, DNSResourceRecord::ANSWER, compress);
+  record.getContent()->toPacket(pwr);
+  uint32_t maxsize = ignoreLimit ? 65535 : 16384;
+  if (pwr.size() > maxsize) {
+    pwr.rollback();
     return false;
   }
   return true;
@@ -824,6 +825,7 @@ template <typename T> static bool sendRecordsOverTCP(int fd, const MOADNSParser&
 {
   vector<uint8_t> packet;
 
+  bool wasRolledBack = false;
   for (auto it = records.cbegin(); it != records.cend();) {
     bool recordsAdded = false;
     packet.clear();
@@ -838,14 +840,21 @@ template <typename T> static bool sendRecordsOverTCP(int fd, const MOADNSParser&
         continue;
       }
 
-      if (addRecordToWriter(pw, mdp.d_qname, *it, g_compress)) {
+      if (addRecordToWriter(pw, mdp.d_qname, *it, g_compress, wasRolledBack && !recordsAdded)) {
         recordsAdded = true;
+        wasRolledBack = false;
         it++;
       }
       else {
+        if (wasRolledBack) {
+          // We did a rollback in the previous loop, and the large single record won't
+          // fit in the new packet by itself. Should be impossible, but here we are.
+          return false;
+        }
         if (recordsAdded) {
           pw.commit();
           sendPacketOverTCP(fd, packet);
+          wasRolledBack = true;
         }
         if (it == records.cbegin()) {
           /* something is wrong */