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