* `setServerPolicyLua(name, function)`: set server selection policy to one named 'name' and provided by 'function'
* `showServerPolicy()`: show name of currently operational server selection policy
* `newServerPolicy(name, function)`: create a policy object from a Lua function
+ * `setServFailWhenNoServer(bool)`: if set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query
* Available policies:
* `firstAvailable`: Pick first server that has not exceeded its QPS limit, ordered by the server 'order' parameter
* `whashed`: Weighted hashed ('sticky') distribution over available servers, based on the server 'weight' parameter
{ "setRules", true, "list of rules", "replace the current rules with the supplied list of pairs of DNS Rules and DNS Actions (see `newRuleAction()`)" },
{ "setServerPolicy", true, "policy", "set server selection policy to that policy" },
{ "setServerPolicyLua", true, "name, function", "set server selection policy to one named 'name' and provided by 'function'" },
+ { "setServFailWhenNoServer", true, "bool", "if set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query" },
{ "setTCPRecvTimeout", true, "n", "set the read timeout on TCP connections from the client, in seconds" },
{ "setTCPSendTimeout", true, "n", "set the write timeout on TCP connections from the client, in seconds" },
{ "setVerboseHealthChecks", true, "bool", "set whether health check errors will be logged" },
}
}
});
+
+ g_lua.writeFunction("setServFailWhenNoServer", [](bool servfail) {
+ setLuaSideEffect();
+ g_servFailOnNoPolicy = servfail;
+ });
}
g_stats.cacheMisses++;
}
- if(!ds) {
- g_stats.noPolicy++;
- break;
- }
+ if(!ds) {
+ g_stats.noPolicy++;
+
+ if (g_servFailOnNoPolicy) {
+ restoreFlags(dh, origFlags);
+ dq.dh->rcode = RCode::ServFail;
+ dq.dh->qr = true;
+
+#ifdef HAVE_DNSCRYPT
+ if (!encryptResponse(queryBuffer, &dq.len, dq.size, true, dnsCryptQuery)) {
+ goto drop;
+ }
+#endif
+ sendResponseToClient(ci.fd, query, dq.len);
+ }
+
+ break;
+ }
int dsock = -1;
if(sockets.count(ds->remote) == 0) {
int g_tcpRecvTimeout{2};
int g_tcpSendTimeout{2};
+bool g_servFailOnNoPolicy{false};
bool g_truncateTC{1};
bool g_fixupCase{0};
static void truncateTC(const char* packet, uint16_t* len)
if(!ss) {
g_stats.noPolicy++;
- continue;
+
+ if (g_servFailOnNoPolicy) {
+ char* response = query;
+ uint16_t responseLen = dq.len;
+ restoreFlags(dh, origFlags);
+
+ dq.dh->rcode = RCode::ServFail;
+ dq.dh->qr = true;
+
+#ifdef HAVE_DNSCRYPT
+ if (!encryptResponse(response, &responseLen, dq.size, false, dnsCryptQuery)) {
+ continue;
+ }
+#endif
+ sendUDPResponse(cs->udpFD, response, responseLen, 0, dest, remote);
+ }
+ continue;
}
ss->queries++;
extern uint32_t g_staleCacheEntriesTTL;
extern bool g_apiReadWrite;
extern std::string g_apiConfigDirectory;
+extern bool g_servFailOnNoPolicy;
struct ConsoleKeyword {
std::string name;
self.assertEquals(response, receivedResponse)
total = 0
- self.assertEquals(self._responsesCounter['UDP Responder'], 0)
+ if 'UDP Responder' in self._responsesCounter:
+ self.assertEquals(self._responsesCounter['UDP Responder'], 0)
self.assertEquals(self._responsesCounter['UDP Responder 2'], numberOfQueries)
- self.assertEquals(self._responsesCounter['TCP Responder'], 0)
+ if 'TCP Responder' in self._responsesCounter:
+ self.assertEquals(self._responsesCounter['TCP Responder'], 0)
self.assertEquals(self._responsesCounter['TCP Responder 2'], numberOfQueries)
+
+class TestRoutingNoServer(DNSDistTest):
+
+ _config_template = """
+ newServer{address="127.0.0.1:%s", pool="real"}
+ setServFailWhenNoServer(true)
+ """
+
+ def testPolicyPoolNoServer(self):
+ """
+ Routing: No server should return ServFail
+ """
+ name = 'noserver.routing.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN')
+ expectedResponse = dns.message.make_response(query)
+ expectedResponse.set_rcode(dns.rcode.SERVFAIL)
+
+ (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+ self.assertEquals(receivedResponse, expectedResponse)
+
+ (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+ self.assertEquals(receivedResponse, expectedResponse)