From 2886c5826dd9af891cbaa3ac9fd928838ef75387 Mon Sep 17 00:00:00 2001 From: Remi Gacogne 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 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