try {
auto& ids = response.d_idstate;
unsigned int qnameWireLength;
- if (!response.d_connection || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, response.d_connection->getRemote(), qnameWireLength)) {
+ if (!response.d_connection || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, response.d_connection->getDS(), qnameWireLength)) {
state->terminateClientConnection();
return;
}
output << "# TYPE " << statesbase << "queries " << "counter" << "\n";
output << "# HELP " << statesbase << "responses " << "Amount of responses received from this server" << "\n";
output << "# TYPE " << statesbase << "responses " << "counter" << "\n";
+ output << "# HELP " << statesbase << "noncompliantresponses " << "Amount of non-compliant responses received from this server" << "\n";
+ output << "# TYPE " << statesbase << "noncompliantresponses " << "counter" << "\n";
output << "# HELP " << statesbase << "drops " << "Amount of queries not answered by server" << "\n";
output << "# TYPE " << statesbase << "drops " << "counter" << "\n";
output << "# HELP " << statesbase << "latency " << "Server's latency when answering questions in milliseconds" << "\n";
output << statesbase << "status" << label << " " << (state->isUp() ? "1" : "0") << "\n";
output << statesbase << "queries" << label << " " << state->queries.load() << "\n";
output << statesbase << "responses" << label << " " << state->responses.load() << "\n";
+ output << statesbase << "noncompliantresponses" << label << " " << state->nonCompliantResponses.load()<< "\n";
output << statesbase << "drops" << label << " " << state->reuseds.load() << "\n";
if (state->isUp()) {
output << statesbase << "latency" << label << " " << state->latencyUsec/1000.0 << "\n";
{"latency", (double)(a->latencyUsec/1000.0)},
{"queries", (double)a->queries},
{"responses", (double)a->responses},
+ {"nonCompliantResponses", (double)a->nonCompliantResponses},
{"sendErrors", (double)a->sendErrors},
{"tcpDiedSendingQuery", (double)a->tcpDiedSendingQuery},
{"tcpDiedReadingResponse", (double)a->tcpDiedReadingResponse},
doAvg(g_stats.latencyAvg1000000, udiff, 1000000);
}
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, unsigned int& qnameWireLength)
{
if (response.size() < sizeof(dnsheader)) {
return false;
const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(response.data());
if (dh->qr == 0) {
++g_stats.nonCompliantResponses;
+ if (remote) {
+ ++remote->nonCompliantResponses;
+ }
return false;
}
}
else {
++g_stats.nonCompliantResponses;
+ if (remote) {
+ ++remote->nonCompliantResponses;
+ }
return false;
}
}
rqname = DNSName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, &rqtype, &rqclass, &qnameWireLength);
}
catch (const std::exception& e) {
- if(response.size() > 0 && static_cast<size_t>(response.size()) > sizeof(dnsheader)) {
- infolog("Backend %s sent us a response with id %d that did not parse: %s", remote.toStringWithPort(), ntohs(dh->id), e.what());
+ if (remote && response.size() > 0 && static_cast<size_t>(response.size()) > sizeof(dnsheader)) {
+ infolog("Backend %s sent us a response with id %d that did not parse: %s", remote->d_config.remote.toStringWithPort(), ntohs(dh->id), e.what());
}
++g_stats.nonCompliantResponses;
+ if (remote) {
+ ++remote->nonCompliantResponses;
+ }
return false;
}
int origFD = ids->origFD;
unsigned int qnameWireLength = 0;
- if (fd != ids->backendFD || !responseContentMatches(response, ids->qname, ids->qtype, ids->qclass, dss->d_config.remote, qnameWireLength)) {
+ if (fd != ids->backendFD || !responseContentMatches(response, ids->qname, ids->qtype, ids->qclass, dss, qnameWireLength)) {
continue;
}
stat_t reuseds{0};
stat_t queries{0};
stat_t responses{0};
+ stat_t nonCompliantResponses{0};
struct {
stat_t sendErrors{0};
stat_t reuseds{0};
bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
void resetLuaSideEffect(); // reset to indeterminate state
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength);
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, unsigned int& qnameWireLength);
bool processResponse(PacketBuffer& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRuleActions, DNSResponse& dr, bool muted, bool receivedOverUDP);
bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::string& ruleresult, bool& drop);
return ProcessQueryResult::Drop;
}
-static std::function<bool(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength)> s_responseContentMatches;
-
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, unsigned int& qnameWireLength)
{
- if (s_responseContentMatches) {
- return s_responseContentMatches(response, qname, qtype, qclass, remote, qnameWireLength);
- }
-
return true;
}
for server in content['servers']:
for key in ['id', 'latency', 'name', 'weight', 'outstanding', 'qpsLimit',
'reuseds', 'state', 'address', 'pools', 'qps', 'queries', 'order', 'sendErrors',
- 'dropRate', 'responses', 'tcpDiedSendingQuery', 'tcpDiedReadingResponse',
+ 'dropRate', 'responses', 'nonCompliantResponses', 'tcpDiedSendingQuery', 'tcpDiedReadingResponse',
'tcpGaveUp', 'tcpReadTimeouts', 'tcpWriteTimeouts', 'tcpCurrentConnections',
'tcpNewConnections', 'tcpReusedConnections', 'tlsResumptions', 'tcpAvgQueriesPerConnection',
'tcpAvgConnectionDuration', 'tcpLatency', 'protocol']:
self.assertIn(key, server)
for key in ['id', 'latency', 'weight', 'outstanding', 'qpsLimit', 'reuseds',
- 'qps', 'queries', 'order', 'tcpLatency']:
+ 'qps', 'queries', 'order', 'tcpLatency', 'responses', 'nonCompliantResponses']:
self.assertTrue(server[key] >= 0)
self.assertTrue(server['state'] in ['up', 'down', 'UP', 'DOWN'])
for server in content['servers']:
for key in ['id', 'latency', 'name', 'weight', 'outstanding', 'qpsLimit',
'reuseds', 'state', 'address', 'pools', 'qps', 'queries', 'order', 'sendErrors',
- 'dropRate', 'responses', 'tcpDiedSendingQuery', 'tcpDiedReadingResponse',
+ 'dropRate', 'responses', 'nonCompliantResponses', 'tcpDiedSendingQuery', 'tcpDiedReadingResponse',
'tcpGaveUp', 'tcpReadTimeouts', 'tcpWriteTimeouts', 'tcpCurrentConnections',
'tcpNewConnections', 'tcpReusedConnections', 'tcpAvgQueriesPerConnection',
'tcpAvgConnectionDuration', 'tcpLatency', 'protocol']:
self.assertIn(key, server)
for key in ['id', 'latency', 'weight', 'outstanding', 'qpsLimit', 'reuseds',
- 'qps', 'queries', 'order', 'tcpLatency']:
+ 'qps', 'queries', 'order', 'tcpLatency', 'responses', 'nonCompliantResponses']:
self.assertTrue(server[key] >= 0)
self.assertTrue(server['state'] in ['up', 'down', 'UP', 'DOWN'])