Blob Blame History Raw
From 2886c5826dd9af891cbaa3ac9fd928838ef75387 Mon Sep 17 00:00:00 2001
From: Remi Gacogne <remi.gacogne@powerdns.com>
Date: Thu, 7 Jul 2016 16:17:22 +0200
Subject: [PATCH 2/2] Add limits to the size of received AXFR, in megabytes

This prevents resource exhaustion in case the master is sending a
very large amount of data in an update.

(cherry picked from commit a014f4c224a7b21f1c648257d1fd1128413129aa)
---
 pdns/common_startup.cc    |  2 ++
 pdns/docs/pdns.xml        | 11 +++++++++++
 pdns/pdns.conf-dist       |  4 ++++
 pdns/resolver.cc          | 15 +++++++++++----
 pdns/resolver.hh          |  5 ++++-
 pdns/slavecommunicator.cc |  2 +-
 6 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/pdns/common_startup.cc b/pdns/common_startup.cc
index 41ca348..adc50e2 100644
--- a/pdns/common_startup.cc
+++ b/pdns/common_startup.cc
@@ -150,6 +150,8 @@ void declareArguments()
 
   ::arg().set("include-dir","Include *.conf files from this directory");
   ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
+
+  ::arg().set("xfr-max-received-mbytes", "Maximum number of megabytes received from an incoming AXFR")="100";
 }
 
 void declareStats(void)
diff --git a/pdns/pdns.conf-dist b/pdns/pdns.conf-dist
index ccb03f9..146f89f 100644
--- a/pdns/pdns.conf-dist
+++ b/pdns/pdns.conf-dist
@@ -464,4 +464,8 @@
 #
 # wildcard-url=no
 
+#################################
+# xfr-max-received-mbytes	Maximum number of megabytes received from an incoming AXFR
+#
+# xfr-max-received-mbytes=100
 
diff --git a/pdns/resolver.cc b/pdns/resolver.cc
index 792c8fb..9dd9182 100644
--- a/pdns/resolver.cc
+++ b/pdns/resolver.cc
@@ -305,8 +305,9 @@ AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
 	const string& tsigkeyname,
 	const string& tsigalgorithm, 
 	const string& tsigsecret,
-	const ComboAddress* laddr)
-: d_tsigkeyname(tsigkeyname), d_tsigsecret(tsigsecret), d_tsigPos(0), d_nonSignedMessages(0)
+	const ComboAddress* laddr,
+	size_t maxReceivedBytes)
+: d_tsigkeyname(tsigkeyname), d_tsigsecret(tsigsecret), d_receivedBytes(0), d_maxReceivedBytes(maxReceivedBytes), d_tsigPos(0), d_nonSignedMessages(0)
 {
   ComboAddress local;
   if (laddr != NULL) {
@@ -384,8 +385,14 @@ int AXFRRetriever::getChunk(Resolver::res_t &res) // Implementation is making su
   int len=getLength();
   if(len<0)
     throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
-  
-  timeoutReadn(len); 
+
+  if (d_maxReceivedBytes > 0 && (d_maxReceivedBytes - d_receivedBytes) < (size_t) len)
+    throw ResolverException("Reached the maximum number of received bytes during AXFR");
+
+  timeoutReadn(len);
+
+  d_receivedBytes += (uint16_t) len;
+
   MOADNSParser mdp(d_buf.get(), len);
 
   int err = parseResult(mdp, "", 0, 0, &res);
diff --git a/pdns/resolver.hh b/pdns/resolver.hh
index 3633bf2..a783b84 100644
--- a/pdns/resolver.hh
+++ b/pdns/resolver.hh
@@ -86,7 +86,8 @@ class AXFRRetriever : public boost::noncopyable
         const string& tsigkeyname=string(),
         const string& tsigalgorithm=string(),
         const string& tsigsecret=string(),
-        const ComboAddress* laddr = NULL);
+        const ComboAddress* laddr = NULL,
+        size_t maxReceivedBytes=0);
 	~AXFRRetriever();
     int getChunk(Resolver::res_t &res);  
   
@@ -105,6 +106,8 @@ class AXFRRetriever : public boost::noncopyable
     string d_tsigsecret;
     string d_prevMac; // RFC2845 4.4
     string d_signData;
+    size_t d_receivedBytes;
+    size_t d_maxReceivedBytes;
     uint32_t d_tsigPos;
     uint d_nonSignedMessages; // RFC2845 4.4
     TSIGRecordContent d_trc;
diff --git a/pdns/slavecommunicator.cc b/pdns/slavecommunicator.cc
index 492ac41..12c2316 100644
--- a/pdns/slavecommunicator.cc
+++ b/pdns/slavecommunicator.cc
@@ -153,7 +153,7 @@ void CommunicatorClass::suck(const string &domain,const string &remote)
     vector<DNSResourceRecord> rrs;
 
     ComboAddress raddr(remote, 53);
-    AXFRRetriever retriever(raddr, domain.c_str(), tsigkeyname, tsigalgorithm, tsigsecret, (laddr.sin4.sin_family == 0) ? NULL : &laddr);
+    AXFRRetriever retriever(raddr, domain.c_str(), tsigkeyname, tsigalgorithm, tsigsecret, (laddr.sin4.sin_family == 0) ? NULL : &laddr, ((size_t) ::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024);
     Resolver::res_t recs;
     while(retriever.getChunk(recs)) {
       if(first) {
-- 
2.10.2