From a014f4c224a7b21f1c648257d1fd1128413129aa Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Thu, 7 Jul 2016 16:17:22 +0200 Subject: [PATCH] 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. --- pdns/common_startup.cc | 2 ++ pdns/docs/pdns.xml | 11 +++++++++++ pdns/pdns.conf-dist | 5 +++++ pdns/resolver.cc | 15 +++++++++++---- pdns/resolver.hh | 5 ++++- pdns/slavecommunicator.cc | 2 +- 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/pdns/common_startup.cc b/pdns/common_startup.cc index b9c2165de5..6a10cea4c7 100644 --- a/pdns/common_startup.cc +++ b/pdns/common_startup.cc @@ -170,6 +170,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"; } static uint64_t uptimeOfProcess(const std::string& str) diff --git a/pdns/docs/pdns.xml b/pdns/docs/pdns.xml index df45dc692d..3b3b7eaf8f 100644 --- a/pdns/docs/pdns.xml +++ b/pdns/docs/pdns.xml @@ -17863,6 +17863,17 @@ This setting will make PowerDNS renotify the slaves after an AXFR is *received* Check for wildcard URL records. + + xfr-max-received-mbytes=... + + + Specifies the maximum number of received megabytes allowed on an incoming AXFR update, to prevent + resource exhaustion. A value of 0 means no restriction. + The default is 100. Available since 3.4.10. + + + + diff --git a/pdns/pdns.conf-dist b/pdns/pdns.conf-dist index b9c0bd2ee0..287eee46f8 100644 --- a/pdns/pdns.conf-dist +++ b/pdns/pdns.conf-dist @@ -534,4 +534,9 @@ # # webserver-print-arguments=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 501ee2554b..f4e30f2a0e 100644 --- a/pdns/resolver.cc +++ b/pdns/resolver.cc @@ -379,8 +379,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) { @@ -461,8 +462,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 28fdb12a1b..78f588b2d1 100644 --- a/pdns/resolver.hh +++ b/pdns/resolver.hh @@ -85,7 +85,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); @@ -104,6 +105,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 542c41d217..e068904784 100644 --- a/pdns/slavecommunicator.cc +++ b/pdns/slavecommunicator.cc @@ -151,7 +151,7 @@ void CommunicatorClass::suck(const string &domain,const string &remote) vector 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.47.2