dnswriter.cc dnswriter.hh \
dolog.hh \
ednscookies.cc ednscookies.hh \
+ ednsextendederror.cc ednsextendederror.hh \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
ext/luawrapper/include/LuaContext.hpp \
test-dnsdistasync.cc \
test-dnsdistbackend_cc.cc \
test-dnsdistdynblocks_hh.cc \
+ test-dnsdistedns.cc \
test-dnsdistkvs_cc.cc \
test-dnsdistlbpolicies_cc.cc \
test-dnsdistluanetwork.cc \
size_t optContentStart = 0;
uint16_t optContentLen = 0;
uint16_t infoCode{0};
- std::string extraText;
+ std::optional<std::string> extraText{std::nullopt};
/* we need at least 2 bytes after the option length (info-code) */
if (!isEDNSOptionInOpt(packet, optStart, optLen, EDNSOptionCode::EXTENDEDERROR, &optContentStart, &optContentLen) || optContentLen < sizeof(infoCode)) {
return std::make_pair(std::nullopt, std::nullopt);
infoCode = ntohs(infoCode);
if (optContentLen > sizeof(infoCode)) {
- extraText.resize(optContentLen - sizeof(infoCode));
- memcpy(extraText.data(), &packet.at(optContentStart + sizeof(infoCode)), optContentLen - sizeof(infoCode));
+ extraText = std::string();
+ extraText->resize(optContentLen - sizeof(infoCode));
+ memcpy(extraText->data(), &packet.at(optContentStart + sizeof(infoCode)), optContentLen - sizeof(infoCode));
}
return std::make_pair(infoCode, std::move(extraText));
}
--- /dev/null
+../ednsextendederror.cc
\ No newline at end of file
--- /dev/null
+../ednsextendederror.hh
\ No newline at end of file
--- /dev/null
+/*
+ * 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.
+ */
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+
+#include "dnsdist-edns.hh"
+#include "dnsname.hh"
+#include "dnswriter.hh"
+#include "ednscookies.hh"
+#include "ednsextendederror.hh"
+#include "ednsoptions.hh"
+#include "ednssubnet.hh"
+
+BOOST_AUTO_TEST_SUITE(test_dnsdist_edns)
+
+BOOST_AUTO_TEST_CASE(getExtendedDNSError)
+{
+ const DNSName name("www.powerdns.com.");
+
+ {
+ /* no EDNS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(!infoCode);
+ BOOST_CHECK(!extraText);
+ }
+
+ {
+ /* EDNS but no EDE */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ pw.addOpt(512, 0, 0);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(!infoCode);
+ BOOST_CHECK(!extraText);
+ }
+
+ {
+ /* EDE with a numerical code but no text */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::NetworkError),
+ .extraText = ""};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(!extraText);
+ }
+
+ {
+ /* EDE with both code and text */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+
+ {
+ /* EDE with truncated text */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ /* truncate the EDE text by one byte */
+ query.resize(query.size() - 1U);
+
+ BOOST_CHECK_THROW(dnsdist::edns::getExtendedDNSError(query), std::range_error);
+ }
+
+ {
+ /* EDE before ECS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ EDNSSubnetOpts ecsOpt;
+ ecsOpt.source = Netmask(ComboAddress("192.0.2.1"), 24U);
+ const auto ecsOptStr = makeEDNSSubnetOptsString(ecsOpt);
+ opts.emplace_back(EDNSOptionCode::ECS, ecsOptStr);
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+
+ {
+ /* EDE after ECS */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ EDNSSubnetOpts ecsOpt;
+ ecsOpt.source = Netmask(ComboAddress("192.0.2.1"), 24U);
+ const auto ecsOptStr = makeEDNSSubnetOptsString(ecsOpt);
+ opts.emplace_back(EDNSOptionCode::ECS, ecsOptStr);
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+
+ {
+ /* Cookie, EDE, padding */
+ PacketBuffer query;
+ GenericDNSPacketWriter<PacketBuffer> pw(query, name, QType::A, QClass::IN, 0);
+ pw.getHeader()->rd = 1;
+ GenericDNSPacketWriter<PacketBuffer>::optvect_t opts;
+ const EDNSCookiesOpt cookieOpt("deadbeefdeadbeef");
+ const auto cookieOptStr = cookieOpt.makeOptString();
+ opts.emplace_back(EDNSOptionCode::COOKIE, cookieOptStr);
+ const EDNSExtendedError ede{
+ .infoCode = static_cast<uint16_t>(EDNSExtendedError::code::Synthesized),
+ .extraText = "Synthesized from aggressive NSEC cache"};
+ opts.emplace_back(EDNSOptionCode::EXTENDEDERROR, makeEDNSExtendedErrorOptString(ede));
+ std::string paddingOptStr;
+ paddingOptStr.resize(42U);
+ opts.emplace_back(EDNSOptionCode::PADDING, paddingOptStr);
+ pw.addOpt(512, 0, 0, opts);
+ pw.commit();
+
+ auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(query);
+ BOOST_CHECK(infoCode);
+ BOOST_CHECK_EQUAL(*infoCode, ede.infoCode);
+ BOOST_CHECK(extraText);
+ BOOST_CHECK_EQUAL(*extraText, ede.extraText);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END();
void startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=QClass::IN, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, bool compress=true);
/** Shorthand way to add an Opt-record, for example for EDNS0 purposes */
- typedef vector<pair<uint16_t,std::string> > optvect_t;
+ using optvect_t = vector<pair<uint16_t,std::string> >;
void addOpt(const uint16_t udpsize, const uint16_t extRCode, const uint16_t ednsFlags, const optvect_t& options=optvect_t(), const uint8_t version=0);
/** needs to be called after the last record is added, but can be called again and again later on. Is called internally by startRecord too.
--- /dev/null
+/*
+ * 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 <limits>
+
+#include "ednsextendederror.hh"
+
+static bool getEDNSExtendedErrorOptFromStringView(const std::string_view& option, EDNSExtendedError& eee)
+{
+ if (option.size() < sizeof(uint16_t)) {
+ return false;
+ }
+ eee.infoCode = static_cast<uint8_t>(option.at(0)) * 256 + static_cast<uint8_t>(option.at(1));
+
+ if (option.size() > sizeof(uint16_t)) {
+ eee.extraText = std::string(&option.at(sizeof(uint16_t)), option.size() - sizeof(uint16_t));
+ }
+
+ return true;
+}
+
+bool getEDNSExtendedErrorOptFromString(const string& option, EDNSExtendedError& eee)
+{
+ return getEDNSExtendedErrorOptFromStringView(std::string_view(option), eee);
+}
+
+bool getEDNSExtendedErrorOptFromString(const char* option, unsigned int len, EDNSExtendedError& eee)
+{
+ return getEDNSExtendedErrorOptFromStringView(std::string_view(option, len), eee);
+}
+
+string makeEDNSExtendedErrorOptString(const EDNSExtendedError& eee)
+{
+ if (eee.extraText.size() > static_cast<size_t>(std::numeric_limits<uint16_t>::max() - 2)) {
+ throw std::runtime_error("Trying to create an EDNS Extended Error option with an extra text of size " + std::to_string(eee.extraText.size()));
+ }
+
+ string ret;
+ ret.reserve(sizeof(uint16_t) + eee.extraText.size());
+ ret.resize(sizeof(uint16_t));
+
+ ret[0] = static_cast<char>(static_cast<uint16_t>(eee.infoCode) / 256);
+ ret[1] = static_cast<char>(static_cast<uint16_t>(eee.infoCode) % 256);
+ ret.append(eee.extraText);
+
+ return ret;
+}
--- /dev/null
+/*
+ * 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 "namespaces.hh"
+
+struct EDNSExtendedError
+{
+ enum class code : uint16_t
+ {
+ Other = 0,
+ UnsupportedDNSKEYAlgorithm = 1,
+ UnsupportedDSDigestType = 2,
+ StaleAnswer = 3,
+ ForgedAnswer = 4,
+ DNSSECIndeterminate = 5,
+ DNSSECBogus = 6,
+ SignatureExpired = 7,
+ SignatureNotYetValid = 8,
+ DNSKEYMissing = 9,
+ RRSIGsMissing = 10,
+ NoZoneKeyBitSet = 11,
+ NSECMissing = 12,
+ CachedError = 13,
+ NotReady = 14,
+ Blocked = 15,
+ Censored = 16,
+ Filtered = 17,
+ Prohibited = 18,
+ StaleNXDOMAINAnswer = 19,
+ NotAuthoritative = 20,
+ NotSupported = 21,
+ NoReachableAuthority = 22,
+ NetworkError = 23,
+ InvalidData = 24,
+ SignatureExpiredBeforeValid = 25,
+ TooEarly = 26,
+ UnsupportedNSEC3IterationsValue = 27,
+ UnableToConformToPolicy = 28,
+ Synthesized = 29,
+ };
+ uint16_t infoCode;
+ std::string extraText;
+};
+
+bool getEDNSExtendedErrorOptFromString(const char* option, unsigned int len, EDNSExtendedError& eee);
+bool getEDNSExtendedErrorOptFromString(const string& option, EDNSExtendedError& eee);
+string makeEDNSExtendedErrorOptString(const EDNSExtendedError& eee);
+++ /dev/null
-/*
- * 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 <limits>
-
-#include "ednsextendederror.hh"
-
-static bool getEDNSExtendedErrorOptFromStringView(const std::string_view& option, EDNSExtendedError& eee)
-{
- if (option.size() < sizeof(uint16_t)) {
- return false;
- }
- eee.infoCode = static_cast<uint8_t>(option.at(0)) * 256 + static_cast<uint8_t>(option.at(1));
-
- if (option.size() > sizeof(uint16_t)) {
- eee.extraText = std::string(&option.at(sizeof(uint16_t)), option.size() - sizeof(uint16_t));
- }
-
- return true;
-}
-
-bool getEDNSExtendedErrorOptFromString(const string& option, EDNSExtendedError& eee)
-{
- return getEDNSExtendedErrorOptFromStringView(std::string_view(option), eee);
-}
-
-bool getEDNSExtendedErrorOptFromString(const char* option, unsigned int len, EDNSExtendedError& eee)
-{
- return getEDNSExtendedErrorOptFromStringView(std::string_view(option, len), eee);
-}
-
-string makeEDNSExtendedErrorOptString(const EDNSExtendedError& eee)
-{
- if (eee.extraText.size() > static_cast<size_t>(std::numeric_limits<uint16_t>::max() - 2)) {
- throw std::runtime_error("Trying to create an EDNS Extended Error option with an extra text of size " + std::to_string(eee.extraText.size()));
- }
-
- string ret;
- ret.reserve(sizeof(uint16_t) + eee.extraText.size());
- ret.resize(sizeof(uint16_t));
-
- ret[0] = static_cast<char>(static_cast<uint16_t>(eee.infoCode) / 256);
- ret[1] = static_cast<char>(static_cast<uint16_t>(eee.infoCode) % 256);
- ret.append(eee.extraText);
-
- return ret;
-}
--- /dev/null
+../ednsextendederror.cc
\ No newline at end of file
+++ /dev/null
-/*
- * 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 "namespaces.hh"
-
-struct EDNSExtendedError
-{
- enum class code : uint16_t
- {
- Other = 0,
- UnsupportedDNSKEYAlgorithm = 1,
- UnsupportedDSDigestType = 2,
- StaleAnswer = 3,
- ForgedAnswer = 4,
- DNSSECIndeterminate = 5,
- DNSSECBogus = 6,
- SignatureExpired = 7,
- SignatureNotYetValid = 8,
- DNSKEYMissing = 9,
- RRSIGsMissing = 10,
- NoZoneKeyBitSet = 11,
- NSECMissing = 12,
- CachedError = 13,
- NotReady = 14,
- Blocked = 15,
- Censored = 16,
- Filtered = 17,
- Prohibited = 18,
- StaleNXDOMAINAnswer = 19,
- NotAuthoritative = 20,
- NotSupported = 21,
- NoReachableAuthority = 22,
- NetworkError = 23,
- InvalidData = 24,
- SignatureExpiredBeforeValid = 25,
- TooEarly = 26,
- UnsupportedNSEC3IterationsValue = 27,
- UnableToConformToPolicy = 28,
- Synthesized = 29,
- };
- uint16_t infoCode;
- std::string extraText;
-};
-
-bool getEDNSExtendedErrorOptFromString(const char* option, unsigned int len, EDNSExtendedError& eee);
-bool getEDNSExtendedErrorOptFromString(const string& option, EDNSExtendedError& eee);
-string makeEDNSExtendedErrorOptString(const EDNSExtendedError& eee);
--- /dev/null
+../ednsextendederror.hh
\ No newline at end of file