]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
ixfrdist: Add option to limit AXFR record count
authorPieter Lexis <pieter.lexis@powerdns.com>
Thu, 23 Aug 2018 09:35:22 +0000 (11:35 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Thu, 23 Aug 2018 15:45:56 +0000 (17:45 +0200)
docs/manpages/ixfrdist.yml.5.rst
pdns/ixfrdist.cc
pdns/ixfrdist.example.yml

index d39b66543daba94cc7a3b507f22e652510f1311a..4f409303df0ca9097e3fdb315d3e7564a4841230 100644 (file)
@@ -54,6 +54,11 @@ Options
   Entries without a netmask will be interpreted as a single address.
   By default, the ACL is set is ``127.0.0.0/8`` and ``::1/128``.
 
+:axfr-max-records:
+  Maximum number of records allowed in an AXFR transaction requested by :program:`ixfrdist`.
+  This may prevent untrusted sources from using all the process memory.
+  By default, this setting is ``0``, which means "unlimited".
+
 :axfr-timeout:
   Timeout in seconds an AXFR transaction requested by :program:`ixfrdist` may take.
   Increase this when the network to the authoritative servers is slow or the domains are very large and you experience timeouts.
index 4a768ddf4b984f777971578620dc25124e2460e6..0c516fdce96bb7bbb7a5d6afff8e5c36a45c8224 100644 (file)
@@ -206,7 +206,7 @@ static void makeIXFRDiff(const records_t& from, const records_t& to, ixfrdiff_t&
   }
 }
 
-void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& axfrTimeout) {
+void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& axfrTimeout, const uint32_t axfrMaxRecords) {
   std::map<DNSName, time_t> lastCheck;
 
   // Initialize the serials we have
@@ -299,7 +299,7 @@ void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& a
       shared_ptr<SOARecordContent> soa;
       try {
         AXFRRetriever axfr(master, domain, tt, &local);
-        unsigned int nrecords=0;
+        uint32_t nrecords=0;
         Resolver::res_t nop;
         vector<DNSRecord> chunk;
         records_t records;
@@ -316,6 +316,9 @@ void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& a
               soa = getRR<SOARecordContent>(dr);
             }
           }
+          if (axfrMaxRecords != 0 && nrecords > axfrMaxRecords) {
+            throw PDNSException("Received more than " + std::to_string(axfrMaxRecords) + " records in AXFR, aborted");
+          }
           axfr_now = time(nullptr);
           if (axfr_now - t_start > axfrTimeout) {
             throw PDNSException("Total AXFR time exceeded!");
@@ -780,6 +783,16 @@ bool parseAndCheckConfig(const string& configpath, YAML::Node& config) {
     config["keep"] = 20;
   }
 
+  if (config["axfr-max-records"]) {
+    try {
+      config["axfr-max-records"].as<uint32_t>();
+    } catch (const runtime_error &e) {
+      g_log<<Logger::Error<<"Unable to read 'axfr-max-records' value: "<<e.what()<<endl;
+    }
+  } else {
+    config["axfr-max-records"] = 0;
+  }
+
   if (config["axfr-timeout"]) {
     try {
       config["axfr-timeout"].as<uint16_t>();
@@ -1062,7 +1075,8 @@ int main(int argc, char** argv) {
   std::thread ut(updateThread,
       config["work-dir"].as<string>(),
       config["keep"].as<uint16_t>(),
-      config["axfr-timeout"].as<uint16_t>());
+      config["axfr-timeout"].as<uint16_t>(),
+      config["axfr-max-records"].as<uint32_t>());
 
   vector<std::thread> tcpHandlers;
   tcpHandlers.reserve(config["tcp-in-threads"].as<uint16_t>());
index 6d991c6ed085fa0e578502f6b62d6737ec854029..beafb192408af3204ce1677d23e5fdc282dff8b4 100644 (file)
@@ -28,6 +28,12 @@ acl:
   - '127.0.0.0/8'
   - '::1'
 
+# Maximum number of records allowed in a single zone. ixfrdist will abort the
+# zone transfer from the master when more than this number of records have been
+# received. A value of 0 (the default) means unlimited
+#
+axfr-max-records: 0
+
 # Timeout in seconds an AXFR transaction requested by ixfrdist may take.
 # Increase this when the network to the authoritative servers is slow or the
 # domains are very large and you experience timeouts. Set to 20 by default or