dnsdist::configuration::updateRuntimeConfiguration([&globalConfig](dnsdist::configuration::RuntimeConfiguration& config) {
for (const auto& rule : globalConfig.query_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::RuleChain::Rules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::RuleChain::Rules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
for (const auto& rule : globalConfig.cache_miss_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::RuleChain::CacheMissRules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::RuleChain::CacheMissRules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
for (const auto& rule : globalConfig.response_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::ResponseRules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::ResponseRules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
for (const auto& rule : globalConfig.cache_hit_response_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::CacheHitResponseRules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::CacheHitResponseRules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
for (const auto& rule : globalConfig.cache_inserted_response_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
for (const auto& rule : globalConfig.self_answered_response_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
for (const auto& rule : globalConfig.xfr_response_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::XFRResponseRules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::XFRResponseRules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
for (const auto& rule : globalConfig.timeout_response_rules) {
boost::uuids::uuid ruleUniqueID = rule.uuid.empty() ? getUniqueID() : getUniqueID(std::string(rule.uuid));
- dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::TimeoutResponseRules, std::move(rule.selector.selector->d_rule), rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
+ dnsdist::rules::add(config.d_ruleChains, dnsdist::rules::ResponseRuleChain::TimeoutResponseRules, rule.selector.selector->d_rule, rule.action.action->d_action, std::string(rule.name), ruleUniqueID, 0);
}
});
}
#ifndef HAVE_DNS_OVER_HTTPS
struct DOHUnitInterface
{
- std::string stubStr;
- std::unordered_map<std::string, std::string> stubHeaders;
-
virtual ~DOHUnitInterface()
{
}
- virtual std::string getHTTPPath()
- {
- return std::string();
- }
-
- virtual std::string getHTTPQueryString()
- {
- return std::string();
- }
-
- virtual const std::string& getHTTPHost()
- {
- return stubStr;
- }
-
- virtual const std::string& getHTTPScheme()
- {
- return stubStr;
- }
-
- virtual const std::unordered_map<std::string, std::string>& getHTTPHeaders()
- {
- return stubHeaders;
- }
-
virtual std::shared_ptr<TCPQuerySender> getQuerySender() const
{
return nullptr;
}
- virtual void setHTTPResponse(uint16_t statusCode, PacketBuffer&& body, const std::string& contentType = "")
- {
- (void)statusCode;
- (void)body;
- (void)contentType;
- }
-
static void handleTimeout(std::unique_ptr<DOHUnitInterface>)
{
}
return true;
}
+bool generateAnswerForTimeoutQuery(const PacketBuffer& query, PacketBuffer& answer, const DNSName& dnsQName, uint16_t qtype, uint16_t qclass)
+{
+ auto& qname = dnsQName.getStorage();
+ if (query.size() < sizeof(dnsheader) || qname.length() <= 1) {
+ return false;
+ }
+ std::vector<uint8_t> qtc = {static_cast<uint8_t>(qtype>>8), static_cast<uint8_t>(qtype&0xff), static_cast<uint8_t>(qclass>>8), static_cast<uint8_t>(qclass&0xff)};
+
+ answer.resize(sizeof(dnsheader) + qname.length() + 4);
+ memcpy(&answer.at(0), &query.at(0), sizeof(dnsheader));
+ memcpy(&answer.at(sizeof(dnsheader)), qname.c_str(), qname.length());
+ memcpy(&answer.at(sizeof(dnsheader)+qname.length()), &qtc.at(0), 4);
+
+ dnsdist::PacketMangling::editDNSHeaderFromPacket(answer, [](dnsheader& header) {
+ header.qr = true;
+ header.qdcount = htons(1);
+ header.ancount = 0;
+ header.nscount = 0;
+ header.arcount = 0;
+ return true;
+ });
+ return true;
+}
+
}
bool generateAnswerFromIPAddresses(DNSQuestion& dnsQuestion, const std::vector<ComboAddress>& addresses, const ResponseConfig& responseConfig);
bool generateAnswerFromRDataEntries(DNSQuestion& dnsQuestion, const std::vector<std::string>& entries, std::optional<uint16_t> typeForAny, const ResponseConfig& responseConfig);
bool generateAnswerFromRawPacket(DNSQuestion& dnsQuestion, const PacketBuffer& packet);
+bool generateAnswerForTimeoutQuery(const PacketBuffer& query, PacketBuffer& answer, const DNSName& dnsQName, uint16_t qtype, uint16_t qclass);
}
type: "Vec<ResponseRuleConfiguration>"
default: true
skip-serde: true
- description: "List of rules executed when a timeout event occurred"
+ description: "List of rules executed when a timeout event triggered from timer expiration or I/O error"
metrics:
description: "Metrics-related settings"
return ProcessQueryResult::Drop;
}
-bool handleTimeoutResponseRules(const std::vector<dnsdist::rules::ResponseRuleAction>& rules, InternalQueryState& ids, std::shared_ptr<DownstreamState> ds, std::shared_ptr<TCPQuerySender> sender)
+bool handleTimeoutResponseRules(const std::vector<dnsdist::rules::ResponseRuleAction>& rules, InternalQueryState& ids, const std::shared_ptr<DownstreamState>& d_ds, const std::shared_ptr<TCPQuerySender>& sender)
{
- PacketBuffer empty;
- DNSResponse dnsResponse(ids, empty, ds);
+ if (!ids.d_packet || ids.d_packet->size() < sizeof(struct dnsheader)) {
+ return false;
+ }
+
+ PacketBuffer answer;
+ if (!dnsdist::self_answers::generateAnswerForTimeoutQuery(*ids.d_packet, answer, ids.qname, ids.qtype, ids.qclass)) {
+ return false;
+ }
+
+ DNSResponse dnsResponse(ids, answer, d_ds);
auto protocol = dnsResponse.getProtocol();
vinfolog("Handling timeout response rules for incoming protocol = %s", protocol.toString());
bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote);
void handleResponseSent(const DNSName& qname, const QType& qtype, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, dnsdist::Protocol incomingProtocol, bool fromBackend);
void handleResponseSent(const InternalQueryState& ids, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, bool fromBackend);
-bool handleTimeoutResponseRules(const std::vector<dnsdist::rules::ResponseRuleAction>& rules, InternalQueryState& ids, std::shared_ptr<DownstreamState> ds, std::shared_ptr<TCPQuerySender> sender);
+bool handleTimeoutResponseRules(const std::vector<dnsdist::rules::ResponseRuleAction>& rules, InternalQueryState& ids, const std::shared_ptr<DownstreamState>& ds, const std::shared_ptr<TCPQuerySender>& sender);
.. versionadded:: 2.0.0
- Add a Rule and Action for timeout responses to the existing rules.
+ Add a Rule and Action for timeout triggered from timer expiration or I/O error.
:param DNSrule rule: A :class:`DNSRule`, e.g. an :func:`AllRule`, or a compounded bunch of rules using e.g. :func:`AndRule`.
:param action: The action to take
return true;
}
-bool handleTimeoutResponseRules(const std::vector<dnsdist::rules::ResponseRuleAction>& rules, InternalQueryState& ids, std::shared_ptr<DownstreamState> ds, std::shared_ptr<TCPQuerySender> sender)
+bool handleTimeoutResponseRules(const std::vector<dnsdist::rules::ResponseRuleAction>& rules, InternalQueryState& ids, const std::shared_ptr<DownstreamState>& d_ds, const std::shared_ptr<TCPQuerySender>& sender)
{
(void)rules;
(void)ids;
- (void)ds;
+ (void)d_ds;
(void)sender;
return false;
}
workerPorts[workerID] = port
return port
-class DropAction(object):
+class ResponderDropAction(object):
"""
An object to indicate a drop action shall be taken
"""
if not wire:
continue
- elif isinstance(wire, DropAction):
+ elif isinstance(wire, ResponderDropAction):
continue
sock.sendto(wire, addr)
if not wire:
conn.close()
return
- elif isinstance(wire, DropAction):
+ elif isinstance(wire, ResponderDropAction):
return
wireLen = struct.pack("!H", len(wire))
conn.close()
conn = None
break
- elif isinstance(wire, DropAction):
+ elif isinstance(wire, ResponderDropAction):
break
headers = [
import ssl
import threading
import dns
-from dnsdisttests import DNSDistTest, pickAvailablePort, DropAction
+from dnsdisttests import DNSDistTest, pickAvailablePort, ResponderDropAction
_common_config = """
addDOHLocal("127.0.0.1:%d", "server.chain", "server.key", {'/dns-query'}, {library='nghttp2'})
"""
def timeoutResponseCallback(request):
- return DropAction()
+ return ResponderDropAction()
def normalResponseCallback(request):
response = dns.message.make_response(request)
_dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
_config_template = """
- newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=2,tcpRecvTimeout=2}:setUp()
- newServer{address="127.0.0.1:%d",pool='',udpTimeout=2,tcpRecvTimeout=2}:setUp()
+ newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=1,tcpRecvTimeout=1}:setUp()
+ newServer{address="127.0.0.1:%d",pool='',udpTimeout=1,tcpRecvTimeout=1}:setUp()
""" + _common_config
_config_params = ['_testNormalServerPort', '_testTimeoutServerPort', '_dohWithNGHTTP2ServerPort', '_doqServerPort', '_doh3ServerPort', '_tlsServerPort']
_verboseMode = True
for method in ("sendUDPQuery", "sendTCPQuery", "sendDOQQueryWrapper", "sendDOH3QueryWrapper", "sendDOTQueryWrapper", "sendDOHWithNGHTTP2QueryWrapper"):
sender = getattr(self, method)
- (_, receivedResponse) = sender(query, response=None, useQueue=False, timeout=6)
+ (_, receivedResponse) = sender(query, response=None, useQueue=False, timeout=3)
self.assertTrue(receivedResponse)
self.assertEqual(receivedResponse, expectedResponse)
class TestTimeoutBackendDOH(TestTimeoutBackendUdpTcp):
_config_template = """
- newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=2,tcpRecvTimeout=2,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com',dohPath='/dns-query'}:setUp()
- newServer{address="127.0.0.1:%d",pool='',udpTimeout=2,tcpRecvTimeout=2,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com',dohPath='/dns-query'}:setUp()
+ newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com',dohPath='/dns-query'}:setUp()
+ newServer{address="127.0.0.1:%d",pool='',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com',dohPath='/dns-query'}:setUp()
""" + _common_config
@classmethod
class TestTimeoutBackendDOT(TestTimeoutBackendUdpTcp):
_config_template = """
- newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=2,tcpRecvTimeout=2,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com'}:setUp()
- newServer{address="127.0.0.1:%d",pool='',udpTimeout=2,tcpRecvTimeout=2,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com'}:setUp()
+ newServer{address="127.0.0.1:%d",pool='restarted',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com'}:setUp()
+ newServer{address="127.0.0.1:%d",pool='',udpTimeout=1,tcpRecvTimeout=1,tls='openssl',validateCertificates=true,caStore='ca.pem',subjectName='powerdns.com'}:setUp()
""" + _common_config
@classmethod