}
// We need to check if EDNS Options exist
- if (dnsquestion->ednsOptions == nullptr && !parseEDNSOptions(*dnsquestion)) {
+ auto ednsOptions = parseEDNSOptions(*dnsquestion);
+ if (!ednsOptions) {
// Maybe parsed, but no EDNS found
return Action::None;
}
- if (dnsquestion->ednsOptions == nullptr) {
- // Parsing failed, log a warning and return
- VERBOSESLOG(infolog("parsing EDNS options failed while looking for OpenTelemetry Trace ID"),
- dnsquestion->getLogger()->info(Logr::Info, "Parsing EDNS options failed while looking for OpenTelemetry Trace ID"));
- return Action::None;
- }
if (d_useIncomingTraceparent) {
pdns::trace::TraceID traceID;
pdns::trace::SpanID spanID;
- if (pdns::trace::extractOTraceIDs(*(dnsquestion->ednsOptions), EDNSOptionCode::EDNSOptionCodeEnum(d_traceparentOptionCode), traceID, spanID)) {
+ if (pdns::trace::extractOTraceIDs(*(ednsOptions), EDNSOptionCode::EDNSOptionCodeEnum(d_traceparentOptionCode), traceID, spanID)) {
tracer->setTraceID(traceID);
if (spanID != pdns::trace::s_emptySpanID) {
tracer->setRootSpanID(spanID);
size_t existingOptLen = optLen;
removeEDNSOptionFromOPT(reinterpret_cast<char*>(&dnsquestion->getMutableData().at(optStart)), &optLen, d_traceparentOptionCode);
dnsquestion->getMutableData().resize(dnsquestion->getData().size() - (existingOptLen - optLen));
- // Ensure the EDNS Option View is not out of date
- dnsquestion->ednsOptions.reset();
}
return Action::None;
/* This function looks for an OPT RR, return true if a valid one was found (even if there was no options)
and false otherwise. */
-bool parseEDNSOptions(const DNSQuestion& dnsQuestion)
+std::optional<EDNSOptionViewMap> parseEDNSOptions(const DNSQuestion& dnsQuestion)
{
+ EDNSOptionViewMap ednsOptions{};
const auto dnsHeader = dnsQuestion.getHeader();
- if (dnsQuestion.ednsOptions != nullptr) {
- return true;
- }
-
- // dnsQuestion.ednsOptions is mutable
- dnsQuestion.ednsOptions = std::make_unique<EDNSOptionViewMap>();
-
if (ntohs(dnsHeader->arcount) == 0) {
/* nothing in additional so no EDNS */
- return false;
+ return std::nullopt;
}
if (ntohs(dnsHeader->ancount) != 0 || ntohs(dnsHeader->nscount) != 0 || ntohs(dnsHeader->arcount) > 1) {
- return slowParseEDNSOptions(dnsQuestion.getData(), *dnsQuestion.ednsOptions);
+ if (slowParseEDNSOptions(dnsQuestion.getData(), ednsOptions)) {
+ return ednsOptions;
+ }
+ return std::nullopt;
}
size_t remaining = 0;
if (res == 0) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- res = getEDNSOptions(reinterpret_cast<const char*>(&dnsQuestion.getData().at(optRDPosition)), remaining, *dnsQuestion.ednsOptions);
- return (res == 0);
+ res = getEDNSOptions(reinterpret_cast<const char*>(&dnsQuestion.getData().at(optRDPosition)), remaining, ednsOptions);
+ if (res != 0) {
+ return std::nullopt;
+ }
+ return ednsOptions;
}
- return false;
+ return std::nullopt;
}
static bool addECSToExistingOPT(PacketBuffer& packet, size_t maximumSize, const string& newECSOption, size_t optRDLenPosition, bool& ecsAdded)
#include <string>
+#include "ednsoptions.hh"
#include "iputils.hh"
#include "noinitvector.hh"
bool handleEDNSClientSubnet(DNSQuestion& dnsQuestion, bool& ednsAdded, bool& ecsAdded);
bool handleEDNSClientSubnet(PacketBuffer& packet, size_t maximumSize, size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption);
-bool parseEDNSOptions(const DNSQuestion& dnsQuestion);
+std::optional<EDNSOptionViewMap> parseEDNSOptions(const DNSQuestion& dnsQuestion);
bool queryHasEDNS(const DNSQuestion& dnsQuestion);
bool getEDNS0Record(const PacketBuffer& packet, EDNS0Record& edns0);
return true;
});
});
- luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView> (DNSQuestion::*)() const>("getEDNSOptions", [](const DNSQuestion& dnsQuestion) {
- if (dnsQuestion.ednsOptions == nullptr) {
- parseEDNSOptions(dnsQuestion);
- if (dnsQuestion.ednsOptions == nullptr) {
- throw std::runtime_error("parseEDNSOptions should have populated the EDNS options");
- }
+ luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView> (DNSQuestion::*)() const>("getEDNSOptions", [](const DNSQuestion& dnsQuestion) -> std::map<uint16_t, EDNSOptionView> {
+ auto ednsOptions = parseEDNSOptions(dnsQuestion);
+ if (!ednsOptions) {
+ return {};
}
- return *dnsQuestion.ednsOptions;
+ return *ednsOptions;
});
luaCtx.registerFunction<std::string (DNSQuestion::*)(void) const>("getTrailingData", [](const DNSQuestion& dnsQuestion) {
return dnsQuestion.getTrailingData();
});
});
- luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView> (DNSResponse::*)() const>("getEDNSOptions", [](const DNSResponse& dnsQuestion) {
- if (dnsQuestion.ednsOptions == nullptr) {
- parseEDNSOptions(dnsQuestion);
- if (dnsQuestion.ednsOptions == nullptr) {
- throw std::runtime_error("parseEDNSOptions should have populated the EDNS options");
- }
+ luaCtx.registerFunction<std::map<uint16_t, EDNSOptionView> (DNSResponse::*)() const>("getEDNSOptions", [](const DNSResponse& dnsQuestion) -> std::map<uint16_t, EDNSOptionView> {
+ auto ednsOptions = parseEDNSOptions(dnsQuestion);
+ if (!ednsOptions) {
+ return {};
}
- return *dnsQuestion.ednsOptions;
+ return *ednsOptions;
});
luaCtx.registerFunction<std::string (DNSResponse::*)(void) const>("getTrailingData", [](const DNSResponse& dnsQuestion) {
return dnsQuestion.getTrailingData();
// returns the length of the resulting 'out' array. 'out' is not set if the length is 0
size_t dnsdist_ffi_dnsquestion_get_edns_options(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_ednsoption_t** out)
{
- if (dq->dq->ednsOptions == nullptr) {
- parseEDNSOptions(*(dq->dq));
-
- if (dq->dq->ednsOptions == nullptr) {
- return 0;
- }
+ auto ednsOptions = parseEDNSOptions(*(dq->dq));
+ if (!ednsOptions) {
+ return 0;
}
size_t totalCount = 0;
- for (const auto& option : *dq->dq->ednsOptions) {
+ for (const auto& option : *ednsOptions) {
totalCount += option.second.values.size();
}
dq->ednsOptionsVect->clear();
dq->ednsOptionsVect->resize(totalCount);
size_t pos = 0;
- for (const auto& option : *dq->dq->ednsOptions) {
+ for (const auto& option : *ednsOptions) {
for (const auto& entry : option.second.values) {
fill_edns_option(entry, dq->ednsOptionsVect->at(pos));
dq->ednsOptionsVect->at(pos).optionCode = option.first;
#include "dnsdist-doh-common.hh"
#include "doq.hh"
#include "doh3.hh"
-#include "ednsoptions.hh"
#include "iputils.hh"
#include "misc.hh"
#include "mplexer.hh"
}
PacketBuffer& getMutableData()
{
- ednsOptions.reset();
return data;
}
InternalQueryState& ids;
std::unique_ptr<Netmask> ecs{nullptr};
std::string sni; /* Server Name Indication, if any (DoT or DoH) */
- mutable std::unique_ptr<EDNSOptionViewMap> ednsOptions; /* this needs to be mutable because it is parsed just in time, when DNSQuestion is read-only */
std::shared_ptr<IncomingTCPConnectionState> d_incomingTCPState{nullptr};
std::unique_ptr<std::vector<ProxyProtocolValue>> proxyProtocolValues{nullptr};
uint16_t ecsPrefixLength;
ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
DNSQuestion dnsQuestion(ids, const_cast<PacketBuffer&>(packet));
- BOOST_CHECK(parseEDNSOptions(dnsQuestion));
- BOOST_REQUIRE(dnsQuestion.ednsOptions != nullptr);
- BOOST_CHECK_EQUAL(dnsQuestion.ednsOptions->size(), 1U);
- const auto& ecsOption = dnsQuestion.ednsOptions->find(EDNSOptionCode::ECS);
- BOOST_REQUIRE(ecsOption != dnsQuestion.ednsOptions->cend());
+ auto ednsOptions = parseEDNSOptions(dnsQuestion);
+ BOOST_REQUIRE(ednsOptions);
+ BOOST_CHECK_EQUAL(ednsOptions->size(), 1U);
+ const auto& ecsOption = ednsOptions->find(EDNSOptionCode::ECS);
+ BOOST_REQUIRE(ecsOption != ednsOptions->cend());
string expectedOption;
generateECSOption(expected, expectedOption, expected.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6);
BOOST_CHECK_EQUAL(edns0.extRCode, 0U);
BOOST_CHECK_EQUAL(ntohs(edns0.extFlags), EDNS_HEADER_FLAG_DO);
- BOOST_REQUIRE(parseEDNSOptions(dnsQuestion));
- BOOST_REQUIRE(dnsQuestion.ednsOptions != nullptr);
- BOOST_CHECK_EQUAL(dnsQuestion.ednsOptions->size(), 1U);
- const auto& ecsOption = dnsQuestion.ednsOptions->find(EDNSOptionCode::COOKIE);
- BOOST_REQUIRE(ecsOption != dnsQuestion.ednsOptions->cend());
+ auto ednsOptions = parseEDNSOptions(dnsQuestion);
+ BOOST_REQUIRE(ednsOptions);
+ BOOST_CHECK_EQUAL(ednsOptions->size(), 1U);
+ const auto& ecsOption = ednsOptions->find(EDNSOptionCode::COOKIE);
+ BOOST_REQUIRE(ecsOption != ednsOptions->cend());
BOOST_REQUIRE_EQUAL(ecsOption->second.values.size(), 1U);
BOOST_CHECK_EQUAL(cookiesOptionStr, std::string(ecsOption->second.values.at(0).content, ecsOption->second.values.at(0).size));