From: Pieter Lexis Date: Fri, 10 Jul 2026 08:54:31 +0000 (+0200) Subject: fix(ixfrdist): Allow 64K AXFR chunks X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=68b3ff000007741bf83662bc0e49bc75ed720c43;p=thirdparty%2Fpdns.git fix(ixfrdist): Allow 64K AXFR chunks 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! --- diff --git a/pdns/ixfrdist.cc b/pdns/ixfrdist.cc index 9eab14178d..56e56c70c9 100644 --- a/pdns/ixfrdist.cc +++ b/pdns/ixfrdist.cc @@ -809,12 +809,13 @@ static bool sendPacketOverTCP(int fd, const std::vector& 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 static bool sendRecordsOverTCP(int fd, const MOADNSParser& { vector packet; + bool wasRolledBack = false; for (auto it = records.cbegin(); it != records.cend();) { bool recordsAdded = false; packet.clear(); @@ -838,14 +840,21 @@ template 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 */