]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/ixfrutils.cc
dnsdist: Add HTTPStatusAction to return a specific HTTP response
[thirdparty/pdns.git] / pdns / ixfrutils.cc
index 9617779ab0b766d21bb0a900b9abbb56cee45ad8..cd5f7155c6e4229e031862dec96a0a5bc4e449dd 100644 (file)
@@ -29,7 +29,7 @@
 #include "zoneparser-tng.hh"
 #include "dnsparser.hh"
 
-uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr, const TSIGTriplet& tt)
+uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr, const TSIGTriplet& tt, const uint16_t timeout)
 {
   vector<uint8_t> packet;
   DNSPacketWriter pw(packet, zone, QType::SOA);
@@ -49,10 +49,18 @@ uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, sh
   s.writen(msg);
 
   string reply;
-  s.read(reply);
+  reply.resize(4096);
+  // will throw a NetworkError on timeout
+  ssize_t got = s.readWithTimeout(&reply[0], reply.size(), timeout);
+  if (got < 0 || static_cast<size_t>(got) < sizeof(dnsheader)) {
+    throw std::runtime_error("Invalid response size " + std::to_string(got));
+  }
+
+  reply.resize(got);
+
   MOADNSParser mdp(false, reply);
   if(mdp.d_header.rcode) {
-    throw std::runtime_error("Unable to retrieve SOA serial from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode));
+    throw std::runtime_error("RCODE from response is not NoError but " + RCode::to_s(mdp.d_header.rcode));
   }
   for(const auto& r: mdp.d_answers) {
     if(r.first.d_type == QType::SOA) {
@@ -91,12 +99,25 @@ uint32_t getSerialFromRecords(const records_t& records, DNSRecord& soaret)
 
   for(auto iter = found.first; iter != found.second; ++iter) {
     auto soa = std::dynamic_pointer_cast<SOARecordContent>(iter->d_content);
-    soaret = *iter;
-    return soa->d_st.serial;
+    if (soa) {
+      soaret = *iter;
+      return soa->d_st.serial;
+    }
   }
   return 0;
 }
 
+static void writeRecords(FILE* fp, const records_t& records)
+{
+  for(const auto& r: records) {
+    fprintf(fp, "%s\t%" PRIu32 "\tIN\t%s\t%s\n",
+            r.d_name.isRoot() ? "@" :  r.d_name.toStringNoDot().c_str(),
+            r.d_ttl,
+            DNSRecordContent::NumberToType(r.d_type).c_str(),
+            r.d_content->getZoneRepresentation().c_str());
+  }
+}
+
 void writeZoneToDisk(const records_t& records, const DNSName& zone, const std::string& directory)
 {
   DNSRecord soa;
@@ -109,17 +130,15 @@ void writeZoneToDisk(const records_t& records, const DNSName& zone, const std::s
   records_t soarecord;
   soarecord.insert(soa);
   fprintf(fp, "$ORIGIN %s\n", zone.toString().c_str());
-  for(const auto& outer : {soarecord, records, soarecord} ) {
-    for(const auto& r: outer) {
-      fprintf(fp, "%s\t%" PRIu32 "\tIN\t%s\t%s\n",
-          r.d_name.isRoot() ? "@" :  r.d_name.toStringNoDot().c_str(),
-          r.d_ttl,
-          DNSRecordContent::NumberToType(r.d_type).c_str(),
-          r.d_content->getZoneRepresentation().c_str());
-    }
-  }
+
+  writeRecords(fp, soarecord);
+  writeRecords(fp, records);
+  writeRecords(fp, soarecord);
+
   fclose(fp);
-  rename( (fname+".partial").c_str(), fname.c_str());
+  if (rename( (fname+".partial").c_str(), fname.c_str()) != 0) {
+    throw std::runtime_error("Unable to move the zone file for " + zone.toLogString() + " from " + fname + ".partial to " + fname + ": " + string(strerror(errno)));
+  }
 }
 
 void loadZoneFromDisk(records_t& records, const string& fname, const DNSName& zone)
@@ -128,9 +147,7 @@ void loadZoneFromDisk(records_t& records, const string& fname, const DNSName& zo
 
   DNSResourceRecord rr;
   bool seenSOA=false;
-  unsigned int nrecords=0;
   while(zpt.get(rr)) {
-    ++nrecords;
     if(rr.qtype.getCode() == QType::CNAME && rr.content.empty())
       rr.content=".";
     rr.qname = rr.qname.makeRelative(zone);
@@ -151,7 +168,7 @@ void loadZoneFromDisk(records_t& records, const string& fname, const DNSName& zo
  * Load the zone `zone` from `fname` and put the first found SOA into `soa`
  * Does NOT check for nullptr
  */
-void loadSOAFromDisk(const DNSName& zone, const string& fname, shared_ptr<SOARecordContent>& soa)
+void loadSOAFromDisk(const DNSName& zone, const string& fname, shared_ptr<SOARecordContent>& soa, uint32_t& soaTTL)
 {
   ZoneParserTNG zpt(fname, zone);
   DNSResourceRecord rr;
@@ -159,6 +176,7 @@ void loadSOAFromDisk(const DNSName& zone, const string& fname, shared_ptr<SOARec
   while(zpt.get(rr)) {
     if (rr.qtype == QType::SOA) {
       soa = getRR<SOARecordContent>(DNSRecord(rr));
+      soaTTL = rr.ttl;
       return;
     }
   }