diff --git a/.not-formatted b/.not-formatted index fc8ed5abd87b..2881313b0288 100644 --- a/.not-formatted +++ b/.not-formatted @@ -50,15 +50,12 @@ ./pdns/dnsdist-ecs.cc ./pdns/dnsdist-ecs.hh ./pdns/dnsdist-lbpolicies.hh -./pdns/dnsdist-lua-actions.cc ./pdns/dnsdist-lua-bindings-dnsquestion.cc ./pdns/dnsdist-lua-bindings.cc ./pdns/dnsdist-lua-inspection.cc ./pdns/dnsdist-lua-rules.cc ./pdns/dnsdist-lua-vars.cc ./pdns/dnsdist-lua.hh -./pdns/dnsdist-protobuf.cc -./pdns/dnsdist-protobuf.hh ./pdns/dnsdist-rings.cc ./pdns/dnsdist-rings.hh ./pdns/dnsdist-snmp.cc @@ -122,8 +119,6 @@ ./pdns/dnssecinfra.hh ./pdns/dnsseckeeper.hh ./pdns/dnssecsigner.cc -./pdns/dnstap.cc -./pdns/dnstap.hh ./pdns/dnstcpbench.cc ./pdns/dnswasher.cc ./pdns/dnswriter.cc diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index e6da31b6c877..22077fcf34a3 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -48,11 +48,11 @@ class DropAction : public DNSAction { public: - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { return Action::Drop; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "drop"; } @@ -61,11 +61,11 @@ class DropAction : public DNSAction class AllowAction : public DNSAction { public: - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { return Action::Allow; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "allow"; } @@ -75,11 +75,11 @@ class NoneAction : public DNSAction { public: // this action does not stop the processing - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "no op"; } @@ -88,22 +88,22 @@ class NoneAction : public DNSAction class QPSAction : public DNSAction { public: - QPSAction(int limit) : d_qps(QPSLimiter(limit, limit)) + QPSAction(int limit) : + d_qps(QPSLimiter(limit, limit)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { if (d_qps.lock()->check()) { return Action::None; } - else { - return Action::Drop; - } + return Action::Drop; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { - return "qps limit to "+std::to_string(d_qps.lock()->getRate()); + return "qps limit to " + std::to_string(d_qps.lock()->getRate()); } + private: mutable LockGuarded d_qps; }; @@ -111,18 +111,20 @@ class QPSAction : public DNSAction class DelayAction : public DNSAction { public: - DelayAction(int msec) : d_msec(msec) + DelayAction(int msec) : + d_msec(msec) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { *ruleresult = std::to_string(d_msec); return Action::Delay; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { - return "delay by "+std::to_string(d_msec)+ " ms"; + return "delay by " + std::to_string(d_msec) + " ms"; } + private: int d_msec; }; @@ -132,9 +134,13 @@ class TeeAction : public DNSAction public: // this action does not stop the processing TeeAction(const ComboAddress& rca, const boost::optional& lca, bool addECS = false, bool addProxyProtocol = false); + TeeAction(TeeAction& other) = delete; + TeeAction(TeeAction&& other) = delete; + TeeAction& operator=(TeeAction& other) = delete; + TeeAction& operator=(TeeAction&& other) = delete; ~TeeAction() override; - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override; - std::string toString() const override; + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override; + [[nodiscard]] std::string toString() const override; std::map getStats() const override; private: @@ -160,8 +166,8 @@ class TeeAction : public DNSAction bool d_addProxyProtocol{false}; }; -TeeAction::TeeAction(const ComboAddress& rca, const boost::optional& lca, bool addECS, bool addProxyProtocol) - : d_remote(rca), d_socket(d_remote.sin4.sin_family, SOCK_DGRAM, 0), d_addECS(addECS), d_addProxyProtocol(addProxyProtocol) +TeeAction::TeeAction(const ComboAddress& rca, const boost::optional& lca, bool addECS, bool addProxyProtocol) : + d_remote(rca), d_socket(d_remote.sin4.sin_family, SOCK_DGRAM, 0), d_addECS(addECS), d_addProxyProtocol(addProxyProtocol) { if (lca) { d_socket.bind(*lca, false); @@ -180,9 +186,9 @@ TeeAction::~TeeAction() d_worker.join(); } -DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult) const +DNSAction::Action TeeAction::operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const { - if (dq->overTCP()) { + if (dnsquestion->overTCP()) { d_tcpdrops++; return DNSAction::Action::None; } @@ -191,22 +197,22 @@ DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult PacketBuffer query; if (d_addECS) { - query = dq->getData(); + query = dnsquestion->getData(); bool ednsAdded = false; bool ecsAdded = false; std::string newECSOption; - generateECSOption(dq->ecs ? dq->ecs->getNetwork() : dq->ids.origRemote, newECSOption, dq->ecs ? dq->ecs->getBits() : dq->ecsPrefixLength); + generateECSOption(dnsquestion->ecs ? dnsquestion->ecs->getNetwork() : dnsquestion->ids.origRemote, newECSOption, dnsquestion->ecs ? dnsquestion->ecs->getBits() : dnsquestion->ecsPrefixLength); - if (!handleEDNSClientSubnet(query, dq->getMaximumSize(), dq->ids.qname.wirelength(), ednsAdded, ecsAdded, dq->ecsOverride, newECSOption)) { + if (!handleEDNSClientSubnet(query, dnsquestion->getMaximumSize(), dnsquestion->ids.qname.wirelength(), ednsAdded, ecsAdded, dnsquestion->ecsOverride, newECSOption)) { return DNSAction::Action::None; } } if (d_addProxyProtocol) { - auto proxyPayload = getProxyProtocolPayload(*dq); + auto proxyPayload = getProxyProtocolPayload(*dnsquestion); if (query.empty()) { - query = dq->getData(); + query = dnsquestion->getData(); } if (!addProxyProtocol(query, proxyPayload)) { return DNSAction::Action::None; @@ -214,7 +220,7 @@ DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult } { - const PacketBuffer& payload = query.empty() ? dq->getData() : query; + const PacketBuffer& payload = query.empty() ? dnsquestion->getData() : query; auto res = send(d_socket.getHandle(), payload.data(), payload.size(), 0); if (res <= 0) { @@ -230,7 +236,7 @@ std::string TeeAction::toString() const return "tee to " + d_remote.toStringWithPort(); } -std::map TeeAction::getStats() const +std::map TeeAction::getStats() const { return {{"queries", d_queries}, {"responses", d_responses}, @@ -241,8 +247,7 @@ std::map TeeAction::getStats() const {"refuseds", d_refuseds}, {"servfails", d_servfails}, {"other-rcode", d_otherrcode}, - {"tcp-drops", d_tcpdrops} - }; + {"tcp-drops", d_tcpdrops}}; } void TeeAction::worker() @@ -250,7 +255,7 @@ void TeeAction::worker() setThreadName("dnsdist/TeeWork"); std::array packet{}; ssize_t res = 0; - const dnsheader_aligned dh(packet.data()); + const dnsheader_aligned dnsheader(packet.data()); for (;;) { res = waitForData(d_socket.getHandle(), 0, 250000); if (d_pleaseQuit) { @@ -273,27 +278,27 @@ void TeeAction::worker() } // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well - if (dh->rcode == RCode::NoError) { + if (dnsheader->rcode == RCode::NoError) { d_noerrors++; } // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well - else if (dh->rcode == RCode::ServFail) { + else if (dnsheader->rcode == RCode::ServFail) { d_servfails++; } // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well - else if (dh->rcode == RCode::NXDomain) { + else if (dnsheader->rcode == RCode::NXDomain) { d_nxdomains++; } // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well - else if (dh->rcode == RCode::Refused) { + else if (dnsheader->rcode == RCode::Refused) { d_refuseds++; } // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well - else if (dh->rcode == RCode::FormErr) { + else if (dnsheader->rcode == RCode::FormErr) { d_formerrs++; } // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions): rcode is unsigned, RCode::rcodes_ as well - else if (dh->rcode == RCode::NotImp) { + else if (dnsheader->rcode == RCode::NotImp) { d_notimps++; } } @@ -302,37 +307,38 @@ void TeeAction::worker() class PoolAction : public DNSAction { public: - PoolAction(const std::string& pool, bool stopProcessing) : d_pool(pool), d_stopProcessing(stopProcessing) {} + PoolAction(std::string pool, bool stopProcessing) : + d_pool(std::move(pool)), d_stopProcessing(stopProcessing) {} - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { if (d_stopProcessing) { /* we need to do it that way to keep compatiblity with custom Lua actions returning DNSAction.Pool, 'poolname' */ *ruleresult = d_pool; return Action::Pool; } - else { - dq->ids.poolName = d_pool; - return Action::None; - } + dnsquestion->ids.poolName = d_pool; + return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "to pool " + d_pool; } private: + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const std::string d_pool; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const bool d_stopProcessing; }; - class QPSPoolAction : public DNSAction { public: - QPSPoolAction(unsigned int limit, const std::string& pool, bool stopProcessing) : d_qps(QPSLimiter(limit, limit)), d_pool(pool), d_stopProcessing(stopProcessing) {} - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + QPSPoolAction(unsigned int limit, std::string pool, bool stopProcessing) : + d_qps(QPSLimiter(limit, limit)), d_pool(std::move(pool)), d_stopProcessing(stopProcessing) {} + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { if (d_qps.lock()->check()) { if (d_stopProcessing) { @@ -340,33 +346,31 @@ class QPSPoolAction : public DNSAction *ruleresult = d_pool; return Action::Pool; } - else { - dq->ids.poolName = d_pool; - return Action::None; - } - } - else { - return Action::None; + dnsquestion->ids.poolName = d_pool; } + return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "max " + std::to_string(d_qps.lock()->getRate()) + " to pool " + d_pool; } private: mutable LockGuarded d_qps; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const std::string d_pool; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const bool d_stopProcessing; }; class RCodeAction : public DNSAction { public: - RCodeAction(uint8_t rcode) : d_rcode(rcode) {} - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + RCodeAction(uint8_t rcode) : + d_rcode(rcode) {} + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) { header.rcode = d_rcode; header.qr = true; // for good measure setResponseHeadersFromConfig(header, d_responseConfig); @@ -374,38 +378,47 @@ class RCodeAction : public DNSAction }); return Action::HeaderModify; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { - return "set rcode "+std::to_string(d_rcode); + return "set rcode " + std::to_string(d_rcode); + } + [[nodiscard]] ResponseConfig& getResponseConfig() + { + return d_responseConfig; } - ResponseConfig d_responseConfig; private: + ResponseConfig d_responseConfig; uint8_t d_rcode; }; class ERCodeAction : public DNSAction { public: - ERCodeAction(uint8_t rcode) : d_rcode(rcode) {} - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + ERCodeAction(uint8_t rcode) : + d_rcode(rcode) {} + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) { header.rcode = (d_rcode & 0xF); header.qr = true; // for good measure setResponseHeadersFromConfig(header, d_responseConfig); return true; }); - dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4); + dnsquestion->ednsRCode = ((d_rcode & 0xFFF0) >> 4); return Action::HeaderModify; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { - return "set ercode "+ERCode::to_s(d_rcode); + return "set ercode " + ERCode::to_s(d_rcode); + } + [[nodiscard]] ResponseConfig& getResponseConfig() + { + return d_responseConfig; } - ResponseConfig d_responseConfig; private: + ResponseConfig d_responseConfig; uint8_t d_rcode; }; @@ -426,88 +439,93 @@ class SpoofSVCAction : public DNSAction d_payloads.push_back(std::move(payload)); for (const auto& hint : param.second.ipv4hints) { - d_additionals4.insert({ param.second.target, ComboAddress(hint) }); + d_additionals4.insert({param.second.target, ComboAddress(hint)}); } for (const auto& hint : param.second.ipv6hints) { - d_additionals6.insert({ param.second.target, ComboAddress(hint) }); + d_additionals6.insert({param.second.target, ComboAddress(hint)}); } } } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { /* it will likely be a bit bigger than that because of additionals */ - uint16_t numberOfRecords = d_payloads.size(); - const auto qnameWireLength = dq->ids.qname.wirelength(); - if (dq->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + d_totalPayloadsSize)) { + auto numberOfRecords = d_payloads.size(); + const auto qnameWireLength = dnsquestion->ids.qname.wirelength(); + if (dnsquestion->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize)) { return Action::None; } PacketBuffer newPacket; - newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + d_totalPayloadsSize); - GenericDNSPacketWriter pw(newPacket, dq->ids.qname, dq->ids.qtype); + newPacket.reserve(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + d_totalPayloadsSize); + GenericDNSPacketWriter packetWriter(newPacket, dnsquestion->ids.qname, dnsquestion->ids.qtype); for (const auto& payload : d_payloads) { - pw.startRecord(dq->ids.qname, dq->ids.qtype, d_responseConfig.ttl); - pw.xfrBlob(payload); - pw.commit(); + packetWriter.startRecord(dnsquestion->ids.qname, dnsquestion->ids.qtype, d_responseConfig.ttl); + packetWriter.xfrBlob(payload); + packetWriter.commit(); } - if (newPacket.size() < dq->getMaximumSize()) { + if (newPacket.size() < dnsquestion->getMaximumSize()) { for (const auto& additional : d_additionals4) { - pw.startRecord(additional.first.isRoot() ? dq->ids.qname : additional.first, QType::A, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL); - pw.xfrCAWithoutPort(4, additional.second); - pw.commit(); + packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::A, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL); + packetWriter.xfrCAWithoutPort(4, additional.second); + packetWriter.commit(); } } - if (newPacket.size() < dq->getMaximumSize()) { + if (newPacket.size() < dnsquestion->getMaximumSize()) { for (const auto& additional : d_additionals6) { - pw.startRecord(additional.first.isRoot() ? dq->ids.qname : additional.first, QType::AAAA, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL); - pw.xfrCAWithoutPort(6, additional.second); - pw.commit(); + packetWriter.startRecord(additional.first.isRoot() ? dnsquestion->ids.qname : additional.first, QType::AAAA, d_responseConfig.ttl, QClass::IN, DNSResourceRecord::ADDITIONAL); + packetWriter.xfrCAWithoutPort(6, additional.second); + packetWriter.commit(); } } - if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) { - bool dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO; - pw.addOpt(g_PayloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0); - pw.commit(); + if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) { + bool dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0); + packetWriter.addOpt(g_PayloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0); + packetWriter.commit(); } - if (newPacket.size() >= dq->getMaximumSize()) { + if (newPacket.size() >= dnsquestion->getMaximumSize()) { /* sorry! */ return Action::None; } - pw.getHeader()->id = dq->getHeader()->id; - pw.getHeader()->qr = true; // for good measure - setResponseHeadersFromConfig(*pw.getHeader(), d_responseConfig); - dq->getMutableData() = std::move(newPacket); + packetWriter.getHeader()->id = dnsquestion->getHeader()->id; + packetWriter.getHeader()->qr = true; // for good measure + setResponseHeadersFromConfig(*packetWriter.getHeader(), d_responseConfig); + dnsquestion->getMutableData() = std::move(newPacket); return Action::HeaderModify; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "spoof SVC record "; } - ResponseConfig d_responseConfig; + [[nodiscard]] ResponseConfig& getResponseConfig() + { + return d_responseConfig; + } + private: - std::vector> d_payloads; - std::set> d_additionals4; - std::set> d_additionals6; + ResponseConfig d_responseConfig; + std::vector> d_payloads{}; + std::set> d_additionals4{}; + std::set> d_additionals6{}; size_t d_totalPayloadsSize{0}; }; class TCAction : public DNSAction { public: - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { return Action::Truncate; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "tc=1 answer"; } @@ -529,18 +547,19 @@ class TCResponseAction : public DNSResponseAction class LuaAction : public DNSAction { public: - typedef std::function >(DNSQuestion* dq)> func_t; - LuaAction(const LuaAction::func_t& func) : d_func(func) + using func_t = std::function>(DNSQuestion* dnsquestion)>; + LuaAction(LuaAction::func_t func) : + d_func(std::move(func)) {} - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { try { - DNSAction::Action result; + DNSAction::Action result{}; { auto lock = g_lua.lock(); - auto ret = d_func(dq); - if (ruleresult) { + auto ret = d_func(dnsquestion); + if (ruleresult != nullptr) { if (boost::optional rule = std::get<1>(ret)) { *ruleresult = *rule; } @@ -553,18 +572,21 @@ class LuaAction : public DNSAction } dnsdist::handleQueuedAsynchronousEvents(); return result; - } catch (const std::exception &e) { + } + catch (const std::exception& e) { warnlog("LuaAction failed inside Lua, returning ServFail: %s", e.what()); - } catch (...) { + } + catch (...) { warnlog("LuaAction failed inside Lua, returning ServFail: [unknown exception]"); } return DNSAction::Action::ServFail; } - string toString() const override + [[nodiscard]] std::string toString() const override { return "Lua script"; } + private: func_t d_func; }; @@ -572,17 +594,18 @@ class LuaAction : public DNSAction class LuaResponseAction : public DNSResponseAction { public: - typedef std::function >(DNSResponse* dr)> func_t; - LuaResponseAction(const LuaResponseAction::func_t& func) : d_func(func) + using func_t = std::function>(DNSResponse* response)>; + LuaResponseAction(LuaResponseAction::func_t func) : + d_func(std::move(func)) {} - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { try { - DNSResponseAction::Action result; + DNSResponseAction::Action result{}; { auto lock = g_lua.lock(); - auto ret = d_func(dr); - if (ruleresult) { + auto ret = d_func(response); + if (ruleresult != nullptr) { if (boost::optional rule = std::get<1>(ret)) { *ruleresult = *rule; } @@ -595,40 +618,44 @@ class LuaResponseAction : public DNSResponseAction } dnsdist::handleQueuedAsynchronousEvents(); return result; - } catch (const std::exception &e) { + } + catch (const std::exception& e) { warnlog("LuaResponseAction failed inside Lua, returning ServFail: %s", e.what()); - } catch (...) { + } + catch (...) { warnlog("LuaResponseAction failed inside Lua, returning ServFail: [unknown exception]"); } return DNSResponseAction::Action::ServFail; } - string toString() const override + [[nodiscard]] std::string toString() const override { return "Lua response script"; } + private: func_t d_func; }; -class LuaFFIAction: public DNSAction +class LuaFFIAction : public DNSAction { public: - typedef std::function func_t; + using func_t = std::function; - LuaFFIAction(const LuaFFIAction::func_t& func): d_func(func) + LuaFFIAction(LuaFFIAction::func_t func) : + d_func(std::move(func)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dnsdist_ffi_dnsquestion_t dqffi(dq); + dnsdist_ffi_dnsquestion_t dqffi(dnsquestion); try { - DNSAction::Action result; + DNSAction::Action result{}; { auto lock = g_lua.lock(); auto ret = d_func(&dqffi); - if (ruleresult) { + if (ruleresult != nullptr) { if (dqffi.result) { *ruleresult = *dqffi.result; } @@ -641,32 +668,36 @@ class LuaFFIAction: public DNSAction } dnsdist::handleQueuedAsynchronousEvents(); return result; - } catch (const std::exception &e) { + } + catch (const std::exception& e) { warnlog("LuaFFIAction failed inside Lua, returning ServFail: %s", e.what()); - } catch (...) { + } + catch (...) { warnlog("LuaFFIAction failed inside Lua, returning ServFail: [unknown exception]"); } return DNSAction::Action::ServFail; } - string toString() const override + [[nodiscard]] std::string toString() const override { return "Lua FFI script"; } + private: func_t d_func; }; -class LuaFFIPerThreadAction: public DNSAction +class LuaFFIPerThreadAction : public DNSAction { public: - typedef std::function func_t; + using func_t = std::function; - LuaFFIPerThreadAction(const std::string& code): d_functionCode(code), d_functionID(s_functionsCounter++) + LuaFFIPerThreadAction(std::string code) : + d_functionCode(std::move(code)), d_functionID(s_functionsCounter++) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { try { auto& state = t_perThreadStates[d_functionID]; @@ -683,9 +714,9 @@ class LuaFFIPerThreadAction: public DNSAction return DNSAction::Action::None; } - dnsdist_ffi_dnsquestion_t dqffi(dq); + dnsdist_ffi_dnsquestion_t dqffi(dnsquestion); auto ret = state.d_func(&dqffi); - if (ruleresult) { + if (ruleresult != nullptr) { if (dqffi.result) { *ruleresult = *dqffi.result; } @@ -697,7 +728,7 @@ class LuaFFIPerThreadAction: public DNSAction dnsdist::handleQueuedAsynchronousEvents(); return static_cast(ret); } - catch (const std::exception &e) { + catch (const std::exception& e) { warnlog("LuaFFIPerThreadAction failed inside Lua, returning ServFail: %s", e.what()); } catch (...) { @@ -706,7 +737,7 @@ class LuaFFIPerThreadAction: public DNSAction return DNSAction::Action::ServFail; } - string toString() const override + [[nodiscard]] std::string toString() const override { return "Lua FFI per-thread script"; } @@ -720,33 +751,36 @@ class LuaFFIPerThreadAction: public DNSAction }; static std::atomic s_functionsCounter; static thread_local std::map t_perThreadStates; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const std::string d_functionCode; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const uint64_t d_functionID; }; std::atomic LuaFFIPerThreadAction::s_functionsCounter = 0; thread_local std::map LuaFFIPerThreadAction::t_perThreadStates; -class LuaFFIResponseAction: public DNSResponseAction +class LuaFFIResponseAction : public DNSResponseAction { public: - typedef std::function func_t; + using func_t = std::function; - LuaFFIResponseAction(const LuaFFIResponseAction::func_t& func): d_func(func) + LuaFFIResponseAction(LuaFFIResponseAction::func_t func) : + d_func(std::move(func)) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { - dnsdist_ffi_dnsresponse_t drffi(dr); + dnsdist_ffi_dnsresponse_t ffiResponse(response); try { - DNSResponseAction::Action result; + DNSResponseAction::Action result{}; { auto lock = g_lua.lock(); - auto ret = d_func(&drffi); - if (ruleresult) { - if (drffi.result) { - *ruleresult = *drffi.result; + auto ret = d_func(&ffiResponse); + if (ruleresult != nullptr) { + if (ffiResponse.result) { + *ruleresult = *ffiResponse.result; } else { // default to empty string @@ -757,32 +791,36 @@ class LuaFFIResponseAction: public DNSResponseAction } dnsdist::handleQueuedAsynchronousEvents(); return result; - } catch (const std::exception &e) { + } + catch (const std::exception& e) { warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: %s", e.what()); - } catch (...) { + } + catch (...) { warnlog("LuaFFIResponseAction failed inside Lua, returning ServFail: [unknown exception]"); } return DNSResponseAction::Action::ServFail; } - string toString() const override + [[nodiscard]] std::string toString() const override { return "Lua FFI script"; } + private: func_t d_func; }; -class LuaFFIPerThreadResponseAction: public DNSResponseAction +class LuaFFIPerThreadResponseAction : public DNSResponseAction { public: - typedef std::function func_t; + using func_t = std::function; - LuaFFIPerThreadResponseAction(const std::string& code): d_functionCode(code), d_functionID(s_functionsCounter++) + LuaFFIPerThreadResponseAction(std::string code) : + d_functionCode(std::move(code)), d_functionID(s_functionsCounter++) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { try { auto& state = t_perThreadStates[d_functionID]; @@ -799,11 +837,11 @@ class LuaFFIPerThreadResponseAction: public DNSResponseAction return DNSResponseAction::Action::None; } - dnsdist_ffi_dnsresponse_t drffi(dr); - auto ret = state.d_func(&drffi); - if (ruleresult) { - if (drffi.result) { - *ruleresult = *drffi.result; + dnsdist_ffi_dnsresponse_t ffiResponse(response); + auto ret = state.d_func(&ffiResponse); + if (ruleresult != nullptr) { + if (ffiResponse.result) { + *ruleresult = *ffiResponse.result; } else { // default to empty string @@ -813,7 +851,7 @@ class LuaFFIPerThreadResponseAction: public DNSResponseAction dnsdist::handleQueuedAsynchronousEvents(); return static_cast(ret); } - catch (const std::exception &e) { + catch (const std::exception& e) { warnlog("LuaFFIPerThreadResponseAction failed inside Lua, returning ServFail: %s", e.what()); } catch (...) { @@ -822,7 +860,7 @@ class LuaFFIPerThreadResponseAction: public DNSResponseAction return DNSResponseAction::Action::ServFail; } - string toString() const override + [[nodiscard]] std::string toString() const override { return "Lua FFI per-thread script"; } @@ -837,7 +875,9 @@ class LuaFFIPerThreadResponseAction: public DNSResponseAction static std::atomic s_functionsCounter; static thread_local std::map t_perThreadStates; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const std::string d_functionCode; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const uint64_t d_functionID; }; @@ -846,38 +886,37 @@ thread_local std::map L thread_local std::default_random_engine SpoofAction::t_randomEngine; -DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresult) const +DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const { - uint16_t qtype = dq->ids.qtype; + uint16_t qtype = dnsquestion->ids.qtype; // do we even have a response? - if (d_cname.empty() && - d_rawResponses.empty() && + 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) { + (d_raw.size() < sizeof(dnsheader)) && d_types.count(qtype) == 0) { return Action::None; } if (d_raw.size() >= sizeof(dnsheader)) { - auto id = dq->getHeader()->id; - dq->getMutableData() = d_raw; - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [id](dnsheader& header) { - header.id = id; + 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; } - vector addrs; - vector rawResponses; + std::vector addrs = {}; + std::vector rawResponses = {}; unsigned int totrdatalen = 0; - uint16_t numberOfRecords = 0; + size_t numberOfRecords = 0; if (!d_cname.empty()) { qtype = QType::CNAME; totrdatalen += d_cname.getStorage().size(); numberOfRecords = 1; - } else if (!d_rawResponses.empty()) { + } + else if (!d_rawResponses.empty()) { rawResponses.reserve(d_rawResponses.size()); - for(const auto& rawResponse : d_rawResponses){ + for (const auto& rawResponse : d_rawResponses) { totrdatalen += rawResponse.size(); rawResponses.push_back(rawResponse); ++numberOfRecords; @@ -887,9 +926,8 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu } } else { - 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))) { + 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; } totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr); @@ -902,25 +940,26 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu shuffle(addrs.begin(), addrs.end(), t_randomEngine); } - unsigned int qnameWireLength=0; - DNSName ignore(reinterpret_cast(dq->getData().data()), dq->getData().size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength); + unsigned int qnameWireLength = 0; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + DNSName ignore(reinterpret_cast(dnsquestion->getData().data()), dnsquestion->getData().size(), sizeof(dnsheader), false, nullptr, nullptr, &qnameWireLength); - if (dq->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen)) { + if (dnsquestion->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords * 12 /* recordstart */ + totrdatalen)) { return Action::None; } bool dnssecOK = false; bool hadEDNS = false; - if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) { + if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) { hadEDNS = true; - dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO; + dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0); } - auto& data = dq->getMutableData(); - data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen); // there goes your EDNS + 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)); - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) { header.qr = true; // for good measure setResponseHeadersFromConfig(header, d_responseConfig); header.ancount = 0; @@ -929,13 +968,15 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu }); uint32_t ttl = htonl(d_responseConfig.ttl); - uint16_t qclass = htons(dq->ids.qclass); - unsigned char recordstart[] = {0xc0, 0x0c, // compressed name - 0, 0, // QTYPE - 0, 0, // QCLASS - 0, 0, 0, 0, // TTL - 0, 0 }; // rdata length - static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid"); + uint16_t qclass = htons(dnsquestion->ids.qclass); + std::array 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)); bool raw = false; @@ -947,10 +988,11 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu memcpy(&recordstart[2], &qtype, sizeof(qtype)); memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen)); - memcpy(dest, recordstart, sizeof(recordstart)); - dest += sizeof(recordstart); + 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(dq->getMutableData(), [](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) { header.ancount++; return true; }); @@ -960,18 +1002,20 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu qtype = *d_rawTypeForAny; } qtype = htons(qtype); - for(const auto& rawResponse : rawResponses){ + for (const auto& rawResponse : rawResponses) { uint16_t rdataLen = htons(rawResponse.size()); memcpy(&recordstart[2], &qtype, sizeof(qtype)); memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen)); - memcpy(dest, recordstart, sizeof(recordstart)); - dest += sizeof(recordstart); + memcpy(dest, recordstart.data(), sizeof(recordstart)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + dest += recordstart.size(); memcpy(dest, rawResponse.c_str(), rawResponse.size()); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) dest += rawResponse.size(); - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) { header.ancount++; return true; }); @@ -979,34 +1023,37 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu raw = true; } else { - for(const auto& addr : addrs) { + 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, sizeof(recordstart)); + 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(&addr.sin4.sin_addr.s_addr) : reinterpret_cast(&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(dq->getMutableData(), [](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) { header.ancount++; return true; }); } } - auto finalANCount = dq->getHeader()->ancount; - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [finalANCount](dnsheader& header) { + auto finalANCount = dnsquestion->getHeader()->ancount; + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [finalANCount](dnsheader& header) { header.ancount = htons(finalANCount); return true; }); - if (hadEDNS && raw == false) { - addEDNS(dq->getMutableData(), dq->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0); + if (hadEDNS && !raw) { + addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0); } return Action::HeaderModify; @@ -1016,59 +1063,62 @@ class SetMacAddrAction : public DNSAction { public: // this action does not stop the processing - SetMacAddrAction(uint16_t code) : d_code(code) + SetMacAddrAction(uint16_t code) : + d_code(code) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { dnsdist::MacAddress mac; - int res = dnsdist::MacAddressesCache::get(dq->ids.origRemote, mac.data(), mac.size()); + int res = dnsdist::MacAddressesCache::get(dnsquestion->ids.origRemote, mac.data(), mac.size()); if (res != 0) { return Action::None; } std::string optRData; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) generateEDNSOption(d_code, reinterpret_cast(mac.data()), optRData); - if (dq->getHeader()->arcount) { + if (dnsquestion->getHeader()->arcount > 0) { bool ednsAdded = false; bool optionAdded = false; PacketBuffer newContent; - newContent.reserve(dq->getData().size()); + newContent.reserve(dnsquestion->getData().size()); - if (!slowRewriteEDNSOptionInQueryWithRecords(dq->getData(), newContent, ednsAdded, d_code, optionAdded, true, optRData)) { + if (!slowRewriteEDNSOptionInQueryWithRecords(dnsquestion->getData(), newContent, ednsAdded, d_code, optionAdded, true, optRData)) { return Action::None; } - if (newContent.size() > dq->getMaximumSize()) { + if (newContent.size() > dnsquestion->getMaximumSize()) { return Action::None; } - dq->getMutableData() = std::move(newContent); - if (!dq->ids.ednsAdded && ednsAdded) { - dq->ids.ednsAdded = true; + dnsquestion->getMutableData() = std::move(newContent); + if (!dnsquestion->ids.ednsAdded && ednsAdded) { + dnsquestion->ids.ednsAdded = true; } return Action::None; } - auto& data = dq->getMutableData(); - if (generateOptRR(optRData, data, dq->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) { - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) { + auto& data = dnsquestion->getMutableData(); + if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) { header.arcount = htons(1); return true; }); // make sure that any EDNS sent by the backend is removed before forwarding the response to the client - dq->ids.ednsAdded = true; + dnsquestion->ids.ednsAdded = true; } return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "add EDNS MAC (code=" + std::to_string(d_code) + ")"; } + private: uint16_t d_code{3}; }; @@ -1077,17 +1127,18 @@ class SetEDNSOptionAction : public DNSAction { public: // this action does not stop the processing - SetEDNSOptionAction(uint16_t code, const std::string& data) : d_code(code), d_data(data) + SetEDNSOptionAction(uint16_t code, std::string data) : + d_code(code), d_data(std::move(data)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - setEDNSOption(*dq, d_code, d_data); + setEDNSOption(*dnsquestion, d_code, d_data); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "add EDNS Option (code=" + std::to_string(d_code) + ")"; } @@ -1101,15 +1152,15 @@ class SetNoRecurseAction : public DNSAction { public: // this action does not stop the processing - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) { header.rd = false; return true; }); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "set rd=0"; } @@ -1119,69 +1170,68 @@ class LogAction : public DNSAction, public boost::noncopyable { public: // this action does not stop the processing - LogAction() - { - } + LogAction() = default; - LogAction(const std::string& str, bool binary=true, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_binary(binary), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered) + LogAction(const std::string& str, bool binary = true, bool append = false, bool buffered = true, bool verboseOnly = true, bool includeTimestamp = false) : + d_fname(str), d_binary(binary), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered) { if (str.empty()) { return; } - if (!reopenLogFile()) { + if (!reopenLogFile()) { throw std::runtime_error("Unable to open file '" + str + "' for logging: " + stringerror()); } } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - auto fp = std::atomic_load_explicit(&d_fp, std::memory_order_acquire); - if (!fp) { + auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire); + if (!filepointer) { if (!d_verboseOnly || g_verbose) { if (d_includeTimestamp) { - infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast(dq->getQueryRealTime().tv_sec), static_cast(dq->getQueryRealTime().tv_nsec), dq->ids.origRemote.toStringWithPort(), dq->ids.qname.toString(), QType(dq->ids.qtype).toString(), dq->getHeader()->id); + infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast(dnsquestion->getQueryRealTime().tv_sec), static_cast(dnsquestion->getQueryRealTime().tv_nsec), dnsquestion->ids.origRemote.toStringWithPort(), dnsquestion->ids.qname.toString(), QType(dnsquestion->ids.qtype).toString(), dnsquestion->getHeader()->id); } else { - infolog("Packet from %s for %s %s with id %d", dq->ids.origRemote.toStringWithPort(), dq->ids.qname.toString(), QType(dq->ids.qtype).toString(), dq->getHeader()->id); + infolog("Packet from %s for %s %s with id %d", dnsquestion->ids.origRemote.toStringWithPort(), dnsquestion->ids.qname.toString(), QType(dnsquestion->ids.qtype).toString(), dnsquestion->getHeader()->id); } } } else { if (d_binary) { - const auto& out = dq->ids.qname.getStorage(); + const auto& out = dnsquestion->ids.qname.getStorage(); if (d_includeTimestamp) { - uint64_t tv_sec = static_cast(dq->getQueryRealTime().tv_sec); - uint32_t tv_nsec = static_cast(dq->getQueryRealTime().tv_nsec); - fwrite(&tv_sec, sizeof(tv_sec), 1, fp.get()); - fwrite(&tv_nsec, sizeof(tv_nsec), 1, fp.get()); + auto tv_sec = static_cast(dnsquestion->getQueryRealTime().tv_sec); + auto tv_nsec = static_cast(dnsquestion->getQueryRealTime().tv_nsec); + fwrite(&tv_sec, sizeof(tv_sec), 1, filepointer.get()); + fwrite(&tv_nsec, sizeof(tv_nsec), 1, filepointer.get()); } - uint16_t id = dq->getHeader()->id; - fwrite(&id, sizeof(id), 1, fp.get()); - fwrite(out.c_str(), 1, out.size(), fp.get()); - fwrite(&dq->ids.qtype, sizeof(dq->ids.qtype), 1, fp.get()); - fwrite(&dq->ids.origRemote.sin4.sin_family, sizeof(dq->ids.origRemote.sin4.sin_family), 1, fp.get()); - if (dq->ids.origRemote.sin4.sin_family == AF_INET) { - fwrite(&dq->ids.origRemote.sin4.sin_addr.s_addr, sizeof(dq->ids.origRemote.sin4.sin_addr.s_addr), 1, fp.get()); + uint16_t queryId = dnsquestion->getHeader()->id; + fwrite(&queryId, sizeof(queryId), 1, filepointer.get()); + fwrite(out.c_str(), 1, out.size(), filepointer.get()); + fwrite(&dnsquestion->ids.qtype, sizeof(dnsquestion->ids.qtype), 1, filepointer.get()); + fwrite(&dnsquestion->ids.origRemote.sin4.sin_family, sizeof(dnsquestion->ids.origRemote.sin4.sin_family), 1, filepointer.get()); + if (dnsquestion->ids.origRemote.sin4.sin_family == AF_INET) { + fwrite(&dnsquestion->ids.origRemote.sin4.sin_addr.s_addr, sizeof(dnsquestion->ids.origRemote.sin4.sin_addr.s_addr), 1, filepointer.get()); } - else if (dq->ids.origRemote.sin4.sin_family == AF_INET6) { - fwrite(&dq->ids.origRemote.sin6.sin6_addr.s6_addr, sizeof(dq->ids.origRemote.sin6.sin6_addr.s6_addr), 1, fp.get()); + else if (dnsquestion->ids.origRemote.sin4.sin_family == AF_INET6) { + fwrite(&dnsquestion->ids.origRemote.sin6.sin6_addr.s6_addr, sizeof(dnsquestion->ids.origRemote.sin6.sin6_addr.s6_addr), 1, filepointer.get()); } - fwrite(&dq->ids.origRemote.sin4.sin_port, sizeof(dq->ids.origRemote.sin4.sin_port), 1, fp.get()); + fwrite(&dnsquestion->ids.origRemote.sin4.sin_port, sizeof(dnsquestion->ids.origRemote.sin4.sin_port), 1, filepointer.get()); } else { if (d_includeTimestamp) { - fprintf(fp.get(), "[%llu.%lu] Packet from %s for %s %s with id %u\n", static_cast(dq->getQueryRealTime().tv_sec), static_cast(dq->getQueryRealTime().tv_nsec), dq->ids.origRemote.toStringWithPort().c_str(), dq->ids.qname.toString().c_str(), QType(dq->ids.qtype).toString().c_str(), dq->getHeader()->id); + fprintf(filepointer.get(), "[%llu.%lu] Packet from %s for %s %s with id %u\n", static_cast(dnsquestion->getQueryRealTime().tv_sec), static_cast(dnsquestion->getQueryRealTime().tv_nsec), dnsquestion->ids.origRemote.toStringWithPort().c_str(), dnsquestion->ids.qname.toString().c_str(), QType(dnsquestion->ids.qtype).toString().c_str(), dnsquestion->getHeader()->id); } else { - fprintf(fp.get(), "Packet from %s for %s %s with id %u\n", dq->ids.origRemote.toStringWithPort().c_str(), dq->ids.qname.toString().c_str(), QType(dq->ids.qtype).toString().c_str(), dq->getHeader()->id); + fprintf(filepointer.get(), "Packet from %s for %s %s with id %u\n", dnsquestion->ids.origRemote.toStringWithPort().c_str(), dnsquestion->ids.qname.toString().c_str(), QType(dnsquestion->ids.qtype).toString().c_str(), dnsquestion->getHeader()->id); } } } return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { if (!d_fname.empty()) { return "log to " + d_fname; @@ -1202,20 +1252,21 @@ class LogAction : public DNSAction, public boost::noncopyable // we are using a naked pointer here because we don't want fclose to be called // with a nullptr, which would happen if we constructor a shared_ptr with fclose // as a custom deleter and nullptr as a FILE* - auto nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w"); - if (!nfp) { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + auto* nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w"); + if (nfp == nullptr) { /* don't fall on our sword when reopening */ return false; } - auto fp = std::shared_ptr(nfp, fclose); + auto filepointer = std::shared_ptr(nfp, fclose); nfp = nullptr; if (!d_buffered) { - setbuf(fp.get(), 0); + setbuf(filepointer.get(), nullptr); } - std::atomic_store_explicit(&d_fp, std::move(fp), std::memory_order_release); + std::atomic_store_explicit(&d_fp, std::move(filepointer), std::memory_order_release); return true; } @@ -1231,11 +1282,10 @@ class LogAction : public DNSAction, public boost::noncopyable class LogResponseAction : public DNSResponseAction, public boost::noncopyable { public: - LogResponseAction() - { - } + LogResponseAction() = default; - LogResponseAction(const std::string& str, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered) + LogResponseAction(const std::string& str, bool append = false, bool buffered = true, bool verboseOnly = true, bool includeTimestamp = false) : + d_fname(str), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp), d_append(append), d_buffered(buffered) { if (str.empty()) { return; @@ -1246,31 +1296,31 @@ class LogResponseAction : public DNSResponseAction, public boost::noncopyable } } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { - auto fp = std::atomic_load_explicit(&d_fp, std::memory_order_acquire); - if (!fp) { + auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire); + if (!filepointer) { if (!d_verboseOnly || g_verbose) { if (d_includeTimestamp) { - infolog("[%u.%u] Answer to %s for %s %s (%s) with id %u", static_cast(dr->getQueryRealTime().tv_sec), static_cast(dr->getQueryRealTime().tv_nsec), dr->ids.origRemote.toStringWithPort(), dr->ids.qname.toString(), QType(dr->ids.qtype).toString(), RCode::to_s(dr->getHeader()->rcode), dr->getHeader()->id); + infolog("[%u.%u] Answer to %s for %s %s (%s) with id %u", static_cast(response->getQueryRealTime().tv_sec), static_cast(response->getQueryRealTime().tv_nsec), response->ids.origRemote.toStringWithPort(), response->ids.qname.toString(), QType(response->ids.qtype).toString(), RCode::to_s(response->getHeader()->rcode), response->getHeader()->id); } else { - infolog("Answer to %s for %s %s (%s) with id %u", dr->ids.origRemote.toStringWithPort(), dr->ids.qname.toString(), QType(dr->ids.qtype).toString(), RCode::to_s(dr->getHeader()->rcode), dr->getHeader()->id); + infolog("Answer to %s for %s %s (%s) with id %u", response->ids.origRemote.toStringWithPort(), response->ids.qname.toString(), QType(response->ids.qtype).toString(), RCode::to_s(response->getHeader()->rcode), response->getHeader()->id); } } } else { if (d_includeTimestamp) { - fprintf(fp.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %u\n", static_cast(dr->getQueryRealTime().tv_sec), static_cast(dr->getQueryRealTime().tv_nsec), dr->ids.origRemote.toStringWithPort().c_str(), dr->ids.qname.toString().c_str(), QType(dr->ids.qtype).toString().c_str(), RCode::to_s(dr->getHeader()->rcode).c_str(), dr->getHeader()->id); + fprintf(filepointer.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %u\n", static_cast(response->getQueryRealTime().tv_sec), static_cast(response->getQueryRealTime().tv_nsec), response->ids.origRemote.toStringWithPort().c_str(), response->ids.qname.toString().c_str(), QType(response->ids.qtype).toString().c_str(), RCode::to_s(response->getHeader()->rcode).c_str(), response->getHeader()->id); } else { - fprintf(fp.get(), "Answer to %s for %s %s (%s) with id %u\n", dr->ids.origRemote.toStringWithPort().c_str(), dr->ids.qname.toString().c_str(), QType(dr->ids.qtype).toString().c_str(), RCode::to_s(dr->getHeader()->rcode).c_str(), dr->getHeader()->id); + fprintf(filepointer.get(), "Answer to %s for %s %s (%s) with id %u\n", response->ids.origRemote.toStringWithPort().c_str(), response->ids.qname.toString().c_str(), QType(response->ids.qtype).toString().c_str(), RCode::to_s(response->getHeader()->rcode).c_str(), response->getHeader()->id); } } return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { if (!d_fname.empty()) { return "log to " + d_fname; @@ -1291,20 +1341,21 @@ class LogResponseAction : public DNSResponseAction, public boost::noncopyable // we are using a naked pointer here because we don't want fclose to be called // with a nullptr, which would happen if we constructor a shared_ptr with fclose // as a custom deleter and nullptr as a FILE* - auto nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w"); - if (!nfp) { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + auto* nfp = fopen(d_fname.c_str(), d_append ? "a+" : "w"); + if (nfp == nullptr) { /* don't fall on our sword when reopening */ return false; } - auto fp = std::shared_ptr(nfp, fclose); + auto filepointer = std::shared_ptr(nfp, fclose); nfp = nullptr; if (!d_buffered) { - setbuf(fp.get(), 0); + setbuf(filepointer.get(), nullptr); } - std::atomic_store_explicit(&d_fp, std::move(fp), std::memory_order_release); + std::atomic_store_explicit(&d_fp, std::move(filepointer), std::memory_order_release); return true; } @@ -1320,15 +1371,15 @@ class SetDisableValidationAction : public DNSAction { public: // this action does not stop the processing - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) { header.cd = true; return true; }); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "set cd=1"; } @@ -1338,12 +1389,12 @@ class SetSkipCacheAction : public DNSAction { public: // this action does not stop the processing - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dq->ids.skipCache = true; + dnsquestion->ids.skipCache = true; return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "skip cache"; } @@ -1352,12 +1403,12 @@ class SetSkipCacheAction : public DNSAction class SetSkipCacheResponseAction : public DNSResponseAction { public: - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { - dr->ids.skipCache = true; + response->ids.skipCache = true; return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "skip cache"; } @@ -1367,18 +1418,20 @@ class SetTempFailureCacheTTLAction : public DNSAction { public: // this action does not stop the processing - SetTempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl) + SetTempFailureCacheTTLAction(uint32_t ttl) : + d_ttl(ttl) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dq->ids.tempFailureTTL = d_ttl; + dnsquestion->ids.tempFailureTTL = d_ttl; return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { - return "set tempfailure cache ttl to "+std::to_string(d_ttl); + return "set tempfailure cache ttl to " + std::to_string(d_ttl); } + private: uint32_t d_ttl; }; @@ -1387,18 +1440,20 @@ class SetECSPrefixLengthAction : public DNSAction { public: // this action does not stop the processing - SetECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length) + SetECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : + d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dq->ecsPrefixLength = dq->ids.origRemote.sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength; + dnsquestion->ecsPrefixLength = dnsquestion->ids.origRemote.sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength; return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength); } + private: uint16_t d_v4PrefixLength; uint16_t d_v6PrefixLength; @@ -1408,33 +1463,34 @@ class SetECSOverrideAction : public DNSAction { public: // this action does not stop the processing - SetECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride) + SetECSOverrideAction(bool ecsOverride) : + d_ecsOverride(ecsOverride) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dq->ecsOverride = d_ecsOverride; + dnsquestion->ecsOverride = d_ecsOverride; return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { - return "set ECS override to " + std::to_string(d_ecsOverride); + return "set ECS override to " + std::to_string(static_cast(d_ecsOverride)); } + private: bool d_ecsOverride; }; - class SetDisableECSAction : public DNSAction { public: // this action does not stop the processing - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dq->useECS = false; + dnsquestion->useECS = false; return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "disable ECS"; } @@ -1444,27 +1500,29 @@ class SetECSAction : public DNSAction { public: // this action does not stop the processing - SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false) + SetECSAction(const Netmask& v4Netmask) : + d_v4(v4Netmask), d_hasV6(false) { } - SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true) + SetECSAction(const Netmask& v4Netmask, const Netmask& v6Netmask) : + d_v4(v4Netmask), d_v6(v6Netmask), d_hasV6(true) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { if (d_hasV6) { - dq->ecs = std::make_unique(dq->ids.origRemote.isIPv4() ? d_v4 : d_v6); + dnsquestion->ecs = std::make_unique(dnsquestion->ids.origRemote.isIPv4() ? d_v4 : d_v6); } else { - dq->ecs = std::make_unique(d_v4); + dnsquestion->ecs = std::make_unique(d_v4); } return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { std::string result = "set ECS to " + d_v4.toString(); if (d_hasV6) { @@ -1485,41 +1543,44 @@ static DnstapMessage::ProtocolType ProtocolToDNSTap(dnsdist::Protocol protocol) if (protocol == dnsdist::Protocol::DoUDP) { return DnstapMessage::ProtocolType::DoUDP; } - else if (protocol == dnsdist::Protocol::DoTCP) { + if (protocol == dnsdist::Protocol::DoTCP) { return DnstapMessage::ProtocolType::DoTCP; } - else if (protocol == dnsdist::Protocol::DoT) { + if (protocol == dnsdist::Protocol::DoT) { return DnstapMessage::ProtocolType::DoT; } - else if (protocol == dnsdist::Protocol::DoH) { + if (protocol == dnsdist::Protocol::DoH || protocol == dnsdist::Protocol::DoH3) { return DnstapMessage::ProtocolType::DoH; } - else if (protocol == dnsdist::Protocol::DNSCryptUDP) { + if (protocol == dnsdist::Protocol::DNSCryptUDP) { return DnstapMessage::ProtocolType::DNSCryptUDP; } - else if (protocol == dnsdist::Protocol::DNSCryptTCP) { + if (protocol == dnsdist::Protocol::DNSCryptTCP) { return DnstapMessage::ProtocolType::DNSCryptTCP; } + if (protocol == dnsdist::Protocol::DoQ) { + return DnstapMessage::ProtocolType::DoQ; + } throw std::runtime_error("Unhandled protocol for dnstap: " + protocol.toPrettyString()); } -static void remoteLoggerQueueData(RemoteLoggerInterface& r, const std::string& data) +static void remoteLoggerQueueData(RemoteLoggerInterface& remoteLogger, const std::string& data) { - auto ret = r.queueData(data); + auto ret = remoteLogger.queueData(data); switch (ret) { case RemoteLoggerInterface::Result::Queued: break; case RemoteLoggerInterface::Result::PipeFull: { - vinfolog("%s: %s", r.name(), RemoteLoggerInterface::toErrorString(ret)); + vinfolog("%s: %s", remoteLogger.name(), RemoteLoggerInterface::toErrorString(ret)); break; } case RemoteLoggerInterface::Result::TooLarge: { - warnlog("%s: %s", r.name(), RemoteLoggerInterface::toErrorString(ret)); + warnlog("%s: %s", remoteLogger.name(), RemoteLoggerInterface::toErrorString(ret)); break; } case RemoteLoggerInterface::Result::OtherError: - warnlog("%s: %s", r.name(), RemoteLoggerInterface::toErrorString(ret)); + warnlog("%s: %s", remoteLogger.name(), RemoteLoggerInterface::toErrorString(ret)); } } @@ -1527,53 +1588,57 @@ class DnstapLogAction : public DNSAction, public boost::noncopyable { public: // this action does not stop the processing - DnstapLogAction(const std::string& identity, std::shared_ptr& logger, boost::optional > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(std::move(alterFunc)) + DnstapLogAction(std::string identity, std::shared_ptr& logger, boost::optional> alterFunc) : + d_identity(std::move(identity)), d_logger(logger), d_alterFunc(std::move(alterFunc)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { static thread_local std::string data; data.clear(); - DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dq->getProtocol()); - DnstapMessage message(data, !dq->getHeader()->qr ? DnstapMessage::MessageType::client_query : DnstapMessage::MessageType::client_response, d_identity, &dq->ids.origRemote, &dq->ids.origDest, protocol, reinterpret_cast(dq->getData().data()), dq->getData().size(), &dq->getQueryRealTime(), nullptr); + DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dnsquestion->getProtocol()); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + DnstapMessage message(std::move(data), !dnsquestion->getHeader()->qr ? DnstapMessage::MessageType::client_query : DnstapMessage::MessageType::client_response, d_identity, &dnsquestion->ids.origRemote, &dnsquestion->ids.origDest, protocol, reinterpret_cast(dnsquestion->getData().data()), dnsquestion->getData().size(), &dnsquestion->getQueryRealTime(), nullptr); { if (d_alterFunc) { auto lock = g_lua.lock(); - (*d_alterFunc)(dq, &message); + (*d_alterFunc)(dnsquestion, &message); } } + data = message.getBuffer(); remoteLoggerQueueData(*d_logger, data); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "remote log as dnstap to " + (d_logger ? d_logger->toString() : ""); } + private: std::string d_identity; std::shared_ptr d_logger; - boost::optional > d_alterFunc; + boost::optional> d_alterFunc; }; namespace { -void addMetaDataToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dq, const std::vector>& metas) +void addMetaDataToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dnsquestion, const std::vector>& metas) { for (const auto& [name, meta] : metas) { - message.addMeta(name, meta.getValues(dq), {}); + message.addMeta(name, meta.getValues(dnsquestion), {}); } } -void addTagsToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dq, const std::unordered_set& allowed) +void addTagsToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dnsquestion, const std::unordered_set& allowed) { - if (!dq.ids.qTag) { + if (!dnsquestion.ids.qTag) { return; } - for (const auto& [key, value] : *dq.ids.qTag) { + for (const auto& [key, value] : *dnsquestion.ids.qTag) { if (!allowed.empty() && allowed.count(key) == 0) { continue; } @@ -1582,14 +1647,17 @@ void addTagsToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dq, c message.addTag(key); } else { - message.addTag(key + ":" + value); + auto tag = key; + tag.append(":"); + tag.append(value); + message.addTag(tag); } } } -void addExtendedDNSErrorToProtobuf(DNSDistProtoBufMessage& message, const DNSResponse& dr, const std::string& metaKey) +void addExtendedDNSErrorToProtobuf(DNSDistProtoBufMessage& message, const DNSResponse& response, const std::string& metaKey) { - auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(dr.getData()); + auto [infoCode, extraText] = dnsdist::edns::getExtendedDNSError(response.getData()); if (!infoCode) { return; } @@ -1607,8 +1675,8 @@ struct RemoteLogActionConfiguration { std::vector> metas; std::optional> tagsToExport{std::nullopt}; - boost::optional > alterQueryFunc{boost::none}; - boost::optional > alterResponseFunc{boost::none}; + boost::optional> alterQueryFunc{boost::none}; + boost::optional> alterResponseFunc{boost::none}; std::shared_ptr logger; std::string serverID; std::string ipEncryptKey; @@ -1620,40 +1688,40 @@ class RemoteLogAction : public DNSAction, public boost::noncopyable { public: // this action does not stop the processing - RemoteLogAction(RemoteLogActionConfiguration& config): d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterQueryFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey) + RemoteLogAction(RemoteLogActionConfiguration& config) : + d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterQueryFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - if (!dq->ids.d_protoBufData) { - dq->ids.d_protoBufData = std::make_unique(); + if (!dnsquestion->ids.d_protoBufData) { + dnsquestion->ids.d_protoBufData = std::make_unique(); } - if (!dq->ids.d_protoBufData->uniqueId) { - dq->ids.d_protoBufData->uniqueId = getUniqueID(); + if (!dnsquestion->ids.d_protoBufData->uniqueId) { + dnsquestion->ids.d_protoBufData->uniqueId = getUniqueID(); } - DNSDistProtoBufMessage message(*dq); + DNSDistProtoBufMessage message(*dnsquestion); if (!d_serverID.empty()) { message.setServerIdentity(d_serverID); } #if HAVE_IPCIPHER - if (!d_ipEncryptKey.empty()) - { - message.setRequestor(encryptCA(dq->ids.origRemote, d_ipEncryptKey)); + if (!d_ipEncryptKey.empty()) { + message.setRequestor(encryptCA(dnsquestion->ids.origRemote, d_ipEncryptKey)); } #endif /* HAVE_IPCIPHER */ if (d_tagsToExport) { - addTagsToProtobuf(message, *dq, *d_tagsToExport); + addTagsToProtobuf(message, *dnsquestion, *d_tagsToExport); } - addMetaDataToProtobuf(message, *dq, d_metas); + addMetaDataToProtobuf(message, *dnsquestion, d_metas); if (d_alterFunc) { auto lock = g_lua.lock(); - (*d_alterFunc)(dq, &message); + (*d_alterFunc)(dnsquestion, &message); } static thread_local std::string data; @@ -1663,15 +1731,16 @@ class RemoteLogAction : public DNSAction, public boost::noncopyable return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "remote log to " + (d_logger ? d_logger->toString() : ""); } + private: std::optional> d_tagsToExport; std::vector> d_metas; std::shared_ptr d_logger; - boost::optional > d_alterFunc; + boost::optional> d_alterFunc; std::string d_serverID; std::string d_ipEncryptKey; }; @@ -1682,21 +1751,23 @@ class SNMPTrapAction : public DNSAction { public: // this action does not stop the processing - SNMPTrapAction(const std::string& reason): d_reason(reason) + SNMPTrapAction(std::string reason) : + d_reason(std::move(reason)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - if (g_snmpAgent && g_snmpTrapsEnabled) { - g_snmpAgent->sendDNSTrap(*dq, d_reason); + if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) { + g_snmpAgent->sendDNSTrap(*dnsquestion, d_reason); } return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "send SNMP trap"; } + private: std::string d_reason; }; @@ -1705,19 +1776,21 @@ class SetTagAction : public DNSAction { public: // this action does not stop the processing - SetTagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value) + SetTagAction(std::string tag, std::string value) : + d_tag(std::move(tag)), d_value(std::move(value)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dq->setTag(d_tag, d_value); + dnsquestion->setTag(d_tag, d_value); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "set tag '" + d_tag + "' to value '" + d_value + "'"; } + private: std::string d_tag; std::string d_value; @@ -1728,80 +1801,84 @@ class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopya { public: // this action does not stop the processing - DnstapLogResponseAction(const std::string& identity, std::shared_ptr& logger, boost::optional > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(std::move(alterFunc)) + DnstapLogResponseAction(std::string identity, std::shared_ptr& logger, boost::optional> alterFunc) : + d_identity(std::move(identity)), d_logger(logger), d_alterFunc(std::move(alterFunc)) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { static thread_local std::string data; - struct timespec now; + struct timespec now = {}; gettime(&now, true); data.clear(); - DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(dr->getProtocol()); - DnstapMessage message(data, DnstapMessage::MessageType::client_response, d_identity, &dr->ids.origRemote, &dr->ids.origDest, protocol, reinterpret_cast(dr->getData().data()), dr->getData().size(), &dr->getQueryRealTime(), &now); + DnstapMessage::ProtocolType protocol = ProtocolToDNSTap(response->getProtocol()); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + DnstapMessage message(std::move(data), DnstapMessage::MessageType::client_response, d_identity, &response->ids.origRemote, &response->ids.origDest, protocol, reinterpret_cast(response->getData().data()), response->getData().size(), &response->getQueryRealTime(), &now); { if (d_alterFunc) { auto lock = g_lua.lock(); - (*d_alterFunc)(dr, &message); + (*d_alterFunc)(response, &message); } } + data = message.getBuffer(); remoteLoggerQueueData(*d_logger, data); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "log response as dnstap to " + (d_logger ? d_logger->toString() : ""); } + private: std::string d_identity; std::shared_ptr d_logger; - boost::optional > d_alterFunc; + boost::optional> d_alterFunc; }; class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable { public: // this action does not stop the processing - RemoteLogResponseAction(RemoteLogActionConfiguration& config): d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterResponseFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_exportExtendedErrorsToMeta(std::move(config.exportExtendedErrorsToMeta)), d_includeCNAME(config.includeCNAME) + RemoteLogResponseAction(RemoteLogActionConfiguration& config) : + d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterResponseFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_exportExtendedErrorsToMeta(std::move(config.exportExtendedErrorsToMeta)), d_includeCNAME(config.includeCNAME) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { - if (!dr->ids.d_protoBufData) { - dr->ids.d_protoBufData = std::make_unique(); + if (!response->ids.d_protoBufData) { + response->ids.d_protoBufData = std::make_unique(); } - if (!dr->ids.d_protoBufData->uniqueId) { - dr->ids.d_protoBufData->uniqueId = getUniqueID(); + if (!response->ids.d_protoBufData->uniqueId) { + response->ids.d_protoBufData->uniqueId = getUniqueID(); } - DNSDistProtoBufMessage message(*dr, d_includeCNAME); + DNSDistProtoBufMessage message(*response, d_includeCNAME); if (!d_serverID.empty()) { message.setServerIdentity(d_serverID); } #if HAVE_IPCIPHER - if (!d_ipEncryptKey.empty()) - { - message.setRequestor(encryptCA(dr->ids.origRemote, d_ipEncryptKey)); + if (!d_ipEncryptKey.empty()) { + message.setRequestor(encryptCA(response->ids.origRemote, d_ipEncryptKey)); } #endif /* HAVE_IPCIPHER */ if (d_tagsToExport) { - addTagsToProtobuf(message, *dr, *d_tagsToExport); + addTagsToProtobuf(message, *response, *d_tagsToExport); } - addMetaDataToProtobuf(message, *dr, d_metas); + addMetaDataToProtobuf(message, *response, d_metas); if (d_exportExtendedErrorsToMeta) { - addExtendedDNSErrorToProtobuf(message, *dr, *d_exportExtendedErrorsToMeta); + addExtendedDNSErrorToProtobuf(message, *response, *d_exportExtendedErrorsToMeta); } if (d_alterFunc) { auto lock = g_lua.lock(); - (*d_alterFunc)(dr, &message); + (*d_alterFunc)(response, &message); } static thread_local std::string data; @@ -1811,15 +1888,16 @@ class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopya return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "remote log response to " + (d_logger ? d_logger->toString() : ""); } + private: std::optional> d_tagsToExport; std::vector> d_metas; std::shared_ptr d_logger; - boost::optional > d_alterFunc; + boost::optional> d_alterFunc; std::string d_serverID; std::string d_ipEncryptKey; std::optional d_exportExtendedErrorsToMeta{std::nullopt}; @@ -1831,11 +1909,11 @@ class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopya class DropResponseAction : public DNSResponseAction { public: - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { return Action::Drop; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "drop"; } @@ -1844,11 +1922,11 @@ class DropResponseAction : public DNSResponseAction class AllowResponseAction : public DNSResponseAction { public: - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { return Action::Allow; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "allow"; } @@ -1857,18 +1935,20 @@ class AllowResponseAction : public DNSResponseAction class DelayResponseAction : public DNSResponseAction { public: - DelayResponseAction(int msec) : d_msec(msec) + DelayResponseAction(int msec) : + d_msec(msec) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { *ruleresult = std::to_string(d_msec); return Action::Delay; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { - return "delay by "+std::to_string(d_msec)+ " ms"; + return "delay by " + std::to_string(d_msec) + " ms"; } + private: int d_msec; }; @@ -1878,21 +1958,23 @@ class SNMPTrapResponseAction : public DNSResponseAction { public: // this action does not stop the processing - SNMPTrapResponseAction(const std::string& reason): d_reason(reason) + SNMPTrapResponseAction(std::string reason) : + d_reason(std::move(reason)) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { if (g_snmpAgent && g_snmpTrapsEnabled) { - g_snmpAgent->sendDNSTrap(*dr, d_reason); + g_snmpAgent->sendDNSTrap(*response, d_reason); } return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "send SNMP trap"; } + private: std::string d_reason; }; @@ -1902,19 +1984,21 @@ class SetTagResponseAction : public DNSResponseAction { public: // this action does not stop the processing - SetTagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value) + SetTagResponseAction(std::string tag, std::string value) : + d_tag(std::move(tag)), d_value(std::move(value)) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { - dr->setTag(d_tag, d_value); + response->setTag(d_tag, d_value); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "set tag '" + d_tag + "' to value '" + d_value + "'"; } + private: std::string d_tag; std::string d_value; @@ -1923,19 +2007,20 @@ class SetTagResponseAction : public DNSResponseAction class ClearRecordTypesResponseAction : public DNSResponseAction, public boost::noncopyable { public: - ClearRecordTypesResponseAction(const std::unordered_set& qtypes) : d_qtypes(qtypes) + ClearRecordTypesResponseAction(std::unordered_set qtypes) : + d_qtypes(std::move(qtypes)) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { - if (d_qtypes.size() > 0) { - clearDNSPacketRecordTypes(dr->getMutableData(), d_qtypes); + if (!d_qtypes.empty()) { + clearDNSPacketRecordTypes(response->getMutableData(), d_qtypes); } return DNSResponseAction::Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "clear record types"; } @@ -1948,32 +2033,31 @@ class ContinueAction : public DNSAction { public: // this action does not stop the processing - ContinueAction(std::shared_ptr& action): d_action(action) + ContinueAction(std::shared_ptr& action) : + d_action(action) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { if (d_action) { /* call the action */ - auto action = (*d_action)(dq, ruleresult); + auto action = (*d_action)(dnsquestion, ruleresult); bool drop = false; /* apply the changes if needed (pool selection, flags, etc */ - processRulesResult(action, *dq, *ruleresult, drop); + processRulesResult(action, *dnsquestion, *ruleresult, drop); } /* but ignore the resulting action no matter what */ return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { if (d_action) { return "continue after: " + (d_action ? d_action->toString() : ""); } - else { - return "no op"; - } + return "no op"; } private: @@ -1981,21 +2065,22 @@ class ContinueAction : public DNSAction }; #ifdef HAVE_DNS_OVER_HTTPS -class HTTPStatusAction: public DNSAction +class HTTPStatusAction : public DNSAction { public: - HTTPStatusAction(int code, const PacketBuffer& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code) + HTTPStatusAction(int code, PacketBuffer body, std::string contentType) : + d_body(std::move(body)), d_contentType(std::move(contentType)), d_code(code) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - if (!dq->ids.du) { + if (!dnsquestion->ids.du) { return Action::None; } - dq->ids.du->setHTTPResponse(d_code, PacketBuffer(d_body), d_contentType); - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) { + dnsquestion->ids.du->setHTTPResponse(d_code, PacketBuffer(d_body), d_contentType); + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) { header.qr = true; // for good measure setResponseHeadersFromConfig(header, d_responseConfig); return true; @@ -2003,13 +2088,18 @@ class HTTPStatusAction: public DNSAction return Action::HeaderModify; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "return an HTTP status of " + std::to_string(d_code); } - ResponseConfig d_responseConfig; + [[nodiscard]] ResponseConfig& getResponseConfig() + { + return d_responseConfig; + } + private: + ResponseConfig d_responseConfig; PacketBuffer d_body; std::string d_contentType; int d_code; @@ -2021,26 +2111,27 @@ class KeyValueStoreLookupAction : public DNSAction { public: // this action does not stop the processing - KeyValueStoreLookupAction(std::shared_ptr& kvs, std::shared_ptr& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag) + KeyValueStoreLookupAction(std::shared_ptr& kvs, std::shared_ptr& lookupKey, std::string destinationTag) : + d_kvs(kvs), d_key(lookupKey), d_tag(std::move(destinationTag)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - std::vector keys = d_key->getKeys(*dq); + std::vector keys = d_key->getKeys(*dnsquestion); std::string result; for (const auto& key : keys) { - if (d_kvs->getValue(key, result) == true) { + if (d_kvs->getValue(key, result)) { break; } } - dq->setTag(d_tag, std::move(result)); + dnsquestion->setTag(d_tag, std::move(result)); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'"; } @@ -2055,26 +2146,27 @@ class KeyValueStoreRangeLookupAction : public DNSAction { public: // this action does not stop the processing - KeyValueStoreRangeLookupAction(std::shared_ptr& kvs, std::shared_ptr& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag) + KeyValueStoreRangeLookupAction(std::shared_ptr& kvs, std::shared_ptr& lookupKey, std::string destinationTag) : + d_kvs(kvs), d_key(lookupKey), d_tag(std::move(destinationTag)) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - std::vector keys = d_key->getKeys(*dq); + std::vector keys = d_key->getKeys(*dnsquestion); std::string result; for (const auto& key : keys) { - if (d_kvs->getRangeValue(key, result) == true) { + if (d_kvs->getRangeValue(key, result)) { break; } } - dq->setTag(d_tag, std::move(result)); + dnsquestion->setTag(d_tag, std::move(result)); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "do a range-based lookup in key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'"; } @@ -2089,17 +2181,18 @@ class KeyValueStoreRangeLookupAction : public DNSAction class MaxReturnedTTLAction : public DNSAction { public: - MaxReturnedTTLAction(uint32_t cap) : d_cap(cap) + MaxReturnedTTLAction(uint32_t cap) : + d_cap(cap) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - dq->ids.ttlCap = d_cap; + dnsquestion->ids.ttlCap = d_cap; return DNSAction::Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "cap the TTL of the returned response to " + std::to_string(d_cap); } @@ -2111,17 +2204,18 @@ class MaxReturnedTTLAction : public DNSAction class MaxReturnedTTLResponseAction : public DNSResponseAction { public: - MaxReturnedTTLResponseAction(uint32_t cap) : d_cap(cap) + MaxReturnedTTLResponseAction(uint32_t cap) : + d_cap(cap) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { - dr->ids.ttlCap = d_cap; + response->ids.ttlCap = d_cap; return DNSResponseAction::Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "cap the TTL of the returned response to " + std::to_string(d_cap); } @@ -2130,20 +2224,30 @@ class MaxReturnedTTLResponseAction : public DNSResponseAction uint32_t d_cap; }; -class NegativeAndSOAAction: public DNSAction +class NegativeAndSOAAction : public DNSAction { public: - NegativeAndSOAAction(bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, bool soaInAuthoritySection): d_zone(zone), d_mname(mname), d_rname(rname), d_ttl(ttl), d_serial(serial), d_refresh(refresh), d_retry(retry), d_expire(expire), d_minimum(minimum), d_nxd(nxd), d_soaInAuthoritySection(soaInAuthoritySection) + struct SOAParams + { + uint32_t serial; + uint32_t refresh; + uint32_t retry; + uint32_t expire; + 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) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - if (!setNegativeAndAdditionalSOA(*dq, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_serial, d_refresh, d_retry, d_expire, d_minimum, d_soaInAuthoritySection)) { + if (!setNegativeAndAdditionalSOA(*dnsquestion, d_nxd, d_zone, d_ttl, d_mname, d_rname, d_params.serial, d_params.refresh, d_params.retry, d_params.expire, d_params.minimum, d_soaInAuthoritySection)) { return Action::None; } - dnsdist::PacketMangling::editDNSHeaderFromPacket(dq->getMutableData(), [this](dnsheader& header) { + dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [this](dnsheader& header) { setResponseHeadersFromConfig(header, d_responseConfig); return true; }); @@ -2151,23 +2255,23 @@ class NegativeAndSOAAction: public DNSAction return Action::Allow; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return std::string(d_nxd ? "NXD " : "NODATA") + " with SOA"; } + [[nodiscard]] ResponseConfig& getResponseConfig() + { + return d_responseConfig; + } +private: ResponseConfig d_responseConfig; -private: DNSName d_zone; DNSName d_mname; DNSName d_rname; uint32_t d_ttl; - uint32_t d_serial; - uint32_t d_refresh; - uint32_t d_retry; - uint32_t d_expire; - uint32_t d_minimum; + SOAParams d_params; bool d_nxd; bool d_soaInAuthoritySection; }; @@ -2184,18 +2288,18 @@ class SetProxyProtocolValuesAction : public DNSAction } } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - if (!dq->proxyProtocolValues) { - dq->proxyProtocolValues = make_unique>(); + if (!dnsquestion->proxyProtocolValues) { + dnsquestion->proxyProtocolValues = make_unique>(); } - *(dq->proxyProtocolValues) = d_values; + *(dnsquestion->proxyProtocolValues) = d_values; return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "set Proxy-Protocol values"; } @@ -2208,22 +2312,23 @@ class SetAdditionalProxyProtocolValueAction : public DNSAction { public: // this action does not stop the processing - SetAdditionalProxyProtocolValueAction(uint8_t type, const std::string& value): d_value(value), d_type(type) + SetAdditionalProxyProtocolValueAction(uint8_t type, std::string value) : + d_value(std::move(value)), d_type(type) { } - DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override { - if (!dq->proxyProtocolValues) { - dq->proxyProtocolValues = make_unique>(); + if (!dnsquestion->proxyProtocolValues) { + dnsquestion->proxyProtocolValues = make_unique>(); } - dq->proxyProtocolValues->push_back({ d_value, d_type }); + dnsquestion->proxyProtocolValues->push_back({d_value, d_type}); return Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "add a Proxy-Protocol value of type " + std::to_string(d_type); } @@ -2237,20 +2342,23 @@ class SetReducedTTLResponseAction : public DNSResponseAction, public boost::nonc { public: // this action does not stop the processing - SetReducedTTLResponseAction(uint8_t percentage) : d_ratio(percentage / 100.0) + SetReducedTTLResponseAction(uint8_t percentage) : + d_ratio(percentage / 100.0) { } - DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { + // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) auto visitor = [&](uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl) { return ttl * d_ratio; }; - editDNSPacketTTL(reinterpret_cast(dr->getMutableData().data()), dr->getData().size(), visitor); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + editDNSPacketTTL(reinterpret_cast(response->getMutableData().data()), response->getData().size(), visitor); return DNSResponseAction::Action::None; } - std::string toString() const override + [[nodiscard]] std::string toString() const override { return "reduce ttl to " + std::to_string(d_ratio * 100) + " percent of its value"; } @@ -2311,23 +2419,24 @@ class SetExtendedDNSErrorResponseAction : public DNSResponseAction EDNSExtendedError d_ede; }; -template -static void addAction(GlobalStateHolder > *someRuleActions, const luadnsrule_t& var, const std::shared_ptr& action, boost::optional& params) { +template +static void addAction(GlobalStateHolder>* someRuleActions, const luadnsrule_t& var, const std::shared_ptr& action, boost::optional& params) +{ setLuaSideEffect(); std::string name; - boost::uuids::uuid uuid; - uint64_t creationOrder; + boost::uuids::uuid uuid{}; + uint64_t creationOrder = 0; parseRuleParams(params, uuid, name, creationOrder); checkAllParametersConsumed("addAction", params); auto rule = makeRule(var, "addAction"); - someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector& ruleactions){ - ruleactions.push_back({std::move(rule), std::move(action), std::move(name), std::move(uuid), creationOrder}); - }); + someRuleActions->modify([&rule, &action, &uuid, creationOrder, &name](vector& ruleactions) { + ruleactions.push_back({std::move(rule), std::move(action), std::move(name), uuid, creationOrder}); + }); } -typedef std::unordered_map > responseParams_t; +using responseParams_t = std::unordered_map>; static void parseResponseConfig(boost::optional& vars, ResponseConfig& config) { @@ -2337,202 +2446,208 @@ static void parseResponseConfig(boost::optional& vars, Respons getOptionalValue(vars, "ra", config.setRA); } -void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config) +void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config) { if (config.setAA) { - dh.aa = *config.setAA; + dnsheader.aa = *config.setAA; } if (config.setAD) { - dh.ad = *config.setAD; + dnsheader.ad = *config.setAD; } else { - dh.ad = false; + dnsheader.ad = false; } if (config.setRA) { - dh.ra = *config.setRA; + dnsheader.ra = *config.setRA; } else { - dh.ra = dh.rd; // for good measure + dnsheader.ra = dnsheader.rd; // for good measure } } // NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold void setupLuaActions(LuaContext& luaCtx) { - luaCtx.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr action, boost::optional params) { - boost::uuids::uuid uuid; - uint64_t creationOrder; - std::string name; - parseRuleParams(params, uuid, name, creationOrder); - checkAllParametersConsumed("newRuleAction", params); + luaCtx.writeFunction("newRuleAction", [](const luadnsrule_t& dnsrule, std::shared_ptr action, boost::optional params) { + boost::uuids::uuid uuid{}; + uint64_t creationOrder = 0; + std::string name; + parseRuleParams(params, uuid, name, creationOrder); + checkAllParametersConsumed("newRuleAction", params); - auto rule = makeRule(dnsrule, "newRuleAction"); - DNSDistRuleAction ra({std::move(rule), std::move(action), std::move(name), uuid, creationOrder}); - return std::make_shared(ra); - }); + auto rule = makeRule(dnsrule, "newRuleAction"); + DNSDistRuleAction ruleaction({std::move(rule), std::move(action), std::move(name), uuid, creationOrder}); + return std::make_shared(ruleaction); + }); - luaCtx.writeFunction("addAction", [](luadnsrule_t var, boost::variant, std::shared_ptr > era, boost::optional params) { - if (era.type() != typeid(std::shared_ptr)) { - throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); - } + luaCtx.writeFunction("addAction", [](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); + } - addAction(&g_ruleactions, var, boost::get >(era), params); - }); + addAction(&g_ruleactions, var, boost::get>(era), params); + }); - luaCtx.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant, std::shared_ptr > era, boost::optional params) { - if (era.type() != typeid(std::shared_ptr)) { - throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); - } + luaCtx.writeFunction("addResponseAction", [](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); + } - addAction(&g_respruleactions, var, boost::get >(era), params); - }); + addAction(&g_respruleactions, var, boost::get>(era), params); + }); - luaCtx.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant, std::shared_ptr> era, boost::optional params) { - if (era.type() != typeid(std::shared_ptr)) { - throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); - } + luaCtx.writeFunction("addCacheHitResponseAction", [](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); + } - addAction(&g_cachehitrespruleactions, var, boost::get >(era), params); - }); + addAction(&g_cachehitrespruleactions, var, boost::get>(era), params); + }); - luaCtx.writeFunction("addCacheInsertedResponseAction", [](luadnsrule_t var, boost::variant, std::shared_ptr> era, boost::optional params) { + luaCtx.writeFunction("addCacheInsertedResponseAction", [](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { if (era.type() != typeid(std::shared_ptr)) { throw std::runtime_error("addCacheInsertedResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); } - addAction(&g_cacheInsertedRespRuleActions, var, boost::get >(era), params); + addAction(&g_cacheInsertedRespRuleActions, var, boost::get>(era), params); }); - luaCtx.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant, std::shared_ptr> era, boost::optional params) { - if (era.type() != typeid(std::shared_ptr)) { - throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); - } + luaCtx.writeFunction("addSelfAnsweredResponseAction", [](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); + } - addAction(&g_selfansweredrespruleactions, var, boost::get >(era), params); - }); + addAction(&g_selfansweredrespruleactions, var, boost::get>(era), params); + }); - luaCtx.registerFunction("printStats", [](const DNSAction& ta) { - setLuaNoSideEffect(); - auto stats = ta.getStats(); - for(const auto& s : stats) { - g_outputBuffer+=s.first+"\t"; - if((uint64_t)s.second == s.second) - g_outputBuffer += std::to_string((uint64_t)s.second)+"\n"; - else - g_outputBuffer += std::to_string(s.second)+"\n"; + luaCtx.registerFunction("printStats", [](const DNSAction& action) { + setLuaNoSideEffect(); + auto stats = action.getStats(); + for (const auto& stat : stats) { + g_outputBuffer += stat.first + "\t"; + double integral = 0; + if (std::modf(stat.second, &integral) == 0.0 && stat.second < static_cast(std::numeric_limits::max())) { + g_outputBuffer += std::to_string(static_cast(stat.second)) + "\n"; } - }); + else { + g_outputBuffer += std::to_string(stat.second) + "\n"; + } + } + }); luaCtx.writeFunction("getAction", [](unsigned int num) { - setLuaNoSideEffect(); - boost::optional> ret; - auto ruleactions = g_ruleactions.getCopy(); - if(num < ruleactions.size()) - ret=ruleactions[num].d_action; - return ret; - }); + setLuaNoSideEffect(); + boost::optional> ret; + auto ruleactions = g_ruleactions.getCopy(); + if (num < ruleactions.size()) { + ret = ruleactions[num].d_action; + } + return ret; + }); luaCtx.registerFunction("getStats", &DNSAction::getStats); luaCtx.registerFunction("reload", &DNSAction::reload); luaCtx.registerFunction("reload", &DNSResponseAction::reload); luaCtx.writeFunction("LuaAction", [](LuaAction::func_t func) { - setLuaSideEffect(); - return std::shared_ptr(new LuaAction(func)); - }); + setLuaSideEffect(); + return std::shared_ptr(new LuaAction(std::move(func))); + }); luaCtx.writeFunction("LuaFFIAction", [](LuaFFIAction::func_t func) { - setLuaSideEffect(); - return std::shared_ptr(new LuaFFIAction(func)); - }); + setLuaSideEffect(); + return std::shared_ptr(new LuaFFIAction(std::move(func))); + }); luaCtx.writeFunction("LuaFFIPerThreadAction", [](const std::string& code) { - setLuaSideEffect(); - return std::shared_ptr(new LuaFFIPerThreadAction(code)); - }); + setLuaSideEffect(); + return std::shared_ptr(new LuaFFIPerThreadAction(code)); + }); luaCtx.writeFunction("SetNoRecurseAction", []() { - return std::shared_ptr(new SetNoRecurseAction); - }); + return std::shared_ptr(new SetNoRecurseAction); + }); luaCtx.writeFunction("SetMacAddrAction", [](int code) { - return std::shared_ptr(new SetMacAddrAction(code)); - }); + return std::shared_ptr(new SetMacAddrAction(code)); + }); luaCtx.writeFunction("SetEDNSOptionAction", [](int code, const std::string& data) { - return std::shared_ptr(new SetEDNSOptionAction(code, data)); - }); + return std::shared_ptr(new SetEDNSOptionAction(code, data)); + }); - luaCtx.writeFunction("PoolAction", [](const std::string& a, boost::optional stopProcessing) { - return std::shared_ptr(new PoolAction(a, stopProcessing ? *stopProcessing : true)); - }); + luaCtx.writeFunction("PoolAction", [](const std::string& poolname, boost::optional stopProcessing) { + return std::shared_ptr(new PoolAction(poolname, stopProcessing ? *stopProcessing : true)); + }); luaCtx.writeFunction("QPSAction", [](int limit) { - return std::shared_ptr(new QPSAction(limit)); - }); + return std::shared_ptr(new QPSAction(limit)); + }); - luaCtx.writeFunction("QPSPoolAction", [](int limit, const std::string& a, boost::optional stopProcessing) { - return std::shared_ptr(new QPSPoolAction(limit, a, stopProcessing ? *stopProcessing : true)); - }); + luaCtx.writeFunction("QPSPoolAction", [](int limit, const std::string& poolname, boost::optional stopProcessing) { + return std::shared_ptr(new QPSPoolAction(limit, poolname, stopProcessing ? *stopProcessing : true)); + }); luaCtx.writeFunction("SpoofAction", [](LuaTypeOrArrayOf inp, boost::optional vars) { - vector addrs; - if(auto s = boost::get(&inp)) { - addrs.push_back(ComboAddress(*s)); - } else { - const auto& v = boost::get>(inp); - for(const auto& a: v) { - addrs.push_back(ComboAddress(a.second)); - } + vector addrs; + if (auto* ipaddr = boost::get(&inp)) { + addrs.emplace_back(*ipaddr); + } + else { + const auto& ipsArray = boost::get>(inp); + for (const auto& ipAddr : ipsArray) { + addrs.emplace_back(ipAddr.second); } + } - auto ret = std::shared_ptr(new SpoofAction(addrs)); - auto sa = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, sa->d_responseConfig); - checkAllParametersConsumed("SpoofAction", vars); - return ret; - }); + auto ret = std::shared_ptr(new SpoofAction(addrs)); + auto spoofaction = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, spoofaction->getResponseConfig()); + checkAllParametersConsumed("SpoofAction", vars); + return ret; + }); luaCtx.writeFunction("SpoofSVCAction", [](const LuaArray& parameters, boost::optional vars) { - auto ret = std::shared_ptr(new SpoofSVCAction(parameters)); - auto sa = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, sa->d_responseConfig); - return ret; - }); + auto ret = std::shared_ptr(new SpoofSVCAction(parameters)); + auto spoofaction = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, spoofaction->getResponseConfig()); + return ret; + }); - luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional vars) { - auto ret = std::shared_ptr(new SpoofAction(DNSName(a))); - auto sa = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, sa->d_responseConfig); - checkAllParametersConsumed("SpoofCNAMEAction", vars); - return ret; - }); + luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& cname, boost::optional vars) { + auto ret = std::shared_ptr(new SpoofAction(DNSName(cname))); + auto spoofaction = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, spoofaction->getResponseConfig()); + checkAllParametersConsumed("SpoofCNAMEAction", vars); + return ret; + }); luaCtx.writeFunction("SpoofRawAction", [](LuaTypeOrArrayOf inp, boost::optional vars) { - vector raws; - if (const auto* str = boost::get(&inp)) { - raws.push_back(*str); - } else { - const auto& vect = boost::get>(inp); - for (const auto& raw: vect) { - raws.push_back(raw.second); - } - } - uint32_t qtypeForAny{0}; - getOptionalValue(vars, "typeForAny", qtypeForAny); - if (qtypeForAny > std::numeric_limits::max()) { - qtypeForAny = 0; - } - std::optional qtypeForAnyParam; - if (qtypeForAny > 0) { - qtypeForAnyParam = static_cast(qtypeForAny); + vector raws; + if (const auto* str = boost::get(&inp)) { + raws.push_back(*str); + } + else { + const auto& vect = boost::get>(inp); + for (const auto& raw : vect) { + raws.push_back(raw.second); } - auto ret = std::shared_ptr(new SpoofAction(raws, qtypeForAnyParam)); - auto sa = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, sa->d_responseConfig); - checkAllParametersConsumed("SpoofRawAction", vars); - return ret; - }); + } + uint32_t qtypeForAny{0}; + getOptionalValue(vars, "typeForAny", qtypeForAny); + if (qtypeForAny > std::numeric_limits::max()) { + qtypeForAny = 0; + } + std::optional qtypeForAnyParam; + if (qtypeForAny > 0) { + qtypeForAnyParam = static_cast(qtypeForAny); + } + auto ret = std::shared_ptr(new SpoofAction(raws, qtypeForAnyParam)); + auto spoofaction = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, spoofaction->getResponseConfig()); + checkAllParametersConsumed("SpoofRawAction", vars); + return ret; + }); luaCtx.writeFunction("SpoofPacketAction", [](const std::string& response, size_t len) { if (len < sizeof(dnsheader)) { @@ -2540,62 +2655,62 @@ void setupLuaActions(LuaContext& luaCtx) } auto ret = std::shared_ptr(new SpoofAction(response.c_str(), len)); return ret; - }); + }); luaCtx.writeFunction("DropAction", []() { - return std::shared_ptr(new DropAction); - }); + return std::shared_ptr(new DropAction); + }); luaCtx.writeFunction("AllowAction", []() { - return std::shared_ptr(new AllowAction); - }); + return std::shared_ptr(new AllowAction); + }); luaCtx.writeFunction("NoneAction", []() { - return std::shared_ptr(new NoneAction); - }); + return std::shared_ptr(new NoneAction); + }); luaCtx.writeFunction("DelayAction", [](int msec) { - return std::shared_ptr(new DelayAction(msec)); - }); + return std::shared_ptr(new DelayAction(msec)); + }); luaCtx.writeFunction("TCAction", []() { - return std::shared_ptr(new TCAction); - }); + return std::shared_ptr(new TCAction); + }); luaCtx.writeFunction("TCResponseAction", []() { - return std::shared_ptr(new TCResponseAction); - }); + return std::shared_ptr(new TCResponseAction); + }); luaCtx.writeFunction("SetDisableValidationAction", []() { - return std::shared_ptr(new SetDisableValidationAction); - }); + return std::shared_ptr(new SetDisableValidationAction); + }); luaCtx.writeFunction("LogAction", [](boost::optional fname, boost::optional binary, boost::optional append, boost::optional buffered, boost::optional verboseOnly, boost::optional includeTimestamp) { - return std::shared_ptr(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); - }); + return std::shared_ptr(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); + }); luaCtx.writeFunction("LogResponseAction", [](boost::optional fname, boost::optional append, boost::optional buffered, boost::optional verboseOnly, boost::optional includeTimestamp) { - return std::shared_ptr(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); - }); + return std::shared_ptr(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); + }); luaCtx.writeFunction("LimitTTLResponseAction", [](uint32_t min, uint32_t max, boost::optional> types) { - std::unordered_set capTypes; - if (types) { - capTypes.reserve(types->size()); - for (const auto& [idx, type] : *types) { - capTypes.insert(QType(type)); - } + std::unordered_set capTypes; + if (types) { + capTypes.reserve(types->size()); + for (const auto& [idx, type] : *types) { + capTypes.insert(QType(type)); } - return std::shared_ptr(new LimitTTLResponseAction(min, max, capTypes)); - }); + } + return std::shared_ptr(new LimitTTLResponseAction(min, max, capTypes)); + }); luaCtx.writeFunction("SetMinTTLResponseAction", [](uint32_t min) { - return std::shared_ptr(new LimitTTLResponseAction(min)); - }); + return std::shared_ptr(new LimitTTLResponseAction(min)); + }); luaCtx.writeFunction("SetMaxTTLResponseAction", [](uint32_t max) { - return std::shared_ptr(new LimitTTLResponseAction(0, max)); - }); + return std::shared_ptr(new LimitTTLResponseAction(0, max)); + }); luaCtx.writeFunction("SetMaxReturnedTTLAction", [](uint32_t max) { return std::shared_ptr(new MaxReturnedTTLAction(max)); @@ -2606,255 +2721,262 @@ void setupLuaActions(LuaContext& luaCtx) }); luaCtx.writeFunction("SetReducedTTLResponseAction", [](uint8_t percentage) { - if (percentage > 100) { - throw std::runtime_error(std::string("SetReducedTTLResponseAction takes a percentage between 0 and 100.")); - } - return std::shared_ptr(new SetReducedTTLResponseAction(percentage)); - }); + if (percentage > 100) { + throw std::runtime_error(std::string("SetReducedTTLResponseAction takes a percentage between 0 and 100.")); + } + return std::shared_ptr(new SetReducedTTLResponseAction(percentage)); + }); luaCtx.writeFunction("ClearRecordTypesResponseAction", [](LuaTypeOrArrayOf types) { - std::unordered_set qtypes{}; - if (types.type() == typeid(int)) { - qtypes.insert(boost::get(types)); - } else if (types.type() == typeid(LuaArray)) { - const auto& v = boost::get>(types); - for (const auto& tpair: v) { - qtypes.insert(tpair.second); - } + std::unordered_set qtypes{}; + if (types.type() == typeid(int)) { + qtypes.insert(boost::get(types)); + } + else if (types.type() == typeid(LuaArray)) { + const auto& typesArray = boost::get>(types); + for (const auto& tpair : typesArray) { + qtypes.insert(tpair.second); } - return std::shared_ptr(new ClearRecordTypesResponseAction(qtypes)); - }); + } + return std::shared_ptr(new ClearRecordTypesResponseAction(qtypes)); + }); luaCtx.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional vars) { - auto ret = std::shared_ptr(new RCodeAction(rcode)); - auto rca = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, rca->d_responseConfig); - checkAllParametersConsumed("RCodeAction", vars); - return ret; - }); + auto ret = std::shared_ptr(new RCodeAction(rcode)); + auto rca = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, rca->getResponseConfig()); + checkAllParametersConsumed("RCodeAction", vars); + return ret; + }); luaCtx.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional vars) { - auto ret = std::shared_ptr(new ERCodeAction(rcode)); - auto erca = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, erca->d_responseConfig); - checkAllParametersConsumed("ERCodeAction", vars); - return ret; - }); + auto ret = std::shared_ptr(new ERCodeAction(rcode)); + auto erca = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, erca->getResponseConfig()); + checkAllParametersConsumed("ERCodeAction", vars); + return ret; + }); luaCtx.writeFunction("SetSkipCacheAction", []() { - return std::shared_ptr(new SetSkipCacheAction); - }); + return std::shared_ptr(new SetSkipCacheAction); + }); luaCtx.writeFunction("SetSkipCacheResponseAction", []() { - return std::shared_ptr(new SetSkipCacheResponseAction); - }); + return std::shared_ptr(new SetSkipCacheResponseAction); + }); luaCtx.writeFunction("SetTempFailureCacheTTLAction", [](int maxTTL) { - return std::shared_ptr(new SetTempFailureCacheTTLAction(maxTTL)); - }); + return std::shared_ptr(new SetTempFailureCacheTTLAction(maxTTL)); + }); luaCtx.writeFunction("DropResponseAction", []() { - return std::shared_ptr(new DropResponseAction); - }); + return std::shared_ptr(new DropResponseAction); + }); luaCtx.writeFunction("AllowResponseAction", []() { - return std::shared_ptr(new AllowResponseAction); - }); + return std::shared_ptr(new AllowResponseAction); + }); luaCtx.writeFunction("DelayResponseAction", [](int msec) { - return std::shared_ptr(new DelayResponseAction(msec)); - }); + return std::shared_ptr(new DelayResponseAction(msec)); + }); luaCtx.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) { - setLuaSideEffect(); - return std::shared_ptr(new LuaResponseAction(func)); - }); + setLuaSideEffect(); + return std::shared_ptr(new LuaResponseAction(std::move(func))); + }); luaCtx.writeFunction("LuaFFIResponseAction", [](LuaFFIResponseAction::func_t func) { - setLuaSideEffect(); - return std::shared_ptr(new LuaFFIResponseAction(func)); - }); + setLuaSideEffect(); + return std::shared_ptr(new LuaFFIResponseAction(std::move(func))); + }); luaCtx.writeFunction("LuaFFIPerThreadResponseAction", [](const std::string& code) { - setLuaSideEffect(); - return std::shared_ptr(new LuaFFIPerThreadResponseAction(code)); - }); + setLuaSideEffect(); + return std::shared_ptr(new LuaFFIPerThreadResponseAction(code)); + }); #ifndef DISABLE_PROTOBUF - luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr logger, boost::optional > alterFunc, boost::optional> vars, boost::optional> metas) { - if (logger) { - // avoids potentially-evaluated-expression warning with clang. - RemoteLoggerInterface& rl = *logger.get(); - if (typeid(rl) != typeid(RemoteLogger)) { - // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong. - throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction.")); - } + luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr logger, boost::optional> alterFunc, boost::optional> vars, boost::optional> metas) { + if (logger) { + // avoids potentially-evaluated-expression warning with clang. + RemoteLoggerInterface& remoteLoggerRef = *logger; + if (typeid(remoteLoggerRef) != typeid(RemoteLogger)) { + // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong. + throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction.")); } + } - std::string tags; - RemoteLogActionConfiguration config; - config.logger = std::move(logger); - config.alterQueryFunc = std::move(alterFunc); - getOptionalValue(vars, "serverID", config.serverID); - getOptionalValue(vars, "ipEncryptKey", config.ipEncryptKey); - getOptionalValue(vars, "exportTags", tags); - - if (metas) { - for (const auto& [key, value] : *metas) { - config.metas.push_back({key, ProtoBufMetaKey(value)}); - } + std::string tags; + RemoteLogActionConfiguration config; + config.logger = std::move(logger); + config.alterQueryFunc = std::move(alterFunc); + getOptionalValue(vars, "serverID", config.serverID); + getOptionalValue(vars, "ipEncryptKey", config.ipEncryptKey); + getOptionalValue(vars, "exportTags", tags); + + if (metas) { + for (const auto& [key, value] : *metas) { + config.metas.emplace_back(key, ProtoBufMetaKey(value)); } + } - if (!tags.empty()) { - config.tagsToExport = std::unordered_set(); - if (tags != "*") { - std::vector tokens; - stringtok(tokens, tags, ","); - for (auto& token : tokens) { - config.tagsToExport->insert(std::move(token)); - } + if (!tags.empty()) { + config.tagsToExport = std::unordered_set(); + if (tags != "*") { + std::vector tokens; + stringtok(tokens, tags, ","); + for (auto& token : tokens) { + config.tagsToExport->insert(std::move(token)); } } + } - checkAllParametersConsumed("RemoteLogAction", vars); + checkAllParametersConsumed("RemoteLogAction", vars); - return std::shared_ptr(new RemoteLogAction(config)); - }); + return std::shared_ptr(new RemoteLogAction(config)); + }); - luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr logger, boost::optional > alterFunc, boost::optional includeCNAME, boost::optional> vars, boost::optional> metas) { - if (logger) { - // avoids potentially-evaluated-expression warning with clang. - RemoteLoggerInterface& rl = *logger.get(); - if (typeid(rl) != typeid(RemoteLogger)) { - // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong. - throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction."); - } + luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr logger, boost::optional> alterFunc, boost::optional includeCNAME, boost::optional> vars, boost::optional> metas) { + if (logger) { + // avoids potentially-evaluated-expression warning with clang. + RemoteLoggerInterface& remoteLoggerRef = *logger; + if (typeid(remoteLoggerRef) != typeid(RemoteLogger)) { + // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong. + throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction."); } + } - std::string tags; - RemoteLogActionConfiguration config; - config.logger = std::move(logger); - config.alterResponseFunc = alterFunc; - config.includeCNAME = includeCNAME ? *includeCNAME : false; - getOptionalValue(vars, "serverID", config.serverID); - getOptionalValue(vars, "ipEncryptKey", config.ipEncryptKey); - getOptionalValue(vars, "exportTags", tags); - getOptionalValue(vars, "exportExtendedErrorsToMeta", config.exportExtendedErrorsToMeta); - - if (metas) { - for (const auto& [key, value] : *metas) { - config.metas.push_back({key, ProtoBufMetaKey(value)}); - } + std::string tags; + RemoteLogActionConfiguration config; + config.logger = std::move(logger); + config.alterResponseFunc = std::move(alterFunc); + config.includeCNAME = includeCNAME ? *includeCNAME : false; + getOptionalValue(vars, "serverID", config.serverID); + getOptionalValue(vars, "ipEncryptKey", config.ipEncryptKey); + getOptionalValue(vars, "exportTags", tags); + getOptionalValue(vars, "exportExtendedErrorsToMeta", config.exportExtendedErrorsToMeta); + + if (metas) { + for (const auto& [key, value] : *metas) { + config.metas.emplace_back(key, ProtoBufMetaKey(value)); } + } - if (!tags.empty()) { - config.tagsToExport = std::unordered_set(); - if (tags != "*") { - std::vector tokens; - stringtok(tokens, tags, ","); - for (auto& token : tokens) { - config.tagsToExport->insert(std::move(token)); - } + if (!tags.empty()) { + config.tagsToExport = std::unordered_set(); + if (tags != "*") { + std::vector tokens; + stringtok(tokens, tags, ","); + for (auto& token : tokens) { + config.tagsToExport->insert(std::move(token)); } } + } - checkAllParametersConsumed("RemoteLogResponseAction", vars); + checkAllParametersConsumed("RemoteLogResponseAction", vars); - return std::shared_ptr(new RemoteLogResponseAction(config)); - }); + return std::shared_ptr(new RemoteLogResponseAction(config)); + }); - luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr logger, boost::optional > alterFunc) { - return std::shared_ptr(new DnstapLogAction(identity, logger, std::move(alterFunc))); - }); + luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr logger, boost::optional> alterFunc) { + return std::shared_ptr(new DnstapLogAction(identity, logger, std::move(alterFunc))); + }); - luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr logger, boost::optional > alterFunc) { - return std::shared_ptr(new DnstapLogResponseAction(identity, logger, std::move(alterFunc))); - }); + luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr logger, boost::optional> alterFunc) { + return std::shared_ptr(new DnstapLogResponseAction(identity, logger, std::move(alterFunc))); + }); #endif /* DISABLE_PROTOBUF */ luaCtx.writeFunction("TeeAction", [](const std::string& remote, boost::optional addECS, boost::optional local, boost::optional addProxyProtocol) { - boost::optional localAddr{boost::none}; - if (local) { - localAddr = ComboAddress(*local, 0); - } + boost::optional localAddr{boost::none}; + if (local) { + localAddr = ComboAddress(*local, 0); + } - return std::shared_ptr(new TeeAction(ComboAddress(remote, 53), localAddr, addECS ? *addECS : false, addProxyProtocol ? *addProxyProtocol : false)); - }); + return std::shared_ptr(new TeeAction(ComboAddress(remote, 53), localAddr, addECS ? *addECS : false, addProxyProtocol ? *addProxyProtocol : false)); + }); luaCtx.writeFunction("SetECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) { - return std::shared_ptr(new SetECSPrefixLengthAction(v4PrefixLength, v6PrefixLength)); - }); + return std::shared_ptr(new SetECSPrefixLengthAction(v4PrefixLength, v6PrefixLength)); + }); luaCtx.writeFunction("SetECSOverrideAction", [](bool ecsOverride) { - return std::shared_ptr(new SetECSOverrideAction(ecsOverride)); - }); + return std::shared_ptr(new SetECSOverrideAction(ecsOverride)); + }); luaCtx.writeFunction("SetDisableECSAction", []() { - return std::shared_ptr(new SetDisableECSAction()); - }); + return std::shared_ptr(new SetDisableECSAction()); + }); - luaCtx.writeFunction("SetECSAction", [](const std::string& v4, boost::optional v6) { - if (v6) { - return std::shared_ptr(new SetECSAction(Netmask(v4), Netmask(*v6))); - } - return std::shared_ptr(new SetECSAction(Netmask(v4))); - }); + luaCtx.writeFunction("SetECSAction", [](const std::string& v4Netmask, boost::optional v6Netmask) { + if (v6Netmask) { + return std::shared_ptr(new SetECSAction(Netmask(v4Netmask), Netmask(*v6Netmask))); + } + return std::shared_ptr(new SetECSAction(Netmask(v4Netmask))); + }); #ifdef HAVE_NET_SNMP luaCtx.writeFunction("SNMPTrapAction", [](boost::optional reason) { - return std::shared_ptr(new SNMPTrapAction(reason ? *reason : "")); - }); + return std::shared_ptr(new SNMPTrapAction(reason ? *reason : "")); + }); luaCtx.writeFunction("SNMPTrapResponseAction", [](boost::optional reason) { - return std::shared_ptr(new SNMPTrapResponseAction(reason ? *reason : "")); - }); + return std::shared_ptr(new SNMPTrapResponseAction(reason ? *reason : "")); + }); #endif /* HAVE_NET_SNMP */ luaCtx.writeFunction("SetTagAction", [](const std::string& tag, const std::string& value) { - return std::shared_ptr(new SetTagAction(tag, value)); - }); + return std::shared_ptr(new SetTagAction(tag, value)); + }); luaCtx.writeFunction("SetTagResponseAction", [](const std::string& tag, const std::string& value) { - return std::shared_ptr(new SetTagResponseAction(tag, value)); - }); + return std::shared_ptr(new SetTagResponseAction(tag, value)); + }); luaCtx.writeFunction("ContinueAction", [](std::shared_ptr action) { - return std::shared_ptr(new ContinueAction(action)); - }); + return std::shared_ptr(new ContinueAction(action)); + }); #ifdef HAVE_DNS_OVER_HTTPS luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional contentType, boost::optional vars) { - auto ret = std::shared_ptr(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : "")); - auto hsa = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, hsa->d_responseConfig); - checkAllParametersConsumed("HTTPStatusAction", vars); - return ret; - }); + auto ret = std::shared_ptr(new HTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : "")); + auto hsa = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, hsa->getResponseConfig()); + checkAllParametersConsumed("HTTPStatusAction", vars); + return ret; + }); #endif /* HAVE_DNS_OVER_HTTPS */ #if defined(HAVE_LMDB) || defined(HAVE_CDB) luaCtx.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr& kvs, std::shared_ptr& lookupKey, const std::string& destinationTag) { - return std::shared_ptr(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag)); - }); + return std::shared_ptr(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag)); + }); luaCtx.writeFunction("KeyValueStoreRangeLookupAction", [](std::shared_ptr& kvs, std::shared_ptr& lookupKey, const std::string& destinationTag) { - return std::shared_ptr(new KeyValueStoreRangeLookupAction(kvs, lookupKey, destinationTag)); - }); + return std::shared_ptr(new KeyValueStoreRangeLookupAction(kvs, lookupKey, destinationTag)); + }); #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 vars) { - bool soaInAuthoritySection = false; - getOptionalValue(vars, "soaInAuthoritySection", soaInAuthoritySection); - auto ret = std::shared_ptr(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), serial, refresh, retry, expire, minimum, soaInAuthoritySection)); - auto action = std::dynamic_pointer_cast(ret); - parseResponseConfig(vars, action->d_responseConfig); - checkAllParametersConsumed("NegativeAndSOAAction", vars); - return ret; + bool soaInAuthoritySection = false; + getOptionalValue(vars, "soaInAuthoritySection", soaInAuthoritySection); + NegativeAndSOAAction::SOAParams params{ + .serial = serial, + .refresh = refresh, + .retry = retry, + .expire = expire, + .minimum = minimum}; + auto ret = std::shared_ptr(new NegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), params, soaInAuthoritySection)); + auto action = std::dynamic_pointer_cast(ret); + parseResponseConfig(vars, action->getResponseConfig()); + checkAllParametersConsumed("NegativeAndSOAAction", vars); + return ret; }); luaCtx.writeFunction("SetProxyProtocolValuesAction", [](const std::vector>& values) { - return std::shared_ptr(new SetProxyProtocolValuesAction(values)); - }); + return std::shared_ptr(new SetProxyProtocolValuesAction(values)); + }); luaCtx.writeFunction("SetAdditionalProxyProtocolValueAction", [](uint8_t type, const std::string& value) { return std::shared_ptr(new SetAdditionalProxyProtocolValueAction(type, value)); diff --git a/pdns/dnsdist-lua.hh b/pdns/dnsdist-lua.hh index 0037d6b9f088..5c35c3fb9d02 100644 --- a/pdns/dnsdist-lua.hh +++ b/pdns/dnsdist-lua.hh @@ -33,7 +33,7 @@ struct ResponseConfig boost::optional setRA{boost::none}; uint32_t ttl{60}; }; -void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config); +void setResponseHeadersFromConfig(dnsheader& dnsheader, const ResponseConfig& config); class SpoofAction : public DNSAction { @@ -66,7 +66,7 @@ public: { } - DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override; + DNSAction::Action operator()(DNSQuestion* dnsquestion, string* ruleresult) const override; string toString() const override { @@ -84,9 +84,13 @@ public: return ret; } + [[nodiscard]] ResponseConfig& getResponseConfig() + { + return d_responseConfig; + } - ResponseConfig d_responseConfig; private: + ResponseConfig d_responseConfig; static thread_local std::default_random_engine t_randomEngine; std::vector d_addrs; std::unordered_set d_types; diff --git a/pdns/dnsdist-protobuf.cc b/pdns/dnsdist-protobuf.cc index 453cba87f554..30445ed24f18 100644 --- a/pdns/dnsdist-protobuf.cc +++ b/pdns/dnsdist-protobuf.cc @@ -27,11 +27,13 @@ #include "dnsdist-protobuf.hh" #include "protozero.hh" -DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSQuestion& dq): d_dq(dq), d_type(pdns::ProtoZero::Message::MessageType::DNSQueryType) +DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSQuestion& dnsquestion) : + d_dq(dnsquestion) { } -DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSResponse& dr, bool includeCNAME): d_dq(dr), d_dr(&dr), d_type(pdns::ProtoZero::Message::MessageType::DNSResponseType), d_includeCNAME(includeCNAME) +DNSDistProtoBufMessage::DNSDistProtoBufMessage(const DNSResponse& dnsresponse, bool includeCNAME) : + d_dq(dnsresponse), d_dr(&dnsresponse), d_type(pdns::ProtoZero::Message::MessageType::DNSResponseType), d_includeCNAME(includeCNAME) { } @@ -149,6 +151,11 @@ void DNSDistProtoBufMessage::serialize(std::string& data) const } else if (distProto == dnsdist::Protocol::DoH) { protocol = pdns::ProtoZero::Message::TransportProtocol::DoH; + m.setHTTPVersion(pdns::ProtoZero::Message::HTTPVersion::HTTP2); + } + else if (distProto == dnsdist::Protocol::DoH3) { + protocol = pdns::ProtoZero::Message::TransportProtocol::DoH; + m.setHTTPVersion(pdns::ProtoZero::Message::HTTPVersion::HTTP3); } else if (distProto == dnsdist::Protocol::DNSCryptUDP) { protocol = pdns::ProtoZero::Message::TransportProtocol::DNSCryptUDP; @@ -156,6 +163,9 @@ void DNSDistProtoBufMessage::serialize(std::string& data) const else if (distProto == dnsdist::Protocol::DNSCryptTCP) { protocol = pdns::ProtoZero::Message::TransportProtocol::DNSCryptTCP; } + else if (distProto == dnsdist::Protocol::DoQ) { + protocol = pdns::ProtoZero::Message::TransportProtocol::DoQ; + } m.setRequest(d_dq.ids.d_protoBufData && d_dq.ids.d_protoBufData->uniqueId ? *d_dq.ids.d_protoBufData->uniqueId : getUniqueID(), d_requestor ? *d_requestor : d_dq.ids.origRemote, d_responder ? *d_responder : d_dq.ids.origDest, d_question ? d_question->d_name : d_dq.ids.qname, d_question ? d_question->d_type : d_dq.ids.qtype, d_question ? d_question->d_class : d_dq.ids.qclass, d_dq.getHeader()->id, protocol, d_bytes ? *d_bytes : d_dq.getData().size()); @@ -258,14 +268,14 @@ ProtoBufMetaKey::ProtoBufMetaKey(const std::string& key) throw std::runtime_error("Invalid ProtoBuf key '" + key + "'"); } -std::vector ProtoBufMetaKey::getValues(const DNSQuestion& dq) const +std::vector ProtoBufMetaKey::getValues(const DNSQuestion& dnsquestion) const { auto& idx = s_types.get(); auto it = idx.find(d_type); if (it == idx.end()) { throw std::runtime_error("Trying to get the values of an unsupported type: " + std::to_string(static_cast(d_type))); } - return (it->d_func)(dq, d_subKey, d_numericSubKey); + return (it->d_func)(dnsquestion, d_subKey, d_numericSubKey); } const std::string& ProtoBufMetaKey::getName() const @@ -279,94 +289,104 @@ const std::string& ProtoBufMetaKey::getName() const } const ProtoBufMetaKey::TypeContainer ProtoBufMetaKey::s_types = { - ProtoBufMetaKey::KeyTypeDescription{ "sni", Type::SNI, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { return {dq.sni}; }, false }, - ProtoBufMetaKey::KeyTypeDescription{ "pool", Type::Pool, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { return {dq.ids.poolName}; }, false }, - ProtoBufMetaKey::KeyTypeDescription{ "b64-content", Type::B64Content, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { const auto& data = dq.getData(); return {Base64Encode(std::string(data.begin(), data.end()))}; }, false }, + ProtoBufMetaKey::KeyTypeDescription{"sni", Type::SNI, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { return {dnsquestion.sni}; }, false}, + ProtoBufMetaKey::KeyTypeDescription{"pool", Type::Pool, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { return {dnsquestion.ids.poolName}; }, false}, + ProtoBufMetaKey::KeyTypeDescription{"b64-content", Type::B64Content, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { const auto& data = dnsquestion.getData(); return {Base64Encode(std::string(data.begin(), data.end()))}; }, false}, #ifdef HAVE_DNS_OVER_HTTPS - ProtoBufMetaKey::KeyTypeDescription{ "doh-header", Type::DoHHeader, [](const DNSQuestion& dq , const std::string& name, uint8_t) -> std::vector { - if (!dq.ids.du) { - return {}; - } - auto headers = dq.ids.du->getHTTPHeaders(); - auto it = headers.find(name); - if (it != headers.end()) { - return {it->second}; - } - return {}; - }, true, false }, - ProtoBufMetaKey::KeyTypeDescription{ "doh-host", Type::DoHHost, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { - if (dq.ids.du) { - return {dq.ids.du->getHTTPHost()}; - } - return {}; - }, true, false }, - ProtoBufMetaKey::KeyTypeDescription{ "doh-path", Type::DoHPath, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { - if (dq.ids.du) { - return {dq.ids.du->getHTTPPath()}; - } - return {}; - }, false }, - ProtoBufMetaKey::KeyTypeDescription{ "doh-query-string", Type::DoHQueryString, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { - if (dq.ids.du) { - return {dq.ids.du->getHTTPQueryString()}; - } - return {}; - }, false }, - ProtoBufMetaKey::KeyTypeDescription{ "doh-scheme", Type::DoHScheme, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { - if (dq.ids.du) { - return {dq.ids.du->getHTTPScheme()}; - } - return {}; - }, false, false }, + ProtoBufMetaKey::KeyTypeDescription{"doh-header", Type::DoHHeader, [](const DNSQuestion& dnsquestion, const std::string& name, uint8_t) -> std::vector { + if (!dnsquestion.ids.du) { + return {}; + } + auto headers = dnsquestion.ids.du->getHTTPHeaders(); + auto iter = headers.find(name); + if (iter != headers.end()) { + return {iter->second}; + } + return {}; + }, + true, false}, + ProtoBufMetaKey::KeyTypeDescription{"doh-host", Type::DoHHost, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { + if (dnsquestion.ids.du) { + return {dnsquestion.ids.du->getHTTPHost()}; + } + return {}; + }, + true, false}, + ProtoBufMetaKey::KeyTypeDescription{"doh-path", Type::DoHPath, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { + if (dnsquestion.ids.du) { + return {dnsquestion.ids.du->getHTTPPath()}; + } + return {}; + }, + false}, + ProtoBufMetaKey::KeyTypeDescription{"doh-query-string", Type::DoHQueryString, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { + if (dnsquestion.ids.du) { + return {dnsquestion.ids.du->getHTTPQueryString()}; + } + return {}; + }, + false}, + ProtoBufMetaKey::KeyTypeDescription{"doh-scheme", Type::DoHScheme, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { + if (dnsquestion.ids.du) { + return {dnsquestion.ids.du->getHTTPScheme()}; + } + return {}; + }, + false, false}, #endif // HAVE_DNS_OVER_HTTPS - ProtoBufMetaKey::KeyTypeDescription{ "proxy-protocol-value", Type::ProxyProtocolValue, [](const DNSQuestion& dq, const std::string&, uint8_t numericSubKey) -> std::vector { - if (!dq.proxyProtocolValues) { - return {}; - } - for (const auto& value : *dq.proxyProtocolValues) { - if (value.type == numericSubKey) { - return {value.content}; - } - } - return {}; - }, true, false, true }, - ProtoBufMetaKey::KeyTypeDescription{ "proxy-protocol-values", Type::ProxyProtocolValues, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { - std::vector result; - if (!dq.proxyProtocolValues) { - return result; - } - for (const auto& value : *dq.proxyProtocolValues) { - result.push_back(std::to_string(value.type) + ":" + value.content); - } - return result; - } }, - ProtoBufMetaKey::KeyTypeDescription{ "tag", Type::Tag, [](const DNSQuestion& dq, const std::string& subKey, uint8_t) -> std::vector { - if (!dq.ids.qTag) { - return {}; - } - for (const auto& [key, value] : *dq.ids.qTag) { - if (key == subKey) { - return {value}; - } - } - return {}; - }, true, true }, - ProtoBufMetaKey::KeyTypeDescription{ "tags", Type::Tags, [](const DNSQuestion& dq, const std::string&, uint8_t) -> std::vector { - std::vector result; - if (!dq.ids.qTag) { - return result; - } - for (const auto& [key, value] : *dq.ids.qTag) { - if (value.empty()) { - /* avoids a spurious ':' when the value is empty */ - result.push_back(key); - } - else { - result.push_back(key + ":" + value); - } - } - return result; - } }, + ProtoBufMetaKey::KeyTypeDescription{"proxy-protocol-value", Type::ProxyProtocolValue, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t numericSubKey) -> std::vector { + if (!dnsquestion.proxyProtocolValues) { + return {}; + } + for (const auto& value : *dnsquestion.proxyProtocolValues) { + if (value.type == numericSubKey) { + return {value.content}; + } + } + return {}; + }, + true, false, true}, + ProtoBufMetaKey::KeyTypeDescription{"proxy-protocol-values", Type::ProxyProtocolValues, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { + std::vector result; + if (!dnsquestion.proxyProtocolValues) { + return result; + } + for (const auto& value : *dnsquestion.proxyProtocolValues) { + result.push_back(std::to_string(value.type) + ":" + value.content); + } + return result; + }}, + ProtoBufMetaKey::KeyTypeDescription{"tag", Type::Tag, [](const DNSQuestion& dnsquestion, const std::string& subKey, uint8_t) -> std::vector { + if (!dnsquestion.ids.qTag) { + return {}; + } + for (const auto& [key, value] : *dnsquestion.ids.qTag) { + if (key == subKey) { + return {value}; + } + } + return {}; + }, + true, true}, + ProtoBufMetaKey::KeyTypeDescription{"tags", Type::Tags, [](const DNSQuestion& dnsquestion, const std::string&, uint8_t) -> std::vector { + std::vector result; + if (!dnsquestion.ids.qTag) { + return result; + } + for (const auto& [key, value] : *dnsquestion.ids.qTag) { + if (value.empty()) { + /* avoids a spurious ':' when the value is empty */ + result.push_back(key); + } + else { + auto tag = key; + tag.append(":"); + tag.append(value); + result.push_back(tag); + } + } + return result; + }}, }; #endif /* DISABLE_PROTOBUF */ diff --git a/pdns/dnsdist-protobuf.hh b/pdns/dnsdist-protobuf.hh index 1e30f2658254..c2dee817daf3 100644 --- a/pdns/dnsdist-protobuf.hh +++ b/pdns/dnsdist-protobuf.hh @@ -30,8 +30,10 @@ class DNSDistProtoBufMessage { public: - DNSDistProtoBufMessage(const DNSQuestion& dq); - DNSDistProtoBufMessage(const DNSResponse& dr, bool includeCNAME); + DNSDistProtoBufMessage(const DNSQuestion& dnsquestion); + DNSDistProtoBufMessage(const DNSResponse& dnsresponse, bool includeCNAME); + DNSDistProtoBufMessage(const DNSQuestion&&) = delete; + DNSDistProtoBufMessage(const DNSResponse&&, bool) = delete; void setServerIdentity(const std::string& serverId); void setRequestor(const ComboAddress& requestor); @@ -40,11 +42,12 @@ public: void setResponderPort(uint16_t port); void setResponseCode(uint8_t rcode); void setType(pdns::ProtoZero::Message::MessageType type); + void setHTTPVersion(pdns::ProtoZero::Message::HTTPVersion version); void setBytes(size_t bytes); void setTime(time_t sec, uint32_t usec); void setQueryTime(time_t sec, uint32_t usec); void setQuestion(const DNSName& name, uint16_t qtype, uint16_t qclass); - void setEDNSSubnet(const Netmask& nm); + void setEDNSSubnet(const Netmask& netmask); void addTag(const std::string& strValue); void addMeta(const std::string& key, std::vector&& strValues, const std::vector& intValues); @@ -52,7 +55,7 @@ public: void serialize(std::string& data) const; - std::string toDebugString() const; + [[nodiscard]] std::string toDebugString() const; private: struct PBRecord @@ -65,7 +68,8 @@ private: }; struct PBQuestion { - PBQuestion(const DNSName& name, uint16_t type, uint16_t class_): d_name(name), d_type(type), d_class(class_) + PBQuestion(DNSName name, uint16_t type, uint16_t class_) : + d_name(std::move(name)), d_type(type), d_class(class_) { } @@ -83,6 +87,7 @@ private: }; std::unordered_map d_metaTags; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const DNSQuestion& d_dq; const DNSResponse* d_dr{nullptr}; const std::string* d_ServerIdentityRef{nullptr}; @@ -103,36 +108,56 @@ private: class ProtoBufMetaKey { - enum class Type : uint8_t { SNI, Pool, B64Content, DoHHeader, DoHHost, DoHPath, DoHQueryString, DoHScheme, ProxyProtocolValue, ProxyProtocolValues, Tag, Tags }; + enum class Type : uint8_t + { + SNI, + Pool, + B64Content, + DoHHeader, + DoHHost, + DoHPath, + DoHQueryString, + DoHScheme, + ProxyProtocolValue, + ProxyProtocolValues, + Tag, + Tags + }; struct KeyTypeDescription { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const std::string d_name; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const Type d_type; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) const std::function(const DNSQuestion&, const std::string&, uint8_t)> d_func; bool d_prefix{false}; bool d_caseSensitive{true}; bool d_numeric{false}; }; - struct NameTag {}; - struct TypeTag {}; + struct NameTag + { + }; + struct TypeTag + { + }; - typedef boost::multi_index_container< + using TypeContainer = boost::multi_index_container< KeyTypeDescription, - indexed_by < + indexed_by< hashed_unique, member>, - hashed_unique, member> - > - > TypeContainer; + hashed_unique, member>>>; static const TypeContainer s_types; public: ProtoBufMetaKey(const std::string& key); - const std::string& getName() const; - std::vector getValues(const DNSQuestion& dq) const; + [[nodiscard]] const std::string& getName() const; + [[nodiscard]] std::vector getValues(const DNSQuestion& dnsquestion) const; + private: std::string d_subKey; uint8_t d_numericSubKey{0}; diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 871d90159639..9d5d06f59296 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -149,6 +149,13 @@ struct DNSQuestion ids.qTag->insert_or_assign(key, value); } + void setTag(const std::string& key, std::string&& value) { + if (!ids.qTag) { + ids.qTag = std::make_unique(); + } + ids.qTag->insert_or_assign(key, std::move(value)); + } + const struct timespec& getQueryRealTime() const { return ids.queryRealTime.d_start; @@ -566,6 +573,12 @@ struct ClientState else if (hasTLS()) { return dnsdist::Protocol::DoT; } + else if (doqFrontend != nullptr) { + return dnsdist::Protocol::DoQ; + } + else if (doh3Frontend != nullptr) { + return dnsdist::Protocol::DoH3; + } else if (udpFD != -1) { return dnsdist::Protocol::DoUDP; } diff --git a/pdns/dnsmessage.proto b/pdns/dnsmessage.proto index 99355dfa35c6..e02cedb6240b 100644 --- a/pdns/dnsmessage.proto +++ b/pdns/dnsmessage.proto @@ -43,6 +43,12 @@ message PBDNSMessage { DOH = 4; // DNS over HTTPS (RFC 8484) DNSCryptUDP = 5; // DNSCrypt over UDP (https://dnscrypt.info/protocol) DNSCryptTCP = 6; // DNSCrypt over TCP (https://dnscrypt.info/protocol) + DOQ = 7; // DNS over QUIC (RFC 9250) + } + enum HTTPVersion { + HTTP1 = 1; // HTTP/1.1 + HTTP2 = 2; // HTTP/2 + HTTP3 = 3; // HTTP/3 } enum PolicyType { UNKNOWN = 1; // No RPZ policy applied, or unknown type @@ -177,6 +183,7 @@ message PBDNSMessage { optional string custom = 8; // The name of the event for custom events } repeated Event trace = 23; + optional HTTPVersion httpVersion = 24; // HTTP version used for DNS over HTTP } message PBDNSMessageList { diff --git a/pdns/dnsname.hh b/pdns/dnsname.hh index 29c8325c5d60..9b9692f51e23 100644 --- a/pdns/dnsname.hh +++ b/pdns/dnsname.hh @@ -100,7 +100,7 @@ public: DNSName(DNSName&& a) = default; explicit DNSName(std::string_view sw); //!< Constructs from a human formatted, escaped presentation - DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=nullptr, uint16_t* qclass=nullptr, unsigned int* consumed=nullptr, uint16_t minOffset=0); //!< Construct from a DNS Packet, taking the first question if offset=12. If supplied, consumed is set to the number of bytes consumed from the packet, which will not be equal to the wire length of the resulting name in case of compression. + DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype = nullptr, uint16_t* qclass = nullptr, unsigned int* consumed = nullptr, uint16_t minOffset = 0); //!< Construct from a DNS Packet, taking the first question if offset=12. If supplied, consumed is set to the number of bytes consumed from the packet, which will not be equal to the wire length of the resulting name in case of compression. bool isPartOf(const DNSName& rhs) const; //!< Are we part of the rhs name? Note that name.isPartOf(name). inline bool operator==(const DNSName& rhs) const; //!< DNS-native comparison (case insensitive) - empty compares to empty diff --git a/pdns/dnstap.cc b/pdns/dnstap.cc index 909f08e0b791..beb7ac5e8d4b 100644 --- a/pdns/dnstap.cc +++ b/pdns/dnstap.cc @@ -7,23 +7,63 @@ #include -namespace DnstapBaseFields { - enum : protozero::pbf_tag_type { identity = 1, version = 2, extra = 3, message = 14, type = 15 }; +namespace DnstapBaseFields +{ +enum : protozero::pbf_tag_type +{ + identity = 1, + version = 2, + extra = 3, + message = 14, + type = 15 +}; +} + +namespace DnstapMessageTypes +{ +enum : protozero::pbf_tag_type +{ + message = 1 +}; } -namespace DnstapMessageTypes { - enum : protozero::pbf_tag_type { message = 1 }; +namespace DnstapSocketFamilyTypes +{ +enum : protozero::pbf_tag_type +{ + inet = 1, + inet6 = 2 +}; } -namespace DnstapSocketFamilyTypes { - enum : protozero::pbf_tag_type { inet = 1, inet6 = 2 }; +namespace DnstapMessageFields +{ +enum : protozero::pbf_tag_type +{ + type = 1, + socket_family = 2, + socket_protocol = 3, + query_address = 4, + response_address = 5, + query_port = 6, + response_port = 7, + query_time_sec = 8, + query_time_nsec = 9, + query_message = 10, + query_zone = 11, + response_time_sec = 12, + response_time_nsec = 13, + response_message = 14 +}; } -namespace DnstapMessageFields { - enum : protozero::pbf_tag_type { type = 1, socket_family = 2, socket_protocol = 3, query_address = 4, response_address = 5, query_port = 6, response_port = 7, query_time_sec = 8, query_time_nsec = 9, query_message = 10, query_zone = 11, response_time_sec = 12, response_time_nsec = 13, response_message = 14 }; +std::string&& DnstapMessage::getBuffer() +{ + return std::move(d_buffer); } -DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, DnstapMessage::ProtocolType protocol, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, boost::optional auth): d_buffer(buffer) +DnstapMessage::DnstapMessage(std::string&& buffer, DnstapMessage::MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, DnstapMessage::ProtocolType protocol, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, const boost::optional& auth) : + d_buffer(buffer) { protozero::pbf_writer pbf{d_buffer}; @@ -33,7 +73,9 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ protozero::pbf_writer pbf_message{pbf, DnstapBaseFields::message}; + // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) pbf_message.add_enum(DnstapMessageFields::type, static_cast(type)); + // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions) pbf_message.add_enum(DnstapMessageFields::socket_protocol, static_cast(protocol)); if (requestor != nullptr) { @@ -45,9 +87,11 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ if (requestor != nullptr) { if (requestor->sin4.sin_family == AF_INET) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) pbf_message.add_bytes(DnstapMessageFields::query_address, reinterpret_cast(&requestor->sin4.sin_addr.s_addr), sizeof(requestor->sin4.sin_addr.s_addr)); } else if (requestor->sin4.sin_family == AF_INET6) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) pbf_message.add_bytes(DnstapMessageFields::query_address, reinterpret_cast(&requestor->sin6.sin6_addr.s6_addr), sizeof(requestor->sin6.sin6_addr.s6_addr)); } pbf_message.add_uint32(DnstapMessageFields::query_port, ntohs(requestor->sin4.sin_port)); @@ -55,9 +99,11 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ if (responder != nullptr) { if (responder->sin4.sin_family == AF_INET) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) pbf_message.add_bytes(DnstapMessageFields::response_address, reinterpret_cast(&responder->sin4.sin_addr.s_addr), sizeof(responder->sin4.sin_addr.s_addr)); } else if (responder->sin4.sin_family == AF_INET6) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) pbf_message.add_bytes(DnstapMessageFields::response_address, reinterpret_cast(&responder->sin6.sin6_addr.s6_addr), sizeof(responder->sin6.sin6_addr.s6_addr)); } pbf_message.add_uint32(DnstapMessageFields::response_port, ntohs(responder->sin4.sin_port)); @@ -74,10 +120,11 @@ DnstapMessage::DnstapMessage(std::string& buffer, DnstapMessage::MessageType typ } if (packet != nullptr && len >= sizeof(dnsheader)) { - const dnsheader_aligned dh(packet); - if (!dh->qr) { + const dnsheader_aligned dnsheader(packet); + if (!dnsheader->qr) { pbf_message.add_bytes(DnstapMessageFields::query_message, packet, len); - } else { + } + else { pbf_message.add_bytes(DnstapMessageFields::response_message, packet, len); } } diff --git a/pdns/dnstap.hh b/pdns/dnstap.hh index 8a62b1a7695b..357319b9a510 100644 --- a/pdns/dnstap.hh +++ b/pdns/dnstap.hh @@ -35,15 +35,39 @@ class DnstapMessage { public: - enum class MessageType : uint32_t { auth_query = 1, auth_response = 2, resolver_query = 3, resolver_response = 4, client_query = 5, client_response = 6, forwarder_query = 7, forwarded_response = 8, stub_query = 9, stub_response = 10, tool_query = 11, tool_response = 12 }; - enum class ProtocolType : uint32_t { DoUDP = 1, DoTCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6 }; + enum class MessageType : uint32_t + { + auth_query = 1, + auth_response = 2, + resolver_query = 3, + resolver_response = 4, + client_query = 5, + client_response = 6, + forwarder_query = 7, + forwarded_response = 8, + stub_query = 9, + stub_response = 10, + tool_query = 11, + tool_response = 12 + }; + enum class ProtocolType : uint32_t + { + DoUDP = 1, + DoTCP = 2, + DoT = 3, + DoH = 4, + DNSCryptUDP = 5, + DNSCryptTCP = 6, + DoQ = 7 + }; - DnstapMessage(std::string& buffer, MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, ProtocolType protocol, const char* packet, const size_t len, const struct timespec* queryTime, const struct timespec* responseTime, boost::optional auth=boost::none); + DnstapMessage(std::string&& buffer, MessageType type, const std::string& identity, const ComboAddress* requestor, const ComboAddress* responder, ProtocolType protocol, const char* packet, size_t len, const struct timespec* queryTime, const struct timespec* responseTime, const boost::optional& auth = boost::none); void setExtra(const std::string& extra); + std::string&& getBuffer(); -protected: - std::string& d_buffer; +private: + std::string d_buffer; }; #endif /* DISABLE_PROTOBUF */ diff --git a/pdns/protozero.hh b/pdns/protozero.hh index 439d862f4b79..8dd49db0df9a 100644 --- a/pdns/protozero.hh +++ b/pdns/protozero.hh @@ -37,14 +37,15 @@ namespace pdns { public: enum class MetaValueField : protozero::pbf_tag_type { stringVal = 1, intVal = 2 }; + enum class HTTPVersion : protozero::pbf_tag_type { HTTP1 = 1, HTTP2 = 2, HTTP3 = 3 }; enum class MetaField : protozero::pbf_tag_type { key = 1, value = 2 }; enum class Event : protozero::pbf_tag_type { ts = 1, event = 2, start = 3, boolVal = 4, intVal = 5, stringVal = 6, bytesVal = 7, custom = 8 }; enum class MessageType : int32_t { DNSQueryType = 1, DNSResponseType = 2, DNSOutgoingQueryType = 3, DNSIncomingResponseType = 4 }; - enum class Field : protozero::pbf_tag_type { type = 1, messageId = 2, serverIdentity = 3, socketFamily = 4, socketProtocol = 5, from = 6, to = 7, inBytes = 8, timeSec = 9, timeUsec = 10, id = 11, question = 12, response = 13, originalRequestorSubnet = 14, requestorId = 15, initialRequestId = 16, deviceId = 17, newlyObservedDomain = 18, deviceName = 19, fromPort = 20, toPort = 21, meta = 22, trace = 23 }; + enum class Field : protozero::pbf_tag_type { type = 1, messageId = 2, serverIdentity = 3, socketFamily = 4, socketProtocol = 5, from = 6, to = 7, inBytes = 8, timeSec = 9, timeUsec = 10, id = 11, question = 12, response = 13, originalRequestorSubnet = 14, requestorId = 15, initialRequestId = 16, deviceId = 17, newlyObservedDomain = 18, deviceName = 19, fromPort = 20, toPort = 21, meta = 22, trace = 23, httpVersion = 24 }; enum class QuestionField : protozero::pbf_tag_type { qName = 1, qType = 2, qClass = 3 }; enum class ResponseField : protozero::pbf_tag_type { rcode = 1, rrs = 2, appliedPolicy = 3, tags = 4, queryTimeSec = 5, queryTimeUsec = 6, appliedPolicyType = 7, appliedPolicyTrigger = 8, appliedPolicyHit = 9, appliedPolicyKind = 10, validationState = 11 }; enum class RRField : protozero::pbf_tag_type { name = 1, type = 2, class_ = 3, ttl = 4, rdata = 5, udr = 6 }; - enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6 }; + enum class TransportProtocol : protozero::pbf_tag_type { UDP = 1, TCP = 2, DoT = 3, DoH = 4, DNSCryptUDP = 5, DNSCryptTCP = 6, DoQ = 7 }; Message(std::string& buffer): d_buffer(buffer), d_message{d_buffer} { @@ -63,6 +64,11 @@ namespace pdns { add_enum(d_message, Field::type, static_cast(mtype)); } + void setHTTPVersion(HTTPVersion version) + { + add_enum(d_message, Field::httpVersion, static_cast(version)); + } + void setMessageIdentity(const boost::uuids::uuid& uniqueId) { add_bytes(d_message, Field::messageId, reinterpret_cast(uniqueId.begin()), uniqueId.size()); diff --git a/pdns/recursordist/lwres.cc b/pdns/recursordist/lwres.cc index 7f840ca890f1..96425df3d518 100644 --- a/pdns/recursordist/lwres.cc +++ b/pdns/recursordist/lwres.cc @@ -112,7 +112,9 @@ static void logFstreamQuery(const std::shared_ptr(&*packet.begin()), packet.size(), &ts, nullptr, auth); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + DnstapMessage message(std::move(str), DnstapMessage::MessageType::resolver_query, SyncRes::s_serverID, &localip, &ip, protocol, reinterpret_cast(packet.data()), packet.size(), &ts, nullptr, auth); + str = message.getBuffer(); for (auto& logger : *fstreamLoggers) { remoteLoggerQueueData(*logger, str); @@ -141,7 +143,9 @@ static void logFstreamResponse(const std::shared_ptr(packet.data()), packet.size(), &ts1, &ts2, auth); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + DnstapMessage message(std::move(str), DnstapMessage::MessageType::resolver_response, SyncRes::s_serverID, &localip, &ip, protocol, reinterpret_cast(packet.data()), packet.size(), &ts1, &ts2, auth); + str = message.getBuffer(); for (auto& logger : *fstreamLoggers) { remoteLoggerQueueData(*logger, str); diff --git a/pdns/recursordist/pdns_recursor.cc b/pdns/recursordist/pdns_recursor.cc index fa8cc105377a..165c3865c36e 100644 --- a/pdns/recursordist/pdns_recursor.cc +++ b/pdns/recursordist/pdns_recursor.cc @@ -1507,8 +1507,8 @@ void startDoResolve(void* arg) // NOLINT(readability-function-cognitive-complexi else { TIMEVAL_TO_TIMESPEC(&comboWriter->d_now, &timeSpec); // NOLINT } - DnstapMessage message(str, DnstapMessage::MessageType::resolver_response, SyncRes::s_serverID, &comboWriter->d_source, &comboWriter->d_destination, comboWriter->d_tcp ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoUDP, reinterpret_cast(&*packet.begin()), packet.size(), &timeSpec, nullptr, comboWriter->d_mdp.d_qname); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - + DnstapMessage message(std::move(str), DnstapMessage::MessageType::resolver_response, SyncRes::s_serverID, &comboWriter->d_source, &comboWriter->d_destination, comboWriter->d_tcp ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoUDP, reinterpret_cast(&*packet.begin()), packet.size(), &timeSpec, nullptr, comboWriter->d_mdp.d_qname); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + str = message.getBuffer(); for (auto& logger : *(t_nodFrameStreamServersInfo.servers)) { if (logger->logUDRs()) { remoteLoggerQueueData(*logger, str); @@ -1666,7 +1666,8 @@ void startDoResolve(void* arg) // NOLINT(readability-function-cognitive-complexi else { TIMEVAL_TO_TIMESPEC(&comboWriter->d_now, &timeSpec); // NOLINT } - DnstapMessage message(str, DnstapMessage::MessageType::client_query, SyncRes::s_serverID, &comboWriter->d_source, &comboWriter->d_destination, comboWriter->d_tcp ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoUDP, nullptr, 0, &timeSpec, nullptr, comboWriter->d_mdp.d_qname); + DnstapMessage message(std::move(str), DnstapMessage::MessageType::client_query, SyncRes::s_serverID, &comboWriter->d_source, &comboWriter->d_destination, comboWriter->d_tcp ? DnstapMessage::ProtocolType::DoTCP : DnstapMessage::ProtocolType::DoUDP, nullptr, 0, &timeSpec, nullptr, comboWriter->d_mdp.d_qname); + str = message.getBuffer(); for (auto& logger : *(t_nodFrameStreamServersInfo.servers)) { if (logger->logNODs()) { diff --git a/regression-tests.dnsdist/dnsdisttests.py b/regression-tests.dnsdist/dnsdisttests.py index 6dff1318ebb8..d8e0cd9fff7e 100644 --- a/regression-tests.dnsdist/dnsdisttests.py +++ b/regression-tests.dnsdist/dnsdisttests.py @@ -1096,6 +1096,8 @@ def sendDOTQueryWrapper(self, query, response, useQueue=True): def sendDOQQueryWrapper(self, query, response, useQueue=True): return self.sendDOQQuery(self._doqServerPort, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName) + def sendDOH3QueryWrapper(self, query, response, useQueue=True): + return self.sendDOH3Query(self._doh3ServerPort, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName) @classmethod def getDOQConnection(cls, port, caFile=None, source=None, source_port=0): diff --git a/regression-tests.dnsdist/test_Protobuf.py b/regression-tests.dnsdist/test_Protobuf.py index 31f7b6c3f814..5f65fd31a910 100644 --- a/regression-tests.dnsdist/test_Protobuf.py +++ b/regression-tests.dnsdist/test_Protobuf.py @@ -634,6 +634,7 @@ def testProtobufMetaDoH(self): self.assertIn('?dns=', tags['query-string']) self.assertIn('scheme', tags) self.assertEqual(tags['scheme'], 'https') + self.assertEqual(msg.httpVersion, dnsmessage_pb2.PBDNSMessage.HTTPVersion.HTTP2) # check the protobuf message corresponding to the response msg = self.getFirstProtobufMessage() @@ -811,3 +812,62 @@ def testProtobuf(self): rr = msg.response.rrs[1] self.checkProtobufResponseRecord(rr, dns.rdataclass.IN, dns.rdatatype.A, target, 3600) self.assertEqual(socket.inet_ntop(socket.AF_INET, rr.rdata), '127.0.0.1') + +class TestProtobufQUIC(DNSDistProtobufTest): + + _serverKey = 'server.key' + _serverCert = 'server.chain' + _serverName = 'tls.tests.dnsdist.org' + _caCert = 'ca.pem' + _doqServerPort = pickAvailablePort() + _doh3ServerPort = pickAvailablePort() + _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort)) + _config_template = """ + newServer{address="127.0.0.1:%d"} + rl = newRemoteLogger('127.0.0.1:%d') + + addDOQLocal("127.0.0.1:%d", "%s", "%s") + addDOH3Local("127.0.0.1:%d", "%s", "%s") + + addAction(AllRule(), RemoteLogAction(rl, nil, {serverID='dnsdist-server-1'})) + """ + _config_params = ['_testServerPort', '_protobufServerPort', '_doqServerPort', '_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey'] + + def testProtobufMetaDoH(self): + """ + Protobuf: Test logged protocol for QUIC and DOH3 + """ + name = 'quic.protobuf.tests.powerdns.com.' + query = dns.message.make_query(name, 'A', 'IN') + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + 3600, + dns.rdataclass.IN, + dns.rdatatype.A, + '127.0.0.1') + response.answer.append(rrset) + + for method in ("sendDOQQueryWrapper", "sendDOH3QueryWrapper"): + sender = getattr(self, method) + (receivedQuery, receivedResponse) = sender(query, response) + + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEqual(query, receivedQuery) + self.assertEqual(response, receivedResponse) + + if self._protobufQueue.empty(): + # let the protobuf messages the time to get there + time.sleep(1) + + # check the protobuf message corresponding to the query + msg = self.getFirstProtobufMessage() + + if method == "sendDOQQueryWrapper": + pbMessageType = dnsmessage_pb2.PBDNSMessage.DOQ + elif method == "sendDOH3QueryWrapper": + pbMessageType = dnsmessage_pb2.PBDNSMessage.DOH + self.assertEqual(msg.httpVersion, dnsmessage_pb2.PBDNSMessage.HTTPVersion.HTTP3) + + self.checkProtobufQuery(msg, pbMessageType, query, dns.rdataclass.IN, dns.rdatatype.A, name)