dnsdist-rule-chains.cc dnsdist-rule-chains.hh \
dnsdist-rules.cc dnsdist-rules.hh \
dnsdist-secpoll.cc dnsdist-secpoll.hh \
+ dnsdist-self-answers.cc dnsdist-self-answers.hh \
dnsdist-session-cache.cc dnsdist-session-cache.hh \
dnsdist-snmp.cc dnsdist-snmp.hh \
dnsdist-svc.cc dnsdist-svc.hh \
dnsdist-rings.cc dnsdist-rings.hh \
dnsdist-rule-chains.cc dnsdist-rule-chains.hh \
dnsdist-rules.cc dnsdist-rules.hh \
+ dnsdist-self-answers.cc dnsdist-self-answers.hh \
dnsdist-session-cache.cc dnsdist-session-cache.hh \
dnsdist-svc.cc dnsdist-svc.hh \
dnsdist-tcp-downstream.cc \
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-kvs.hh"
#include "dnsdist-rule-chains.hh"
+#include "dnsdist-self-answers.hh"
#include "dnsdist-snmp.hh"
#include "dnsdist-svc.hh"
class RCodeAction : public DNSAction
{
public:
- RCodeAction(uint8_t rcode) :
- d_rcode(rcode) {}
+ RCodeAction(uint8_t rcode, dnsdist::ResponseConfig responseConfig) :
+ d_responseConfig(responseConfig), d_rcode(rcode) {}
DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
{
return "set rcode " + std::to_string(d_rcode);
}
- [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
- {
- return d_responseConfig;
- }
private:
dnsdist::ResponseConfig d_responseConfig;
class ERCodeAction : public DNSAction
{
public:
- ERCodeAction(uint8_t rcode) :
- d_rcode(rcode) {}
+ ERCodeAction(uint8_t rcode, dnsdist::ResponseConfig responseConfig) :
+ d_responseConfig(responseConfig), d_rcode(rcode) {}
DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
{
dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
{
return "set ercode " + ERCode::to_s(d_rcode);
}
- [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
- {
- return d_responseConfig;
- }
private:
dnsdist::ResponseConfig d_responseConfig;
class SpoofSVCAction : public DNSAction
{
public:
- SpoofSVCAction(const LuaArray<SVCRecordParameters>& parameters)
+ SpoofSVCAction(const LuaArray<SVCRecordParameters>& parameters, dnsdist::ResponseConfig responseConfig) :
+ d_responseConfig(responseConfig)
{
d_payloads.reserve(parameters.size());
return "spoof SVC record ";
}
- [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
- {
- return d_responseConfig;
- }
-
private:
dnsdist::ResponseConfig d_responseConfig;
std::vector<std::vector<uint8_t>> d_payloads{};
std::atomic<uint64_t> LuaFFIPerThreadResponseAction::s_functionsCounter = 0;
thread_local std::map<uint64_t, LuaFFIPerThreadResponseAction::PerThreadState> LuaFFIPerThreadResponseAction::t_perThreadStates;
-thread_local std::default_random_engine SpoofAction::t_randomEngine;
-
-DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const
+class SpoofAction : public DNSAction
{
- uint16_t qtype = dnsquestion->ids.qtype;
- // do we even have a response?
- if (d_cname.empty() && d_rawResponses.empty() &&
- // make sure pre-forged response is greater than sizeof(dnsheader)
- (d_raw.size() < sizeof(dnsheader)) && d_types.count(qtype) == 0) {
- return Action::None;
- }
-
- if (d_raw.size() >= sizeof(dnsheader)) {
- auto questionId = dnsquestion->getHeader()->id;
- dnsquestion->getMutableData() = d_raw;
- dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [questionId](dnsheader& header) {
- header.id = questionId;
- return true;
- });
- return Action::HeaderModify;
- }
- std::vector<ComboAddress> addrs = {};
- std::vector<std::string> rawResponses = {};
- unsigned int totrdatalen = 0;
- size_t numberOfRecords = 0;
- if (!d_cname.empty()) {
- qtype = QType::CNAME;
- totrdatalen += d_cname.getStorage().size();
- numberOfRecords = 1;
- }
- else if (!d_rawResponses.empty()) {
- rawResponses.reserve(d_rawResponses.size());
- for (const auto& rawResponse : d_rawResponses) {
- totrdatalen += rawResponse.size();
- rawResponses.push_back(rawResponse);
- ++numberOfRecords;
- }
- if (rawResponses.size() > 1) {
- shuffle(rawResponses.begin(), rawResponses.end(), t_randomEngine);
- }
- }
- else {
+public:
+ SpoofAction(const vector<ComboAddress>& addrs, const dnsdist::ResponseConfig& responseConfig) :
+ d_responseConfig(responseConfig), d_addrs(addrs)
+ {
for (const auto& addr : d_addrs) {
- if (qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) || (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
- continue;
+ if (addr.isIPv4()) {
+ d_types.insert(QType::A);
+ }
+ else if (addr.isIPv6()) {
+ d_types.insert(QType::AAAA);
}
- totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
- addrs.push_back(addr);
- ++numberOfRecords;
}
- }
- if (addrs.size() > 1) {
- shuffle(addrs.begin(), addrs.end(), t_randomEngine);
+ if (!d_addrs.empty()) {
+ d_types.insert(QType::ANY);
+ }
}
- unsigned int qnameWireLength = 0;
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- DNSName ignore(reinterpret_cast<const char*>(dnsquestion->getData().data()), dnsquestion->getData().size(), sizeof(dnsheader), false, nullptr, nullptr, &qnameWireLength);
-
- if (dnsquestion->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen)) {
- return Action::None;
+ SpoofAction(const DNSName& cname, const dnsdist::ResponseConfig& responseConfig) :
+ d_responseConfig(responseConfig), d_cname(cname)
+ {
}
- bool dnssecOK = false;
- bool hadEDNS = false;
- if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
- hadEDNS = true;
- dnssecOK = ((dnsdist::getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
+ SpoofAction(const PacketBuffer& rawresponse) :
+ d_raw(rawresponse)
+ {
}
- auto& data = dnsquestion->getMutableData();
- data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen); // there goes your EDNS
- uint8_t* dest = &(data.at(sizeof(dnsheader) + qnameWireLength + 4));
+ SpoofAction(const vector<std::string>& raws, std::optional<uint16_t> typeForAny, const dnsdist::ResponseConfig& responseConfig) :
+ d_responseConfig(responseConfig), d_rawResponses(raws), d_rawTypeForAny(typeForAny)
+ {
+ }
- dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) {
- header.qr = true; // for good measure
- setResponseHeadersFromConfig(header, d_responseConfig);
- header.ancount = 0;
- header.arcount = 0; // for now, forget about your EDNS, we're marching over it
- return true;
- });
+ DNSAction::Action operator()(DNSQuestion* dnsquestion, string* ruleresult) const override;
- uint32_t ttl = htonl(d_responseConfig.ttl);
- uint16_t qclass = htons(dnsquestion->ids.qclass);
- std::array<unsigned char, 12> recordstart = {
- 0xc0, 0x0c, // compressed name
- 0, 0, // QTYPE
- 0, 0, // QCLASS
- 0, 0, 0, 0, // TTL
- 0, 0 // rdata length
- };
- static_assert(recordstart.size() == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
- memcpy(&recordstart[4], &qclass, sizeof(qclass));
- memcpy(&recordstart[6], &ttl, sizeof(ttl));
-
- if (qtype == QType::CNAME) {
- const auto& wireData = d_cname.getStorage(); // Note! This doesn't do compression!
- uint16_t rdataLen = htons(wireData.length());
- qtype = htons(qtype);
- memcpy(&recordstart[2], &qtype, sizeof(qtype));
- memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
-
- memcpy(dest, recordstart.data(), recordstart.size());
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- dest += recordstart.size();
- memcpy(dest, wireData.c_str(), wireData.length());
- dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
- header.ancount++;
- return true;
- });
- }
- else if (!rawResponses.empty()) {
- if (qtype == QType::ANY && d_rawTypeForAny) {
- qtype = *d_rawTypeForAny;
+ string toString() const override
+ {
+ string ret = "spoof in ";
+ if (!d_cname.empty()) {
+ ret += d_cname.toString() + " ";
+ }
+ if (d_rawResponses.size() > 0) {
+ ret += "raw bytes ";
+ }
+ else {
+ for (const auto& a : d_addrs)
+ ret += a.toString() + " ";
}
- qtype = htons(qtype);
- for (const auto& rawResponse : rawResponses) {
- uint16_t rdataLen = htons(rawResponse.size());
- memcpy(&recordstart[2], &qtype, sizeof(qtype));
- memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
+ return ret;
+ }
- memcpy(dest, recordstart.data(), sizeof(recordstart));
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- dest += recordstart.size();
+private:
+ dnsdist::ResponseConfig d_responseConfig;
+ std::vector<ComboAddress> d_addrs;
+ std::unordered_set<uint16_t> d_types;
+ std::vector<std::string> d_rawResponses;
+ PacketBuffer d_raw;
+ DNSName d_cname;
+ std::optional<uint16_t> d_rawTypeForAny{};
+};
- memcpy(dest, rawResponse.c_str(), rawResponse.size());
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- dest += rawResponse.size();
+DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const
+{
+ uint16_t qtype = dnsquestion->ids.qtype;
+ // do we even have a response?
+ if (d_cname.empty() && d_rawResponses.empty() &&
+ // make sure pre-forged response is greater than sizeof(dnsheader)
+ (d_raw.size() < sizeof(dnsheader)) && d_types.count(qtype) == 0) {
+ return Action::None;
+ }
- dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
- header.ancount++;
- return true;
- });
+ if (d_raw.size() >= sizeof(dnsheader)) {
+ dnsdist::self_answers::generateAnswerFromRawPacket(*dnsquestion, d_raw);
+ return Action::HeaderModify;
+ }
+
+ if (!d_cname.empty()) {
+ if (dnsdist::self_answers::generateAnswerFromCNAME(*dnsquestion, d_cname, d_responseConfig)) {
+ return Action::HeaderModify;
}
}
- else {
- for (const auto& addr : addrs) {
- uint16_t rdataLen = htons(addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
- qtype = htons(addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA);
- memcpy(&recordstart[2], &qtype, sizeof(qtype));
- memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
-
- memcpy(dest, recordstart.data(), recordstart.size());
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- dest += sizeof(recordstart);
-
- memcpy(dest,
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- addr.sin4.sin_family == AF_INET ? reinterpret_cast<const void*>(&addr.sin4.sin_addr.s_addr) : reinterpret_cast<const void*>(&addr.sin6.sin6_addr.s6_addr),
- addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- dest += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
- dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
- header.ancount++;
- return true;
- });
+ else if (!d_rawResponses.empty()) {
+ if (dnsdist::self_answers::generateAnswerFromRDataEntries(*dnsquestion, d_rawResponses, d_rawTypeForAny, d_responseConfig)) {
+ return Action::HeaderModify;
}
}
-
- auto finalANCount = dnsquestion->getHeader()->ancount;
- dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [finalANCount](dnsheader& header) {
- header.ancount = htons(finalANCount);
- return true;
- });
-
- if (hadEDNS) {
- addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0);
+ else {
+ if (dnsdist::self_answers::generateAnswerFromIPAddresses(*dnsquestion, d_addrs, d_responseConfig)) {
+ return Action::HeaderModify;
+ }
}
- return Action::HeaderModify;
+ return Action::None;
}
class SetMacAddrAction : public DNSAction
class HTTPStatusAction : public DNSAction
{
public:
- HTTPStatusAction(int code, PacketBuffer body, std::string contentType) :
- d_body(std::move(body)), d_contentType(std::move(contentType)), d_code(code)
+ HTTPStatusAction(int code, PacketBuffer body, std::string contentType, dnsdist::ResponseConfig responseConfig) :
+ d_responseConfig(responseConfig), d_body(std::move(body)), d_contentType(std::move(contentType)), d_code(code)
{
}
return "return an HTTP status of " + std::to_string(d_code);
}
- [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
- {
- return d_responseConfig;
- }
-
private:
dnsdist::ResponseConfig d_responseConfig;
PacketBuffer d_body;
uint32_t minimum;
};
- NegativeAndSOAAction(bool nxd, DNSName zone, uint32_t ttl, DNSName mname, DNSName rname, SOAParams params, bool soaInAuthoritySection) :
- d_zone(std::move(zone)), d_mname(std::move(mname)), d_rname(std::move(rname)), d_ttl(ttl), d_params(params), d_nxd(nxd), d_soaInAuthoritySection(soaInAuthoritySection)
+ NegativeAndSOAAction(bool nxd, DNSName zone, uint32_t ttl, DNSName mname, DNSName rname, SOAParams params, bool soaInAuthoritySection, dnsdist::ResponseConfig responseConfig) :
+ d_responseConfig(responseConfig), d_zone(std::move(zone)), d_mname(std::move(mname)), d_rname(std::move(rname)), d_ttl(ttl), d_params(params), d_nxd(nxd), d_soaInAuthoritySection(soaInAuthoritySection)
{
}
{
return std::string(d_nxd ? "NXD" : "NODATA") + " with SOA";
}
- [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
- {
- return d_responseConfig;
- }
private:
dnsdist::ResponseConfig d_responseConfig;
using responseParams_t = std::unordered_map<std::string, boost::variant<bool, uint32_t>>;
-static void parseResponseConfig(boost::optional<responseParams_t>& vars, dnsdist::ResponseConfig& config)
+static dnsdist::ResponseConfig parseResponseConfig(boost::optional<responseParams_t>& vars)
{
+ dnsdist::ResponseConfig config;
getOptionalValue<uint32_t>(vars, "ttl", config.ttl);
getOptionalValue<bool>(vars, "aa", config.setAA);
getOptionalValue<bool>(vars, "ad", config.setAD);
getOptionalValue<bool>(vars, "ra", config.setRA);
+ return config;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
}
}
- auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs));
- auto spoofaction = std::dynamic_pointer_cast<SpoofAction>(ret);
- parseResponseConfig(vars, spoofaction->getResponseConfig());
+ auto responseConfig = parseResponseConfig(vars);
checkAllParametersConsumed("SpoofAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs, responseConfig));
return ret;
});
luaCtx.writeFunction("SpoofSVCAction", [](const LuaArray<SVCRecordParameters>& parameters, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new SpoofSVCAction(parameters));
- auto spoofaction = std::dynamic_pointer_cast<SpoofSVCAction>(ret);
- parseResponseConfig(vars, spoofaction->getResponseConfig());
+ auto responseConfig = parseResponseConfig(vars);
+ checkAllParametersConsumed("SpoofAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new SpoofSVCAction(parameters, responseConfig));
return ret;
});
luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& cname, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(cname)));
- auto spoofaction = std::dynamic_pointer_cast<SpoofAction>(ret);
- parseResponseConfig(vars, spoofaction->getResponseConfig());
+ auto responseConfig = parseResponseConfig(vars);
checkAllParametersConsumed("SpoofCNAMEAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(cname), responseConfig));
return ret;
});
if (qtypeForAny > 0) {
qtypeForAnyParam = static_cast<uint16_t>(qtypeForAny);
}
- auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raws, qtypeForAnyParam));
- auto spoofaction = std::dynamic_pointer_cast<SpoofAction>(ret);
- parseResponseConfig(vars, spoofaction->getResponseConfig());
+ auto responseConfig = parseResponseConfig(vars);
checkAllParametersConsumed("SpoofRawAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raws, qtypeForAnyParam, responseConfig));
return ret;
});
if (len < sizeof(dnsheader)) {
throw std::runtime_error(std::string("SpoofPacketAction: given packet len is too small"));
}
- auto ret = std::shared_ptr<DNSAction>(new SpoofAction(response.c_str(), len));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto ret = std::shared_ptr<DNSAction>(new SpoofAction(PacketBuffer(response.data(), response.data() + len)));
return ret;
});
});
luaCtx.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode));
- auto rca = std::dynamic_pointer_cast<RCodeAction>(ret);
- parseResponseConfig(vars, rca->getResponseConfig());
+ auto responseConfig = parseResponseConfig(vars);
checkAllParametersConsumed("RCodeAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode, responseConfig));
return ret;
});
luaCtx.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
- auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret);
- parseResponseConfig(vars, erca->getResponseConfig());
+ auto responseConfig = parseResponseConfig(vars);
checkAllParametersConsumed("ERCodeAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode, responseConfig));
return ret;
});
#ifdef HAVE_DNS_OVER_HTTPS
luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : ""));
- auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
- parseResponseConfig(vars, hsa->getResponseConfig());
+ auto responseConfig = parseResponseConfig(vars);
checkAllParametersConsumed("HTTPStatusAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : "", responseConfig));
return ret;
});
#endif /* HAVE_DNS_OVER_HTTPS */
#endif /* defined(HAVE_LMDB) || defined(HAVE_CDB) */
luaCtx.writeFunction("NegativeAndSOAAction", [](bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, boost::optional<responseParams_t> vars) {
+ auto responseConfig = parseResponseConfig(vars);
bool soaInAuthoritySection = false;
getOptionalValue<bool>(vars, "soaInAuthoritySection", soaInAuthoritySection);
NegativeAndSOAAction::SOAParams params{
.retry = retry,
.expire = expire,
.minimum = minimum};
- auto ret = std::shared_ptr<DNSAction>(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), params, soaInAuthoritySection));
- auto action = std::dynamic_pointer_cast<NegativeAndSOAAction>(ret);
- parseResponseConfig(vars, action->getResponseConfig());
checkAllParametersConsumed("NegativeAndSOAAction", vars);
+ auto ret = std::shared_ptr<DNSAction>(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), params, soaInAuthoritySection, responseConfig));
return ret;
});
#include "dnsdist-ecs.hh"
#include "dnsdist-internal-queries.hh"
#include "dnsdist-lua.hh"
+#include "dnsdist-self-answers.hh"
#include "dnsdist-snmp.hh"
#include "dnsparser.hh"
});
luaCtx.registerFunction<void (DNSQuestion::*)(const boost::variant<LuaArray<ComboAddress>, LuaArray<std::string>>&, boost::optional<uint16_t>)>("spoof", [](DNSQuestion& dnsQuestion, const boost::variant<LuaArray<ComboAddress>, LuaArray<std::string>>& response, boost::optional<uint16_t> typeForAny) {
+ dnsdist::ResponseConfig responseConfig;
if (response.type() == typeid(LuaArray<ComboAddress>)) {
std::vector<ComboAddress> data;
auto responses = boost::get<LuaArray<ComboAddress>>(response);
for (const auto& resp : responses) {
data.push_back(resp.second);
}
- std::string result;
- SpoofAction tempSpoofAction(data);
- tempSpoofAction(&dnsQuestion, &result);
+ dnsdist::self_answers::generateAnswerFromIPAddresses(dnsQuestion, data, responseConfig);
return;
}
if (response.type() == typeid(LuaArray<std::string>)) {
for (const auto& resp : responses) {
data.push_back(resp.second);
}
- std::string result;
- SpoofAction tempSpoofAction(data, typeForAny ? *typeForAny : std::optional<uint16_t>());
- tempSpoofAction(&dnsQuestion, &result);
+ dnsdist::self_answers::generateAnswerFromRDataEntries(dnsQuestion, data, typeForAny ? *typeForAny : std::optional<uint16_t>(), responseConfig);
return;
}
});
#include "dnsdist-lua.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-rings.hh"
+#include "dnsdist-self-answers.hh"
#include "dnsdist-svc.hh"
#include "dnsdist-snmp.hh"
#include "dolog.hh"
void dnsdist_ffi_dnsquestion_spoof_packet(dnsdist_ffi_dnsquestion_t* dq, const char* raw, size_t len)
{
- std::string result;
- SpoofAction tempSpoofAction(raw, len);
- tempSpoofAction(dq->dq, &result);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ dnsdist::self_answers::generateAnswerFromRawPacket(*dq->dq, PacketBuffer(raw, raw + len));
}
void dnsdist_ffi_dnsquestion_spoof_raw(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
data.emplace_back(values[idx].value, values[idx].size);
}
- std::string result;
- SpoofAction tempSpoofAction(data, std::nullopt);
- tempSpoofAction(dq->dq, &result);
+ dnsdist::ResponseConfig config{};
+ dnsdist::self_answers::generateAnswerFromRDataEntries(*dq->dq, data, std::nullopt, config);
}
void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_raw_value_t* values, size_t valuesCount)
}
}
- std::string result;
- SpoofAction tempSpoofAction(data);
- tempSpoofAction(dq->dq, &result);
+ dnsdist::ResponseConfig config{};
+ dnsdist::self_answers::generateAnswerFromIPAddresses(*dq->dq, data, config);
}
void dnsdist_ffi_dnsquestion_set_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t max)
extern RecursiveLockGuarded<LuaContext> g_lua;
extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
-class SpoofAction : public DNSAction
-{
-public:
- SpoofAction(const vector<ComboAddress>& addrs) :
- d_addrs(addrs)
- {
- for (const auto& addr : d_addrs) {
- if (addr.isIPv4()) {
- d_types.insert(QType::A);
- }
- else if (addr.isIPv6()) {
- d_types.insert(QType::AAAA);
- }
- }
-
- if (!d_addrs.empty()) {
- d_types.insert(QType::ANY);
- }
- }
-
- SpoofAction(const DNSName& cname) :
- d_cname(cname)
- {
- }
-
- SpoofAction(const char* rawresponse, size_t len) :
- d_raw(rawresponse, rawresponse + len)
- {
- }
-
- SpoofAction(const vector<std::string>& raws, std::optional<uint16_t> typeForAny) :
- d_rawResponses(raws), d_rawTypeForAny(typeForAny)
- {
- }
-
- DNSAction::Action operator()(DNSQuestion* dnsquestion, string* ruleresult) const override;
-
- string toString() const override
- {
- string ret = "spoof in ";
- if (!d_cname.empty()) {
- ret += d_cname.toString() + " ";
- }
- if (d_rawResponses.size() > 0) {
- ret += "raw bytes ";
- }
- else {
- for (const auto& a : d_addrs)
- ret += a.toString() + " ";
- }
- return ret;
- }
-
- [[nodiscard]] dnsdist::ResponseConfig& getResponseConfig()
- {
- return d_responseConfig;
- }
-
-private:
- dnsdist::ResponseConfig d_responseConfig;
- static thread_local std::default_random_engine t_randomEngine;
- std::vector<ComboAddress> d_addrs;
- std::unordered_set<uint16_t> d_types;
- std::vector<std::string> d_rawResponses;
- PacketBuffer d_raw;
- DNSName d_cname;
- std::optional<uint16_t> d_rawTypeForAny{};
-};
-
template <class T>
using LuaArray = std::vector<std::pair<int, T>>;
template <class T>
--- /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 <random>
+
+#include "dnsdist-self-answers.hh"
+
+#include "dnsdist-configuration.hh"
+#include "dnsdist-ecs.hh"
+
+namespace dnsdist::self_answers
+{
+static thread_local std::default_random_engine t_randomEngine;
+
+static void addRecordHeader(PacketBuffer& packet, size_t& position, uint16_t qclass, uint32_t ttl, QType qtype, uint16_t rdataLen)
+{
+ std::array<unsigned char, 12> recordstart{
+ 0xc0, 0x0c, // compressed name
+ 0, 0, // QTYPE
+ 0, 0, // QCLASS
+ 0, 0, 0, 0, // TTL
+ 0, 0 // rdata length
+ };
+ ttl = htonl(ttl);
+ qclass = htons(qclass);
+ qtype = htons(qtype);
+ rdataLen = htons(rdataLen);
+ static_assert(recordstart.size() == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
+ memcpy(&recordstart.at(2), &qtype, sizeof(qtype));
+ memcpy(&recordstart.at(4), &qclass, sizeof(qclass));
+ memcpy(&recordstart.at(6), &ttl, sizeof(ttl));
+ memcpy(&recordstart.at(10), &rdataLen, sizeof(rdataLen));
+ memcpy(&packet.at(position), recordstart.data(), recordstart.size());
+ position += recordstart.size();
+}
+
+bool generateAnswerFromCNAME(DNSQuestion& dnsQuestion, const DNSName& cname, const dnsdist::ResponseConfig& responseConfig)
+{
+ QType qtype = QType::CNAME;
+ unsigned int totrdatalen = cname.getStorage().size();
+ size_t numberOfRecords = 1U;
+ auto qnameWireLength = dnsQuestion.ids.qname.wirelength();
+ if (dnsQuestion.getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen)) {
+ return false;
+ }
+
+ bool dnssecOK = false;
+ bool hadEDNS = false;
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses && queryHasEDNS(dnsQuestion)) {
+ hadEDNS = true;
+ dnssecOK = ((dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0);
+ }
+
+ auto& data = dnsQuestion.getMutableData();
+ data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen); // there goes your EDNS
+ size_t position = sizeof(dnsheader) + qnameWireLength + 4;
+
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [responseConfig](dnsheader& header) {
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, responseConfig);
+ header.ancount = 0;
+ header.arcount = 0; // for now, forget about your EDNS, we're marching over it
+ return true;
+ });
+
+ const auto& wireData = cname.getStorage(); // Note! This doesn't do compression!
+ addRecordHeader(data, position, dnsQuestion.ids.qclass, responseConfig.ttl, qtype, wireData.length());
+ memcpy(&data.at(position), wireData.c_str(), wireData.length());
+
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [numberOfRecords](dnsheader& header) {
+ header.ancount = htons(numberOfRecords);
+ return true;
+ });
+
+ if (hadEDNS) {
+ addEDNS(dnsQuestion.getMutableData(), dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0);
+ }
+
+ return true;
+}
+
+bool generateAnswerFromIPAddresses(DNSQuestion& dnsQuestion, const std::vector<ComboAddress>& addresses, const dnsdist::ResponseConfig& responseConfig)
+{
+ uint16_t qtype = dnsQuestion.ids.qtype;
+ std::vector<ComboAddress> addrs = {};
+ unsigned int totrdatalen = 0;
+ size_t numberOfRecords = 0;
+ for (const auto& addr : addresses) {
+ if (qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) || (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
+ continue;
+ }
+ totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
+ addrs.push_back(addr);
+ ++numberOfRecords;
+ }
+
+ if (addrs.size() > 1) {
+ shuffle(addrs.begin(), addrs.end(), t_randomEngine);
+ }
+
+ unsigned int qnameWireLength = dnsQuestion.ids.qname.wirelength();
+ if (dnsQuestion.getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen)) {
+ return false;
+ }
+
+ bool dnssecOK = false;
+ bool hadEDNS = false;
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses && queryHasEDNS(dnsQuestion)) {
+ hadEDNS = true;
+ dnssecOK = ((dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0);
+ }
+
+ auto& data = dnsQuestion.getMutableData();
+ data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen); // there goes your EDNS
+ size_t position = sizeof(dnsheader) + qnameWireLength + 4;
+
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [responseConfig](dnsheader& header) {
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, responseConfig);
+ header.ancount = 0;
+ header.arcount = 0; // for now, forget about your EDNS, we're marching over it
+ return true;
+ });
+
+ for (const auto& addr : addrs) {
+ uint16_t rdataLen = addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
+ qtype = addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA;
+
+ addRecordHeader(data, position, dnsQuestion.ids.qclass, responseConfig.ttl, qtype, rdataLen);
+
+ memcpy(&data.at(position),
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ addr.sin4.sin_family == AF_INET ? reinterpret_cast<const void*>(&addr.sin4.sin_addr.s_addr) : reinterpret_cast<const void*>(&addr.sin6.sin6_addr.s6_addr),
+ addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
+
+ position += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
+ }
+
+ auto finalANCount = addrs.size();
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [finalANCount](dnsheader& header) {
+ header.ancount = htons(finalANCount);
+ return true;
+ });
+
+ if (hadEDNS) {
+ addEDNS(dnsQuestion.getMutableData(), dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0);
+ }
+
+ return true;
+}
+
+bool generateAnswerFromRDataEntries(DNSQuestion& dnsQuestion, const std::vector<std::string>& entries, std::optional<uint16_t> typeForAny, const dnsdist::ResponseConfig& responseConfig)
+{
+ unsigned int totrdatalen = 0;
+ size_t numberOfRecords = 0;
+ auto shuffledEntries = entries;
+ for (const auto& entry : shuffledEntries) {
+ totrdatalen += entry.size();
+ ++numberOfRecords;
+ }
+ if (shuffledEntries.size() > 1) {
+ shuffle(shuffledEntries.begin(), shuffledEntries.end(), t_randomEngine);
+ }
+
+ auto qnameWireLength = dnsQuestion.ids.qname.wirelength();
+ if (dnsQuestion.getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen)) {
+ return false;
+ }
+
+ bool dnssecOK = false;
+ bool hadEDNS = false;
+ if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses && queryHasEDNS(dnsQuestion)) {
+ hadEDNS = true;
+ dnssecOK = ((dnsdist::getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0);
+ }
+
+ auto& data = dnsQuestion.getMutableData();
+ data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen); // there goes your EDNS
+ size_t position = sizeof(dnsheader) + qnameWireLength + 4;
+
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [&responseConfig](dnsheader& header) {
+ header.qr = true; // for good measure
+ setResponseHeadersFromConfig(header, responseConfig);
+ header.ancount = 0;
+ header.arcount = 0; // for now, forget about your EDNS, we're marching over it
+ return true;
+ });
+
+ QType qtype = dnsQuestion.ids.qtype;
+ if (qtype == QType::ANY && typeForAny) {
+ qtype = *typeForAny;
+ }
+
+ for (const auto& entry : shuffledEntries) {
+ uint16_t rdataLen = entry.size();
+ addRecordHeader(data, position, dnsQuestion.ids.qclass, responseConfig.ttl, qtype, rdataLen);
+ memcpy(&data.at(position), entry.c_str(), entry.size());
+ position += entry.size();
+ }
+
+ auto finalANCount = shuffledEntries.size();
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [finalANCount](dnsheader& header) {
+ header.ancount = htons(finalANCount);
+ return true;
+ });
+
+ if (hadEDNS) {
+ addEDNS(dnsQuestion.getMutableData(), dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0);
+ }
+
+ return true;
+}
+
+bool generateAnswerFromRawPacket(DNSQuestion& dnsQuestion, const PacketBuffer& packet)
+{
+ auto questionId = dnsQuestion.getHeader()->id;
+ dnsQuestion.getMutableData() = packet;
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [questionId](dnsheader& header) {
+ header.id = questionId;
+ return true;
+ });
+ return true;
+}
+
+}
--- /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 "dnsdist.hh"
+#include "dnsdist-dnsparser.hh"
+
+namespace dnsdist::self_answers
+{
+bool generateAnswerFromCNAME(DNSQuestion& dnsQuestion, const DNSName& cname, const dnsdist::ResponseConfig& responseConfig);
+bool generateAnswerFromIPAddresses(DNSQuestion& dnsQuestion, const std::vector<ComboAddress>& addresses, const ResponseConfig& responseConfig);
+bool generateAnswerFromRDataEntries(DNSQuestion& dnsQuestion, const std::vector<std::string>& entries, std::optional<uint16_t> typeForAny, const ResponseConfig& responseConfig);
+bool generateAnswerFromRawPacket(DNSQuestion& dnsQuestion, const PacketBuffer& packet);
+}
#include "dnsdist-random.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-secpoll.hh"
+#include "dnsdist-self-answers.hh"
#include "dnsdist-snmp.hh"
#include "dnsdist-tcp.hh"
#include "dnsdist-tcp-downstream.hh"
string result;
if (raw) {
+ dnsdist::ResponseConfig config;
std::vector<std::string> raws;
stringtok(raws, spoofContent, ",");
- SpoofAction tempSpoofAction(raws, std::nullopt);
- tempSpoofAction(&dnsQuestion, &result);
+ dnsdist::self_answers::generateAnswerFromRDataEntries(dnsQuestion, raws, std::nullopt, config);
}
else {
std::vector<std::string> addrs;
stringtok(addrs, spoofContent, " ,");
if (addrs.size() == 1) {
+ dnsdist::ResponseConfig config;
try {
ComboAddress spoofAddr(spoofContent);
- SpoofAction tempSpoofAction({spoofAddr});
- tempSpoofAction(&dnsQuestion, &result);
+ dnsdist::self_answers::generateAnswerFromIPAddresses(dnsQuestion, {spoofAddr}, config);
}
catch (const PDNSException& e) {
DNSName cname(spoofContent);
- SpoofAction tempSpoofAction(cname); // CNAME then
- tempSpoofAction(&dnsQuestion, &result);
+ dnsdist::self_answers::generateAnswerFromCNAME(dnsQuestion, cname, config);
}
}
else {
+ dnsdist::ResponseConfig config;
std::vector<ComboAddress> cas;
for (const auto& addr : addrs) {
try {
catch (...) {
}
}
- SpoofAction tempSpoofAction(cas);
- tempSpoofAction(&dnsQuestion, &result);
+ dnsdist::self_answers::generateAnswerFromIPAddresses(dnsQuestion, cas, config);
}
}
}
static void spoofPacketFromString(DNSQuestion& dnsQuestion, const string& spoofContent)
{
- string result;
-
- SpoofAction tempSpoofAction(spoofContent.c_str(), spoofContent.size());
- tempSpoofAction(&dnsQuestion, &result);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ dnsdist::self_answers::generateAnswerFromRawPacket(dnsQuestion, PacketBuffer(spoofContent.data(), spoofContent.data() + spoofContent.size()));
}
bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dnsQuestion, std::string& ruleresult, bool& drop)
DNSQuestion dq(ids, query);
dnsdist_ffi_dnsquestion_t lightDQ(&dq);
+ const auto initialData = dq.getData();
{
// dnsdist_ffi_dnsquestion_get_qtype
}
{
-#if 0
- // SpoofAction::operator() is a stub in the test runner
- auto oldData = dq.getData();
+ dq.getMutableData() = initialData;
+ const auto oldData = dq.getData();
std::vector<dnsdist_ffi_raw_value> values;
ComboAddress v4("192.0.2.1");
ComboAddress v6("[2001:db8::42]");
- values.push_back({ reinterpret_cast<const char*>(&v4.sin4.sin_addr.s_addr), sizeof(v4.sin4.sin_addr.s_addr)});
- values.push_back({ reinterpret_cast<const char*>(&v6.sin6.sin6_addr.s6_addr), sizeof(v6.sin6.sin6_addr.s6_addr)});
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ values.push_back({reinterpret_cast<const char*>(&v4.sin4.sin_addr.s_addr), sizeof(v4.sin4.sin_addr.s_addr)});
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ values.push_back({reinterpret_cast<const char*>(&v6.sin6.sin6_addr.s6_addr), sizeof(v6.sin6.sin6_addr.s6_addr)});
dnsdist_ffi_dnsquestion_spoof_addrs(&lightDQ, values.data(), values.size());
BOOST_CHECK(dq.getData().size() > oldData.size());
MOADNSParser mdp(false, reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size());
BOOST_CHECK_EQUAL(mdp.d_qname, ids.qname);
BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
- BOOST_CHECK_EQUAL(mdp.d_header.ancount, values.size());
+ /* only the A has been added since the query was not ANY */
+ BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0U);
BOOST_REQUIRE_EQUAL(mdp.d_answers.size(), 1U);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_type, static_cast<uint16_t>(QType::A));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(0).first.d_name, ids.qname);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_type, static_cast<uint16_t>(QType::AAAA));
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_class, QClass::IN);
- BOOST_CHECK_EQUAL(mdp.d_answers.at(1).first.d_name, ids.qname);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_type, static_cast<uint16_t>(QType::A));
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_class, QClass::IN);
+ BOOST_CHECK_EQUAL(mdp.d_answers.at(0).d_name, ids.qname);
dq.getMutableData() = oldData;
-#endif
}
{
{
}
-DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsQuestion, std::string* ruleresult) const
-{
- return DNSAction::Action::None;
-}
-
bool setupDoTProtocolNegotiation(std::shared_ptr<TLSCtx>& tlsCtx)
{
(void)tlsCtx;