exclude:
- compiler: clang
env: PDNS_BUILD_PRODUCT=docs
+ - compiler: clang
+ env: PDNS_BUILD_PRODUCT=recursor
+ include:
+ - compiler: clang
+ env: PDNS_BUILD_PRODUCT=recursor COMPILER=clang++-3.6
+ addons:
+ apt:
+ packages: ['clang-3.6']
before_script:
- git describe --always --dirty=+
run "tar xf pdns-recursor-*.tar.bz2"
run "rm -f pdns-recursor-*.tar.bz2"
run "cd pdns-recursor-*"
- run "CFLAGS='-O1' CXXFLAGS='-O1' ./configure \
+ run "CFLAGS='-O1' CXXFLAGS='-O1' CXX=${COMPILER} ./configure \
--prefix=$PDNS_RECURSOR_DIR \
--enable-unit-tests \
--disable-silent-rules"
#include "iputils.hh"
#include "dnsname.hh"
-extern NetmaskGroup g_ednssubnets;
-extern SuffixMatchNode g_ednsdomains;
-extern bool g_useIncomingECS;
-
struct EDNSSubnetOpts
{
Netmask source;
typedef map<ComboAddress, uint32_t, ComboAddress::addressOnlyLessThan> tcpClientCounts_t;
-static __thread shared_ptr<RecursorLua4>* t_pdl;
-static __thread unsigned int t_id;
-static __thread shared_ptr<Regex>* t_traceRegex;
-static __thread tcpClientCounts_t* t_tcpClientCounts;
-
-__thread MT_t* MT; // the big MTasker
-__thread MemRecursorCache* t_RC;
-__thread RecursorPacketCache* t_packetCache;
-__thread FDMultiplexer* t_fdm;
-__thread addrringbuf_t* t_remotes, *t_servfailremotes, *t_largeanswerremotes;
-__thread boost::circular_buffer<pair<DNSName, uint16_t> >* t_queryring, *t_servfailqueryring;
-__thread NetmaskGroup* t_allowFrom;
+static thread_local std::shared_ptr<RecursorLua4> t_pdl;
+static thread_local unsigned int t_id;
+static thread_local std::shared_ptr<Regex> t_traceRegex;
+static thread_local std::unique_ptr<tcpClientCounts_t> t_tcpClientCounts;
+
+thread_local std::unique_ptr<MT_t> MT; // the big MTasker
+thread_local std::unique_ptr<MemRecursorCache> t_RC;
+thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
+thread_local FDMultiplexer* t_fdm{nullptr};
+thread_local std::unique_ptr<addrringbuf_t> t_remotes, t_servfailremotes, t_largeanswerremotes;
+thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > > t_queryring, t_servfailqueryring;
+thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
#ifdef HAVE_PROTOBUF
-__thread boost::uuids::random_generator* t_uuidGenerator;
+thread_local std::unique_ptr<boost::uuids::random_generator> t_uuidGenerator;
#endif
__thread struct timeval g_now; // timestamp, updated (too) frequently
static set<int> g_fromtosockets; // listen sockets that use 'sendfromto()' mechanism
static vector<ComboAddress> g_localQueryAddresses4, g_localQueryAddresses6;
static AtomicCounter counter;
-static SyncRes::domainmap_t* g_initialDomainMap; // new threads needs this to be setup
-static NetmaskGroup* g_initialAllowFrom; // new thread needs to be setup with this
+static std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // new threads needs this to be setup
+static std::shared_ptr<NetmaskGroup> g_initialAllowFrom; // new thread needs to be setup with this
static size_t g_tcpMaxQueriesPerConn;
static uint64_t g_latencyStatSize;
static uint32_t g_disthashseed;
static bool g_useOneSocketPerThread;
static bool g_gettagNeedsEDNSOptions{false};
static time_t g_statisticsInterval;
+static bool g_useIncomingECS;
-std::unordered_set<DNSName> g_delegationOnly;
RecursorControlChannel s_rcc; // only active in thread 0
RecursorStats g_stats;
-NetmaskGroup* g_dontQuery;
string s_programname="pdns_recursor";
string s_pidfname;
unsigned int g_numThreads;
}
};
-static __thread UDPClientSocks* t_udpclientsocks;
+static thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
/* these two functions are used by LWRes */
// -2 is OS error, -1 is error that depends on the remote, > 0 is success
SyncRes sr(dc->d_now);
bool DNSSECOK=false;
if(t_pdl) {
- sr.setLuaEngine(*t_pdl);
+ sr.setLuaEngine(t_pdl);
sr.d_requestor=dc->d_remote;
}
goto sendit;
}
- if(t_traceRegex->get() && (*t_traceRegex)->match(dc->d_mdp.d_qname.toString())) {
+ if(t_traceRegex && t_traceRegex->match(dc->d_mdp.d_qname.toString())) {
sr.setLogMode(SyncRes::Store);
tracedQuery=true;
}
if(!dc->d_mdp.d_header.rd)
sr.setCacheOnly();
- if (t_pdl->get()) {
- (*t_pdl)->prerpz(dq, res);
+ if (t_pdl) {
+ t_pdl->prerpz(dq, res);
}
// Check if the query has a policy attached to it
}
// if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
- if(!t_pdl->get() || !(*t_pdl)->preresolve(dq, res)) {
+ if(!t_pdl || !t_pdl->preresolve(dq, res)) {
sr.setWantsRPZ(wantsRPZ);
if(wantsRPZ) {
appliedPolicy = luaconfsLocal->dfe.getPostPolicy(ret, sr.d_discardedPolicies);
}
- if(t_pdl->get()) {
+ if(t_pdl) {
if(res == RCode::NoError) {
auto i=ret.cbegin();
for(; i!= ret.cend(); ++i)
if(i->d_type == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER)
break;
- if(i == ret.cend() && (*t_pdl)->nodata(dq, res))
+ if(i == ret.cend() && t_pdl->nodata(dq, res))
shouldNotValidate = true;
}
- else if(res == RCode::NXDomain && (*t_pdl)->nxdomain(dq, res))
+ else if(res == RCode::NXDomain && t_pdl->nxdomain(dq, res))
shouldNotValidate = true;
- if((*t_pdl)->postresolve(dq, res))
+ if(t_pdl->postresolve(dq, res))
shouldNotValidate = true;
}
if(conn->bytesread==conn->qlen) {
t_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read
- DNSComboWriter* dc=0;
+ DNSComboWriter* dc=nullptr;
try {
dc=new DNSComboWriter(conn->data, conn->qlen, g_now);
}
}
#endif
- if(needECS || (t_pdl->get() && (*t_pdl)->d_gettag)) {
+ if(needECS || (t_pdl && t_pdl->d_gettag)) {
try {
std::map<uint16_t, EDNSOptionView> ednsOptions;
dc->d_ecsParsed = true;
dc->d_ecsFound = getQNameAndSubnet(std::string(conn->data, conn->qlen), &qname, &qtype, &qclass, &dc->d_ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr);
- if(t_pdl->get() && (*t_pdl)->d_gettag) {
+ if(t_pdl && t_pdl->d_gettag) {
try {
- dc->d_tag = (*t_pdl)->gettag(conn->d_remote, dc->d_ednssubnet.source, dest, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId);
+ dc->d_tag = t_pdl->gettag(conn->d_remote, dc->d_ednssubnet.source, dest, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId);
}
catch(std::exception& e) {
if(g_logCommonErrors)
}
setNonBlocking(newsock);
- shared_ptr<TCPConnection> tc(new TCPConnection(newsock, addr));
+ std::shared_ptr<TCPConnection> tc = std::make_shared<TCPConnection>(newsock, addr);
tc->state=TCPConnection::BYTE0;
t_fdm->addReadFD(tc->getFD(), handleRunningTCPQuestion, tc);
*/
#endif
- if(needECS || (t_pdl->get() && (*t_pdl)->d_gettag)) {
+ if(needECS || (t_pdl && t_pdl->d_gettag)) {
try {
std::map<uint16_t, EDNSOptionView> ednsOptions;
ecsFound = getQNameAndSubnet(question, &qname, &qtype, &qclass, &ednssubnet, g_gettagNeedsEDNSOptions ? &ednsOptions : nullptr);
qnameParsed = true;
ecsParsed = true;
- if(t_pdl->get() && (*t_pdl)->d_gettag) {
+ if(t_pdl && t_pdl->d_gettag) {
try {
- ctag=(*t_pdl)->gettag(fromaddr, ednssubnet.source, destaddr, qname, qtype, &policyTags, data, ednsOptions, false, requestorId);
+ ctag=t_pdl->gettag(fromaddr, ednssubnet.source, destaddr, qname, qtype, &policyTags, data, ednsOptions, false, requestorId);
}
catch(std::exception& e) {
if(g_logCommonErrors)
return 0;
}
- if(t_pdl->get()) {
- if((*t_pdl)->ipfilter(fromaddr, destaddr, *dh)) {
+ if(t_pdl) {
+ if(t_pdl->ipfilter(fromaddr, destaddr, *dh)) {
if(!g_quiet)
L<<Logger::Notice<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] DROPPED question from "<<fromaddr.toStringWithPort()<<" based on policy"<<endl;
g_stats.policyDrops++;
static void houseKeeping(void *)
{
- static __thread time_t last_stat, last_rootupdate, last_prune, last_secpoll;
- static __thread int cleanCounter=0;
- static __thread bool s_running; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
+ static thread_local time_t last_stat, last_rootupdate, last_prune, last_secpoll;
+ static thread_local int cleanCounter=0;
+ static thread_local bool s_running; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
try {
if(s_running)
return;
t_RC->doPrune(); // this function is local to a thread, so fine anyhow
t_packetCache->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numWorkerThreads);
- t_sstorage->negcache.prune(::arg().asNum("max-cache-entries") / (g_numWorkerThreads * 10));
+ SyncRes::pruneNegCache(::arg().asNum("max-cache-entries") / (g_numWorkerThreads * 10));
if(!((cleanCounter++)%40)) { // this is a full scan!
time_t limit=now.tv_sec-300;
- for(SyncRes::nsspeeds_t::iterator i = t_sstorage->nsSpeeds.begin() ; i!= t_sstorage->nsSpeeds.end(); )
- if(i->second.stale(limit))
- t_sstorage->nsSpeeds.erase(i++);
- else
- ++i;
+ SyncRes::pruneNSSpeeds(limit);
}
last_prune=time(0);
}
static void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var)
{
- ThreadMSG* tmsg;
+ ThreadMSG* tmsg = nullptr;
if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread
unixDie("read from thread pipe returned wrong size or error");
FDMultiplexer* getMultiplexer()
{
FDMultiplexer* ret;
- for(FDMultiplexer::FDMultiplexermap_t::const_iterator i = FDMultiplexer::getMultiplexerMap().begin();
- i != FDMultiplexer::getMultiplexerMap().end(); ++i) {
+ for(const auto& i : FDMultiplexer::getMultiplexerMap()) {
try {
- ret=i->second();
+ ret=i.second();
return ret;
}
catch(FDMultiplexerException &fe) {
string fname= ::arg()["lua-dns-script"];
try {
if(fname.empty()) {
- t_pdl->reset();
+ t_pdl.reset();
L<<Logger::Error<<t_id<<" Unloaded current lua script"<<endl;
return new string("unloaded\n");
}
else {
- *t_pdl = shared_ptr<RecursorLua4>(new RecursorLua4(fname));
+ t_pdl = std::make_shared<RecursorLua4>(fname);
}
}
catch(std::exception& e) {
try
{
if(newRegex.empty()) {
- t_traceRegex->reset();
+ t_traceRegex.reset();
return new string("unset\n");
}
else {
- (*t_traceRegex) = shared_ptr<Regex>(new Regex(newRegex));
+ t_traceRegex = std::make_shared<Regex>(newRegex);
return new string("ok\n");
}
}
static void* recursorThread(void*);
-static void* pleaseSupplantACLs(NetmaskGroup *ng)
+static void* pleaseSupplantACLs(std::shared_ptr<NetmaskGroup> ng)
{
t_allowFrom = ng;
- return 0;
+ return nullptr;
}
int g_argc;
::arg().preParse(g_argc, g_argv, "allow-from");
}
- NetmaskGroup* oldAllowFrom = t_allowFrom, *allowFrom=new NetmaskGroup;
+ std::shared_ptr<NetmaskGroup> oldAllowFrom = t_allowFrom;
+ std::shared_ptr<NetmaskGroup> allowFrom = std::make_shared<NetmaskGroup>();
if(!::arg()["allow-from-file"].empty()) {
string line;
ifstream ifs(::arg()["allow-from-file"].c_str());
if(!ifs) {
- delete allowFrom;
throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
}
else {
if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl;
- delete allowFrom;
- allowFrom = 0;
+ allowFrom = nullptr;
}
g_initialAllowFrom = allowFrom;
broadcastFunction(boost::bind(pleaseSupplantACLs, allowFrom));
- delete oldAllowFrom;
+ oldAllowFrom = nullptr;
l_initialized = true;
}
vector<string> parts;
stringtok(parts, ::arg()["delegation-only"], ", \t");
for(const auto& p : parts) {
- g_delegationOnly.insert(DNSName(p));
+ SyncRes::addDelegationOnly(DNSName(p));
}
}
sortPublicSuffixList();
if(!::arg()["dont-query"].empty()) {
- g_dontQuery=new NetmaskGroup;
vector<string> ips;
stringtok(ips, ::arg()["dont-query"], ", ");
ips.push_back("0.0.0.0");
L<<Logger::Warning<<"Will not send queries to: ";
for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
- g_dontQuery->addMask(*i);
+ SyncRes::addDontQuery(*i);
if(i!=ips.begin())
L<<Logger::Warning<<", ";
L<<Logger::Warning<<*i;
makeTCPServerSockets(0);
}
- parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
+ SyncRes::parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet");
int forks;
{
t_id=(int) (long) ptr;
SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so..
- t_sstorage->domainmap = g_initialDomainMap;
+ SyncRes::setDomainMap(g_initialDomainMap);
t_allowFrom = g_initialAllowFrom;
- t_udpclientsocks = new UDPClientSocks();
- t_tcpClientCounts = new tcpClientCounts_t();
+ t_udpclientsocks = std::unique_ptr<UDPClientSocks>(new UDPClientSocks());
+ t_tcpClientCounts = std::unique_ptr<tcpClientCounts_t>(new tcpClientCounts_t());
primeHints();
- t_packetCache = new RecursorPacketCache();
+ t_packetCache = std::unique_ptr<RecursorPacketCache>(new RecursorPacketCache());
#ifdef HAVE_PROTOBUF
- t_uuidGenerator = new boost::uuids::random_generator();
+ t_uuidGenerator = std::unique_ptr<boost::uuids::random_generator>(new boost::uuids::random_generator());
#endif
L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
- t_pdl = new shared_ptr<RecursorLua4>();
-
try {
if(!::arg()["lua-dns-script"].empty()) {
- *t_pdl = shared_ptr<RecursorLua4>(new RecursorLua4(::arg()["lua-dns-script"]));
+ t_pdl = std::make_shared<RecursorLua4>(::arg()["lua-dns-script"]);
L<<Logger::Warning<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl;
}
}
_exit(99);
}
- t_traceRegex = new shared_ptr<Regex>();
unsigned int ringsize=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads;
if(ringsize) {
- t_remotes = new addrringbuf_t();
+ t_remotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
if(g_weDistributeQueries) // if so, only 1 thread does recvfrom
t_remotes->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
else
t_remotes->set_capacity(ringsize);
- t_servfailremotes = new addrringbuf_t();
+ t_servfailremotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
t_servfailremotes->set_capacity(ringsize);
- t_largeanswerremotes = new addrringbuf_t();
+ t_largeanswerremotes = std::unique_ptr<addrringbuf_t>(new addrringbuf_t());
t_largeanswerremotes->set_capacity(ringsize);
- t_queryring = new boost::circular_buffer<pair<DNSName, uint16_t> >();
+ t_queryring = std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > >(new boost::circular_buffer<pair<DNSName, uint16_t> >());
t_queryring->set_capacity(ringsize);
- t_servfailqueryring = new boost::circular_buffer<pair<DNSName, uint16_t> >();
+ t_servfailqueryring = std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t> > >(new boost::circular_buffer<pair<DNSName, uint16_t> >());
t_servfailqueryring->set_capacity(ringsize);
}
- MT=new MTasker<PacketID,string>(::arg().asNum("stack-size"));
+ MT=std::unique_ptr<MTasker<PacketID,string> >(new MTasker<PacketID,string>(::arg().asNum("stack-size")));
PacketID pident;
static uint64_t* pleaseDump(int fd)
{
- return new uint64_t(t_RC->doDump(fd) + dumpNegCache(t_sstorage->negcache, fd) + t_packetCache->doDump(fd));
+ return new uint64_t(t_RC->doDump(fd) + dumpNegCache(SyncRes::t_sstorage.negcache, fd) + t_packetCache->doDump(fd));
}
static uint64_t* pleaseDumpNSSpeeds(int fd)
{
- return new uint64_t(t_RC->doDumpNSSpeeds(fd));
+ return new uint64_t(SyncRes::doDumpNSSpeeds(fd));
}
template<typename T>
uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree)
{
- uint64_t ret = t_sstorage->negcache.wipe(canon, subtree);
+ uint64_t ret = SyncRes::wipeNegCache(canon, subtree);
return new uint64_t(ret);
}
uint64_t* pleaseGetThrottleSize()
{
- return new uint64_t(t_sstorage ? t_sstorage->throttle.size() : 0);
+ return new uint64_t(SyncRes::getThrottledServersSize());
}
static uint64_t getThrottleSize()
uint64_t* pleaseGetNegCacheSize()
{
- uint64_t tmp=(t_sstorage ? t_sstorage->negcache.size() : 0);
+ uint64_t tmp=(SyncRes::getNegCacheSize());
return new uint64_t(tmp);
}
uint64_t* pleaseGetFailedHostsSize()
{
- uint64_t tmp=(t_sstorage ? t_sstorage->fails.size() : 0);
+ uint64_t tmp=(SyncRes::getThrottledServersSize());
return new uint64_t(tmp);
}
uint64_t getFailedHostsSize()
uint64_t* pleaseGetNsSpeedsSize()
{
- return new uint64_t(t_sstorage ? t_sstorage->nsSpeeds.size() : 0);
+ return new uint64_t(SyncRes::getNSSpeedsSize());
}
uint64_t getNsSpeedsSize()
return false;
}
-uint64_t MemRecursorCache::doDumpNSSpeeds(int fd)
-{
- FILE* fp=fdopen(dup(fd), "w");
- if(!fp)
- return 0;
- fprintf(fp, "; nsspeed dump from thread follows\n;\n");
- uint64_t count=0;
-
- for(SyncRes::nsspeeds_t::iterator i = t_sstorage->nsSpeeds.begin() ; i!= t_sstorage->nsSpeeds.end(); ++i)
- {
- count++;
- fprintf(fp, "%s -> ", i->first.toString().c_str());
- for(SyncRes::DecayingEwmaCollection::collection_t::iterator j = i->second.d_collection.begin(); j!= i->second.d_collection.end(); ++j)
- {
- // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
- fprintf(fp, "%s/%f ", j->first.toString().c_str(), j->second.peek());
- }
- fprintf(fp, "\n");
- }
- fclose(fp);
- return count;
-}
-
uint64_t MemRecursorCache::doDump(int fd)
{
FILE* fp=fdopen(dup(fd), "w");
void replace(time_t, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, bool auth, boost::optional<Netmask> ednsmask=boost::optional<Netmask>());
void doPrune(void);
uint64_t doDump(int fd);
- uint64_t doDumpNSSpeeds(int fd);
int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL);
dnssecinfra.hh dnssecinfra.cc \
dnsseckeeper.hh \
dnswriter.cc dnswriter.hh \
- ecs.cc \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
filterpo.cc filterpo.hh \
dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
ednscookies.cc ednscookies.hh \
- ecs.cc \
ednsoptions.cc ednsoptions.hh \
ednssubnet.cc ednssubnet.hh \
filterpo.cc filterpo.hh \
+++ /dev/null
-#include "syncres.hh"
-#include "arguments.hh"
-
-NetmaskGroup g_ednssubnets;
-SuffixMatchNode g_ednsdomains;
-bool g_useIncomingECS;
-
-void parseEDNSSubnetWhitelist(const std::string& wlist)
-{
- vector<string> parts;
- stringtok(parts, wlist, ",; ");
- for(const auto& a : parts) {
- try {
- Netmask nm(a);
- g_ednssubnets.addMask(nm);
- }
- catch(...) {
- g_ednsdomains.add(DNSName(a));
- }
- }
-}
#include "rec-lua-conf.hh"
#include "root-dnssec.hh"
#include "syncres.hh"
+#include "utility.hh"
#include "validate-recursor.hh"
-std::unordered_set<DNSName> g_delegationOnly;
RecursorStats g_stats;
GlobalStateHolder<LuaConfigItems> g_luaconfs;
-NetmaskGroup* g_dontQuery{nullptr};
-__thread MemRecursorCache* t_RC{nullptr};
-SyncRes::domainmap_t* g_initialDomainMap{nullptr};
+thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
unsigned int g_numThreads = 1;
/* Fake some required functions we didn't want the trouble to
{
vector<DNSRecord> nsset;
if(!t_RC)
- t_RC = new MemRecursorCache();
+ t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
DNSRecord arr, aaaarr, nsrr;
nsrr.d_name=g_rootdnsname;
seedRandom("/dev/urandom");
reportAllTypes();
- if (g_dontQuery)
- delete g_dontQuery;
- g_dontQuery = new NetmaskGroup();
-
- if (t_RC)
- delete t_RC;
- t_RC = new MemRecursorCache();
-
- if (g_initialDomainMap)
- delete g_initialDomainMap;
- g_initialDomainMap = new SyncRes::domainmap_t(); // new threads needs this to be setup
+ t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
SyncRes::s_maxqperq = 50;
SyncRes::s_maxtotusec = 1000*7000;
SyncRes::s_rootNXTrust = true;
SyncRes::s_minimumTTL = 0;
SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
-
- g_ednssubnets = NetmaskGroup();
- g_ednsdomains = SuffixMatchNode();
- g_useIncomingECS = false;
- g_delegationOnly.clear();
+ SyncRes::clearEDNSSubnets();
+ SyncRes::clearEDNSDomains();
+ SyncRes::clearDelegationOnly();
+ SyncRes::clearDontQuery();
+
+ SyncRes::clearNSSpeeds();
+ BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
+ SyncRes::clearEDNSStatuses();
+ BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
+ SyncRes::clearThrottle();
+ BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
+ SyncRes::clearFailedServers();
+ BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
auto luaconfsCopy = g_luaconfs.getCopy();
luaconfsCopy.dfe.clear();
sr->setDoEDNS0(edns0);
sr->setDoDNSSEC(dnssec);
sr->setLogMode(lm);
- t_sstorage->domainmap = g_initialDomainMap;
- t_sstorage->negcache.clear();
- t_sstorage->nsSpeeds.clear();
- t_sstorage->ednsstatus.clear();
- t_sstorage->throttle.clear();
- t_sstorage->fails.clear();
- t_sstorage->dnssecmap.clear();
+ SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
+ SyncRes::clearNegCache();
}
static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
BOOST_CHECK(downServers.size() > 0);
/* we explicitly refuse to mark the root servers down */
for (const auto& server : downServers) {
- BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 0);
+ BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
}
}
BOOST_CHECK_EQUAL(ret.size(), 1);
BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
- BOOST_CHECK_EQUAL(t_sstorage->ednsstatus.size(), 1);
- BOOST_CHECK_EQUAL(t_sstorage->ednsstatus[noEDNSServer].mode, SyncRes::EDNSStatus::NOEDNS);
+ BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
+ BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
}
BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
BOOST_CHECK_EQUAL(res, 0);
}
+BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ size_t tcpQueriesCount = 0;
+
+ sr->setAsyncCallback([&tcpQueriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+ if (!doTCP) {
+ setLWResult(res, 0, true, true, false);
+ return 1;
+ }
+
+ /* first TCP query is answered with a TC response */
+ tcpQueriesCount++;
+ if (tcpQueriesCount == 1) {
+ setLWResult(res, 0, true, true, false);
+ }
+ else {
+ setLWResult(res, 0, true, false, false);
+ }
+
+ addRecordToLW(res, domain, QType::A, "192.0.2.1");
+ return 1;
+ });
+
+ primeHints();
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
+}
+
BOOST_AUTO_TEST_CASE(test_all_nss_down) {
std::unique_ptr<SyncRes> sr;
init();
BOOST_CHECK_EQUAL(downServers.size(), 4);
for (const auto& server : downServers) {
- BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 1);
- BOOST_CHECK(t_sstorage->throttle.shouldThrottle(time(nullptr), boost::make_tuple(server, target, QType::A)));
+ BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
+ BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
}
}
BOOST_CHECK_EQUAL(downServers.size(), 4);
for (const auto& server : downServers) {
- BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 1);
- BOOST_CHECK(t_sstorage->throttle.shouldThrottle(time(nullptr), boost::make_tuple(server, target, QType::A)));
+ BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
+ BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
+;
}
}
/* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
for (const auto& server : downServers) {
- BOOST_CHECK_EQUAL(t_sstorage->fails.value(server), 0);
- BOOST_CHECK(!t_sstorage->throttle.shouldThrottle(time(nullptr), boost::make_tuple(server, target, QType::A)));
+ BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
+ BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
}
}
primeHints();
const DNSName target("powerdns.com.");
- g_useIncomingECS = true;
- g_ednsdomains.add(target);
+ SyncRes::addEDNSDomain(target);
EDNSSubnetOpts incomingECS;
incomingECS.source = Netmask("192.0.2.128/32");
primeHints();
const DNSName target("powerdns.com.");
- g_useIncomingECS = true;
- g_ednssubnets.addMask("192.0.2.1/32");
+ SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
EDNSSubnetOpts incomingECS;
incomingECS.source = Netmask("2001:DB8::FF/128");
});
/* mark ns as down */
- t_sstorage->throttle.throttle(time(nullptr), boost::make_tuple(ns, "", 0), SyncRes::s_serverdownthrottletime, 10000);
+ SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
const size_t blocks = 10;
/* mark ns as down for 'blocks' queries */
- t_sstorage->throttle.throttle(time(nullptr), boost::make_tuple(ns, "", 0), SyncRes::s_serverdownthrottletime, blocks);
+ SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
for (size_t idx = 0; idx < blocks; idx++) {
- BOOST_CHECK(t_sstorage->throttle.shouldThrottle(time(nullptr), boost::make_tuple(ns, "", 0)));
+ BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
}
/* we have been throttled 'blocks' times, we should not be throttled anymore */
- BOOST_CHECK(!t_sstorage->throttle.shouldThrottle(time(nullptr), boost::make_tuple(ns, "", 0)));
+ BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
}
BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
const size_t seconds = 1;
/* mark ns as down for 'seconds' seconds */
- t_sstorage->throttle.throttle(time(nullptr), boost::make_tuple(ns, "", 0), seconds, 10000);
- BOOST_CHECK(t_sstorage->throttle.shouldThrottle(time(nullptr), boost::make_tuple(ns, "", 0)));
+ SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
+
+ BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
sleep(seconds + 1);
/* we should not be throttled anymore */
- BOOST_CHECK(!t_sstorage->throttle.shouldThrottle(time(nullptr), boost::make_tuple(ns, "", 0)));
+ BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
}
BOOST_AUTO_TEST_CASE(test_dont_query_server) {
});
/* prevent querying this NS */
- g_dontQuery->addMask(Netmask(ns));
+ SyncRes::addDontQuery(Netmask(ns));
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1);
/* one for target1 and one for the entire TLD */
- BOOST_CHECK_EQUAL(t_sstorage->negcache.size(), 2);
+ BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1);
/* one for target1 and one for the entire TLD */
- BOOST_CHECK_EQUAL(t_sstorage->negcache.size(), 2);
+ BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
/* we should have sent only one query */
BOOST_CHECK_EQUAL(queriesCount, 1);
/* even with root-nx-trust on and a NX answer from the root,
we should not have cached the entire TLD this time. */
- BOOST_CHECK_EQUAL(t_sstorage->negcache.size(), 1);
+ BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(ret[0].d_name, target2);
BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
- BOOST_CHECK_EQUAL(t_sstorage->negcache.size(), 1);
+ BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
BOOST_CHECK_EQUAL(queriesCount, 3);
}
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1);
/* one for target1 */
- BOOST_CHECK_EQUAL(t_sstorage->negcache.size(), 1);
+ BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(ret.size(), 1);
/* one for target1 */
- BOOST_CHECK_EQUAL(t_sstorage->negcache.size(), 1);
+ BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
/* we should have sent three queries */
BOOST_CHECK_EQUAL(queriesCount, 3);
const DNSName target("www.powerdns.com.");
const DNSName cnameTarget("cname.powerdns.com.");
- g_useIncomingECS = true;
- g_ednsdomains.add(DNSName("powerdns.com."));
+ SyncRes::addEDNSDomain(DNSName("powerdns.com."));
EDNSSubnetOpts incomingECS;
incomingECS.source = Netmask("192.0.2.128/32");
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 2);
/* no negative cache entry because the response was variable */
- BOOST_CHECK_EQUAL(t_sstorage->negcache.size(), 0);
+ BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
}
BOOST_AUTO_TEST_CASE(test_ns_speed) {
/* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
then pdns-public-ns1.powerdns.com. on IPv4 */
- t_sstorage->nsSpeeds[DNSName("pdns-public-ns1.powerdns.com.")].submit(ComboAddress("192.0.2.1:53"), 100, &now);
- t_sstorage->nsSpeeds[DNSName("pdns-public-ns1.powerdns.com.")].submit(ComboAddress("[2001:DB8::1]:53"), 10000, &now);
- t_sstorage->nsSpeeds[DNSName("pdns-public-ns2.powerdns.com.")].submit(ComboAddress("192.0.2.2:53"), 10, &now);
- t_sstorage->nsSpeeds[DNSName("pdns-public-ns2.powerdns.com.")].submit(ComboAddress("[2001:DB8::2]:53"), 1, &now);
- t_sstorage->nsSpeeds[DNSName("pdns-public-ns3.powerdns.com.")].submit(ComboAddress("192.0.2.3:53"), 10000, &now);
- t_sstorage->nsSpeeds[DNSName("pdns-public-ns3.powerdns.com.")].submit(ComboAddress("[2001:DB8::3]:53"), 10000, &now);
+ SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
+ SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
+ SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
+ SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
+ SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
+ SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(ret.size(), 1);
}
+BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ const DNSName target("powerdns.com.");
+ size_t queriesCount = 0;
+
+ sr->setAsyncCallback([&queriesCount,target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ if (isRootServer(ip) && domain == target) {
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
+ addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
+ return 1;
+ } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
+ return 1;
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::ServFail);
+ BOOST_CHECK_EQUAL(ret.size(), 0);
+ /* one query to get NSs, then A and AAAA for each NS */
+ BOOST_CHECK_EQUAL(queriesCount, 5);
+}
+
BOOST_AUTO_TEST_CASE(test_cache_hit) {
std::unique_ptr<SyncRes> sr;
init();
primeHints();
/* Thanks, Verisign */
- g_delegationOnly.insert(DNSName("com."));
- g_delegationOnly.insert(DNSName("net."));
+ SyncRes::addDelegationOnly(DNSName("com."));
+ SyncRes::addDelegationOnly(DNSName("net."));
const DNSName target("nx-powerdns.com.");
SyncRes::AuthDomain ad;
ad.d_rdForward = false;
ad.d_servers.push_back(forwardedNS);
- (*t_sstorage->domainmap)[target] = ad;
+ (*SyncRes::t_sstorage.domainmap)[target] = ad;
sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
if (ip == forwardedNS) {
+ BOOST_CHECK_EQUAL(sendRDQuery, false);
+
setLWResult(res, 0, true, false, true);
addRecordToLW(res, domain, QType::A, "192.0.2.42");
return 1;
SyncRes::AuthDomain ad;
ad.d_rdForward = false;
ad.d_servers.push_back(forwardedNS);
- (*t_sstorage->domainmap)[target] = ad;
+ (*SyncRes::t_sstorage.domainmap)[target] = ad;
sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
if (ip == forwardedNS) {
+ BOOST_CHECK_EQUAL(sendRDQuery, false);
+
setLWResult(res, 0, true, false, true);
addRecordToLW(res, domain, QType::A, "192.0.2.42");
return 1;
SyncRes::AuthDomain ad;
ad.d_rdForward = true;
ad.d_servers.push_back(forwardedNS);
- (*t_sstorage->domainmap)[target] = ad;
+ (*SyncRes::t_sstorage.domainmap)[target] = ad;
sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
if (ip == forwardedNS) {
+ BOOST_CHECK_EQUAL(sendRDQuery, false);
+
setLWResult(res, 0, true, false, true);
addRecordToLW(res, domain, QType::A, "192.0.2.42");
return 1;
SyncRes::AuthDomain ad;
ad.d_rdForward = true;
ad.d_servers.push_back(forwardedNS);
- (*t_sstorage->domainmap)[target] = ad;
+ (*SyncRes::t_sstorage.domainmap)[target] = ad;
sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
if (ip == forwardedNS) {
+ BOOST_CHECK_EQUAL(sendRDQuery, true);
+
setLWResult(res, 0, true, false, true);
addRecordToLW(res, domain, QType::A, "192.0.2.42");
return 1;
dr.d_content = std::make_shared<ARecordContent>(nsAddr);
ad.d_records.insert(dr);
- (*t_sstorage->domainmap)[authZone] = ad;
+ (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
queriesCount++;
BOOST_CHECK(sr->wasOutOfBand());
}
+BOOST_AUTO_TEST_CASE(test_auth_zone) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("powerdns.com.");
+ const ComboAddress addr("192.0.2.5");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = target;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(addr);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[target] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, domain, QType::A, "192.0.2.42");
+ return 1;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_CHECK_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::A);
+ BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("powerdns.com.");
+ const DNSName authZone("internal.powerdns.com.");
+ const ComboAddress addr("192.0.2.5");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = authZone;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = authZone;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = authZone;
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(addr);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[authZone] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount,target,authZone](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ if (domain == target) {
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
+ return 1;
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_CHECK_EQUAL(ret.size(), 2);
+ BOOST_CHECK(ret[0].d_type == QType::CNAME);
+ BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
+ BOOST_CHECK(ret[1].d_type == QType::A);
+ BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
+ BOOST_CHECK_EQUAL(queriesCount, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("powerdns.com.");
+ const DNSName externalCNAME("www.open-xchange.com.");
+ const ComboAddress addr("192.0.2.5");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = target;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::CNAME;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[target] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount,externalCNAME,addr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ if (domain == externalCNAME) {
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
+ return 1;
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_CHECK_EQUAL(ret.size(), 2);
+ BOOST_CHECK(ret[0].d_type == QType::CNAME);
+ BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
+ BOOST_CHECK(ret[1].d_type == QType::A);
+ BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
+ BOOST_CHECK_EQUAL(queriesCount, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("nodata.powerdns.com.");
+ const DNSName authZone("powerdns.com");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = authZone;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = authZone;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[authZone] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::SOA);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("nx.powerdns.com.");
+ const DNSName authZone("powerdns.com");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = authZone;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = DNSName("powerdns.com.");
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[authZone] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, RCode::NXDomain);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::SOA);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("www.test.powerdns.com.");
+ const ComboAddress targetAddr("192.0.2.2");
+ const DNSName ns("ns1.test.powerdns.com.");
+ const ComboAddress nsAddr("192.0.2.1");
+ const DNSName authZone("powerdns.com");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = authZone;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = authZone;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = DNSName("test.powerdns.com.");
+ dr.d_type = QType::NS;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<NSRecordContent>(ns);
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = ns;
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(nsAddr);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[authZone] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+ if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
+ return 1;
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::A);
+ BOOST_CHECK_EQUAL(queriesCount, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("test.powerdns.com.");
+ const ComboAddress targetAddr("192.0.2.2");
+ const DNSName ns("ns1.test.powerdns.com.");
+ const ComboAddress nsAddr("192.0.2.1");
+ const DNSName authZone("powerdns.com");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = authZone;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = authZone;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = DNSName("test.powerdns.com.");
+ dr.d_type = QType::NS;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<NSRecordContent>(ns);
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = ns;
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(nsAddr);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[authZone] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
+ return 1;
+ }
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::A);
+ BOOST_CHECK_EQUAL(queriesCount, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("test.powerdns.com.");
+ const ComboAddress targetAddr("192.0.2.2");
+ const DNSName authZone("powerdns.com");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = authZone;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = authZone;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = DNSName("*.powerdns.com.");
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(targetAddr);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[authZone] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::A);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("test.powerdns.com.");
+ const ComboAddress targetAddr("192.0.2.2");
+ const DNSName authZone("powerdns.com");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = authZone;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = authZone;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = DNSName("*.powerdns.com.");
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(targetAddr);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[authZone] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+
+ return 0;
+ });
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_REQUIRE_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::SOA);
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
+ std::unique_ptr<SyncRes> sr;
+ init();
+ initSR(sr, true, false);
+
+ primeHints();
+
+ size_t queriesCount = 0;
+ const DNSName target("powerdns.com.");
+ const ComboAddress addr("192.0.2.5");
+
+ SyncRes::AuthDomain ad;
+ ad.d_name = target;
+ DNSRecord dr;
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::SOA;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
+ ad.d_records.insert(dr);
+
+ dr.d_place = DNSResourceRecord::ANSWER;
+ dr.d_name = target;
+ dr.d_type = QType::A;
+ dr.d_ttl = 3600;
+ dr.d_content = std::make_shared<ARecordContent>(addr);
+ ad.d_records.insert(dr);
+
+ auto map = std::make_shared<SyncRes::domainmap_t>();
+ (*map)[target] = ad;
+ SyncRes::setDomainMap(map);
+
+ sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
+
+ queriesCount++;
+ setLWResult(res, 0, true, false, true);
+ addRecordToLW(res, domain, QType::A, "192.0.2.42");
+ return 1;
+ });
+
+ /* simulate a no-RD query */
+ sr->setCacheOnly();
+
+ vector<DNSRecord> ret;
+ int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_CHECK_EQUAL(ret.size(), 1);
+ BOOST_CHECK(ret[0].d_type == QType::A);
+ BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
+ BOOST_CHECK_EQUAL(queriesCount, 0);
+}
+
/*
// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
// prime root cache
vector<DNSRecord> nsset;
if(!t_RC)
- t_RC = new MemRecursorCache();
+ t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
if(::arg()["hint-file"].empty()) {
DNSRecord arr, aaaarr, nsrr;
t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), false); // and stuff in the cache
}
-static void makeNameToIPZone(SyncRes::domainmap_t* newMap, const DNSName& hostname, const string& ip)
+static void makeNameToIPZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const DNSName& hostname, const string& ip)
{
SyncRes::AuthDomain ad;
ad.d_rdForward=false;
}
else {
L<<Logger::Warning<<"Inserting forward zone '"<<dr.d_name<<"' based on hosts file"<<endl;
- (*newMap)[dr.d_name]=ad;
+ ad.d_name=dr.d_name;
+ (*newMap)[ad.d_name]=ad;
}
}
//! parts[0] must be an IP address, the rest must be host names
-static void makeIPToNamesZone(SyncRes::domainmap_t* newMap, const vector<string>& parts)
+static void makeIPToNamesZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const vector<string>& parts)
{
string address=parts[0];
vector<string> ipparts;
else {
if(ipparts.size()==4)
L<<Logger::Warning<<"Inserting reverse zone '"<<dr.d_name<<"' based on hosts file"<<endl;
- (*newMap)[dr.d_name]=ad;
+ ad.d_name = dr.d_name;
+ (*newMap)[ad.d_name]=ad;
}
}
void* pleaseWipeNegCache()
{
- t_sstorage->negcache.clear();
+ SyncRes::clearNegCache();
return 0;
}
-void* pleaseUseNewSDomainsMap(SyncRes::domainmap_t* newmap)
+void* pleaseUseNewSDomainsMap(std::shared_ptr<SyncRes::domainmap_t> newmap)
{
- t_sstorage->domainmap = newmap;
+ SyncRes::setDomainMap(newmap);
return 0;
}
string reloadAuthAndForwards()
{
- SyncRes::domainmap_t* original=t_sstorage->domainmap;
+ std::shared_ptr<SyncRes::domainmap_t> original=SyncRes::getDomainMap();
try {
L<<Logger::Warning<<"Reloading zones, purging data from cache"<<endl;
-
- for(SyncRes::domainmap_t::const_iterator i = t_sstorage->domainmap->begin(); i != t_sstorage->domainmap->end(); ++i) {
- for(SyncRes::AuthDomain::records_t::const_iterator j = i->second.d_records.begin(); j != i->second.d_records.end(); ++j)
- broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, j->d_name, false));
+
+ if (original) {
+ for(const auto& i : *original) {
+ for(const auto& j : i.second.d_records)
+ broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, j.d_name, false));
+ }
}
string configname=::arg()["config-dir"]+"/recursor.conf";
::arg().preParse(g_argc, g_argv, "export-etc-hosts");
::arg().preParse(g_argc, g_argv, "serve-rfc1918");
- SyncRes::domainmap_t* newDomainMap = parseAuthAndForwards();
+ std::shared_ptr<SyncRes::domainmap_t> newDomainMap = parseAuthAndForwards();
// purge again - new zones need to blank out the cache
- for(SyncRes::domainmap_t::const_iterator i = newDomainMap->begin(); i != newDomainMap->end(); ++i) {
- broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, i->first, true));
- broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, i->first, true));
- broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, i->first, true));
+ for(const auto& i : *newDomainMap) {
+ broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, i.first, true));
+ broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, i.first, true));
+ broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, i.first, true));
}
- broadcastFunction(boost::bind(pleaseUseNewSDomainsMap, newDomainMap));
- delete original;
+ broadcastFunction(boost::bind(pleaseUseNewSDomainsMap, newDomainMap));
return "ok\n";
}
catch(std::exception& e) {
}
}
-SyncRes::domainmap_t* parseAuthAndForwards()
+std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards()
{
TXTRecordContent::report();
OPTRecordContent::report();
- SyncRes::domainmap_t* newMap = new SyncRes::domainmap_t();
+ auto newMap = std::make_shared<SyncRes::domainmap_t>();
typedef vector<string> parts_t;
parts_t parts;
dr.d_place=DNSResourceRecord::ANSWER;
}
catch(std::exception &e) {
- delete newMap;
throw PDNSException("Error parsing record '"+rr.qname.toString()+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"': "+e.what());
}
catch(...) {
- delete newMap;
throw PDNSException("Error parsing record '"+rr.qname.toString()+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"'");
}
ad.d_rdForward = true;
}
}
-
- (*newMap)[DNSName(headers.first)]=ad;
+
+ ad.d_name = DNSName(headers.first);
+ (*newMap)[ad.d_name]=ad;
}
}
FILE *rfp=fopen(::arg()["forward-zones-file"].c_str(), "r");
if(!rfp) {
- delete newMap;
throw PDNSException("Error opening forward-zones-file '"+::arg()["forward-zones-file"]+"': "+stringerror());
}
else
ad.d_rdForward = false;
if(domain.empty()) {
- delete newMap;
throw PDNSException("Error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]);
}
convertServersForAD(instructions, ad, ",; ", false);
}
catch(...) {
- delete newMap;
throw PDNSException("Conversion error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]);
}
- (*newMap)[DNSName(domain)]=ad;
+ ad.d_name = DNSName(domain);
+ (*newMap)[ad.d_name]=ad;
}
L<<Logger::Warning<<"Done parsing " << newMap->size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"<<endl;
}
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include <boost/algorithm/string.hpp>
-#include "lua-recursor4.hh"
-#include "utility.hh"
-#include "syncres.hh"
-#include <iostream>
-#include <map>
-#include "dnsrecords.hh"
-#include <algorithm>
-#include <set>
-#include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <utility>
-#include <deque>
-#include "logger.hh"
-#include "validate.hh"
-#include "misc.hh"
#include "arguments.hh"
-#include "lwres.hh"
-#include "recursor_cache.hh"
-#include "dnsparser.hh"
+#include "cachecleaner.hh"
#include "dns_random.hh"
-#include "lock.hh"
+#include "dnsparser.hh"
+#include "dnsrecords.hh"
#include "ednssubnet.hh"
-#include "cachecleaner.hh"
+#include "logger.hh"
+#include "lua-recursor4.hh"
#include "rec-lua-conf.hh"
-__thread SyncRes::StaticStorage* t_sstorage;
+#include "syncres.hh"
+
+thread_local SyncRes::ThreadLocalStorage SyncRes::t_sstorage;
+
+std::unordered_set<DNSName> SyncRes::s_delegationOnly;
+std::unique_ptr<NetmaskGroup> SyncRes::s_dontQuery{nullptr};
+NetmaskGroup SyncRes::s_ednssubnets;
+SuffixMatchNode SyncRes::s_ednsdomains;
+string SyncRes::s_serverID;
+SyncRes::LogMode SyncRes::s_lm;
unsigned int SyncRes::s_maxnegttl;
unsigned int SyncRes::s_maxcachettl;
+unsigned int SyncRes::s_maxqperq;
+unsigned int SyncRes::s_maxtotusec;
+unsigned int SyncRes::s_maxdepth;
+unsigned int SyncRes::s_minimumTTL;
unsigned int SyncRes::s_packetcachettl;
unsigned int SyncRes::s_packetcacheservfailttl;
unsigned int SyncRes::s_serverdownmaxfails;
std::atomic<uint64_t> SyncRes::s_unreachables;
uint8_t SyncRes::s_ecsipv4limit;
uint8_t SyncRes::s_ecsipv6limit;
-unsigned int SyncRes::s_minimumTTL;
bool SyncRes::s_doIPv6;
bool SyncRes::s_nopacketcache;
bool SyncRes::s_rootNXTrust;
-unsigned int SyncRes::s_maxqperq;
-unsigned int SyncRes::s_maxtotusec;
-unsigned int SyncRes::s_maxdepth;
-string SyncRes::s_serverID;
-SyncRes::LogMode SyncRes::s_lm;
+bool SyncRes::s_noEDNS;
#define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
-bool SyncRes::s_noEDNS;
-
static void accountAuthLatency(int usec, int family)
{
if(family == AF_INET) {
SyncRes::SyncRes(const struct timeval& now) : 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_nocache(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm)
+ d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm)
{
- if(!t_sstorage) {
- t_sstorage = new StaticStorage();
- }
}
/** everything begins here - this is the entry point just after receiving a packet */
* - version.pdns. CH TXT
* - id.server. CH TXT
*/
-bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t &qclass, vector<DNSRecord> &ret)
+bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret)
{
static const DNSName arpa("1.0.0.127.in-addr.arpa."), ip6_arpa("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."),
localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
//! This is the 'out of band resolver', in other words, the authoritative server
-bool SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int& res)
+void SyncRes::AuthDomain::addSOA(std::vector<DNSRecord>& records) const
{
- string prefix;
- if(doLog()) {
- prefix=d_prefix;
- prefix.append(depth, ' ');
+ SyncRes::AuthDomain::records_t::const_iterator ziter = d_records.find(boost::make_tuple(getName(), QType::SOA));
+ if (ziter != d_records.end()) {
+ DNSRecord dr = *ziter;
+ dr.d_place = DNSResourceRecord::AUTHORITY;
+ records.push_back(dr);
}
+ else {
+ // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
+ }
+}
- LOG(prefix<<qname<<": checking auth storage for '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
- DNSName authdomain(qname);
+int SyncRes::AuthDomain::getRecords(const DNSName& qname, uint16_t qtype, std::vector<DNSRecord>& records) const
+{
+ int result = RCode::NoError;
+ records.clear();
- domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
- if(iter==t_sstorage->domainmap->end()) {
- LOG(prefix<<qname<<": auth storage has no zone for this query!"<<endl);
- return false;
- }
- LOG(prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl);
- pair<AuthDomain::records_t::const_iterator, AuthDomain::records_t::const_iterator> range;
-
- range=iter->second.d_records.equal_range(tie(qname)); // partial lookup
-
- ret.clear();
- AuthDomain::records_t::const_iterator ziter;
- bool somedata=false;
- for(ziter=range.first; ziter!=range.second; ++ziter) {
- somedata=true;
- if(qtype.getCode()==QType::ANY || ziter->d_type==qtype.getCode() || ziter->d_type==QType::CNAME) // let rest of nameserver do the legwork on this one
- ret.push_back(*ziter);
- else if(ziter->d_type == QType::NS && ziter->d_name.countLabels() > authdomain.countLabels()) { // we hit a delegation point!
- DNSRecord dr=*ziter;
+ // partial lookup
+ std::pair<records_t::const_iterator,records_t::const_iterator> range = d_records.equal_range(tie(qname));
+
+ SyncRes::AuthDomain::records_t::const_iterator ziter;
+ bool somedata = false;
+
+ for(ziter = range.first; ziter != range.second; ++ziter) {
+ somedata = true;
+
+ if(qtype == QType::ANY || ziter->d_type == qtype || ziter->d_type == QType::CNAME) {
+ // let rest of nameserver do the legwork on this one
+ records.push_back(*ziter);
+ }
+ else if (ziter->d_type == QType::NS && ziter->d_name.countLabels() > getName().countLabels()) {
+ // we hit a delegation point!
+ DNSRecord dr = *ziter;
dr.d_place=DNSResourceRecord::AUTHORITY;
- ret.push_back(dr);
+ records.push_back(dr);
}
}
- if(!ret.empty()) {
- LOG(prefix<<qname<<": exact match in zone '"<<authdomain<<"'"<<endl);
- res=0;
- return true;
+
+ if (!records.empty()) {
+ /* We have found an exact match, we're done */
+ // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
+ return result;
}
- if(somedata) {
- LOG(prefix<<qname<<": found record in '"<<authdomain<<"', but nothing of the right type, sending SOA"<<endl);
- ziter=iter->second.d_records.find(boost::make_tuple(authdomain, QType::SOA));
- if(ziter!=iter->second.d_records.end()) {
- DNSRecord dr=*ziter;
- dr.d_place=DNSResourceRecord::AUTHORITY;
- ret.push_back(dr);
- }
- else
- LOG(prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl);
- res=RCode::NoError;
- return true;
+
+ if (somedata) {
+ /* We have records for that name, but not of the wanted qtype */
+ // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
+ addSOA(records);
+
+ return result;
}
- LOG(prefix<<qname<<": nothing found so far in '"<<authdomain<<"', trying wildcards"<<endl);
+ // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
DNSName wcarddomain(qname);
- while(wcarddomain != iter->first && wcarddomain.chopOff()) {
- LOG(prefix<<qname<<": trying '*."<<wcarddomain<<"' in "<<authdomain<<endl);
- range=iter->second.d_records.equal_range(boost::make_tuple(g_wildcarddnsname+wcarddomain));
- if(range.first==range.second)
+ while(wcarddomain != getName() && wcarddomain.chopOff()) {
+ // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
+ range = d_records.equal_range(boost::make_tuple(g_wildcarddnsname + wcarddomain));
+ if (range.first==range.second)
continue;
- for(ziter=range.first; ziter!=range.second; ++ziter) {
- DNSRecord dr=*ziter;
+ for(ziter = range.first; ziter != range.second; ++ziter) {
+ DNSRecord dr = *ziter;
// if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
- if(dr.d_type == qtype.getCode() || qtype.getCode() == QType::ANY || dr.d_type == QType::CNAME) {
+ if(dr.d_type == qtype || qtype == QType::ANY || dr.d_type == QType::CNAME) {
dr.d_name = qname;
- dr.d_place=DNSResourceRecord::ANSWER;
- ret.push_back(dr);
+ dr.d_place = DNSResourceRecord::ANSWER;
+ records.push_back(dr);
}
}
- LOG(prefix<<qname<<": in '"<<authdomain<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl);
- res=RCode::NoError;
- return true;
+
+ if (records.empty()) {
+ addSOA(records);
+ }
+
+ // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
+ return result;
}
+ /* Nothing for this name, no wildcard, let's see if there is some NS */
DNSName nsdomain(qname);
-
- while(nsdomain.chopOff() && nsdomain != iter->first) {
- range=iter->second.d_records.equal_range(boost::make_tuple(nsdomain,QType::NS));
- if(range.first==range.second)
+ while (nsdomain.chopOff() && nsdomain != getName()) {
+ range = d_records.equal_range(boost::make_tuple(nsdomain,QType::NS));
+ if(range.first == range.second)
continue;
- for(ziter=range.first; ziter!=range.second; ++ziter) {
- DNSRecord dr=*ziter;
- dr.d_place=DNSResourceRecord::AUTHORITY;
- ret.push_back(dr);
+ for(ziter = range.first; ziter != range.second; ++ziter) {
+ DNSRecord dr = *ziter;
+ dr.d_place = DNSResourceRecord::AUTHORITY;
+ records.push_back(dr);
}
}
- if(ret.empty()) {
- LOG(prefix<<qname<<": no NS match in zone '"<<authdomain<<"' either, handing out SOA"<<endl);
- ziter=iter->second.d_records.find(boost::make_tuple(authdomain, QType::SOA));
- if(ziter!=iter->second.d_records.end()) {
- DNSRecord dr=*ziter;
- dr.d_place=DNSResourceRecord::AUTHORITY;
- ret.push_back(dr);
- }
- else {
- LOG(prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl);
- }
- res=RCode::NXDomain;
+
+ if(records.empty()) {
+ // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
+ addSOA(records);
+ result = RCode::NXDomain;
}
- else
- res=0;
+ return result;
+}
+
+bool SyncRes::doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res) const
+{
+ res = domain.getRecords(qname, qtype.getCode(), ret);
return true;
}
+bool SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int& res)
+{
+ string prefix;
+ if(doLog()) {
+ prefix=d_prefix;
+ prefix.append(depth, ' ');
+ }
+
+ DNSName authdomain(qname);
+ domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
+ if(iter==t_sstorage.domainmap->end() || !iter->second.isAuth()) {
+ LOG(prefix<<qname<<": auth storage has no zone for this query!"<<endl);
+ return false;
+ }
+
+ LOG(prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl);
+ return doOOBResolve(iter->second, qname, qtype, ret, res);
+}
+
void SyncRes::doEDNSDumpAndClose(int fd)
{
FILE* fp=fdopen(fd, "w");
return;
}
fprintf(fp,"IP Address\tMode\tMode last updated at\n");
- for(const auto& eds : t_sstorage->ednsstatus) {
+ for(const auto& eds : t_sstorage.ednsstatus) {
fprintf(fp, "%s\t%d\t%s", eds.first.toString().c_str(), (int)eds.second.mode, ctime(&eds.second.modeSetAt));
}
fclose(fp);
}
+uint64_t SyncRes::doDumpNSSpeeds(int fd)
+{
+ FILE* fp=fdopen(dup(fd), "w");
+ if(!fp)
+ return 0;
+ fprintf(fp, "; nsspeed dump from thread follows\n;\n");
+ uint64_t count=0;
+
+ for(const auto& i : t_sstorage.nsSpeeds)
+ {
+ count++;
+ fprintf(fp, "%s -> ", i.first.toString().c_str());
+ for(const auto& j : i.second.d_collection)
+ {
+ // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
+ fprintf(fp, "%s/%f ", j.first.toString().c_str(), j.second.peek());
+ }
+ fprintf(fp, "\n");
+ }
+ fclose(fp);
+ return count;
+}
+
/* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
so that if there are RRSIGs for a name, we'll have them.
*/
SyncRes::EDNSStatus* ednsstatus;
- ednsstatus = &t_sstorage->ednsstatus[ip]; // does this include port? YES
+ ednsstatus = &t_sstorage.ednsstatus[ip]; // does this include port? YES
if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
*ednsstatus=SyncRes::EDNSStatus();
int res=0;
// This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
- if(!(d_nocache && qtype.getCode()==QType::NS && qname.isRoot())) {
+ if(!(d_updatingRootNS && qtype.getCode()==QType::NS && qname.isRoot())) {
if(d_cacheonly) { // very limited OOB support
LWResult lwr;
LOG(prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl);
DNSName authname(qname);
domainmap_t::const_iterator iter=getBestAuthZone(&authname);
- if(iter != t_sstorage->domainmap->end()) {
- const vector<ComboAddress>& servers = iter->second.d_servers;
- if(servers.empty()) {
+ if(iter != t_sstorage.domainmap->end()) {
+ if(iter->second.isAuth()) {
ret.clear();
d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, res);
return res;
}
else {
+ const vector<ComboAddress>& servers = iter->second.d_servers;
const ComboAddress remoteIP = servers.front();
LOG(prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl);
random_shuffle(ret.begin(), ret.end(), dns_random);
// move 'best' address for this nameserver name up front
- nsspeeds_t::iterator best = t_sstorage->nsSpeeds.find(qname);
+ nsspeeds_t::iterator best = t_sstorage.nsSpeeds.find(qname);
- if(best != t_sstorage->nsSpeeds.end())
+ if(best != t_sstorage.nsSpeeds.end())
for(ret_t::iterator i=ret.begin(); i != ret.end(); ++i) {
if(*i==best->second.d_best) { // got the fastest one
if(i!=ret.begin()) {
// We lost the root NS records
primeHints();
LOG(prefix<<qname<<": reprimed the root"<<endl);
- getRootNS(d_now, d_asyncResolve);
+ /* let's prevent an infinite loop */
+ if (!d_updatingRootNS) {
+ getRootNS(d_now, d_asyncResolve);
+ }
}
}while(subdomain.chopOff());
}
{
SyncRes::domainmap_t::const_iterator ret;
do {
- ret=t_sstorage->domainmap->find(*qname);
- if(ret!=t_sstorage->domainmap->end())
+ ret=t_sstorage.domainmap->find(*qname);
+ if(ret!=t_sstorage.domainmap->end())
break;
}while(qname->chopOff());
return ret;
DNSName authdomain(qname);
domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
- if(iter!=t_sstorage->domainmap->end()) {
- if( iter->second.d_servers.empty() )
+ if(iter!=t_sstorage.domainmap->end()) {
+ if( iter->second.isAuth() )
// this gets picked up in doResolveAt, the empty DNSName, combined with the
// empty vector means 'we are auth for this zone'
nsset.insert({DNSName(), {{}, false}});
else {
// Again, picked up in doResolveAt. An empty DNSName, combined with a
// non-empty vector of ComboAddresses means 'this is a forwarded domain'
- nsset.insert({DNSName(), {iter->second.d_servers, iter->second.d_rdForward}});
+ // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
+ nsset.insert({DNSName(), {iter->second.d_servers, iter->second.shouldRecurse() }});
}
return authdomain;
}
bool wasForwardedOrAuth = false;
bool wasAuth = false;
domainmap_t::const_iterator iter=getBestAuthZone(&authname);
- if(iter != t_sstorage->domainmap->end()) {
+ if(iter != t_sstorage.domainmap->end()) {
wasForwardedOrAuth = true;
const vector<ComboAddress>& servers = iter->second.d_servers;
if(servers.empty()) {
NegCache::NegCacheEntry ne;
if(s_rootNXTrust &&
- t_sstorage->negcache.getRootNXTrust(qname, d_now, ne) &&
+ t_sstorage.negcache.getRootNXTrust(qname, d_now, ne) &&
ne.d_auth.isRoot() &&
!(wasForwardedOrAuth && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
sttl = ne.d_ttd - d_now.tv_sec;
res = RCode::NXDomain;
giveNegative = true;
}
- else if (t_sstorage->negcache.get(qname, qtype, d_now, ne) &&
+ else if (t_sstorage.negcache.get(qname, qtype, d_now, ne) &&
!(wasForwardedOrAuth && ne.d_auth != authname)) { // Only the authname nameserver can neg cache entries
res = 0;
sttl = ne.d_ttd - d_now.tv_sec;
for(const auto& val: rnameservers) {
double speed;
- speed=t_sstorage->nsSpeeds[val].get(&d_now);
+ speed=t_sstorage.nsSpeeds[val].get(&d_now);
speeds[val]=speed;
}
random_shuffle(rnameservers.begin(),rnameservers.end(), dns_random);
bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery)
{
- extern NetmaskGroup* g_dontQuery;
-
- if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) {
+ if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) {
LOG(prefix<<qname<<": server throttled "<<endl);
s_throttledqueries++; d_throttledqueries++;
return true;
}
- else if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) {
- LOG(prefix<<qname<<": query throttled "<<endl);
+ else if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) {
+ LOG(prefix<<qname<<": query throttled "<<remoteIP.toString()<<", "<<qname<<"; "<<qtype.getName()<<endl);
s_throttledqueries++; d_throttledqueries++;
return true;
}
- else if(!pierceDontQuery && g_dontQuery && g_dontQuery->match(&remoteIP)) {
+ else if(!pierceDontQuery && s_dontQuery && s_dontQuery->match(&remoteIP)) {
LOG(prefix<<qname<<": not sending query to " << remoteIP.toString() << ", blocked by 'dont-query' setting" << endl);
s_dontqueries++;
return true;
return false;
}
-RCode::rcodes_ SyncRes::updateCacheFromRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, NsSet& nameservers, const DNSName& tns, const boost::optional<Netmask> ednsmask)
+RCode::rcodes_ SyncRes::updateCacheFromRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask)
{
struct CachePair
{
if(rec.d_type == QType::RRSIG) {
LOG("RRSIG - separate"<<endl);
}
- else if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && rec.d_place==DNSResourceRecord::ANSWER && (rec.d_type != QType::DNSKEY || rec.d_name != auth) && g_delegationOnly.count(auth)) {
+ else if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && rec.d_place==DNSResourceRecord::ANSWER && (rec.d_type != QType::DNSKEY || rec.d_name != auth) && s_delegationOnly.count(auth)) {
LOG("NO! Is from delegation-only zone"<<endl);
s_nodelegated++;
return RCode::NXDomain;
}
else {
bool haveLogged = false;
- if (!t_sstorage->domainmap->empty()) {
+ if (!t_sstorage.domainmap->empty()) {
// Check if we are authoritative for a zone in this answer
DNSName tmp_qname(rec.d_name);
auto auth_domain_iter=getBestAuthZone(&tmp_qname);
- if(auth_domain_iter!=t_sstorage->domainmap->end() &&
+ if(auth_domain_iter!=t_sstorage.domainmap->end() &&
auth.countLabels() <= auth_domain_iter->first.countLabels()) {
if (auth_domain_iter->first != auth) {
LOG("NO! - we are authoritative for the zone "<<auth_domain_iter->first<<endl);
continue;
} else {
LOG("YES! - This answer was ");
- if (nameservers[tns].first.empty()) {
+ if (!wasForwarded) {
LOG("retrieved from the local auth store.");
} else {
LOG("received from a server we forward to.");
// cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
continue;
+
t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, lwr.d_aabit, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::optional<Netmask>());
+
if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
d_wasVariable=true;
}
return RCode::NoError;
}
-bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, bool& sawDS)
+bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic)
{
bool done = false;
ne.d_qtype = QType(0); // this encodes 'whole record'
ne.d_auth = rec.d_name;
harvestNXRecords(lwr.d_records, ne);
- t_sstorage->negcache.add(ne);
+ t_sstorage.negcache.add(ne);
if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot()) {
ne.d_name = ne.d_name.getLastLabel();
- t_sstorage->negcache.add(ne);
+ t_sstorage.negcache.add(ne);
}
}
}
else if(rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::DS) {
LOG(prefix<<qname<<": got DS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
- sawDS=true;
}
else if(!done && rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::SOA &&
lwr.d_rcode==RCode::NoError) {
ne.d_qtype = qtype;
harvestNXRecords(lwr.d_records, ne);
if(qtype.getCode()) { // prevents us from blacking out a whole domain
- t_sstorage->negcache.add(ne);
+ t_sstorage.negcache.add(ne);
}
}
negindic=true;
return done;
}
+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;
+ s_outqueries++;
+ d_outqueries++;
+
+ if(d_outqueries + d_throttledqueries > s_maxqperq) {
+ throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
+ }
+
+ if(s_maxtotusec && d_totUsec > s_maxtotusec) {
+ throw ImmediateServFailException("Too much time waiting for "+qname.toLogString()+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries) + ", queries: "+std::to_string(d_outqueries)+", "+std::to_string(d_totUsec/1000)+"msec");
+ }
+
+ if(doTCP) {
+ LOG(prefix<<qname<<": using TCP with "<< remoteIP.toStringWithPort() <<endl);
+ s_tcpoutqueries++;
+ d_tcpoutqueries++;
+ }
+
+ if(d_pdl && d_pdl->preoutquery(remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
+ LOG(prefix<<qname<<": query handled by Lua"<<endl);
+ }
+ else {
+ ednsmask=getEDNSSubnetMask(d_requestor, qname, remoteIP);
+ if(ednsmask) {
+ LOG(prefix<<qname<<": Adding EDNS Client Subnet Mask "<<ednsmask->toString()<<" to query"<<endl);
+ }
+ resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(),
+ doTCP, sendRDQuery, &d_now, ednsmask, &lwr); // <- we go out on the wire!
+ if(ednsmask) {
+ LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
+ }
+ }
+
+ /* preoutquery killed the query by setting dq.rcode to -3 */
+ if(resolveret==-3) {
+ throw ImmediateServFailException("Query killed by policy");
+ }
+
+ d_totUsec += lwr.d_usec;
+ accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
+
+ if(resolveret != 1) {
+ /* Error while resolving */
+ if(resolveret == 0) {
+ /* Time out */
+
+ LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
+ d_timeouts++;
+ s_outgoingtimeouts++;
+
+ if(remoteIP.sin4.sin_family == AF_INET)
+ s_outgoing4timeouts++;
+ else
+ s_outgoing6timeouts++;
+ }
+ else if(resolveret == -2) {
+ /* OS resource limit reached */
+ LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
+ g_stats.resourceLimits++;
+ }
+ else {
+ /* -1 means server unreachable */
+ s_unreachables++;
+ d_unreachables++;
+ 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
+ t_sstorage.nsSpeeds[nsName].submit(remoteIP, 1000000, &d_now); // 1 sec
+
+ // code below makes sure we don't filter COM or the root
+ if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP) >= s_serverdownmaxfails) {
+ LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP.toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
+ // mark server as down
+ t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0), s_serverdownthrottletime, 10000);
+ }
+ else if (resolveret == -1) {
+ // unreachable, 1 minute or 100 queries
+ t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 100);
+ }
+ else {
+ // timeout
+ t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 10, 5);
+ }
+ }
+
+ return false;
+ }
+
+ /* 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);
+ return false;
+ }
+
+ /* this server sent a valid answer, mark it backup up if it was down */
+ if(s_serverdownmaxfails > 0) {
+ t_sstorage.fails.clear(remoteIP);
+ }
+
+ if(lwr.d_tcbit) {
+ *truncated = true;
+
+ if (doTCP) {
+ LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
+ /* let's treat that as a ServFail answer from this server */
+ t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
+ return false;
+ }
+
+ return true;
+ }
+
+ return true;
+}
+
+bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode)
+{
+ string prefix;
+ if(doLog()) {
+ prefix=d_prefix;
+ prefix.append(depth, ' ');
+ }
+
+ if(s_minimumTTL) {
+ for(auto& rec : lwr.d_records) {
+ rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
+ }
+ }
+
+ *rcode = updateCacheFromRecords(prefix, lwr, qname, auth, wasForwarded, ednsmask);
+ if (*rcode != RCode::NoError) {
+ return true;
+ }
+
+ LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
+
+ set<DNSName> nsset;
+ bool realreferral=false, negindic=false;
+ DNSName newauth;
+ DNSName newtarget;
+
+ bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic);
+
+ if(done){
+ LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
+ *rcode = RCode::NoError;
+ return true;
+ }
+
+ if(!newtarget.empty()) {
+ if(newtarget == qname) {
+ LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
+ *rcode = RCode::ServFail;
+ return true;
+ }
+
+ if(depth > 10) {
+ LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
+ *rcode = RCode::ServFail;
+ return true;
+ }
+
+ LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
+
+ set<GetBestNSAnswer> beenthere2;
+ *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2);
+ return true;
+ }
+
+ if(lwr.d_rcode == RCode::NXDomain) {
+ LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
+
+ if(d_doDNSSEC)
+ addNXNSECS(ret, lwr.d_records);
+
+ *rcode = RCode::NXDomain;
+ return true;
+ }
+
+ if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
+ LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
+
+ if(d_doDNSSEC)
+ addNXNSECS(ret, lwr.d_records);
+
+ *rcode = RCode::NoError;
+ return true;
+ }
+
+ if(realreferral) {
+ LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
+ auth=newauth;
+
+ nameservers.clear();
+ for (auto const &nameserver : nsset) {
+ if (d_wantsRPZ) {
+ d_appliedPolicy = dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
+ if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
+ LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
+ *rcode = -2;
+ return true;
+ }
+ }
+ nameservers.insert({nameserver, {{}, false}});
+ }
+ LOG("looping to them"<<endl);
+ *gotNewServers = true;
+ return false;
+ }
+
+ return false;
+}
+
/** returns:
* -1 in case of no results
* -2 when a FilterEngine Policy was hit
}
return -1;
}
+
// this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
if(qname == *tns && qtype.getCode()==QType::A && rnameservers.size() > (size_t)(1+1*s_doIPv6)) {
LOG(prefix<<qname<<": Not using NS to resolve itself! ("<<(1+tns-rnameservers.cbegin())<<"/"<<rnameservers.size()<<")"<<endl);
typedef vector<ComboAddress> remoteIPs_t;
remoteIPs_t remoteIPs;
remoteIPs_t::const_iterator remoteIP;
- bool doTCP=false;
bool pierceDontQuery=false;
bool sendRDQuery=false;
boost::optional<Netmask> ednsmask;
LWResult lwr;
- if(tns->empty() && nameservers[*tns].first.empty() ) {
+ const bool wasForwarded = tns->empty() && (!nameservers[*tns].first.empty());
+ int rcode = RCode::NoError;
+ bool gotNewServers = false;
+
+ if(tns->empty() && !wasForwarded) {
LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
lwr.d_tcbit=false;
lwr.d_aabit=true;
+
+ /* we have received an answer, are we done ? */
+ bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode);
+ if (done) {
+ return rcode;
+ }
+ if (gotNewServers) {
+ break;
+ }
}
else {
+ /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet);
if(remoteIPs.empty()) {
for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
LOG(prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
+
if (throttledOrBlocked(prefix, *remoteIP, qname, qtype, pierceDontQuery)) {
continue;
}
- else {
- int resolveret;
- s_outqueries++; d_outqueries++;
- if(d_outqueries + d_throttledqueries > s_maxqperq) throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
- TryTCP:
- if(doTCP) {
- LOG(prefix<<qname<<": using TCP with "<< remoteIP->toStringWithPort() <<endl);
- s_tcpoutqueries++; d_tcpoutqueries++;
- }
-
- if(s_maxtotusec && d_totUsec > s_maxtotusec)
- throw ImmediateServFailException("Too much time waiting for "+qname.toLogString()+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries) + ", queries: "+std::to_string(d_outqueries)+", "+std::to_string(d_totUsec/1000)+"msec");
-
- if(d_pdl && d_pdl->preoutquery(*remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
- LOG(prefix<<qname<<": query handled by Lua"<<endl);
- }
- else {
- ednsmask=getEDNSSubnetMask(d_requestor, qname, *remoteIP);
- if(ednsmask) {
- LOG(prefix<<qname<<": Adding EDNS Client Subnet Mask "<<ednsmask->toString()<<" to query"<<endl);
- }
- resolveret=asyncresolveWrapper(*remoteIP, d_doDNSSEC, qname, qtype.getCode(),
- doTCP, sendRDQuery, &d_now, ednsmask, &lwr); // <- we go out on the wire!
- if(ednsmask) {
- LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
- }
+ bool truncated = false;
+ bool gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
+ *tns, *remoteIP, false, &truncated);
+ if (gotAnswer && truncated ) {
+ /* retry, over TCP this time */
+ gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
+ *tns, *remoteIP, true, &truncated);
+ }
- }
- if(resolveret==-3)
- throw ImmediateServFailException("Query killed by policy");
-
- d_totUsec += lwr.d_usec;
- accountAuthLatency(lwr.d_usec, remoteIP->sin4.sin_family);
- if(resolveret != 1) {
- if(resolveret==0) {
- LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
- d_timeouts++;
- s_outgoingtimeouts++;
- if(remoteIP->sin4.sin_family == AF_INET)
- s_outgoing4timeouts++;
- else
- s_outgoing6timeouts++;
- }
- else if(resolveret==-2) {
- LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
- g_stats.resourceLimits++;
- }
- else {
- s_unreachables++; d_unreachables++;
- 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
- t_sstorage->nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec
-
- // code below makes sure we don't filter COM or the root
- if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage->fails.incr(*remoteIP) >= s_serverdownmaxfails) {
- LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP->toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
- t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, "", 0), s_serverdownthrottletime, 10000); // mark server as down
- } else if(resolveret==-1)
- t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable, 1 minute or 100 queries
- else
- t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 10, 5); // timeout
- }
- continue;
- }
+ if (!gotAnswer) {
+ continue;
+ }
-// if(d_timeouts + 0.5*d_throttledqueries > 6.0 && d_timeouts > 2) throw ImmediateServFailException("Too much work resolving "+qname+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries));
+ LOG(prefix<<qname<<": Got "<<(unsigned int)lwr.d_records.size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
- if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
- LOG(prefix<<qname<<": "<<*tns<<" ("<<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); // servfail or refused
- continue;
- }
+ /* // for you IPv6 fanatics :-)
+ if(remoteIP->sin4.sin_family==AF_INET6)
+ lwr.d_usec/=3;
+ */
+ // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
- if(s_serverdownmaxfails > 0)
- t_sstorage->fails.clear(*remoteIP);
+ t_sstorage.nsSpeeds[*tns].submit(*remoteIP, lwr.d_usec, &d_now);
- break; // this IP address worked!
- wasLame:; // well, it didn't
- LOG(prefix<<qname<<": status=NS "<<*tns<<" ("<< remoteIP->toString() <<") is lame for '"<<auth<<"', trying sibling IP or NS"<<endl);
- t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // lame
+ /* we have received an answer, are we done ? */
+ bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode);
+ if (done) {
+ return rcode;
}
- }
-
- if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked
- continue;
-
- if(lwr.d_tcbit) {
- if(!doTCP) {
- doTCP=true;
- LOG(prefix<<qname<<": truncated bit set, retrying via TCP"<<endl);
- goto TryTCP;
+ if (gotNewServers) {
+ break;
}
- LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
- return RCode::ServFail;
+ /* was lame */
+ t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100);
}
- LOG(prefix<<qname<<": Got "<<(unsigned int)lwr.d_records.size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
-
- /* // for you IPv6 fanatics :-)
- if(remoteIP->sin4.sin_family==AF_INET6)
- lwr.d_usec/=3;
- */
- // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
-
- t_sstorage->nsSpeeds[*tns].submit(*remoteIP, lwr.d_usec, &d_now);
- }
-
- if(s_minimumTTL) {
- for(auto& rec : lwr.d_records) {
- rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
- }
- }
-
- RCode::rcodes_ rcode = updateCacheFromRecords(prefix, lwr, qname, auth, nameservers, *tns, ednsmask);
- if (rcode != RCode::NoError) {
- return rcode;
- }
- LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
-
- set<DNSName> nsset;
- bool realreferral=false, negindic=false, sawDS=false;
- DNSName newauth;
- DNSName newtarget;
-
- bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, sawDS);
-
- if(done){
- LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
- return 0;
- }
- if(!newtarget.empty()) {
- if(newtarget == qname) {
- LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
- return RCode::ServFail;
- }
- if(depth > 10) {
- LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
- return RCode::ServFail;
+ if (gotNewServers) {
+ break;
}
- LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
-
- set<GetBestNSAnswer> beenthere2;
- return doResolve(newtarget, qtype, ret, depth + 1, beenthere2);
- }
- if(lwr.d_rcode==RCode::NXDomain) {
- LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
- if(d_doDNSSEC)
- addNXNSECS(ret, lwr.d_records);
+ if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked
+ continue;
- return RCode::NXDomain;
- }
- if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
- LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
-
- if(d_doDNSSEC)
- addNXNSECS(ret, lwr.d_records);
- return 0;
- }
- else if(realreferral) {
- LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
- if(sawDS) {
- t_sstorage->dnssecmap[newauth]=true;
- /* for(const auto& e : t_sstorage->dnssecmap)
- cout<<e.first<<' ';
- cout<<endl;*/
- }
- auth=newauth;
-
- nameservers.clear();
- for (auto const &nameserver : nsset) {
- if (d_wantsRPZ) {
- d_appliedPolicy = luaconfsLocal->dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
- if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
- LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
- return -2;
- }
- }
- nameservers.insert({nameserver, {{}, false}});
- }
- LOG("looping to them"<<endl);
- break;
- }
- else if(!tns->empty()) { // means: not OOB, OOB == empty
- goto wasLame;
}
}
}
return result;
}
- if(g_ednsdomains.check(dn) || g_ednssubnets.match(rem)) {
+ if(s_ednsdomains.check(dn) || s_ednssubnets.match(rem)) {
bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit));
trunc.truncate(bits);
return boost::optional<Netmask>(Netmask(trunc, bits));
return result;
}
+void SyncRes::parseEDNSSubnetWhitelist(const std::string& wlist)
+{
+ vector<string> parts;
+ stringtok(parts, wlist, ",; ");
+ for(const auto& a : parts) {
+ try {
+ s_ednssubnets.addMask(Netmask(a));
+ }
+ catch(...) {
+ s_ednsdomains.add(DNSName(a));
+ }
+ }
+}
+
// used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret)
{
int SyncRes::getRootNS(struct timeval now, asyncresolve_t asyncCallback) {
SyncRes sr(now);
sr.setDoEDNS0(true);
- sr.setNoCache();
+ sr.setUpdatingRootNS();
sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off);
sr.setAsyncCallback(asyncCallback);
#include <boost/uuid/uuid_generators.hpp>
#endif
-void primeHints(void);
-
class RecursorLua4;
typedef map<
{
}
- struct timeval getOrMakeTime(struct timeval* tv)
+ void submit(int val, const struct timeval* tv)
{
- if(tv)
- return *tv;
- else {
- struct timeval ret;
- Utility::gettimeofday(&ret, 0);
- return ret;
- }
- }
-
- void submit(int val, struct timeval* tv)
- {
- struct timeval now=getOrMakeTime(tv);
+ struct timeval now=*tv;
if(d_needinit) {
d_last=now;
}
}
- double get(struct timeval* tv)
+ double get(const struct timeval* tv)
{
- struct timeval now=getOrMakeTime(tv);
+ struct timeval now=*tv;
float diff=makeFloat(d_lastget-now);
d_lastget=now;
float factor=exp(diff/60.0f); // is 1.0 or less
{
public:
enum LogMode { LogNone, Log, Store};
+ typedef std::function<int(const ComboAddress& ip, const DNSName& qdomain, int qtype, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult *lwr)> asyncresolve_t;
- explicit SyncRes(const struct timeval& now);
+ struct EDNSStatus
+ {
+ EDNSStatus() : mode(UNKNOWN), modeSetAt(0) {}
+ enum EDNSMode { UNKNOWN=0, EDNSOK=1, EDNSIGNORANT=2, NOEDNS=3 } mode;
+ time_t modeSetAt;
+ };
- typedef std::function<int(const ComboAddress& ip, const DNSName& qdomain, int qtype, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult *lwr)> asyncresolve_t;
+ //! This represents a number of decaying Ewmas, used to store performance per nameserver-name.
+ /** Modelled to work mostly like the underlying DecayingEwma. After you've called get,
+ d_best is filled out with the best address for this collection */
+ struct DecayingEwmaCollection
+ {
+ void submit(const ComboAddress& remote, int usecs, const struct timeval* now)
+ {
+ collection_t::iterator pos;
+ for(pos=d_collection.begin(); pos != d_collection.end(); ++pos)
+ if(pos->first==remote)
+ break;
+ if(pos!=d_collection.end()) {
+ pos->second.submit(usecs, now);
+ }
+ else {
+ DecayingEwma de;
+ de.submit(usecs, now);
+ d_collection.push_back(make_pair(remote, de));
+ }
+ }
+
+ double get(const struct timeval* now)
+ {
+ if(d_collection.empty())
+ return 0;
+ double ret=std::numeric_limits<double>::max();
+ double tmp;
+ for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) {
+ if((tmp=pos->second.get(now)) < ret) {
+ ret=tmp;
+ d_best=pos->first;
+ }
+ }
+
+ return ret;
+ }
+
+ bool stale(time_t limit) const
+ {
+ for(collection_t::const_iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos)
+ if(!pos->second.stale(limit))
+ return false;
+ return true;
+ }
+
+ typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
+ collection_t d_collection;
+ ComboAddress d_best;
+ };
+
+ typedef map<DNSName, DecayingEwmaCollection> nsspeeds_t;
+ typedef map<ComboAddress, EDNSStatus> ednsstatus_t;
+
+ class AuthDomain
+ {
+ public:
+ typedef multi_index_container <
+ DNSRecord,
+ indexed_by <
+ ordered_non_unique<
+ composite_key< DNSRecord,
+ member<DNSRecord, DNSName, &DNSRecord::d_name>,
+ member<DNSRecord, uint16_t, &DNSRecord::d_type>
+ >,
+ composite_key_compare<std::less<DNSName>, std::less<uint16_t> >
+ >
+ >
+ > records_t;
+
+ records_t d_records;
+ vector<ComboAddress> d_servers;
+ DNSName d_name;
+ bool d_rdForward{false};
+
+ int getRecords(const DNSName& qname, uint16_t qtype, std::vector<DNSRecord>& records) const;
+ bool isAuth() const
+ {
+ return d_servers.empty();
+ }
+ bool isForward() const
+ {
+ return !isAuth();
+ }
+ bool shouldRecurse() const
+ {
+ return d_rdForward;
+ }
+ const DNSName& getName() const
+ {
+ return d_name;
+ }
+
+ private:
+ void addSOA(std::vector<DNSRecord>& records) const;
+ };
+
+ typedef map<DNSName, AuthDomain> domainmap_t;
+ typedef Throttle<boost::tuple<ComboAddress,DNSName,uint16_t> > throttle_t;
+ typedef Counters<ComboAddress> fails_t;
+
+ struct ThreadLocalStorage {
+ NegCache negcache;
+ nsspeeds_t nsSpeeds;
+ throttle_t throttle;
+ ednsstatus_t ednsstatus;
+ fails_t fails;
+ std::shared_ptr<domainmap_t> domainmap;
+ };
+
+ static void setDefaultLogMode(LogMode lm)
+ {
+ s_lm = lm;
+ }
+ static void doEDNSDumpAndClose(int fd);
+ static uint64_t doDumpNSSpeeds(int fd);
+ static int getRootNS(struct timeval now, asyncresolve_t asyncCallback);
+ static void clearDelegationOnly()
+ {
+ s_delegationOnly.clear();
+ }
+ static void addDelegationOnly(const DNSName& name)
+ {
+ s_delegationOnly.insert(name);
+ }
+ static void addDontQuery(const std::string& mask)
+ {
+ if (!s_dontQuery)
+ s_dontQuery = std::unique_ptr<NetmaskGroup>(new NetmaskGroup());
+
+ s_dontQuery->addMask(mask);
+ }
+ static void addDontQuery(const Netmask& mask)
+ {
+ if (!s_dontQuery)
+ s_dontQuery = std::unique_ptr<NetmaskGroup>(new NetmaskGroup());
+
+ s_dontQuery->addMask(mask);
+ }
+ static void clearDontQuery()
+ {
+ s_dontQuery = nullptr;
+ }
+ static void parseEDNSSubnetWhitelist(const std::string& wlist);
+ static void addEDNSSubnet(const Netmask& subnet)
+ {
+ s_ednssubnets.addMask(subnet);
+ }
+ static void addEDNSDomain(const DNSName& domain)
+ {
+ s_ednsdomains.add(domain);
+ }
+ static void clearEDNSSubnets()
+ {
+ s_ednssubnets.clear();
+ }
+ static void clearEDNSDomains()
+ {
+ s_ednsdomains = SuffixMatchNode();
+ }
+ static void pruneNSSpeeds(time_t limit)
+ {
+ for(auto i = t_sstorage.nsSpeeds.begin(), end = t_sstorage.nsSpeeds.end(); i != end; ) {
+ if(i->second.stale(limit)) {
+ i = t_sstorage.nsSpeeds.erase(i);
+ }
+ else {
+ ++i;
+ }
+ }
+ }
+ static uint64_t getNSSpeedsSize()
+ {
+ return t_sstorage.nsSpeeds.size();
+ }
+ static void submitNSSpeed(const DNSName& server, const ComboAddress& ca, uint32_t usec, const struct timeval* now)
+ {
+ t_sstorage.nsSpeeds[server].submit(ca, usec, now);
+ }
+ static void clearNSSpeeds()
+ {
+ t_sstorage.nsSpeeds.clear();
+ }
+ static EDNSStatus::EDNSMode getEDNSStatus(const ComboAddress& server)
+ {
+ const auto& it = t_sstorage.ednsstatus.find(server);
+ if (it == t_sstorage.ednsstatus.end())
+ return EDNSStatus::UNKNOWN;
+
+ return it->second.mode;
+ }
+ static uint64_t getEDNSStatusesSize()
+ {
+ return t_sstorage.ednsstatus.size();
+ }
+ static void clearEDNSStatuses()
+ {
+ t_sstorage.ednsstatus.clear();
+ }
+ static uint64_t getThrottledServersSize()
+ {
+ return t_sstorage.throttle.size();
+ }
+ static void clearThrottle()
+ {
+ t_sstorage.throttle.clear();
+ }
+ static bool isThrottled(time_t now, const ComboAddress& server, const DNSName& target, uint16_t qtype)
+ {
+ return t_sstorage.throttle.shouldThrottle(now, boost::make_tuple(server, target, qtype));
+ }
+ static bool isThrottled(time_t now, const ComboAddress& server)
+ {
+ return t_sstorage.throttle.shouldThrottle(now, boost::make_tuple(server, "", 0));
+ }
+ static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries)
+ {
+ t_sstorage.throttle.throttle(now, boost::make_tuple(server, "", 0), duration, tries);
+ }
+ static uint64_t getFailedServersSize()
+ {
+ return t_sstorage.fails.size();
+ }
+ static void clearFailedServers()
+ {
+ t_sstorage.fails.clear();
+ }
+ static unsigned long getServerFailsCount(const ComboAddress& server)
+ {
+ return t_sstorage.fails.value(server);
+ }
+
+ static void clearNegCache()
+ {
+ t_sstorage.negcache.clear();
+ }
+
+ static uint64_t getNegCacheSize()
+ {
+ return t_sstorage.negcache.size();
+ }
+
+ static void pruneNegCache(unsigned int maxEntries)
+ {
+ t_sstorage.negcache.prune(maxEntries);
+ }
+
+ static uint64_t wipeNegCache(const DNSName& name, bool subtree = false)
+ {
+ return t_sstorage.negcache.wipe(name, subtree);
+ }
+
+ static void setDomainMap(std::shared_ptr<domainmap_t> newMap)
+ {
+ t_sstorage.domainmap = newMap;
+ }
+
+ static const std::shared_ptr<domainmap_t> getDomainMap()
+ {
+ return t_sstorage.domainmap;
+ }
+
+ explicit SyncRes(const struct timeval& now);
int beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret);
void setId(int id)
if(doLog())
d_prefix="["+itoa(id)+"] ";
}
- static void setDefaultLogMode(LogMode lm)
- {
- s_lm = lm;
- }
void setLogMode(LogMode lm)
{
{
d_cacheonly=state;
}
- void setNoCache(bool state=true)
- {
- d_nocache=state;
- }
void setDoEDNS0(bool state=true)
{
d_asyncResolve = func;
}
- static void doEDNSDumpAndClose(int fd);
- static int getRootNS(struct timeval now, asyncresolve_t asyncCallback);
+ static thread_local ThreadLocalStorage t_sstorage;
static std::atomic<uint64_t> s_queries;
static std::atomic<uint64_t> s_outgoingtimeouts;
static std::atomic<uint64_t> s_tcpoutqueries;
static std::atomic<uint64_t> s_nodelegated;
static std::atomic<uint64_t> s_unreachables;
+
+ static string s_serverID;
static unsigned int s_minimumTTL;
- static bool s_doIPv6;
static unsigned int s_maxqperq;
static unsigned int s_maxtotusec;
static unsigned int s_maxdepth;
+ static unsigned int s_maxnegttl;
+ static unsigned int s_maxcachettl;
+ static unsigned int s_packetcachettl;
+ static unsigned int s_packetcacheservfailttl;
+ static unsigned int s_serverdownmaxfails;
+ static unsigned int s_serverdownthrottletime;
+ static uint8_t s_ecsipv4limit;
+ static uint8_t s_ecsipv6limit;
+ static bool s_doIPv6;
+ static bool s_noEDNSPing;
+ static bool s_noEDNS;
+ static bool s_rootNXTrust;
+ static bool s_nopacketcache;
+
std::unordered_map<std::string,bool> d_discardedPolicies;
DNSFilterEngine::Policy d_appliedPolicy;
unsigned int d_outqueries;
unsigned int d_totUsec;
ComboAddress d_requestor;
- //! This represents a number of decaying Ewmas, used to store performance per nameserver-name.
- /** Modelled to work mostly like the underlying DecayingEwma. After you've called get,
- d_best is filled out with the best address for this collection */
- struct DecayingEwmaCollection
- {
- void submit(const ComboAddress& remote, int usecs, struct timeval* now)
- {
- collection_t::iterator pos;
- for(pos=d_collection.begin(); pos != d_collection.end(); ++pos)
- if(pos->first==remote)
- break;
- if(pos!=d_collection.end()) {
- pos->second.submit(usecs, now);
- }
- else {
- DecayingEwma de;
- de.submit(usecs, now);
- d_collection.push_back(make_pair(remote, de));
- }
- }
-
- double get(struct timeval* now)
- {
- if(d_collection.empty())
- return 0;
- double ret=std::numeric_limits<double>::max();
- double tmp;
- for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) {
- if((tmp=pos->second.get(now)) < ret) {
- ret=tmp;
- d_best=pos->first;
- }
- }
+private:
- return ret;
- }
+ static std::unordered_set<DNSName> s_delegationOnly;
+ static NetmaskGroup s_ednssubnets;
+ static SuffixMatchNode s_ednsdomains;
+ static LogMode s_lm;
+ static std::unique_ptr<NetmaskGroup> s_dontQuery;
- bool stale(time_t limit) const
+ struct GetBestNSAnswer
+ {
+ DNSName qname;
+ set<pair<DNSName,DNSName> > bestns;
+ uint8_t qtype; // only A and AAAA anyhow
+ bool operator<(const GetBestNSAnswer &b) const
{
- for(collection_t::const_iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos)
- if(!pos->second.stale(limit))
- return false;
- return true;
+ return boost::tie(qname, qtype, bestns) <
+ boost::tie(b.qname, b.qtype, b.bestns);
}
-
- typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
- collection_t d_collection;
- ComboAddress d_best;
- };
-
- typedef map<DNSName, DecayingEwmaCollection> nsspeeds_t;
-
- struct EDNSStatus
- {
- EDNSStatus() : mode(UNKNOWN), modeSetAt(0) {}
- enum EDNSMode { UNKNOWN=0, EDNSOK=1, EDNSIGNORANT=2, NOEDNS=3 } mode;
- time_t modeSetAt;
- };
-
- typedef map<ComboAddress, EDNSStatus> ednsstatus_t;
-
- static bool s_noEDNSPing;
- static bool s_noEDNS;
- static bool s_rootNXTrust;
- struct AuthDomain
- {
- vector<ComboAddress> d_servers;
- bool d_rdForward;
- typedef multi_index_container <
- DNSRecord,
- indexed_by <
- ordered_non_unique<
- composite_key< DNSRecord,
- member<DNSRecord, DNSName, &DNSRecord::d_name>,
- member<DNSRecord, uint16_t, &DNSRecord::d_type>
- >,
- composite_key_compare<std::less<DNSName>, std::less<uint16_t> >
- >
- >
- > records_t;
- records_t d_records;
};
-
- typedef map<DNSName, AuthDomain> domainmap_t;
-
-
- typedef Throttle<boost::tuple<ComboAddress,DNSName,uint16_t> > throttle_t;
-
- typedef Counters<ComboAddress> fails_t;
-
- static unsigned int s_maxnegttl;
- static unsigned int s_maxcachettl;
- static unsigned int s_packetcachettl;
- static unsigned int s_packetcacheservfailttl;
- static unsigned int s_serverdownmaxfails;
- static unsigned int s_serverdownthrottletime;
- static uint8_t s_ecsipv4limit;
- static uint8_t s_ecsipv6limit;
- static bool s_nopacketcache;
- static string s_serverID;
-
- struct StaticStorage {
- nsspeeds_t nsSpeeds;
- ednsstatus_t ednsstatus;
- throttle_t throttle;
- fails_t fails;
- domainmap_t* domainmap;
- map<DNSName, bool> dnssecmap;
- NegCache negcache;
- };
-
-private:
- struct GetBestNSAnswer;
int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret,
unsigned int depth, set<GetBestNSAnswer>&beenthere);
+ bool 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);
+ bool processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode);
+
int doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere);
+ bool doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res) const;
bool doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res);
domainmap_t::const_iterator getBestAuthZone(DNSName* qname) const;
bool doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res);
bool throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery);
vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<DNSName >::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<DNSName >& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet);
- RCode::rcodes_ updateCacheFromRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, NsSet& nameservers, const DNSName& tns, const boost::optional<Netmask>);
- bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, bool& sawDS);
+ RCode::rcodes_ updateCacheFromRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>);
+ bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic);
- bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t &qclass, vector<DNSRecord> &ret);
+ bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret);
int 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;
boost::optional<Netmask> getEDNSSubnetMask(const ComboAddress& local, const DNSName&dn, const ComboAddress& rem);
+ void setUpdatingRootNS()
+ {
+ d_updatingRootNS = true;
+ }
+
+
ostringstream d_trace;
shared_ptr<RecursorLua4> d_pdl;
boost::optional<const EDNSSubnetOpts&> d_incomingECS;
* This is set when the RD bit is unset in the incoming query
*/
bool d_cacheonly;
- /* d_nocache is *only* set in getRootNS() (in pdns_recursor.cc).
- * It forces us to not look in the cache or local auth.
- */
- bool d_nocache;
bool d_doDNSSEC;
bool d_doEDNS0{true};
bool d_incomingECSFound{false};
bool d_skipCNAMECheck{false};
+ bool d_updatingRootNS{false};
bool d_wantsRPZ{true};
bool d_wasOutOfBand{false};
bool d_wasVariable{false};
- static LogMode s_lm;
LogMode d_lm;
-
- struct GetBestNSAnswer
- {
- DNSName qname;
- set<pair<DNSName,DNSName> > bestns;
- uint8_t qtype; // only A and AAAA anyhow
- bool operator<(const GetBestNSAnswer &b) const
- {
- return boost::tie(qname, qtype, bestns) <
- boost::tie(b.qname, b.qtype, b.bestns);
- }
- };
-
};
-extern __thread SyncRes::StaticStorage* t_sstorage;
class Socket;
/* external functions, opaque to us */
return a.domain < b.domain;
}
};
-extern __thread MemRecursorCache* t_RC;
-extern __thread RecursorPacketCache* t_packetCache;
+extern thread_local std::unique_ptr<MemRecursorCache> t_RC;
+extern thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
typedef MTasker<PacketID,string> MT_t;
-extern __thread MT_t* MT;
+extern thread_local std::unique_ptr<MT_t> MT;
struct RecursorStats
{
#else
typedef boost::circular_buffer<ComboAddress> addrringbuf_t;
#endif
-extern __thread addrringbuf_t* t_servfailremotes, *t_largeanswerremotes, *t_remotes;
+extern thread_local std::unique_ptr<addrringbuf_t> t_servfailremotes, t_largeanswerremotes, t_remotes;
-extern __thread boost::circular_buffer<pair<DNSName,uint16_t> >* t_queryring, *t_servfailqueryring;
-extern __thread NetmaskGroup* t_allowFrom;
+extern thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName,uint16_t> > > t_queryring, t_servfailqueryring;
+extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end);
string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end);
void parseACLs();
extern RecursorStats g_stats;
extern unsigned int g_numThreads;
-extern std::unordered_set<DNSName> g_delegationOnly;
extern uint16_t g_outgoingEDNSBufsize;
template<class T> T broadcastAccFunction(const boost::function<T*()>& func, bool skipSelf=false);
-SyncRes::domainmap_t* parseAuthAndForwards();
+std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards();
uint64_t* pleaseGetNsSpeedsSize();
uint64_t* pleaseGetCacheSize();
uint64_t* pleaseGetNegCacheSize();
uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree);
uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree=false);
void doCarbonDump(void*);
-void parseEDNSSubnetWhitelist(const std::string& wlist);
+void primeHints(void);
extern __thread struct timeval g_now;
-extern NetmaskGroup g_ednssubnets;
-extern SuffixMatchNode g_ednsdomains;
-
#ifdef HAVE_PROTOBUF
-extern __thread boost::uuids::random_generator* t_uuidGenerator;
+extern thread_local std::unique_ptr<boost::uuids::random_generator> t_uuidGenerator;
#endif
#include "logger.hh"
#include "ext/incbin/incbin.h"
-extern __thread FDMultiplexer* t_fdm;
+extern thread_local FDMultiplexer* t_fdm;
using json11::Json;
static void fillZone(const DNSName& zonename, HttpResponse* resp)
{
- auto iter = t_sstorage->domainmap->find(zonename);
- if (iter == t_sstorage->domainmap->end())
+ auto iter = SyncRes::t_sstorage.domainmap->find(zonename);
+ if (iter == SyncRes::t_sstorage.domainmap->end())
throw ApiException("Could not find domain '"+zonename.toString()+"'");
const SyncRes::AuthDomain& zone = iter->second;
DNSName zonename = apiNameToDNSName(stringFromJson(document, "name"));
- auto iter = t_sstorage->domainmap->find(zonename);
- if (iter != t_sstorage->domainmap->end())
+ auto iter = SyncRes::t_sstorage.domainmap->find(zonename);
+ if (iter != SyncRes::t_sstorage.domainmap->end())
throw ApiException("Zone already exists");
doCreateZone(document);
throw HttpMethodNotAllowedException();
Json::array doc;
- for(const SyncRes::domainmap_t::value_type& val : *t_sstorage->domainmap) {
+ for(const SyncRes::domainmap_t::value_type& val : *SyncRes::t_sstorage.domainmap) {
const SyncRes::AuthDomain& zone = val.second;
Json::array servers;
for(const ComboAddress& server : zone.d_servers) {
{
DNSName zonename = apiZoneIdToName(req->parameters["id"]);
- SyncRes::domainmap_t::const_iterator iter = t_sstorage->domainmap->find(zonename);
- if (iter == t_sstorage->domainmap->end())
+ SyncRes::domainmap_t::const_iterator iter = SyncRes::t_sstorage.domainmap->find(zonename);
+ if (iter == SyncRes::t_sstorage.domainmap->end())
throw ApiException("Could not find domain '"+zonename.toString()+"'");
if(req->method == "PUT" && !::arg().mustDo("api-readonly")) {
throw ApiException("Query q can't be blank");
Json::array doc;
- for(const SyncRes::domainmap_t::value_type& val : *t_sstorage->domainmap) {
+ for(const SyncRes::domainmap_t::value_type& val : *SyncRes::t_sstorage.domainmap) {
string zoneId = apiZoneNameToId(val.first);
string zoneName = val.first.toString();
if (pdns_ci_find(zoneName, q) != string::npos) {