From 1886a4b3ddf045c4b952a8f126d3dff02371b86d Mon Sep 17 00:00:00 2001 From: Pieter Lexis Date: Thu, 12 Nov 2020 14:32:02 +0100 Subject: [PATCH] Allow ip ranges as trusted-notification-proxy This also stops us from doing string comparison for that setting. Fixes #9711 --- docs/settings.rst | 7 +- pdns/Makefile.am | 3 + pdns/common_startup.cc | 3 + pdns/packethandler.cc | 5 +- pdns/test-trusted-notification-proxy_cc.cc | 88 ++++++++++++++++++++++ pdns/trusted-notification-proxy.cc | 46 +++++++++++ pdns/trusted-notification-proxy.hh | 39 ++++++++++ 7 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 pdns/test-trusted-notification-proxy_cc.cc create mode 100644 pdns/trusted-notification-proxy.cc create mode 100644 pdns/trusted-notification-proxy.hh diff --git a/docs/settings.rst b/docs/settings.rst index d9fa5f0607a9..314c865a5cd1 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -1723,9 +1723,12 @@ Enable the Linux-only traceback handler. ``trusted-notification-proxy`` ------------------------------ -- String +.. versionchanged:: 4.4.0 + This option now accepts a comma-separated list of IP ranges. This was a single IP address as a string before + +- IP ranges, separated by commas -IP address of incoming notification proxy +IP ranges of incoming notification proxies. .. _setting-udp-truncation-threshold: diff --git a/pdns/Makefile.am b/pdns/Makefile.am index d85f1d7050c1..dfdaf2289964 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -250,6 +250,7 @@ pdns_server_SOURCES = \ tcpreceiver.cc tcpreceiver.hh \ threadname.hh threadname.cc \ tkey.cc \ + trusted-notification-proxy.hh trusted-notification-proxy.cc \ tsigutils.hh tsigutils.cc \ tsigverifier.cc tsigverifier.hh \ ueberbackend.cc ueberbackend.hh \ @@ -1358,11 +1359,13 @@ testrunner_SOURCES = \ test-signers.cc \ test-statbag_cc.cc \ test-svc_records_cc.cc \ + test-trusted-notification-proxy_cc.cc \ test-tsig.cc \ test-ueberbackend_cc.cc \ test-zoneparser_tng_cc.cc \ testrunner.cc \ threadname.hh threadname.cc \ + trusted-notification-proxy.cc \ tsigverifier.cc tsigverifier.hh \ ueberbackend.cc ueberbackend.hh \ unix_utility.cc \ diff --git a/pdns/common_startup.cc b/pdns/common_startup.cc index 32fca88ede51..437ca3f7084f 100644 --- a/pdns/common_startup.cc +++ b/pdns/common_startup.cc @@ -32,6 +32,7 @@ #include "threadname.hh" #include "misc.hh" #include "query-local-address.hh" +#include "trusted-notification-proxy.hh" #include @@ -641,6 +642,8 @@ void mainthread() pdns::parseQueryLocalAddress(::arg()["query-local-address6"]); } + pdns::parseTrustedNotificationProxy(::arg()["trusted-notification-proxy"]); + // NOW SAFE TO CREATE THREADS! dl->go(); diff --git a/pdns/packethandler.cc b/pdns/packethandler.cc index 67a39c7ad98a..1cdb4470b884 100644 --- a/pdns/packethandler.cc +++ b/pdns/packethandler.cc @@ -45,6 +45,7 @@ #include "dnsproxy.hh" #include "version.hh" #include "common_startup.hh" +#include "trusted-notification-proxy.hh" #if 0 #undef DLOG @@ -864,7 +865,7 @@ int PacketHandler::trySuperMaster(const DNSPacket& p, const DNSName& tsigkeyname int PacketHandler::trySuperMasterSynchronous(const DNSPacket& p, const DNSName& tsigkeyname) { ComboAddress remote = p.getRemote(); - if(p.hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote.toString())) { + if(p.hasEDNSSubnet() && pdns::isAddressTrustedNotificationProxy(remote)) { remote = p.getRealRemote().getNetwork(); } remote.setPort(53); @@ -980,7 +981,7 @@ int PacketHandler::processNotify(const DNSPacket& p) return RCode::Refused; } - if(::arg().contains("trusted-notification-proxy", p.getRemote().toString())) { + if(pdns::isAddressTrustedNotificationProxy(p.getRemote())) { g_log< +#include "trusted-notification-proxy.hh" + +using namespace boost; + +BOOST_AUTO_TEST_SUITE(test_trusted_notification_proxy_cc) + +BOOST_AUTO_TEST_CASE(test_trusted_notification_proxy_bad_addrs) { + string addrs = "127.0.0.1111"; + BOOST_CHECK_THROW(pdns::parseTrustedNotificationProxy(addrs), PDNSException); + addrs = "127.0.0.1,:::2"; + BOOST_CHECK_THROW(pdns::parseTrustedNotificationProxy(addrs), PDNSException); +} + +BOOST_AUTO_TEST_CASE(test_trusted_notification_proxy_addresses_only) { + string addrs = "127.0.0.1"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.2"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + + addrs = "::1"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); + + addrs = "::1,192.0.2.4"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.4"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); +} + +BOOST_AUTO_TEST_CASE(test_trusted_notification_proxy_with_netmasks) { + string addrs = "127.0.0.0/8"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.1"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.2"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("128.0.0.2"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + + addrs = "192.0.2.0/25"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.2"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("128.0.0.2"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.128"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8::1"))); + + addrs = "2001:db8:15::/64"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8::1"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8:15::fee:1:2"))); + + addrs = "192.0.2.0/24,2001:db8:16::/64"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8:15::fee:1:2"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8:16::5353"))); +} + +BOOST_AUTO_TEST_CASE(test_trusted_notification_proxy_with_netmasks_and_addresses) { + string addrs = "192.0.2.1,2001:db8:16::/64"; + BOOST_CHECK_NO_THROW(pdns::parseTrustedNotificationProxy(addrs)); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("127.0.0.1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8::1"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8:15::fee:1:2"))); + BOOST_CHECK(!pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.2"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("192.0.2.1"))); + BOOST_CHECK(pdns::isAddressTrustedNotificationProxy(ComboAddress("2001:db8:16::5353"))); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/pdns/trusted-notification-proxy.cc b/pdns/trusted-notification-proxy.cc new file mode 100644 index 000000000000..f851493de626 --- /dev/null +++ b/pdns/trusted-notification-proxy.cc @@ -0,0 +1,46 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include +#include "trusted-notification-proxy.hh" + +namespace pdns { + static NetmaskGroup g_trustedNotificationProxies; + + void parseTrustedNotificationProxy(const std::string &addresses) { + g_trustedNotificationProxies.clear(); + std::vector parts; + stringtok(parts, addresses, ",\t "); + for (auto const &a : parts) { + try { + g_trustedNotificationProxies.addMask(Netmask(a)); + } catch (const PDNSException &e) { + throw PDNSException("Unable to add address " + a + " as a trusted-notification-proxy: " + e.reason); + } catch (const std::exception &e) { + throw PDNSException("Unable to add address " + a + " as a trusted-notification-proxy: " + e.what()); + } + } + } + + bool isAddressTrustedNotificationProxy(const ComboAddress &address) { + return g_trustedNotificationProxies.match(address); + } +} // namespace pdns diff --git a/pdns/trusted-notification-proxy.hh b/pdns/trusted-notification-proxy.hh new file mode 100644 index 000000000000..903832be14e6 --- /dev/null +++ b/pdns/trusted-notification-proxy.hh @@ -0,0 +1,39 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +#include +#include "iputils.hh" + +namespace pdns { + /*! Parses the provided string into the trusted-notification variable + * + * Replaces any existing masks + * + * Throws on error. + * + * @param addresses String of addresses, separated by comma's + */ + void parseTrustedNotificationProxy(const std::string &addresses); + + bool isAddressTrustedNotificationProxy(const ComboAddress &address); +} // namespace pdns