#include "config.h"
#endif
+#include "syncres.hh"
#include "arguments.hh"
#include "cachecleaner.hh"
#include "dns_random.hh"
#include "logger.hh"
#include "lua-recursor4.hh"
#include "rec-lua-conf.hh"
-#include "syncres.hh"
#include "dnsseckeeper.hh"
#include "validate-recursor.hh"
unsigned int SyncRes::s_packetcacheservfailttl;
unsigned int SyncRes::s_serverdownmaxfails;
unsigned int SyncRes::s_serverdownthrottletime;
+std::atomic<uint64_t> SyncRes::s_authzonequeries;
std::atomic<uint64_t> SyncRes::s_queries;
std::atomic<uint64_t> SyncRes::s_outgoingtimeouts;
std::atomic<uint64_t> SyncRes::s_outgoing4timeouts;
}
-SyncRes::SyncRes(const struct timeval& now) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
+SyncRes::SyncRes(const struct timeval& now) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
d_totUsec(0), d_now(now),
d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm)
/** everything begins here - this is the entry point just after receiving a packet */
int SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret)
{
+ /* rfc6895 section 3.1 + RRSIG and NSEC3 */
+ static const std::set<uint16_t> metaTypes = { QType::AXFR, QType::IXFR, QType::RRSIG, QType::NSEC3, QType::OPT, QType::TSIG, QType::TKEY, QType::MAILA, QType::MAILB };
vState state = Indeterminate;
s_queries++;
d_wasVariable=false;
d_wasOutOfBand=false;
if (doSpecialNamesResolve(qname, qtype, qclass, ret)) {
- d_queryValidationState = Insecure;
- return 0;
+ d_queryValidationState = Insecure; // this could fool our stats into thinking a validation took place
+ return 0; // so do check before updating counters (we do now)
}
- if( (qtype.getCode() == QType::AXFR) || (qtype.getCode() == QType::IXFR) || (qtype.getCode() == QType::RRSIG) || (qtype.getCode() == QType::NSEC3))
+ if (metaTypes.count(qtype.getCode())) {
return -1;
+ }
if(qclass==QClass::ANY)
qclass=QClass::IN;
int res=doResolve(qname, qtype, ret, 0, beenthere, state);
d_queryValidationState = state;
- if (d_queryValidationState != Indeterminate) {
- g_stats.dnssecValidations++;
- }
if (shouldValidate()) {
+ if (d_queryValidationState != Indeterminate) {
+ g_stats.dnssecValidations++;
+ }
increaseDNSSECStateCounter(d_queryValidationState);
}
return result;
}
-bool SyncRes::doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res) const
+bool SyncRes::doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res)
{
+ d_authzonequeries++;
+ s_authzonequeries++;
+
res = domain.getRecords(qname, qtype.getCode(), ret);
return true;
}
For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
*/
-int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res) const
+int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res, bool* chained) const
{
/* what is your QUEST?
the goal is to get as many remotes as possible on the highest level of EDNS support
sendQname.makeUsLowerCase();
if (d_asyncResolve) {
- ret = d_asyncResolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res);
+ ret = d_asyncResolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res, chained);
}
else {
- ret=asyncresolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res);
+ ret=asyncresolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res, chained);
}
if(ret < 0) {
return ret; // transport error, nothing to learn here
LOG(prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl);
boost::optional<Netmask> nm;
- res=asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(), false, false, &d_now, nm, &lwr);
+ bool chained = false;
+ res=asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(), false, false, &d_now, nm, &lwr, &chained);
d_totUsec += lwr.d_usec;
accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
set the TC bit solely because these RRSIG RRs didn't fit."
*/
bool isAA = lwr.d_aabit && i->first.place != DNSResourceRecord::ADDITIONAL;
- if (isAA && isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) {
+ if (isAA && isCNAMEAnswer && i->first.place == DNSResourceRecord::ANSWER && (i->first.type != QType::CNAME || i->first.name != qname)) {
/*
rfc2181 states:
Note that the answer section of an authoritative answer normally
bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool const sendRDQuery, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool* truncated)
{
- int resolveret;
+ bool chained = false;
+ int resolveret = RCode::NoError;
s_outqueries++;
d_outqueries++;
s_ecsqueries++;
}
resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(),
- doTCP, sendRDQuery, &d_now, ednsmask, &lwr); // <- we go out on the wire!
+ doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained); // <- we go out on the wire!
if(ednsmask) {
s_ecsresponses++;
LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
LOG(prefix<<qname<<": error resolving from "<<remoteIP.toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl);
}
- if(resolveret != -2) { // don't account for resource limits, they are our own fault
+ if(resolveret != -2 && !chained) { // don't account for resource limits, they are our own fault
t_sstorage.nsSpeeds[nsName].submit(remoteIP, 1000000, &d_now); // 1 sec
// code below makes sure we don't filter COM or the root
/* we got an answer */
if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
LOG(prefix<<qname<<": "<<nsName<<" ("<<remoteIP.toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
- t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
+ if (!chained) {
+ t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
+ }
return false;
}