* Default: yes
If a PID file should be written. Available since 4.0.
+
+## `xfr-max-received-mbytes`
+* Integer
+* Default: 100
+
+Specifies the maximum number of received megabytes allowed on an incoming AXFR/IXFR update, to prevent
+resource exhaustion. A value of 0 means no restriction.
* tsigalgo = the name of the TSIG algorithm (like 'hmac-md5') used
* tsigsecret = base64 encoded TSIG secret
* refresh = an integer describing the interval between checks for updates. By default, the RPZ zone's default is used
+* maxReceivedMBytes = the maximum size in megabytes of an AXFR/IXFR update, to prevent resource exhaustion.
+The default value of 0 means no restriction.
If no settings are included, the RPZ is taken literally with no overrides applied.
::arg().setSwitch("outgoing-axfr-expand-alias", "Expand ALIAS records during outgoing AXFR")="no";
::arg().setSwitch("8bit-dns", "Allow 8bit dns queries")="no";
+
+ ::arg().set("xfr-max-received-mbytes", "Maximum number of megabytes received from an incoming XFR")="100";
}
static time_t s_start=time(0);
// Returns pairs of "remove & add" vectors. If you get an empty remove, it means you got an AXFR!
vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr,
- const TSIGTriplet& tt, const ComboAddress* laddr)
+ const TSIGTriplet& tt, const ComboAddress* laddr, size_t maxReceivedBytes)
{
vector<pair<vector<DNSRecord>, vector<DNSRecord> > > ret;
vector<uint8_t> packet;
// CURRENT MASTER SOA
shared_ptr<SOARecordContent> masterSOA;
vector<DNSRecord> records;
+ size_t receivedBytes = 0;
for(;;) {
if(s.read((char*)&len, 2)!=2)
break;
// cout<<"Got chunk of "<<len<<" bytes"<<endl;
if(!len)
break;
+
+ if (maxReceivedBytes > 0 && (maxReceivedBytes - receivedBytes) < (size_t) len)
+ throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toString()+"' from master '"+master.toStringWithPort());
+
char reply[len];
readn2(s.getHandle(), reply, len);
+ receivedBytes += len;
MOADNSParser mdp(string(reply, len));
if(mdp.d_header.rcode)
throw std::runtime_error("Got an error trying to IXFR zone '"+zone.toString()+"' from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode));
vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone,
const DNSRecord& sr, const TSIGTriplet& tt=TSIGTriplet(),
- const ComboAddress* laddr=0);
+ const ComboAddress* laddr=0, size_t maxReceivedBytes=0);
TSIGTriplet tt;
int refresh=0;
std::string polName;
+ size_t maxReceivedXFRMBytes = 0;
if(options) {
auto& have = *options;
if(have.count("policyName")) {
if(have.count("refresh")) {
refresh = boost::get<int>(constGet(have,"refresh"));
}
+ if(have.count("maxReceivedMBytes")) {
+ maxReceivedXFRMBytes = static_cast<size_t>(boost::get<int>(constGet(have,"maxReceivedMBytes")));
+ }
}
ComboAddress master(master_, 53);
DNSName zone(zone_);
- auto sr=loadRPZFromServer(master, zone, lci.dfe, polName, defpol, 0, tt);
+ auto sr=loadRPZFromServer(master, zone, lci.dfe, polName, defpol, 0, tt, maxReceivedXFRMBytes * 1024 * 1024);
if(refresh)
sr->d_st.refresh=refresh;
- std::thread t(RPZIXFRTracker, master, zone, polName, tt, sr);
+ std::thread t(RPZIXFRTracker, master, zone, polName, tt, sr, maxReceivedXFRMBytes * 1024 * 1024);
t.detach();
}
catch(std::exception& e) {
}
-void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const std::string& polName, const TSIGTriplet& tt, shared_ptr<SOARecordContent> oursr)
+void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const std::string& polName, const TSIGTriplet& tt, shared_ptr<SOARecordContent> oursr, size_t maxReceivedBytes)
{
int refresh = oursr->d_st.refresh;
for(;;) {
L<<Logger::Info<<"Getting IXFR deltas for "<<zone<<" from "<<master.toStringWithPort()<<", our serial: "<<getRR<SOARecordContent>(dr)->d_st.serial<<endl;
vector<pair<vector<DNSRecord>, vector<DNSRecord> > > deltas;
try {
- deltas = getIXFRDeltas(master, zone, dr, tt);
+ deltas = getIXFRDeltas(master, zone, dr, tt, nullptr, maxReceivedBytes);
} catch(std::runtime_error& e ){
L<<Logger::Warning<<e.what()<<endl;
continue;
AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
const DNSName& domain,
const TSIGTriplet& tt,
- const ComboAddress* laddr)
- : d_tt(tt), d_tsigPos(0), d_nonSignedMessages(0)
+ const ComboAddress* laddr,
+ size_t maxReceivedBytes)
+ : d_tt(tt), d_receivedBytes(0), d_maxReceivedBytes(maxReceivedBytes), d_tsigPos(0), d_nonSignedMessages(0)
{
ComboAddress local;
if (laddr != NULL) {
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;
AXFRRetriever(const ComboAddress& remote,
const DNSName& zone,
const TSIGTriplet& tt = TSIGTriplet(),
- const ComboAddress* laddr = NULL);
- ~AXFRRetriever();
+ const ComboAddress* laddr = NULL,
+ size_t maxReceivedBytes=0);
+ ~AXFRRetriever();
int getChunk(Resolver::res_t &res, vector<DNSRecord>* records=0);
private:
TSIGTriplet d_tt;
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;
}
}
-shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, const std::string& polName, boost::optional<DNSFilterEngine::Policy> defpol, int place, const TSIGTriplet& tt)
+shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, const std::string& polName, boost::optional<DNSFilterEngine::Policy> defpol, int place, const TSIGTriplet& tt, size_t maxReceivedBytes)
{
L<<Logger::Warning<<"Loading RPZ zone '"<<zone<<"' from "<<master.toStringWithPort()<<endl;
if(!tt.name.empty())
L<<Logger::Warning<<"With TSIG key '"<<tt.name<<"' of algorithm '"<<tt.algo<<"'"<<endl;
ComboAddress local= master.sin4.sin_family == AF_INET ? ComboAddress("0.0.0.0") : ComboAddress("::"); // should be configurable
- AXFRRetriever axfr(master, zone, tt, &local);
+ AXFRRetriever axfr(master, zone, tt, &local, maxReceivedBytes);
unsigned int nrecords=0;
Resolver::res_t nop;
vector<DNSRecord> chunk;
#include "dnsrecords.hh"
int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, const std::string& policyName, boost::optional<DNSFilterEngine::Policy> defpol, int place);
-std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, const std::string& policyName, boost::optional<DNSFilterEngine::Policy> defpol, int place, const TSIGTriplet& tt);
+std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, const std::string& policyName, boost::optional<DNSFilterEngine::Policy> defpol, int place, const TSIGTriplet& tt, size_t maxReceivedBytes);
void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, const std::string& policyName, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, int place);
-void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const std::string& policyName, const TSIGTriplet &tt, shared_ptr<SOARecordContent> oursr);
+void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const std::string& policyName, const TSIGTriplet &tt, shared_ptr<SOARecordContent> oursr, size_t maxReceivedBytes);
DNSRecord dr;
dr.d_content = std::make_shared<SOARecordContent>(DNSName("."), DNSName("."), st);
- auto deltas = getIXFRDeltas(remote, domain, dr, tt, laddr.sin4.sin_family ? &laddr : 0);
+ auto deltas = getIXFRDeltas(remote, domain, dr, tt, laddr.sin4.sin_family ? &laddr : 0, ((size_t) ::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024);
zs.numDeltas=deltas.size();
// cout<<"Got "<<deltas.size()<<" deltas from serial "<<di.serial<<", applying.."<<endl;
vector<DNSResourceRecord> doAxfr(const ComboAddress& raddr, const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, scoped_ptr<AuthLua>& pdl, ZoneStatus& zs)
{
vector<DNSResourceRecord> rrs;
- AXFRRetriever retriever(raddr, domain, tt, (laddr.sin4.sin_family == 0) ? NULL : &laddr);
+ AXFRRetriever retriever(raddr, domain, tt, (laddr.sin4.sin_family == 0) ? NULL : &laddr, ((size_t) ::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024);
Resolver::res_t recs;
bool first=true;
bool firstNSEC3{true};