]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Cope with exceptions thrown by MOADNSParser initialization.
authorMiod Vallat <miod.vallat@powerdns.com>
Wed, 20 May 2026 07:28:22 +0000 (09:28 +0200)
committerMiod Vallat <miod.vallat@powerdns.com>
Wed, 20 May 2026 07:28:22 +0000 (09:28 +0200)
Signed-off-by: Miod Vallat <miod.vallat@powerdns.com>
pdns/axfr-retriever.cc
pdns/comfun.cc
pdns/dnspacket.cc
pdns/resolver.cc
pdns/stubresolver.cc

index b11895a39801267184ced0a355eac5b08a8497b9..35193c746c33ed279a9496096dca7c021e5c9298 100644 (file)
@@ -128,48 +128,46 @@ int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records, ui
 
   d_receivedBytes += (uint16_t) len;
 
-  MOADNSParser mdp(false, d_buf.data(), len);
-
-  int err = mdp.d_header.rcode;
+  try {
+    MOADNSParser mdp(false, d_buf.data(), len);
 
-  if(err) {
-    throw ResolverException("AXFR chunk error: " + RCode::to_s(err));
-  }
+    int err = mdp.d_header.rcode;
+    if (err != 0) {
+      throw ResolverException("AXFR chunk error: " + RCode::to_s(err));
+    }
 
-  if(mdp.d_header.tc) {
-    throw ResolverException("AXFR chunk had TC bit set");
-  }
+    if(mdp.d_header.tc) {
+      throw ResolverException("AXFR chunk had TC bit set");
+    }
 
-  try {
     d_tsigVerifier.check(std::string(d_buf.data(), len), mdp);
-  }
-  catch(const std::runtime_error& re) {
-    throw ResolverException(re.what());
-  }
 
-  if(!records) {
-    err = parseResult(mdp, DNSName(), 0, 0, &res);
-
-    if (!err) {
-      for(const auto& answer :  mdp.d_answers) {
-        if (answer.d_type == QType::SOA) {
-          d_soacount++;
+    if (records == nullptr) {
+      err = parseResult(mdp, DNSName(), 0, 0, &res);
+      if (err == 0) {
+        for(const auto& answer : mdp.d_answers) {
+          if (answer.d_type == QType::SOA) {
+            d_soacount++;
+          }
         }
       }
     }
-  }
-  else {
-    records->clear();
-    records->reserve(mdp.d_answers.size());
+    else {
+      records->clear();
+      records->reserve(mdp.d_answers.size());
 
-    for(auto& r: mdp.d_answers) {
-      if (r.d_type == QType::SOA) {
-        d_soacount++;
-      }
+      for(auto& r: mdp.d_answers) {
+        if (r.d_type == QType::SOA) {
+          d_soacount++;
+        }
 
-      records->push_back(std::move(r));
+        records->push_back(std::move(r));
+      }
     }
   }
+  catch(const std::runtime_error& re) {
+    throw ResolverException(re.what());
+  }
 
   return true;
 }
index 3aafd8142b25b15c5d1a157e26a129a778b1972e..9e7af8932d88965a4369c18942d474015cd3f925 100644 (file)
@@ -550,6 +550,9 @@ try
   }
   //  cout<<g_mtracer->topAllocatorsString(20)<<endl;
 }
-catch(PDNSException& pe) {
-  cerr<<"Fatal error: "<<pe.reason<<endl;
+catch(const PDNSException& exc) {
+  cerr<<"Fatal error: "<<exc.reason<<endl;
+}
+catch(const std::exception& exc) {
+  cerr<<"Fatal error: "<<exc.what()<<endl;
 }
index e26c482367cd065cbb0c99287278e77f3d47b776..ecb0666f3750c2073b9dba713c80f4a4b6e60a33 100644 (file)
@@ -513,74 +513,99 @@ void DNSPacket::setTSIGDetails(const TSIGRecordContent& tr, const DNSName& keyna
 
 bool DNSPacket::getTSIGDetails(TSIGRecordContent* trc, DNSName* keyname, uint16_t* tsigPosOut) const
 {
-  MOADNSParser mdp(d_isQuery, d_rawpacket);
-  uint16_t tsigPos = mdp.getTSIGPos();
-  if(!tsigPos)
-    return false;
+  try {
+    MOADNSParser mdp(d_isQuery, d_rawpacket);
+    uint16_t tsigPos = mdp.getTSIGPos();
+    if (tsigPos == 0) {
+      return false;
+    }
 
-  bool gotit=false;
-  for(const auto & answer : mdp.d_answers) {
-    if(answer.d_type == QType::TSIG && answer.d_class == QType::ANY) {
-      // cast can fail, f.e. if d_content is an UnknownRecordContent.
-      auto content = getRR<TSIGRecordContent>(answer);
-      if (!content) {
-        SLOG(g_log<<Logger::Error<<"TSIG record has no or invalid content (invalid packet)"<<endl,
-             d_slog->info(Logr::Error, "TSIG record has no or invalid content (invalid packet)"));
-        return false;
+    bool gotit=false;
+    for(const auto & answer : mdp.d_answers) {
+      if(answer.d_type == QType::TSIG && answer.d_class == QType::ANY) {
+        // cast can fail, f.e. if d_content is an UnknownRecordContent.
+        auto content = getRR<TSIGRecordContent>(answer);
+        if (!content) {
+          SLOG(g_log<<Logger::Error<<"TSIG record has no or invalid content (invalid packet)"<<endl,
+               d_slog->info(Logr::Error, "TSIG record has no or invalid content (invalid packet)"));
+          return false;
+        }
+        *trc = *content;
+        *keyname = answer.d_name;
+        gotit=true;
       }
-      *trc = *content;
-      *keyname = answer.d_name;
-      gotit=true;
     }
+    if(!gotit)
+      return false;
+
+    if (tsigPosOut != nullptr) {
+      *tsigPosOut = tsigPos;
+    }
+
+    return true;
   }
-  if(!gotit)
+  catch (const MOADNSException&) {
+    // If execution has reached this routine, we can reasonably assume that
+    // the packet is good enough to pass the sanity checks of
+    // MOADNSParser::init(). But just in case it doesn't, better handle this.
     return false;
-
-  if (tsigPosOut) {
-    *tsigPosOut = tsigPos;
   }
-
-  return true;
 }
 
 bool DNSPacket::validateTSIG(const TSIGTriplet& tsigTriplet, const TSIGRecordContent& tsigContent, const std::string& previousMAC, const std::string& theirMAC, bool timersOnly) const
 {
-  MOADNSParser mdp(d_isQuery, d_rawpacket);
-  uint16_t tsigPos = mdp.getTSIGPos();
-  if (tsigPos == 0) {
+  try {
+    MOADNSParser mdp(d_isQuery, d_rawpacket);
+    uint16_t tsigPos = mdp.getTSIGPos();
+    if (tsigPos == 0) {
+      return false;
+    }
+
+    return ::validateTSIG(d_slog, d_rawpacket, tsigPos, tsigTriplet, tsigContent, previousMAC, theirMAC, timersOnly);
+  }
+  catch (const MOADNSException&) {
+    // If execution has reached this routine, we can reasonably assume that
+    // the packet is good enough to pass the sanity checks of
+    // MOADNSParser::init(). But just in case it doesn't, better handle this.
     return false;
   }
-
-  return ::validateTSIG(d_slog, d_rawpacket, tsigPos, tsigTriplet, tsigContent, previousMAC, theirMAC, timersOnly);
 }
 
 bool DNSPacket::getTKEYRecord(TKEYRecordContent *tr, DNSName *keyname) const
 {
-  MOADNSParser mdp(d_isQuery, d_rawpacket);
-  bool gotit=false;
-
-  for(const auto & answer : mdp.d_answers) {
-    if (gotit) {
-      SLOG(g_log<<Logger::Error<<"More than one TKEY record found in query"<<endl,
-           d_slog->info(Logr::Error, "More than one TKEY record found in query"));
-      return false;
-    }
+  try {
+    MOADNSParser mdp(d_isQuery, d_rawpacket);
+    bool gotit=false;
 
-    if(answer.d_type == QType::TKEY) {
-      // cast can fail, f.e. if d_content is an UnknownRecordContent.
-      auto content = getRR<TKEYRecordContent>(answer);
-      if (!content) {
-        SLOG(g_log<<Logger::Error<<"TKEY record has no or invalid content (invalid packet)"<<endl,
-             d_slog->info(Logr::Error, "TKEY record has no or invalid content (invalid packet)"));
+    for(const auto & answer : mdp.d_answers) {
+      if (gotit) {
+        SLOG(g_log<<Logger::Error<<"More than one TKEY record found in query"<<endl,
+             d_slog->info(Logr::Error, "More than one TKEY record found in query"));
         return false;
       }
-      *tr = *content;
-      *keyname = answer.d_name;
-      gotit=true;
+
+      if(answer.d_type == QType::TKEY) {
+        // cast can fail, f.e. if d_content is an UnknownRecordContent.
+        auto content = getRR<TKEYRecordContent>(answer);
+        if (!content) {
+          SLOG(g_log<<Logger::Error<<"TKEY record has no or invalid content (invalid packet)"<<endl,
+               d_slog->info(Logr::Error, "TKEY record has no or invalid content (invalid packet)"));
+          return false;
+        }
+        *tr = *content;
+        *keyname = answer.d_name;
+        gotit=true;
+      }
     }
-  }
 
-  return gotit;
+    return gotit;
+  }
+  catch (const MOADNSException&) {
+    // If execution has reached this routine, we can reasonably assume that
+    // the packet is good enough to pass the sanity checks of
+    // MOADNSParser::init(). But just in case it doesn't, better handle this.
+    return false;
+  }
 }
 
 /** This function takes data from the network, possibly received with recvfrom, and parses
index adbb469d0abf945ea397a8101dc18bae58bfbe4d..05c0446acfba29ebdfabdba4a91a2919a2044e07 100644 (file)
@@ -269,42 +269,52 @@ bool Resolver::tryGetSOASerial(DNSName *domain, ComboAddress* remote, uint32_t *
     throw ResolverException("recvfrom error waiting for answer: "+stringerror());
   }
 
-  MOADNSParser mdp(false, (char*)buf, err);
-  *id=mdp.d_header.id;
-  *domain = mdp.d_qname;
-
-  if(domain->empty())
-    throw ResolverException("SOA query to '" + remote->toLogString() + "' produced response without domain name (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")");
-
-  if(mdp.d_answers.empty())
-    throw ResolverException("Query to '" + remote->toLogString() + "' for SOA of '" + domain->toLogString() + "' produced no results (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")");
-
-  if(mdp.d_qtype != QType::SOA)
-    throw ResolverException("Query to '" + remote->toLogString() + "' for SOA of '" + domain->toLogString() + "' returned wrong record type");
-
-  if(mdp.d_header.rcode != 0)
-    throw ResolverException("Query to '" + remote->toLogString() + "' for SOA of '" + domain->toLogString() + "' returned Rcode " + RCode::to_s(mdp.d_header.rcode));
-
-  *theirInception = *theirExpire = 0;
-  bool gotSOA=false;
-  for(const MOADNSParser::answers_t::value_type& drc :  mdp.d_answers) {
-    if(drc.d_type == QType::SOA && drc.d_name == *domain) {
-      auto src = getRR<SOARecordContent>(drc);
-      if (src) {
-        *theirSerial = src->d_st.serial;
-        gotSOA = true;
-      }
+  bool gotSOA{false};
+  try {
+    MOADNSParser mdp(false, (char*)buf, err);
+    *id=mdp.d_header.id;
+    *domain = mdp.d_qname;
+
+    if(domain->empty()) {
+      throw ResolverException("SOA query to '" + remote->toLogString() + "' produced response without domain name (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")");
+    }
+
+    if(mdp.d_answers.empty()) {
+      throw ResolverException("Query to '" + remote->toLogString() + "' for SOA of '" + domain->toLogString() + "' produced no results (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")");
+    }
+
+    if(mdp.d_qtype != QType::SOA) {
+      throw ResolverException("Query to '" + remote->toLogString() + "' for SOA of '" + domain->toLogString() + "' returned wrong record type");
     }
-    if(drc.d_type == QType::RRSIG && drc.d_name == *domain) {
-      auto rrc = getRR<RRSIGRecordContent>(drc);
-      if(rrc && rrc->d_type == QType::SOA) {
-        *theirInception= std::max(*theirInception, rrc->d_siginception);
-        *theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
+
+    if(mdp.d_header.rcode != 0) {
+      throw ResolverException("Query to '" + remote->toLogString() + "' for SOA of '" + domain->toLogString() + "' returned Rcode " + RCode::to_s(mdp.d_header.rcode));
+    }
+
+    *theirInception = *theirExpire = 0;
+    for(const MOADNSParser::answers_t::value_type& drc :  mdp.d_answers) {
+      if(drc.d_type == QType::SOA && drc.d_name == *domain) {
+        auto src = getRR<SOARecordContent>(drc);
+        if (src) {
+          *theirSerial = src->d_st.serial;
+          gotSOA = true;
+        }
+      }
+      if(drc.d_type == QType::RRSIG && drc.d_name == *domain) {
+        auto rrc = getRR<RRSIGRecordContent>(drc);
+        if(rrc && rrc->d_type == QType::SOA) {
+          *theirInception= std::max(*theirInception, rrc->d_siginception);
+          *theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
+        }
       }
     }
   }
-  if(!gotSOA)
+  catch (const MOADNSException& exc) {
+    throw ResolverException("SOA Query to '" + remote->toLogString() + "' produced ill-formed response: " + exc.what());
+  }
+  if(!gotSOA) {
     throw ResolverException("Query to '" + remote->toLogString() + "' for SOA of '" + domain->toLogString() + "' did not return a SOA");
+  }
   return true;
 }
 
@@ -339,6 +349,9 @@ int Resolver::resolve(const ComboAddress& to, const DNSName &domain, int type, R
   catch(ResolverException &re) {
     throw ResolverException(re.reason+" from "+to.toLogString());
   }
+  catch (const MOADNSException& exc) {
+    throw ResolverException(std::string(exc.what()) + " from " + to.toLogString());
+  }
 }
 
 int Resolver::resolve(const ComboAddress& ipport, const DNSName &domain, int type, Resolver::res_t* res) {
index a6da7039d121bb52195f2fe42c7eed75b969f07b..f095616274b604b5e5cf8c7fb0ec85e5f9727ec3 100644 (file)
@@ -174,22 +174,30 @@ int stubDoResolve(Logr::log_t slog, const DNSName& qname, uint16_t qtype, vector
     catch (...) {
       continue;
     }
-    MOADNSParser mdp(false, reply);
-    if (mdp.d_header.rcode == RCode::ServFail) {
-      continue;
-    }
 
-    for (const auto& answer : mdp.d_answers) {
-      if (answer.d_place == 1 && answer.d_type == qtype) {
-        DNSZoneRecord zrr;
-        zrr.dr = answer;
-        zrr.auth = true;
-        ret.push_back(std::move(zrr));
+    try {
+      MOADNSParser mdp(false, reply);
+      if (mdp.d_header.rcode == RCode::ServFail) {
+        continue;
+      }
+
+      for (const auto& answer : mdp.d_answers) {
+        if (answer.d_place == 1 && answer.d_type == qtype) {
+          DNSZoneRecord zrr;
+          zrr.dr = answer;
+          zrr.auth = true;
+          ret.push_back(std::move(zrr));
+        }
       }
+      SLOG(g_log << Logger::Debug << logPrefix << "Question for '" << queryNameType << "' got answered by " << dest.toString() << endl,
+           slog->info(Logr::Debug, "stub-resolver: got an answer", "query", Logging::Loggable(qname), "type", Logging::Loggable(QType(qtype)), "resolver", Logging::Loggable(dest)));
+      return mdp.d_header.rcode;
+    }
+    catch (const MOADNSException& exc) {
+      SLOG(g_log << Logger::Debug << logPrefix << "Question for '" << queryNameType << "' got ill-formed answer from " << dest.toString() << ": " << exc.what() << endl,
+           slog->error(Logr::Debug, exc.what(), "stub-resolver: got an ill-formed answer", "query", Logging::Loggable(qname), "type", Logging::Loggable(QType(qtype)), "resolver", Logging::Loggable(dest)));
+      continue;
     }
-    SLOG(g_log << Logger::Debug << logPrefix << "Question for '" << queryNameType << "' got answered by " << dest.toString() << endl,
-         slog->info(Logr::Debug, "stub-resolver: got an answer", "query", Logging::Loggable(qname), "type", Logging::Loggable(QType(qtype)), "resolver", Logging::Loggable(dest)));
-    return mdp.d_header.rcode;
   }
   return RCode::ServFail;
 }