From: Pieter Lexis Date: Thu, 23 Aug 2018 09:35:22 +0000 (+0200) Subject: ixfrdist: Add option to limit AXFR record count X-Git-Tag: auth-4.2.0-beta1~1^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ef6f0c6ff3b4f710e0e87d70c84756a6280d003f;p=thirdparty%2Fpdns.git ixfrdist: Add option to limit AXFR record count --- diff --git a/docs/manpages/ixfrdist.yml.5.rst b/docs/manpages/ixfrdist.yml.5.rst index d39b66543d..4f409303df 100644 --- a/docs/manpages/ixfrdist.yml.5.rst +++ b/docs/manpages/ixfrdist.yml.5.rst @@ -54,6 +54,11 @@ Options Entries without a netmask will be interpreted as a single address. By default, the ACL is set is ``127.0.0.0/8`` and ``::1/128``. +:axfr-max-records: + Maximum number of records allowed in an AXFR transaction requested by :program:`ixfrdist`. + This may prevent untrusted sources from using all the process memory. + By default, this setting is ``0``, which means "unlimited". + :axfr-timeout: Timeout in seconds an AXFR transaction requested by :program:`ixfrdist` may take. Increase this when the network to the authoritative servers is slow or the domains are very large and you experience timeouts. diff --git a/pdns/ixfrdist.cc b/pdns/ixfrdist.cc index 4a768ddf4b..0c516fdce9 100644 --- a/pdns/ixfrdist.cc +++ b/pdns/ixfrdist.cc @@ -206,7 +206,7 @@ static void makeIXFRDiff(const records_t& from, const records_t& to, ixfrdiff_t& } } -void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& axfrTimeout) { +void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& axfrTimeout, const uint32_t axfrMaxRecords) { std::map lastCheck; // Initialize the serials we have @@ -299,7 +299,7 @@ void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& a shared_ptr soa; try { AXFRRetriever axfr(master, domain, tt, &local); - unsigned int nrecords=0; + uint32_t nrecords=0; Resolver::res_t nop; vector chunk; records_t records; @@ -316,6 +316,9 @@ void updateThread(const string& workdir, const uint16_t& keep, const uint16_t& a soa = getRR(dr); } } + if (axfrMaxRecords != 0 && nrecords > axfrMaxRecords) { + throw PDNSException("Received more than " + std::to_string(axfrMaxRecords) + " records in AXFR, aborted"); + } axfr_now = time(nullptr); if (axfr_now - t_start > axfrTimeout) { throw PDNSException("Total AXFR time exceeded!"); @@ -780,6 +783,16 @@ bool parseAndCheckConfig(const string& configpath, YAML::Node& config) { config["keep"] = 20; } + if (config["axfr-max-records"]) { + try { + config["axfr-max-records"].as(); + } catch (const runtime_error &e) { + g_log<(); @@ -1062,7 +1075,8 @@ int main(int argc, char** argv) { std::thread ut(updateThread, config["work-dir"].as(), config["keep"].as(), - config["axfr-timeout"].as()); + config["axfr-timeout"].as(), + config["axfr-max-records"].as()); vector tcpHandlers; tcpHandlers.reserve(config["tcp-in-threads"].as()); diff --git a/pdns/ixfrdist.example.yml b/pdns/ixfrdist.example.yml index 6d991c6ed0..beafb19240 100644 --- a/pdns/ixfrdist.example.yml +++ b/pdns/ixfrdist.example.yml @@ -28,6 +28,12 @@ acl: - '127.0.0.0/8' - '::1' +# Maximum number of records allowed in a single zone. ixfrdist will abort the +# zone transfer from the master when more than this number of records have been +# received. A value of 0 (the default) means unlimited +# +axfr-max-records: 0 + # Timeout in seconds an AXFR transaction requested by ixfrdist may take. # Increase this when the network to the authoritative servers is slow or the # domains are very large and you experience timeouts. Set to 20 by default or