]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
SVCB: Lookup IP auto hints on response and XFR
authorPieter Lexis <pieter.lexis@powerdns.com>
Tue, 9 Feb 2021 16:08:44 +0000 (17:08 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 29 Mar 2021 17:10:32 +0000 (19:10 +0200)
pdns/dnspacket.cc
pdns/dnspacket.hh
pdns/dnsrecords.cc
pdns/dnsrecords.hh
pdns/packethandler.cc
pdns/tcpreceiver.cc

index d1707aa990a01c1a3b2ddb35803b914f2cb8e56a..705956c2f52b164fe29020b5b9b9be93329414d7 100644 (file)
@@ -160,6 +160,19 @@ vector<DNSZoneRecord*> DNSPacket::getAPRecords()
   return arrs;
 }
 
+vector<DNSZoneRecord*> DNSPacket::getServiceRecords()
+{
+  vector<DNSZoneRecord*> arrs;
+
+  for(auto & i : d_rrs) {
+    if (i.dr.d_type==QType::SVCB ||
+        i.dr.d_type==QType::HTTPS) {
+      arrs.push_back(&i);
+    }
+  }
+  return arrs;
+}
+
 vector<DNSZoneRecord*> DNSPacket::getAnswerRecords()
 {
   vector<DNSZoneRecord*> arrs;
index 86ef68b7315af4441bb15a0261dad0b2024ae23d..4456847d6df55879c0ed76e5bebe5a2113e60269 100644 (file)
@@ -109,6 +109,7 @@ public:
 
   vector<DNSZoneRecord*> getAPRecords(); //!< get a vector with DNSZoneRecords that need additional processing
   vector<DNSZoneRecord*> getAnswerRecords(); //!< get a vector with DNSZoneRecords that are answers
+  vector<DNSZoneRecord*> getServiceRecords(); //!< Get a vector with all Service-style (SVCB) records
   void setCompress(bool compress);
 
   std::unique_ptr<DNSPacket> replyPacket() const; //!< convenience function that creates a virgin answer packet to this question
index fa267e4b33f27d0ce051dd624138d74a3fb04ffc..995aef5fdd9e1288bf1a48942dc0fc5f74626f78 100644 (file)
@@ -749,6 +749,17 @@ void SVCBBaseRecordContent::setHints(const SvcParam::SvcParamKey &key, const std
   }
 }
 
+void SVCBBaseRecordContent::removeParam(const SvcParam::SvcParamKey &key) {
+  auto p = std::find_if(d_params.begin(), d_params.end(),
+      [&key](const SvcParam &param) {
+        return param.getKey() == key;
+      });
+  if (p == d_params.end()) {
+    return;
+  }
+  d_params.erase(p);
+}
+
 /* SVCB end */
 
 boilerplate_conv(TKEY,
index bafe372989b6e0569c5b948e9631e5cad2c4d9b3..963663d5e6c5266db6214b441ef735c6f0fd2597 100644 (file)
@@ -506,6 +506,8 @@ class SVCBBaseRecordContent : public DNSRecordContent
     bool autoHint(const SvcParam::SvcParamKey &key) const;
     // Sets the |addresses| to the existing hints for |key|
     void setHints(const SvcParam::SvcParamKey &key, const std::vector<ComboAddress> &addresses);
+    // Removes the parameter for |key| from d_params
+    void removeParam(const SvcParam::SvcParamKey &key);
 
   protected:
     uint16_t d_priority;
index ee45ff65be8800e2625d3107ca2825f662005496..00f8900b1c50210886831a10bc10a6be245b748b 100644 (file)
@@ -522,6 +522,41 @@ void PacketHandler::doAdditionalProcessing(DNSPacket& p, std::unique_ptr<DNSPack
       }
     }
   }
+  // TODO should we have a setting to do this?
+  for (auto &rec : r->getServiceRecords()) {
+    // Process auto hints
+    auto rrc = getRR<SVCBBaseRecordContent>(rec->dr);
+    DNSName target = rrc->getTarget().isRoot() ? rec->dr.d_name : rrc->getTarget();
+    if (rrc->autoHint(SvcParam::ipv4hint)) {
+      B.lookup(QType::A, target, d_sd.domain_id);
+      vector<ComboAddress> hints;
+      DNSZoneRecord rr;
+      while (B.get(rr)) {
+        auto arrc = getRR<ARecordContent>(rr.dr);
+        hints.push_back(arrc->getCA());
+      }
+      if (hints.size() == 0) {
+        rrc->removeParam(SvcParam::ipv4hint);
+      } else {
+        rrc->setHints(SvcParam::ipv4hint, hints);
+      }
+    }
+
+    if (rrc->autoHint(SvcParam::ipv6hint)) {
+      B.lookup(QType::AAAA, target, d_sd.domain_id);
+      vector<ComboAddress> hints;
+      DNSZoneRecord rr;
+      while (B.get(rr)) {
+        auto arrc = getRR<AAAARecordContent>(rr.dr);
+        hints.push_back(arrc->getCA());
+      }
+      if (hints.size() == 0) {
+        rrc->removeParam(SvcParam::ipv6hint);
+      } else {
+        rrc->setHints(SvcParam::ipv6hint, hints);
+      }
+    }
+  }
 
   DNSZoneRecord dzr;
   for(const auto& name : lookup) {
index 3fefed1413019c42c49567cf6bc6563d02b2a726..7110f5b135a654d6db079e44254b263f3769d190 100644 (file)
@@ -726,6 +726,47 @@ int TCPNameserver::doAXFR(const DNSName &target, std::unique_ptr<DNSPacket>& q,
     }
   }
 
+  for (auto loopRR : zrrs) {
+    if ((loopRR.dr.d_type == QType::SVCB || loopRR.dr.d_type == QType::HTTPS)) {
+      // Process auto hints
+      // TODO this is an almost copy of the code in the packethandler
+      auto rrc = getRR<SVCBBaseRecordContent>(loopRR.dr);
+      if (rrc == nullptr) {
+        continue;
+      }
+      DNSName svcTarget = rrc->getTarget().isRoot() ? loopRR.dr.d_name : rrc->getTarget();
+      if (rrc->autoHint(SvcParam::ipv4hint)) {
+        sd.db->lookup(QType::A, svcTarget, sd.domain_id);
+        vector<ComboAddress> hints;
+        DNSZoneRecord rr;
+        while (sd.db->get(rr)) {
+          auto arrc = getRR<ARecordContent>(rr.dr);
+          hints.push_back(arrc->getCA());
+        }
+        if (hints.size() == 0) {
+          rrc->removeParam(SvcParam::ipv4hint);
+        } else {
+          rrc->setHints(SvcParam::ipv4hint, hints);
+        }
+      }
+
+      if (rrc->autoHint(SvcParam::ipv6hint)) {
+        sd.db->lookup(QType::AAAA, svcTarget, sd.domain_id);
+        vector<ComboAddress> hints;
+        DNSZoneRecord rr;
+        while (sd.db->get(rr)) {
+          auto arrc = getRR<AAAARecordContent>(rr.dr);
+          hints.push_back(arrc->getCA());
+        }
+        if (hints.size() == 0) {
+          rrc->removeParam(SvcParam::ipv6hint);
+        } else {
+          rrc->setHints(SvcParam::ipv6hint, hints);
+        }
+      }
+    }
+  }
+
   // Group records by name and type, signpipe stumbles over interrupted rrsets
   if(securedZone && !presignedZone) {
     sort(zrrs.begin(), zrrs.end(), [](const DNSZoneRecord& a, const DNSZoneRecord& b) {