From 0eb03ead48ab3010c8d641e8a9cc842c6ae4429e Mon Sep 17 00:00:00 2001 From: Pieter Lexis Date: Fri, 19 Jan 2018 11:25:03 +0100 Subject: [PATCH] ixfrdist: Send AXFR or SOA on certain IXFR requests --- pdns/ixfrdist.cc | 53 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/pdns/ixfrdist.cc b/pdns/ixfrdist.cc index 7dddc8c57..83da30159 100644 --- a/pdns/ixfrdist.cc +++ b/pdns/ixfrdist.cc @@ -31,7 +31,7 @@ #include "dns_random.hh" #include "sstuff.hh" #include "mplexer.hh" - +#include "misc.hh" /* BEGIN Needed because of deeper dependencies */ #include "arguments.hh" @@ -227,11 +227,8 @@ bool checkQuery(const MOADNSParser& mdp, const ComboAddress& saddr, const bool u /* * Returns a vector that represents the full response to a SOA * query. QNAME is read from mdp. - * - * TODO Maybe return void and modify the vector in-place? */ -vector makeSOAPacket(const MOADNSParser& mdp) { - vector packet; +bool makeSOAPacket(const MOADNSParser& mdp, vector& packet) { DNSPacketWriter pw(packet, mdp.d_qname, mdp.d_qtype); pw.getHeader()->id = mdp.d_header.id; pw.getHeader()->rd = mdp.d_header.rd; @@ -241,7 +238,7 @@ vector makeSOAPacket(const MOADNSParser& mdp) { g_soas[mdp.d_qname]->toPacket(pw); pw.commit(); - return packet; + return true; } bool makeAXFRPacket(const MOADNSParser& mdp, vector& packet) { @@ -290,14 +287,30 @@ bool makeAXFRPacket(const MOADNSParser& mdp, vector& packet) { return true; } -/* Produces an IXFR packet and if one can not be made, an AXFR packet in `packet` +/* Produces an IXFR if one can be made according to the rules in RFC 1995 and + * creates a SOA or AXFR packet when required by the RFC. */ bool makeIXFRPacket(const MOADNSParser& mdp, const shared_ptr& clientSOA, vector& packet) { string dir = g_workdir + "/" + mdp.d_qname.toString(); + // Get the new SOA only once, so it will not change under our noses from the + // updateThread. + uint32_t newSerial = g_soas[mdp.d_qname]->d_st.serial; // Let's see if we have the old zone // TODO lock the zone from clean up (when implemented) string oldZoneFname = dir + "/" + std::to_string(clientSOA->d_st.serial); + string newZoneFname = dir + "/" + std::to_string(newSerial); + + if (rfc1982LessThan(newSerial, clientSOA->d_st.serial)){ + /* RFC 1995 Section 2 + * If an IXFR query with the same or newer version number than that of + * the server is received, it is replied to with a single SOA record of + * the server's current version, just as in AXFR. + */ + return makeSOAPacket(mdp, packet); + } + + // Check if we can actually make an IXFR struct stat s; if (stat(oldZoneFname.c_str(), &s) == -1) { if (errno == ENOENT) { @@ -310,12 +323,9 @@ bool makeIXFRPacket(const MOADNSParser& mdp, const shared_ptr& return false; } - auto newSerial = getSerialsFromDir(dir); - string newZoneFname = dir + "/" + std::to_string(newSerial); - - // Use the SOA from the file, the one in g_soas _may_ have changed shared_ptr newSOA; loadSOAFromDisk(mdp.d_qname, newZoneFname, newSOA); + if (newSOA == nullptr) { // :( cerr<<"[WARNING] Could not retrieve SOA record from "< packet; + makeSOAPacket(mdp, packet); if(sendto(fd, &packet[0], packet.size(), 0, (struct sockaddr*) &saddr, fromlen) < 0) { cerr<<"[WARNING] Could not send reply for "< packet; if (mdp.d_qtype == QType::SOA) { - packet = makeSOAPacket(mdp); + if (!makeSOAPacket(mdp,packet)) { + close(cfd); + return; + } } if (mdp.d_qtype == QType::AXFR) { -- 2.40.0