From: Remi Gacogne Date: Tue, 12 Jun 2018 14:36:39 +0000 (+0200) Subject: rec: Add support for multiple rpz masters as failover X-Git-Tag: dnsdist-1.3.1~19^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5f31188631d00d7c8d05abae064b72f29ccabb63;p=pdns rec: Add support for multiple rpz masters as failover --- diff --git a/pdns/rec-lua-conf.cc b/pdns/rec-lua-conf.cc index daa254200..6f79ab01b 100644 --- a/pdns/rec-lua-conf.cc +++ b/pdns/rec-lua-conf.cc @@ -92,7 +92,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly) if(!ifs) throw PDNSException("Cannot open file '"+fname+"': "+strerror(errno)); - std::vector, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t, std::shared_ptr, std::string> > rpzMasterThreads; + std::vector, boost::optional, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t, std::shared_ptr, std::string> > rpzMasterThreads; auto luaconfsLocal = g_luaconfs.getLocal(); lci.generation = luaconfsLocal->generation + 1; @@ -139,7 +139,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly) } }); - Lua.writeFunction("rpzMaster", [&lci, &rpzMasterThreads](const string& master_, const string& zoneName, const boost::optional>>& options) { + Lua.writeFunction("rpzMaster", [&lci, &rpzMasterThreads](const boost::variant > >& masters_, const string& zoneName, const boost::optional>>& options) { boost::optional defpol; std::shared_ptr zone = std::make_shared(); @@ -149,7 +149,16 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly) uint16_t axfrTimeout = 20; uint32_t maxTTL = std::numeric_limits::max(); ComboAddress localAddress; - ComboAddress master(master_, 53); + std::vector masters; + if (masters_.type() == typeid(string)) { + masters.push_back(ComboAddress(boost::get(masters_), 53)); + } + else { + for (const auto& master : boost::get>>(masters_)) { + masters.push_back(ComboAddress(master.second, 53)); + } + } + size_t zoneIdx; std::string dumpFile; std::shared_ptr sr = nullptr; @@ -198,9 +207,13 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly) } } - if (localAddress != ComboAddress() && localAddress.sin4.sin_family != master.sin4.sin_family) { - // We were passed a localAddress, check if its AF matches the master's - throw PDNSException("Master address("+master.toString()+") is not of the same Address Family as the local address ("+localAddress.toString()+")."); + if (localAddress != ComboAddress()) { + // We were passed a localAddress, check if its AF matches the masters' + for (const auto& master : masters) { + if (localAddress.sin4.sin_family != master.sin4.sin_family) { + throw PDNSException("Master address("+master.toString()+") is not of the same Address Family as the local address ("+localAddress.toString()+")."); + } + } } DNSName domain(zoneName); @@ -236,7 +249,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly) exit(1); // FIXME proper exit code? } - rpzMasterThreads.push_back(std::make_tuple(master, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, sr, dumpFile)); + rpzMasterThreads.push_back(std::make_tuple(masters, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, sr, dumpFile)); }); typedef vector > > > > argvec_t; diff --git a/pdns/recursordist/docs/lua-config/rpz.rst b/pdns/recursordist/docs/lua-config/rpz.rst index 40abc8761..fe1785c15 100644 --- a/pdns/recursordist/docs/lua-config/rpz.rst +++ b/pdns/recursordist/docs/lua-config/rpz.rst @@ -33,9 +33,13 @@ In this example, 'policy.rpz' denotes the name of the zone to query for. .. function:: rpzMaster(address, name, settings) + .. versionchanged:: 4.2.0: + + The first parameter can be a list of addresses. + Load an RPZ from AXFR and keep retrieving with IXFR. - :param str address: The IP address to transfer the RPZ from + :param str address: The IP address to transfer the RPZ from. Also accepts a list of addresses since 4.2.0 in which case they will be tried one after another in the submitted order until a response is obtained :param str name: The name of this RPZ :param {} settings: A table to settings, see below diff --git a/pdns/rpzloader.cc b/pdns/rpzloader.cc index 9f26311f3..6ecc9c324 100644 --- a/pdns/rpzloader.cc +++ b/pdns/rpzloader.cc @@ -175,7 +175,7 @@ void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr zone, boost::optional defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, uint16_t axfrTimeout) +static shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr zone, boost::optional defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, uint16_t axfrTimeout) { g_log< defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout, std::shared_ptr sr, std::string dumpZoneFileName, uint64_t configGeneration) +void RPZIXFRTracker(const std::vector masters, boost::optional defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout, std::shared_ptr sr, std::string dumpZoneFileName, uint64_t configGeneration) { bool isPreloaded = sr != nullptr; auto luaconfsLocal = g_luaconfs.getLocal(); @@ -356,29 +356,34 @@ void RPZIXFRTracker(const ComboAddress& master, boost::optional newZone = std::make_shared(*oldZone); - try { - sr=loadRPZFromServer(master, zoneName, newZone, defpol, maxTTL, tt, maxReceivedBytes, localAddress, axfrTimeout); - if(refresh == 0) { - refresh = sr->d_st.refresh; + for (const auto& master : masters) { + try { + sr = loadRPZFromServer(master, zoneName, newZone, defpol, maxTTL, tt, maxReceivedBytes, localAddress, axfrTimeout); + if(refresh == 0) { + refresh = sr->d_st.refresh; + } + newZone->setSerial(sr->d_st.serial); + setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), true); + + g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) { + lci.dfe.setZone(zoneIdx, newZone); + }); + + if (!dumpZoneFileName.empty()) { + dumpZoneToDisk(zoneName, newZone, dumpZoneFileName); + } + + /* no need to try another master */ + break; } - newZone->setSerial(sr->d_st.serial); - setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), true); - - g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) { - lci.dfe.setZone(zoneIdx, newZone); - }); - - if (!dumpZoneFileName.empty()) { - dumpZoneToDisk(zoneName, newZone, dumpZoneFileName); + catch(const std::exception& e) { + g_log< 0 ? refresh : 10)<<" seconds...)"< 0 ? refresh : 10)<<" seconds...)"< 0 ? refresh : 10)<<" seconds...)"< 0 ? refresh : 10)<<" seconds...)"<(dr)->d_st.serial<, vector > > deltas; + for (const auto& master : masters) { + g_log<(dr)->d_st.serial<dfe.getZone(zoneIdx); diff --git a/pdns/rpzloader.hh b/pdns/rpzloader.hh index 5faf77d8b..b29f14501 100644 --- a/pdns/rpzloader.hh +++ b/pdns/rpzloader.hh @@ -27,9 +27,8 @@ extern bool g_logRPZChanges; std::shared_ptr loadRPZFromFile(const std::string& fname, std::shared_ptr zone, boost::optional defpol, uint32_t maxTTL); -std::shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr zone, boost::optional defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout); void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr zone, bool addOrRemove, boost::optional defpol, uint32_t maxTTL); -void RPZIXFRTracker(const ComboAddress& master, boost::optional defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout, shared_ptr sr, std::string dumpZoneFileName, uint64_t configGeneration); +void RPZIXFRTracker(const std::vector master, boost::optional defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout, shared_ptr sr, std::string dumpZoneFileName, uint64_t configGeneration); struct rpzStats { diff --git a/regression-tests.recursor-dnssec/test_RPZ.py b/regression-tests.recursor-dnssec/test_RPZ.py index 9ea04fe93..b2ca1bf96 100644 --- a/regression-tests.recursor-dnssec/test_RPZ.py +++ b/regression-tests.recursor-dnssec/test_RPZ.py @@ -150,7 +150,8 @@ class RPZRecursorTest(RecursorTest): global rpzServerPort _lua_config_file = """ - rpzMaster('127.0.0.1:%d', 'zone.rpz.', { refresh=1 }) + -- The first server is a bogus one, to test that we correctly fail over to the second one + rpzMaster({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1 }) """ % (rpzServerPort) _confdir = 'RPZ' _config_template = """