]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/syncres.cc
rec: Cleanup global variables usage in `SyncRes`
[thirdparty/pdns.git] / pdns / syncres.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <boost/algorithm/string.hpp>
26
27 #include "lua-recursor4.hh"
28 #include "utility.hh"
29 #include "syncres.hh"
30 #include <iostream>
31 #include <map>
32 #include "dnsrecords.hh"
33 #include <algorithm>
34 #include <set>
35 #include <cerrno>
36 #include <cstdio>
37 #include <cstdlib>
38 #include <utility>
39 #include <deque>
40 #include "logger.hh"
41 #include "validate.hh"
42 #include "misc.hh"
43 #include "arguments.hh"
44 #include "lwres.hh"
45 #include "recursor_cache.hh"
46 #include "dnsparser.hh"
47 #include "dns_random.hh"
48 #include "lock.hh"
49 #include "ednssubnet.hh"
50 #include "cachecleaner.hh"
51 #include "rec-lua-conf.hh"
52 __thread SyncRes::StaticStorage* t_sstorage;
53
54 unsigned int SyncRes::s_maxnegttl;
55 unsigned int SyncRes::s_maxcachettl;
56 unsigned int SyncRes::s_packetcachettl;
57 unsigned int SyncRes::s_packetcacheservfailttl;
58 unsigned int SyncRes::s_serverdownmaxfails;
59 unsigned int SyncRes::s_serverdownthrottletime;
60 std::atomic<uint64_t> SyncRes::s_queries;
61 std::atomic<uint64_t> SyncRes::s_outgoingtimeouts;
62 std::atomic<uint64_t> SyncRes::s_outgoing4timeouts;
63 std::atomic<uint64_t> SyncRes::s_outgoing6timeouts;
64 std::atomic<uint64_t> SyncRes::s_outqueries;
65 std::atomic<uint64_t> SyncRes::s_tcpoutqueries;
66 std::atomic<uint64_t> SyncRes::s_throttledqueries;
67 std::atomic<uint64_t> SyncRes::s_dontqueries;
68 std::atomic<uint64_t> SyncRes::s_nodelegated;
69 std::atomic<uint64_t> SyncRes::s_unreachables;
70 uint8_t SyncRes::s_ecsipv4limit;
71 uint8_t SyncRes::s_ecsipv6limit;
72 unsigned int SyncRes::s_minimumTTL;
73 bool SyncRes::s_doIPv6;
74 bool SyncRes::s_nopacketcache;
75 bool SyncRes::s_rootNXTrust;
76 unsigned int SyncRes::s_maxqperq;
77 unsigned int SyncRes::s_maxtotusec;
78 unsigned int SyncRes::s_maxdepth;
79 string SyncRes::s_serverID;
80 SyncRes::LogMode SyncRes::s_lm;
81 std::unordered_set<DNSName> SyncRes::s_delegationOnly;
82 std::unique_ptr<NetmaskGroup> SyncRes::s_dontQuery{nullptr};
83 NetmaskGroup SyncRes::s_ednssubnets;
84 SuffixMatchNode SyncRes::s_ednsdomains;
85
86 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
87
88 bool SyncRes::s_noEDNS;
89
90 static void accountAuthLatency(int usec, int family)
91 {
92 if(family == AF_INET) {
93 if(usec < 1000)
94 g_stats.auth4Answers0_1++;
95 else if(usec < 10000)
96 g_stats.auth4Answers1_10++;
97 else if(usec < 100000)
98 g_stats.auth4Answers10_100++;
99 else if(usec < 1000000)
100 g_stats.auth4Answers100_1000++;
101 else
102 g_stats.auth4AnswersSlow++;
103 } else {
104 if(usec < 1000)
105 g_stats.auth6Answers0_1++;
106 else if(usec < 10000)
107 g_stats.auth6Answers1_10++;
108 else if(usec < 100000)
109 g_stats.auth6Answers10_100++;
110 else if(usec < 1000000)
111 g_stats.auth6Answers100_1000++;
112 else
113 g_stats.auth6AnswersSlow++;
114 }
115
116 }
117
118
119 SyncRes::SyncRes(const struct timeval& now) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
120 d_totUsec(0), d_now(now),
121 d_cacheonly(false), d_nocache(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm)
122
123 {
124 if(!t_sstorage) {
125 t_sstorage = new StaticStorage();
126 }
127 }
128
129 /** everything begins here - this is the entry point just after receiving a packet */
130 int SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret)
131 {
132 s_queries++;
133 d_wasVariable=false;
134 d_wasOutOfBand=false;
135
136 if (doSpecialNamesResolve(qname, qtype, qclass, ret))
137 return 0;
138
139 if( (qtype.getCode() == QType::AXFR) || (qtype.getCode() == QType::IXFR))
140 return -1;
141
142 if(qclass==QClass::ANY)
143 qclass=QClass::IN;
144 else if(qclass!=QClass::IN)
145 return -1;
146
147 set<GetBestNSAnswer> beenthere;
148 int res=doResolve(qname, qtype, ret, 0, beenthere);
149 return res;
150 }
151
152 /*! Handles all special, built-in names
153 * Fills ret with an answer and returns true if it handled the query.
154 *
155 * Handles the following queries (and their ANY variants):
156 *
157 * - localhost. IN A
158 * - localhost. IN AAAA
159 * - 1.0.0.127.in-addr.arpa. IN PTR
160 * - 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. IN PTR
161 * - version.bind. CH TXT
162 * - version.pdns. CH TXT
163 * - id.server. CH TXT
164 */
165 bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t &qclass, vector<DNSRecord> &ret)
166 {
167 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."),
168 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
169
170 bool handled = false;
171 vector<pair<QType::typeenum, string> > answers;
172
173 if ((qname == arpa || qname == ip6_arpa) &&
174 qclass == QClass::IN) {
175 handled = true;
176 if (qtype == QType::PTR || qtype == QType::ANY)
177 answers.push_back({QType::PTR, "localhost."});
178 }
179
180 if (qname == localhost &&
181 qclass == QClass::IN) {
182 handled = true;
183 if (qtype == QType::A || qtype == QType::ANY)
184 answers.push_back({QType::A, "127.0.0.1"});
185 if (qtype == QType::AAAA || qtype == QType::ANY)
186 answers.push_back({QType::AAAA, "::1"});
187 }
188
189 if ((qname == versionbind || qname == idserver || qname == versionpdns) &&
190 qclass == QClass::CHAOS) {
191 handled = true;
192 if (qtype == QType::TXT || qtype == QType::ANY) {
193 if(qname == versionbind || qname == versionpdns)
194 answers.push_back({QType::TXT, "\""+::arg()["version-string"]+"\""});
195 else
196 answers.push_back({QType::TXT, "\""+s_serverID+"\""});
197 }
198 }
199
200 if (handled && !answers.empty()) {
201 ret.clear();
202 d_wasOutOfBand=true;
203
204 DNSRecord dr;
205 dr.d_name = qname;
206 dr.d_place = DNSResourceRecord::ANSWER;
207 dr.d_class = qclass;
208 dr.d_ttl = 86400;
209 for (const auto& ans : answers) {
210 dr.d_type = ans.first;
211 dr.d_content = shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(ans.first, qclass, ans.second));
212 ret.push_back(dr);
213 }
214 }
215
216 return handled;
217 }
218
219
220 //! This is the 'out of band resolver', in other words, the authoritative server
221 bool SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int& res)
222 {
223 string prefix;
224 if(doLog()) {
225 prefix=d_prefix;
226 prefix.append(depth, ' ');
227 }
228
229 LOG(prefix<<qname<<": checking auth storage for '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
230 DNSName authdomain(qname);
231
232 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
233 if(iter==t_sstorage->domainmap->end()) {
234 LOG(prefix<<qname<<": auth storage has no zone for this query!"<<endl);
235 return false;
236 }
237 LOG(prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl);
238 pair<AuthDomain::records_t::const_iterator, AuthDomain::records_t::const_iterator> range;
239
240 range=iter->second.d_records.equal_range(tie(qname)); // partial lookup
241
242 ret.clear();
243 AuthDomain::records_t::const_iterator ziter;
244 bool somedata=false;
245 for(ziter=range.first; ziter!=range.second; ++ziter) {
246 somedata=true;
247 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
248 ret.push_back(*ziter);
249 else if(ziter->d_type == QType::NS && ziter->d_name.countLabels() > authdomain.countLabels()) { // we hit a delegation point!
250 DNSRecord dr=*ziter;
251 dr.d_place=DNSResourceRecord::AUTHORITY;
252 ret.push_back(dr);
253 }
254 }
255 if(!ret.empty()) {
256 LOG(prefix<<qname<<": exact match in zone '"<<authdomain<<"'"<<endl);
257 res=0;
258 return true;
259 }
260 if(somedata) {
261 LOG(prefix<<qname<<": found record in '"<<authdomain<<"', but nothing of the right type, sending SOA"<<endl);
262 ziter=iter->second.d_records.find(boost::make_tuple(authdomain, QType::SOA));
263 if(ziter!=iter->second.d_records.end()) {
264 DNSRecord dr=*ziter;
265 dr.d_place=DNSResourceRecord::AUTHORITY;
266 ret.push_back(dr);
267 }
268 else
269 LOG(prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl);
270 res=RCode::NoError;
271 return true;
272 }
273
274 LOG(prefix<<qname<<": nothing found so far in '"<<authdomain<<"', trying wildcards"<<endl);
275 DNSName wcarddomain(qname);
276 while(wcarddomain != iter->first && wcarddomain.chopOff()) {
277 LOG(prefix<<qname<<": trying '*."<<wcarddomain<<"' in "<<authdomain<<endl);
278 range=iter->second.d_records.equal_range(boost::make_tuple(g_wildcarddnsname+wcarddomain));
279 if(range.first==range.second)
280 continue;
281
282 for(ziter=range.first; ziter!=range.second; ++ziter) {
283 DNSRecord dr=*ziter;
284 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
285 if(dr.d_type == qtype.getCode() || qtype.getCode() == QType::ANY || dr.d_type == QType::CNAME) {
286 dr.d_name = qname;
287 dr.d_place=DNSResourceRecord::ANSWER;
288 ret.push_back(dr);
289 }
290 }
291 LOG(prefix<<qname<<": in '"<<authdomain<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl);
292 res=RCode::NoError;
293 return true;
294 }
295
296 DNSName nsdomain(qname);
297
298 while(nsdomain.chopOff() && nsdomain != iter->first) {
299 range=iter->second.d_records.equal_range(boost::make_tuple(nsdomain,QType::NS));
300 if(range.first==range.second)
301 continue;
302
303 for(ziter=range.first; ziter!=range.second; ++ziter) {
304 DNSRecord dr=*ziter;
305 dr.d_place=DNSResourceRecord::AUTHORITY;
306 ret.push_back(dr);
307 }
308 }
309 if(ret.empty()) {
310 LOG(prefix<<qname<<": no NS match in zone '"<<authdomain<<"' either, handing out SOA"<<endl);
311 ziter=iter->second.d_records.find(boost::make_tuple(authdomain, QType::SOA));
312 if(ziter!=iter->second.d_records.end()) {
313 DNSRecord dr=*ziter;
314 dr.d_place=DNSResourceRecord::AUTHORITY;
315 ret.push_back(dr);
316 }
317 else {
318 LOG(prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl);
319 }
320 res=RCode::NXDomain;
321 }
322 else
323 res=0;
324
325 return true;
326 }
327
328 void SyncRes::doEDNSDumpAndClose(int fd)
329 {
330 FILE* fp=fdopen(fd, "w");
331 if (!fp) {
332 return;
333 }
334 fprintf(fp,"IP Address\tMode\tMode last updated at\n");
335 for(const auto& eds : t_sstorage->ednsstatus) {
336 fprintf(fp, "%s\t%d\t%s", eds.first.toString().c_str(), (int)eds.second.mode, ctime(&eds.second.modeSetAt));
337 }
338
339 fclose(fp);
340 }
341
342 uint64_t SyncRes::doDumpNSSpeeds(int fd)
343 {
344 FILE* fp=fdopen(dup(fd), "w");
345 if(!fp)
346 return 0;
347 fprintf(fp, "; nsspeed dump from thread follows\n;\n");
348 uint64_t count=0;
349
350 for(const auto& i : t_sstorage->nsSpeeds)
351 {
352 count++;
353 fprintf(fp, "%s -> ", i.first.toString().c_str());
354 for(const auto& j : i.second.d_collection)
355 {
356 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
357 fprintf(fp, "%s/%f ", j.first.toString().c_str(), j.second.peek());
358 }
359 fprintf(fp, "\n");
360 }
361 fclose(fp);
362 return count;
363 }
364
365 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
366 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
367 so that if there are RRSIGs for a name, we'll have them.
368
369 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
370 * No answer
371 * FormErr
372 * Nonsense answer
373
374 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
375 Another cause of "No answer" may simply be a network condition.
376 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
377
378 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
379 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
380 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
381 elsewhere. It may not have happened yet.
382
383 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
384 */
385
386 int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res) const
387 {
388 /* what is your QUEST?
389 the goal is to get as many remotes as possible on the highest level of EDNS support
390 The levels are:
391
392 0) UNKNOWN Unknown state
393 1) EDNS: Honors EDNS0
394 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
395 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
396
397 Everybody starts out assumed to be '0'.
398 If '0', send out EDNS0
399 If you FORMERR us, go to '3',
400 If no EDNS in response, go to '2'
401 If '1', send out EDNS0
402 If FORMERR, downgrade to 3
403 If '2', keep on including EDNS0, see what happens
404 Same behaviour as 0
405 If '3', send bare queries
406 */
407
408 SyncRes::EDNSStatus* ednsstatus;
409 ednsstatus = &t_sstorage->ednsstatus[ip]; // does this include port? YES
410
411 if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
412 *ednsstatus=SyncRes::EDNSStatus();
413 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
414 }
415
416 SyncRes::EDNSStatus::EDNSMode& mode=ednsstatus->mode;
417 SyncRes::EDNSStatus::EDNSMode oldmode = mode;
418 int EDNSLevel=0;
419 auto luaconfsLocal = g_luaconfs.getLocal();
420 ResolveContext ctx;
421 #ifdef HAVE_PROTOBUF
422 ctx.d_initialRequestId = d_initialRequestId;
423 #endif
424
425 int ret;
426 for(int tries = 0; tries < 3; ++tries) {
427 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
428
429 if(mode==EDNSStatus::NOEDNS) {
430 g_stats.noEdnsOutQueries++;
431 EDNSLevel = 0; // level != mode
432 }
433 else if(ednsMANDATORY || mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode==EDNSStatus::EDNSIGNORANT)
434 EDNSLevel = 1;
435
436 if (d_asyncResolve) {
437 ret = d_asyncResolve(ip, domain, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res);
438 }
439 else {
440 ret=asyncresolve(ip, domain, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res);
441 }
442 if(ret < 0) {
443 return ret; // transport error, nothing to learn here
444 }
445
446 if(ret == 0) { // timeout, not doing anything with it now
447 return ret;
448 }
449 else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) {
450 if(res->d_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp) {
451 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
452 mode = EDNSStatus::NOEDNS;
453 continue;
454 }
455 else if(!res->d_haveEDNS) {
456 if(mode != EDNSStatus::EDNSIGNORANT) {
457 mode = EDNSStatus::EDNSIGNORANT;
458 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
459 }
460 }
461 else {
462 mode = EDNSStatus::EDNSOK;
463 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
464 }
465
466 }
467 if(oldmode != mode || !ednsstatus->modeSetAt)
468 ednsstatus->modeSetAt=d_now.tv_sec;
469 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
470 return ret;
471 }
472 return ret;
473 }
474
475 /*! This function will check the cache and go out to the internet if the answer is not in cache
476 *
477 * \param qname The name we need an answer for
478 * \param qtype
479 * \param ret The vector of DNSRecords we need to fill with the answers
480 * \param depth The recursion depth we are in
481 * \param beenthere
482 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
483 */
484 int SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere)
485 {
486 string prefix;
487 if(doLog()) {
488 prefix=d_prefix;
489 prefix.append(depth, ' ');
490 }
491
492 LOG(prefix<<qname<<": Wants "<< (d_doDNSSEC ? "" : "NO ") << "DNSSEC processing in query for "<<qtype.getName()<<endl);
493
494 if(s_maxdepth && depth > s_maxdepth)
495 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth)+" (max-recursion-depth) levels of recursion needed while resolving "+qname.toLogString());
496
497 int res=0;
498
499 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
500 if(!(d_nocache && qtype.getCode()==QType::NS && qname.isRoot())) {
501 if(d_cacheonly) { // very limited OOB support
502 LWResult lwr;
503 LOG(prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl);
504 DNSName authname(qname);
505 domainmap_t::const_iterator iter=getBestAuthZone(&authname);
506 if(iter != t_sstorage->domainmap->end()) {
507 const vector<ComboAddress>& servers = iter->second.d_servers;
508 if(servers.empty()) {
509 ret.clear();
510 d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, res);
511 return res;
512 }
513 else {
514 const ComboAddress remoteIP = servers.front();
515 LOG(prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl);
516
517 boost::optional<Netmask> nm;
518 res=asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(), false, false, &d_now, nm, &lwr);
519 // filter out the good stuff from lwr.result()
520 if (res == 1) {
521 for(const auto& rec : lwr.d_records) {
522 if(rec.d_place == DNSResourceRecord::ANSWER)
523 ret.push_back(rec);
524 }
525 return 0;
526 }
527 else {
528 return RCode::ServFail;
529 }
530 }
531 }
532 }
533
534 if(!d_skipCNAMECheck && doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed
535 return res;
536
537 if(doCacheCheck(qname,qtype,ret,depth,res)) // we done
538 return res;
539 }
540
541 if(d_cacheonly)
542 return 0;
543
544 LOG(prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl);
545
546 DNSName subdomain(qname);
547 if(qtype == QType::DS) subdomain.chopOff();
548
549 NsSet nsset;
550 bool flawedNSSet=false;
551
552 // the two retries allow getBestNSNamesFromCache&co to reprime the root
553 // hints, in case they ever go missing
554 for(int tries=0;tries<2 && nsset.empty();++tries) {
555 subdomain=getBestNSNamesFromCache(subdomain, qtype, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions
556 }
557
558 if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere)))
559 return 0;
560
561 LOG(prefix<<qname<<": failed (res="<<res<<")"<<endl);
562 ;
563
564 if (res == -2)
565 return res;
566
567 return res<0 ? RCode::ServFail : res;
568 }
569
570 #if 0
571 // for testing purposes
572 static bool ipv6First(const ComboAddress& a, const ComboAddress& b)
573 {
574 return !(a.sin4.sin_family < a.sin4.sin_family);
575 }
576 #endif
577
578 /** This function explicitly goes out for A or AAAA addresses
579 */
580 vector<ComboAddress> SyncRes::getAddrs(const DNSName &qname, unsigned int depth, set<GetBestNSAnswer>& beenthere)
581 {
582 typedef vector<DNSRecord> res_t;
583 res_t res;
584
585 typedef vector<ComboAddress> ret_t;
586 ret_t ret;
587
588 QType type;
589
590 for(int j=1; j<2+s_doIPv6; j++)
591 {
592 bool done=false;
593 switch(j) {
594 case 0:
595 type = QType::ANY;
596 break;
597 case 1:
598 type = QType::A;
599 break;
600 case 2:
601 type = QType::AAAA;
602 break;
603 }
604
605 if(!doResolve(qname, type, res,depth+1, beenthere) && !res.empty()) { // this consults cache, OR goes out
606 for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i) {
607 if(i->d_type == QType::A || i->d_type == QType::AAAA) {
608 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(i->d_content))
609 ret.push_back(rec->getCA(53));
610 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(i->d_content))
611 ret.push_back(aaaarec->getCA(53));
612 done=true;
613 }
614 }
615 }
616 if(done) {
617 if(j==1 && s_doIPv6) { // we got an A record, see if we have some AAAA lying around
618 vector<DNSRecord> cset;
619 if(t_RC->get(d_now.tv_sec, qname, QType(QType::AAAA), &cset, d_requestor) > 0) {
620 for(auto k=cset.cbegin();k!=cset.cend();++k) {
621 if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
622 if (auto drc = std::dynamic_pointer_cast<AAAARecordContent>(k->d_content)) {
623 ComboAddress ca=drc->getCA(53);
624 ret.push_back(ca);
625 }
626 }
627 }
628 }
629 }
630 break;
631 }
632 }
633
634 if(ret.size() > 1) {
635 random_shuffle(ret.begin(), ret.end(), dns_random);
636
637 // move 'best' address for this nameserver name up front
638 nsspeeds_t::iterator best = t_sstorage->nsSpeeds.find(qname);
639
640 if(best != t_sstorage->nsSpeeds.end())
641 for(ret_t::iterator i=ret.begin(); i != ret.end(); ++i) {
642 if(*i==best->second.d_best) { // got the fastest one
643 if(i!=ret.begin()) {
644 *i=*ret.begin();
645 *ret.begin()=best->second.d_best;
646 }
647 break;
648 }
649 }
650 }
651
652 return ret;
653 }
654
655 void SyncRes::getBestNSFromCache(const DNSName &qname, const QType& qtype, vector<DNSRecord>& bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere)
656 {
657 string prefix;
658 DNSName subdomain(qname);
659 if(doLog()) {
660 prefix=d_prefix;
661 prefix.append(depth, ' ');
662 }
663 bestns.clear();
664 bool brokeloop;
665 do {
666 brokeloop=false;
667 LOG(prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl);
668 vector<DNSRecord> ns;
669 *flawedNSSet = false;
670 if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), &ns, d_requestor) > 0) {
671 for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
672 if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
673 vector<DNSRecord> aset;
674
675 const DNSRecord& dr=*k;
676 auto nrr = getRR<NSRecordContent>(dr);
677 if(nrr && (!nrr->getNS().isPartOf(subdomain) || t_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
678 doLog() ? &aset : 0, d_requestor) > 5)) {
679 bestns.push_back(dr);
680 LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);
681 LOG(prefix<<qname<<": within bailiwick: "<< nrr->getNS().isPartOf(subdomain));
682 if(!aset.empty()) {
683 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->d_ttl- d_now.tv_sec ))<<endl);
684 }
685 else {
686 LOG(", not in cache / did not look at cache"<<endl);
687 }
688 }
689 else {
690 *flawedNSSet=true;
691 LOG(prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<nrr->getNS()<<") which we miss or is expired"<<endl);
692 }
693 }
694 }
695 if(!bestns.empty()) {
696 GetBestNSAnswer answer;
697 answer.qname=qname;
698 answer.qtype=qtype.getCode();
699 for(const auto& dr : bestns)
700 answer.bestns.insert(make_pair(dr.d_name, getRR<NSRecordContent>(dr)->getNS()));
701
702 if(beenthere.count(answer)) {
703 brokeloop=true;
704 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP (already seen "<<answer.qname<<")! Trying less specific NS"<<endl);
705 ;
706 if(doLog())
707 for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j) {
708 bool neo = !(*j< answer || answer<*j);
709 LOG(prefix<<qname<<": beenthere"<<(neo?"*":"")<<": "<<j->qname<<"|"<<DNSRecordContent::NumberToType(j->qtype)<<" ("<<(unsigned int)j->bestns.size()<<")"<<endl);
710 }
711 bestns.clear();
712 }
713 else {
714 beenthere.insert(answer);
715 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl);
716 return;
717 }
718 }
719 }
720 LOG(prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl);
721 ;
722 if(subdomain.isRoot() && !brokeloop) {
723 // We lost the root NS records
724 primeHints();
725 LOG(prefix<<qname<<": reprimed the root"<<endl);
726 getRootNS(d_now, d_asyncResolve);
727 }
728 }while(subdomain.chopOff());
729 }
730
731 SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(DNSName* qname) const
732 {
733 SyncRes::domainmap_t::const_iterator ret;
734 do {
735 ret=t_sstorage->domainmap->find(*qname);
736 if(ret!=t_sstorage->domainmap->end())
737 break;
738 }while(qname->chopOff());
739 return ret;
740 }
741
742 /** doesn't actually do the work, leaves that to getBestNSFromCache */
743 DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere)
744 {
745 DNSName subdomain(qname);
746 DNSName authdomain(qname);
747
748 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
749 if(iter!=t_sstorage->domainmap->end()) {
750 if( iter->second.d_servers.empty() )
751 // this gets picked up in doResolveAt, the empty DNSName, combined with the
752 // empty vector means 'we are auth for this zone'
753 nsset.insert({DNSName(), {{}, false}});
754 else {
755 // Again, picked up in doResolveAt. An empty DNSName, combined with a
756 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
757 nsset.insert({DNSName(), {iter->second.d_servers, iter->second.d_rdForward}});
758 }
759 return authdomain;
760 }
761
762 vector<DNSRecord> bestns;
763 getBestNSFromCache(subdomain, qtype, bestns, flawedNSSet, depth, beenthere);
764
765 for(auto k=bestns.cbegin() ; k != bestns.cend(); ++k) {
766 // The actual resolver code will not even look at the ComboAddress or bool
767 nsset.insert({std::dynamic_pointer_cast<NSRecordContent>(k->d_content)->getNS(), {{}, false}});
768 if(k==bestns.cbegin())
769 subdomain=k->d_name;
770 }
771 return subdomain;
772 }
773
774 bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res)
775 {
776 string prefix;
777 if(doLog()) {
778 prefix=d_prefix;
779 prefix.append(depth, ' ');
780 }
781
782 if((depth>9 && d_outqueries>10 && d_throttledqueries>5) || depth > 15) {
783 LOG(prefix<<qname<<": recursing (CNAME or other indirection) too deep, depth="<<depth<<endl);
784 res=RCode::ServFail;
785 return true;
786 }
787
788 LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
789 vector<DNSRecord> cset;
790 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
791 if(t_RC->get(d_now.tv_sec, qname,QType(QType::CNAME), &cset, d_requestor, &signatures) > 0) {
792
793 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
794 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
795 LOG(prefix<<qname<<": Found cache CNAME hit for '"<< qname << "|CNAME" <<"' to '"<<j->d_content->getZoneRepresentation()<<"'"<<endl);
796 DNSRecord dr=*j;
797 dr.d_ttl-=d_now.tv_sec;
798 ret.push_back(dr);
799
800 for(const auto& signature : signatures) {
801 DNSRecord sigdr;
802 sigdr.d_type=QType::RRSIG;
803 sigdr.d_name=qname;
804 sigdr.d_ttl=j->d_ttl - d_now.tv_sec;
805 sigdr.d_content=signature;
806 sigdr.d_place=DNSResourceRecord::ANSWER;
807 sigdr.d_class=1;
808 ret.push_back(sigdr);
809 }
810
811 if(qtype != QType::CNAME) { // perhaps they really wanted a CNAME!
812 set<GetBestNSAnswer>beenthere;
813 res=doResolve(std::dynamic_pointer_cast<CNAMERecordContent>(j->d_content)->getTarget(), qtype, ret, depth+1, beenthere);
814 }
815 else
816 res=0;
817 return true;
818 }
819 }
820 }
821 LOG(prefix<<qname<<": No CNAME cache hit of '"<< qname << "|CNAME" <<"' found"<<endl);
822 return false;
823 }
824
825 /*!
826 * Convience function to push the records from records into ret with a new TTL
827 *
828 * \param records DNSRecords that need to go into ret
829 * \param ttl The new TTL for these records
830 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
831 */
832 static void addTTLModifiedRecords(const vector<DNSRecord>& records, const uint32_t ttl, vector<DNSRecord>& ret) {
833 for (const auto& rec : records) {
834 DNSRecord r(rec);
835 r.d_ttl = ttl;
836 ret.push_back(r);
837 }
838 }
839
840
841 bool SyncRes::doCacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res)
842 {
843 bool giveNegative=false;
844
845 string prefix;
846 if(doLog()) {
847 prefix=d_prefix;
848 prefix.append(depth, ' ');
849 }
850
851 // sqname and sqtype are used contain 'higher' names if we have them (e.g. powerdns.com|SOA when we find a negative entry for doesnotexists.powerdns.com|A)
852 DNSName sqname(qname);
853 QType sqt(qtype);
854 uint32_t sttl=0;
855 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
856
857 DNSName authname(qname);
858 bool wasForwardedOrAuth = false;
859 bool wasAuth = false;
860 domainmap_t::const_iterator iter=getBestAuthZone(&authname);
861 if(iter != t_sstorage->domainmap->end()) {
862 wasForwardedOrAuth = true;
863 const vector<ComboAddress>& servers = iter->second.d_servers;
864 if(servers.empty()) {
865 wasAuth = true;
866 }
867 }
868 NegCache::NegCacheEntry ne;
869
870 if(s_rootNXTrust &&
871 t_sstorage->negcache.getRootNXTrust(qname, d_now, ne) &&
872 ne.d_auth.isRoot() &&
873 !(wasForwardedOrAuth && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
874 sttl = ne.d_ttd - d_now.tv_sec;
875 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne.d_auth<<"' & '"<<ne.d_name<<"' for another "<<sttl<<" seconds"<<endl);
876 res = RCode::NXDomain;
877 giveNegative = true;
878 }
879 else if (t_sstorage->negcache.get(qname, qtype, d_now, ne) &&
880 !(wasForwardedOrAuth && ne.d_auth != authname)) { // Only the authname nameserver can neg cache entries
881 res = 0;
882 sttl = ne.d_ttd - d_now.tv_sec;
883 giveNegative = true;
884 if(ne.d_qtype.getCode()) {
885 LOG(prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ne.d_auth<<"' for another "<<sttl<<" seconds"<<endl);
886 res = RCode::NoError;
887 }
888 else {
889 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne.d_auth<<"' for another "<<sttl<<" seconds"<<endl);
890 res = RCode::NXDomain;
891 }
892 if(d_doDNSSEC) {
893 addTTLModifiedRecords(ne.DNSSECRecords.records, sttl, ret);
894 addTTLModifiedRecords(ne.DNSSECRecords.signatures, sttl, ret);
895 }
896 }
897
898 if (giveNegative) {
899 // Transplant SOA to the returned packet
900 addTTLModifiedRecords(ne.authoritySOA.records, sttl, ret);
901 if(d_doDNSSEC)
902 addTTLModifiedRecords(ne.authoritySOA.signatures, sttl, ret);
903 return true;
904 }
905
906 vector<DNSRecord> cset;
907 bool found=false, expired=false;
908 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
909 uint32_t ttl=0;
910 if(t_RC->get(d_now.tv_sec, sqname, sqt, &cset, d_requestor, d_doDNSSEC ? &signatures : 0) > 0) {
911 LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
912 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
913 LOG(j->d_content->getZoneRepresentation());
914 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
915 DNSRecord dr=*j;
916 ttl = (dr.d_ttl-=d_now.tv_sec);
917 ret.push_back(dr);
918 LOG("[ttl="<<dr.d_ttl<<"] ");
919 found=true;
920 }
921 else {
922 LOG("[expired] ");
923 expired=true;
924 }
925 }
926
927 for(const auto& signature : signatures) {
928 DNSRecord dr;
929 dr.d_type=QType::RRSIG;
930 dr.d_name=sqname;
931 dr.d_ttl=ttl;
932 dr.d_content=signature;
933 dr.d_place = DNSResourceRecord::ANSWER;
934 dr.d_class=1;
935 ret.push_back(dr);
936 }
937
938 LOG(endl);
939 if(found && !expired) {
940 if(!giveNegative)
941 res=0;
942 d_wasOutOfBand = wasAuth;
943 return true;
944 }
945 else
946 LOG(prefix<<qname<<": cache had only stale entries"<<endl);
947 }
948
949 return false;
950 }
951
952 bool SyncRes::moreSpecificThan(const DNSName& a, const DNSName &b) const
953 {
954 return (a.isPartOf(b) && a.countLabels() > b.countLabels());
955 }
956
957 struct speedOrder
958 {
959 speedOrder(map<DNSName,double> &speeds) : d_speeds(speeds) {}
960 bool operator()(const DNSName &a, const DNSName &b) const
961 {
962 return d_speeds[a] < d_speeds[b];
963 }
964 map<DNSName, double>& d_speeds;
965 };
966
967 inline vector<DNSName> SyncRes::shuffleInSpeedOrder(NsSet &tnameservers, const string &prefix)
968 {
969 vector<DNSName> rnameservers;
970 rnameservers.reserve(tnameservers.size());
971 for(const auto& tns:tnameservers) {
972 rnameservers.push_back(tns.first);
973 }
974 map<DNSName, double> speeds;
975
976 for(const auto& val: rnameservers) {
977 double speed;
978 speed=t_sstorage->nsSpeeds[val].get(&d_now);
979 speeds[val]=speed;
980 }
981 random_shuffle(rnameservers.begin(),rnameservers.end(), dns_random);
982 speedOrder so(speeds);
983 stable_sort(rnameservers.begin(),rnameservers.end(), so);
984
985 if(doLog()) {
986 LOG(prefix<<"Nameservers: ");
987 for(vector<DNSName>::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) {
988 if(i!=rnameservers.begin()) {
989 LOG(", ");
990 if(!((i-rnameservers.begin())%3)) {
991 LOG(endl<<prefix<<" ");
992 }
993 }
994 LOG((i->empty() ? string("<empty>") : i->toString())<<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
995 }
996 LOG(endl);
997 }
998 return rnameservers;
999 }
1000
1001 static bool magicAddrMatch(const QType& query, const QType& answer)
1002 {
1003 if(query.getCode() != QType::ADDR)
1004 return false;
1005 return answer.getCode() == QType::A || answer.getCode() == QType::AAAA;
1006 }
1007
1008 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1009 *
1010 * \param records The records to parse for the authority SOA and NSEC(3) records
1011 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1012 */
1013 static void harvestNXRecords(const vector<DNSRecord>& records, NegCache::NegCacheEntry& ne) {
1014 static const set<uint16_t> nsecTypes = {QType::NSEC, QType::NSEC3};
1015 for(const auto& rec : records) {
1016 if(rec.d_place != DNSResourceRecord::AUTHORITY)
1017 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1018 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1019 // records MUST be in the same section as the records they cover.
1020 // Hence, we ignore all records outside of the AUTHORITY section.
1021 continue;
1022
1023 if(rec.d_type == QType::RRSIG) {
1024 auto rrsig = getRR<RRSIGRecordContent>(rec);
1025 if(rrsig) {
1026 if(rrsig->d_type == QType::SOA) {
1027 ne.authoritySOA.signatures.push_back(rec);
1028 }
1029 if(nsecTypes.count(rrsig->d_type)) {
1030 ne.DNSSECRecords.signatures.push_back(rec);
1031 }
1032 }
1033 continue;
1034 }
1035 if(rec.d_type == QType::SOA) {
1036 ne.authoritySOA.records.push_back(rec);
1037 continue;
1038 }
1039 if(nsecTypes.count(rec.d_type)) {
1040 ne.DNSSECRecords.records.push_back(rec);
1041 continue;
1042 }
1043 }
1044 }
1045
1046 // TODO remove after processRecords is fixed!
1047 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1048 static void addNXNSECS(vector<DNSRecord>&ret, const vector<DNSRecord>& records)
1049 {
1050 NegCache::NegCacheEntry ne;
1051 harvestNXRecords(records, ne);
1052 ret.insert(ret.end(), ne.authoritySOA.signatures.begin(), ne.authoritySOA.signatures.end());
1053 ret.insert(ret.end(), ne.DNSSECRecords.records.begin(), ne.DNSSECRecords.records.end());
1054 ret.insert(ret.end(), ne.DNSSECRecords.signatures.begin(), ne.DNSSECRecords.signatures.end());
1055 }
1056
1057 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers)
1058 {
1059 if(d_wantsRPZ) {
1060 for (auto const &ns : nameservers) {
1061 d_appliedPolicy = dfe.getProcessingPolicy(ns.first, d_discardedPolicies);
1062 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1063 LOG(", however nameserver "<<ns.first<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1064 return true;
1065 }
1066
1067 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1068 for (auto const &address : ns.second.first) {
1069 d_appliedPolicy = dfe.getProcessingPolicy(address, d_discardedPolicies);
1070 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1071 LOG(", however nameserver "<<ns.first<<" IP address "<<address.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1072 return true;
1073 }
1074 }
1075 }
1076 }
1077 return false;
1078 }
1079
1080 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress& remoteIP)
1081 {
1082 if (d_wantsRPZ) {
1083 d_appliedPolicy = dfe.getProcessingPolicy(remoteIP, d_discardedPolicies);
1084 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) {
1085 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')");
1086 return true;
1087 }
1088 }
1089 return false;
1090 }
1091
1092 vector<ComboAddress> SyncRes::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)
1093 {
1094 vector<ComboAddress> result;
1095
1096 if(!tns->empty()) {
1097 LOG(prefix<<qname<<": Trying to resolve NS '"<<*tns<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
1098 result = getAddrs(*tns, depth+2, beenthere);
1099 pierceDontQuery=false;
1100 }
1101 else {
1102 LOG(prefix<<qname<<": Domain has hardcoded nameserver");
1103
1104 result = nameservers[*tns].first;
1105 if(result.size() > 1) {
1106 LOG("s");
1107 }
1108 LOG(endl);
1109
1110 sendRDQuery = nameservers[*tns].second;
1111 pierceDontQuery=true;
1112 }
1113 return result;
1114 }
1115
1116 bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery)
1117 {
1118 if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) {
1119 LOG(prefix<<qname<<": server throttled "<<endl);
1120 s_throttledqueries++; d_throttledqueries++;
1121 return true;
1122 }
1123 else if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) {
1124 LOG(prefix<<qname<<": query throttled "<<endl);
1125 s_throttledqueries++; d_throttledqueries++;
1126 return true;
1127 }
1128 else if(!pierceDontQuery && s_dontQuery && s_dontQuery->match(&remoteIP)) {
1129 LOG(prefix<<qname<<": not sending query to " << remoteIP.toString() << ", blocked by 'dont-query' setting" << endl);
1130 s_dontqueries++;
1131 return true;
1132 }
1133 return false;
1134 }
1135
1136 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)
1137 {
1138 struct CachePair
1139 {
1140 vector<DNSRecord> records;
1141 vector<shared_ptr<RRSIGRecordContent>> signatures;
1142 };
1143 struct CacheKey
1144 {
1145 DNSName name;
1146 uint16_t type;
1147 DNSResourceRecord::Place place;
1148 bool operator<(const CacheKey& rhs) const {
1149 return tie(name, type) < tie(rhs.name, rhs.type);
1150 }
1151 };
1152 typedef map<CacheKey, CachePair> tcache_t;
1153 tcache_t tcache;
1154
1155 for(const auto& rec : lwr.d_records) {
1156 if(rec.d_type == QType::RRSIG) {
1157 auto rrsig = getRR<RRSIGRecordContent>(rec);
1158 if (rrsig) {
1159 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1160 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
1161 }
1162 }
1163 }
1164
1165 // reap all answers from this packet that are acceptable
1166 for(auto& rec : lwr.d_records) {
1167 if(rec.d_type == QType::OPT) {
1168 LOG(prefix<<qname<<": OPT answer '"<<rec.d_name<<"' from '"<<auth<<"' nameservers" <<endl);
1169 continue;
1170 }
1171 LOG(prefix<<qname<<": accept answer '"<<rec.d_name<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"|"<<rec.d_content->getZoneRepresentation()<<"' from '"<<auth<<"' nameservers? "<<(int)rec.d_place<<" ");
1172 if(rec.d_type == QType::ANY) {
1173 LOG("NO! - we don't accept 'ANY' data"<<endl);
1174 continue;
1175 }
1176
1177 if(rec.d_name.isPartOf(auth)) {
1178 if(rec.d_type == QType::RRSIG) {
1179 LOG("RRSIG - separate"<<endl);
1180 }
1181 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)) {
1182 LOG("NO! Is from delegation-only zone"<<endl);
1183 s_nodelegated++;
1184 return RCode::NXDomain;
1185 }
1186 else {
1187 bool haveLogged = false;
1188 if (!t_sstorage->domainmap->empty()) {
1189 // Check if we are authoritative for a zone in this answer
1190 DNSName tmp_qname(rec.d_name);
1191 auto auth_domain_iter=getBestAuthZone(&tmp_qname);
1192 if(auth_domain_iter!=t_sstorage->domainmap->end() &&
1193 auth.countLabels() <= auth_domain_iter->first.countLabels()) {
1194 if (auth_domain_iter->first != auth) {
1195 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter->first<<endl);
1196 continue;
1197 } else {
1198 LOG("YES! - This answer was ");
1199 if (nameservers[tns].first.empty()) {
1200 LOG("retrieved from the local auth store.");
1201 } else {
1202 LOG("received from a server we forward to.");
1203 }
1204 haveLogged = true;
1205 LOG(endl);
1206 }
1207 }
1208 }
1209 if (!haveLogged) {
1210 LOG("YES!"<<endl);
1211 }
1212
1213 rec.d_ttl=min(s_maxcachettl, rec.d_ttl);
1214
1215 DNSRecord dr(rec);
1216 dr.d_place=DNSResourceRecord::ANSWER;
1217
1218 dr.d_ttl += d_now.tv_sec;
1219 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(dr);
1220 }
1221 }
1222 else
1223 LOG("NO!"<<endl);
1224 }
1225
1226 // supplant
1227 for(tcache_t::iterator i=tcache.begin();i!=tcache.end();++i) {
1228 if(i->second.records.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
1229 uint32_t lowestTTL=std::numeric_limits<uint32_t>::max();
1230 for(const auto& record : i->second.records)
1231 lowestTTL=min(lowestTTL, record.d_ttl);
1232
1233 for(auto& record : i->second.records)
1234 *const_cast<uint32_t*>(&record.d_ttl)=lowestTTL; // boom
1235 }
1236
1237 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
1238 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
1239 if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
1240 continue;
1241 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>());
1242 if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
1243 d_wasVariable=true;
1244 }
1245
1246 return RCode::NoError;
1247 }
1248
1249 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)
1250 {
1251 bool done = false;
1252
1253 for(auto& rec : lwr.d_records) {
1254 if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN)
1255 continue;
1256
1257 if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
1258 lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) {
1259 LOG(prefix<<qname<<": got negative caching indication for name '"<<qname<<"' (accept="<<rec.d_name.isPartOf(auth)<<"), newtarget='"<<newtarget<<"'"<<endl);
1260
1261 rec.d_ttl = min(rec.d_ttl, s_maxnegttl);
1262 if(newtarget.empty()) // only add a SOA if we're not going anywhere after this
1263 ret.push_back(rec);
1264 if(!wasVariable()) {
1265 NegCache::NegCacheEntry ne;
1266
1267 ne.d_ttd = d_now.tv_sec + rec.d_ttl;
1268 ne.d_name = qname;
1269 ne.d_qtype = QType(0); // this encodes 'whole record'
1270 ne.d_auth = rec.d_name;
1271 harvestNXRecords(lwr.d_records, ne);
1272 t_sstorage->negcache.add(ne);
1273 if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot()) {
1274 ne.d_name = ne.d_name.getLastLabel();
1275 t_sstorage->negcache.add(ne);
1276 }
1277 }
1278
1279 negindic=true;
1280 }
1281 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname && rec.d_type==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
1282 ret.push_back(rec);
1283 if (auto content = getRR<CNAMERecordContent>(rec)) {
1284 newtarget=content->getTarget();
1285 }
1286 }
1287 else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER){
1288 if(rec.d_type != QType::RRSIG || rec.d_name == qname)
1289 ret.push_back(rec); // enjoy your DNSSEC
1290 }
1291 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
1292 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname &&
1293 (
1294 rec.d_type==qtype.getCode() || (lwr.d_aabit && (qtype==QType(QType::ANY) || magicAddrMatch(qtype, QType(rec.d_type)) ) ) || sendRDQuery
1295 )
1296 )
1297 {
1298 LOG(prefix<<qname<<": answer is in: resolved to '"<< rec.d_content->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"'"<<endl);
1299
1300 done=true;
1301 ret.push_back(rec);
1302 }
1303 else if(rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::NS) {
1304 if(moreSpecificThan(rec.d_name,auth)) {
1305 newauth=rec.d_name;
1306 LOG(prefix<<qname<<": got NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
1307 realreferral=true;
1308 }
1309 else {
1310 LOG(prefix<<qname<<": got upwards/level NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"', had '"<<auth<<"'"<<endl);
1311 }
1312 if (auto content = getRR<NSRecordContent>(rec)) {
1313 nsset.insert(content->getNS());
1314 }
1315 }
1316 else if(rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::DS) {
1317 LOG(prefix<<qname<<": got DS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
1318 sawDS=true;
1319 }
1320 else if(!done && rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::SOA &&
1321 lwr.d_rcode==RCode::NoError) {
1322 LOG(prefix<<qname<<": got negative caching indication for '"<< qname<<"|"<<qtype.getName()<<"'"<<endl);
1323
1324 if(!newtarget.empty()) {
1325 LOG(prefix<<qname<<": Hang on! Got a redirect to '"<<newtarget<<"' already"<<endl);
1326 }
1327 else {
1328 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
1329 ret.push_back(rec);
1330 if(!wasVariable()) {
1331 NegCache::NegCacheEntry ne;
1332 ne.d_auth = rec.d_name;
1333 ne.d_ttd = d_now.tv_sec + rec.d_ttl;
1334 ne.d_name = qname;
1335 ne.d_qtype = qtype;
1336 harvestNXRecords(lwr.d_records, ne);
1337 if(qtype.getCode()) { // prevents us from blacking out a whole domain
1338 t_sstorage->negcache.add(ne);
1339 }
1340 }
1341 negindic=true;
1342 }
1343 }
1344 }
1345
1346 return done;
1347 }
1348
1349 /** returns:
1350 * -1 in case of no results
1351 * -2 when a FilterEngine Policy was hit
1352 * rcode otherwise
1353 */
1354 int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
1355 vector<DNSRecord>&ret,
1356 unsigned int depth, set<GetBestNSAnswer>&beenthere)
1357 {
1358 auto luaconfsLocal = g_luaconfs.getLocal();
1359 string prefix;
1360 if(doLog()) {
1361 prefix=d_prefix;
1362 prefix.append(depth, ' ');
1363 }
1364
1365 LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact");
1366
1367 if (nameserversBlockedByRPZ(luaconfsLocal->dfe, nameservers)) {
1368 return -2;
1369 }
1370
1371 LOG(endl);
1372
1373 for(;;) { // we may get more specific nameservers
1374 vector<DNSName > rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
1375
1376 for(auto tns=rnameservers.cbegin();;++tns) {
1377 if(tns==rnameservers.cend()) {
1378 LOG(prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl);
1379 if(!auth.isRoot() && flawedNSSet) {
1380 LOG(prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl);
1381
1382 if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
1383 g_stats.nsSetInvalidations++;
1384 }
1385 return -1;
1386 }
1387 // this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
1388 if(qname == *tns && qtype.getCode()==QType::A && rnameservers.size() > (size_t)(1+1*s_doIPv6)) {
1389 LOG(prefix<<qname<<": Not using NS to resolve itself! ("<<(1+tns-rnameservers.cbegin())<<"/"<<rnameservers.size()<<")"<<endl);
1390 continue;
1391 }
1392
1393 typedef vector<ComboAddress> remoteIPs_t;
1394 remoteIPs_t remoteIPs;
1395 remoteIPs_t::const_iterator remoteIP;
1396 bool doTCP=false;
1397 bool pierceDontQuery=false;
1398 bool sendRDQuery=false;
1399 boost::optional<Netmask> ednsmask;
1400 LWResult lwr;
1401 if(tns->empty() && nameservers[*tns].first.empty() ) {
1402 LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
1403 d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
1404 lwr.d_tcbit=false;
1405 lwr.d_aabit=true;
1406 }
1407 else {
1408 remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet);
1409
1410 if(remoteIPs.empty()) {
1411 LOG(prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl);
1412 flawedNSSet=true;
1413 continue;
1414 }
1415 else {
1416 bool hitPolicy{false};
1417 LOG(prefix<<qname<<": Resolved '"<<auth<<"' NS "<<*tns<<" to: ");
1418 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
1419 if(remoteIP != remoteIPs.cbegin()) {
1420 LOG(", ");
1421 }
1422 LOG(remoteIP->toString());
1423 if(nameserverIPBlockedByRPZ(luaconfsLocal->dfe, *remoteIP)) {
1424 hitPolicy = true;
1425 }
1426 }
1427 LOG(endl);
1428 if (hitPolicy) //implies d_wantsRPZ
1429 return -2;
1430 }
1431
1432 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
1433 LOG(prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
1434 if (throttledOrBlocked(prefix, *remoteIP, qname, qtype, pierceDontQuery)) {
1435 continue;
1436 }
1437 else {
1438 int resolveret;
1439 s_outqueries++; d_outqueries++;
1440 if(d_outqueries + d_throttledqueries > s_maxqperq) throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
1441 TryTCP:
1442 if(doTCP) {
1443 LOG(prefix<<qname<<": using TCP with "<< remoteIP->toStringWithPort() <<endl);
1444 s_tcpoutqueries++; d_tcpoutqueries++;
1445 }
1446
1447 if(s_maxtotusec && d_totUsec > s_maxtotusec)
1448 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");
1449
1450 if(d_pdl && d_pdl->preoutquery(*remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
1451 LOG(prefix<<qname<<": query handled by Lua"<<endl);
1452 }
1453 else {
1454 ednsmask=getEDNSSubnetMask(d_requestor, qname, *remoteIP);
1455 if(ednsmask) {
1456 LOG(prefix<<qname<<": Adding EDNS Client Subnet Mask "<<ednsmask->toString()<<" to query"<<endl);
1457 }
1458 resolveret=asyncresolveWrapper(*remoteIP, d_doDNSSEC, qname, qtype.getCode(),
1459 doTCP, sendRDQuery, &d_now, ednsmask, &lwr); // <- we go out on the wire!
1460 if(ednsmask) {
1461 LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
1462 }
1463
1464
1465 }
1466 if(resolveret==-3)
1467 throw ImmediateServFailException("Query killed by policy");
1468
1469 d_totUsec += lwr.d_usec;
1470 accountAuthLatency(lwr.d_usec, remoteIP->sin4.sin_family);
1471 if(resolveret != 1) {
1472 if(resolveret==0) {
1473 LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
1474 d_timeouts++;
1475 s_outgoingtimeouts++;
1476 if(remoteIP->sin4.sin_family == AF_INET)
1477 s_outgoing4timeouts++;
1478 else
1479 s_outgoing6timeouts++;
1480 }
1481 else if(resolveret==-2) {
1482 LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
1483 g_stats.resourceLimits++;
1484 }
1485 else {
1486 s_unreachables++; d_unreachables++;
1487 LOG(prefix<<qname<<": error resolving from "<<remoteIP->toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl);
1488 }
1489
1490 if(resolveret!=-2) { // don't account for resource limits, they are our own fault
1491 t_sstorage->nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec
1492
1493 // code below makes sure we don't filter COM or the root
1494 if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage->fails.incr(*remoteIP) >= s_serverdownmaxfails) {
1495 LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP->toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
1496 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, "", 0), s_serverdownthrottletime, 10000); // mark server as down
1497 } else if(resolveret==-1)
1498 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable, 1 minute or 100 queries
1499 else
1500 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 10, 5); // timeout
1501 }
1502 continue;
1503 }
1504
1505 // 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));
1506
1507 if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
1508 LOG(prefix<<qname<<": "<<*tns<<" ("<<remoteIP->toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
1509 t_sstorage->throttle.throttle(d_now.tv_sec,boost::make_tuple(*remoteIP, qname, qtype.getCode()),60,3); // servfail or refused
1510 continue;
1511 }
1512
1513 if(s_serverdownmaxfails > 0)
1514 t_sstorage->fails.clear(*remoteIP);
1515
1516 break; // this IP address worked!
1517 wasLame:; // well, it didn't
1518 LOG(prefix<<qname<<": status=NS "<<*tns<<" ("<< remoteIP->toString() <<") is lame for '"<<auth<<"', trying sibling IP or NS"<<endl);
1519 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // lame
1520 }
1521 }
1522
1523 if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked
1524 continue;
1525
1526 if(lwr.d_tcbit) {
1527 if(!doTCP) {
1528 doTCP=true;
1529 LOG(prefix<<qname<<": truncated bit set, retrying via TCP"<<endl);
1530 goto TryTCP;
1531 }
1532 LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
1533 return RCode::ServFail;
1534 }
1535 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);
1536
1537 /* // for you IPv6 fanatics :-)
1538 if(remoteIP->sin4.sin_family==AF_INET6)
1539 lwr.d_usec/=3;
1540 */
1541 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
1542
1543 t_sstorage->nsSpeeds[*tns].submit(*remoteIP, lwr.d_usec, &d_now);
1544 }
1545
1546 if(s_minimumTTL) {
1547 for(auto& rec : lwr.d_records) {
1548 rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
1549 }
1550 }
1551
1552 RCode::rcodes_ rcode = updateCacheFromRecords(prefix, lwr, qname, auth, nameservers, *tns, ednsmask);
1553 if (rcode != RCode::NoError) {
1554 return rcode;
1555 }
1556
1557 LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
1558
1559 set<DNSName> nsset;
1560 bool realreferral=false, negindic=false, sawDS=false;
1561 DNSName newauth;
1562 DNSName newtarget;
1563
1564 bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, sawDS);
1565
1566 if(done){
1567 LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
1568 return 0;
1569 }
1570 if(!newtarget.empty()) {
1571 if(newtarget == qname) {
1572 LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
1573 return RCode::ServFail;
1574 }
1575 if(depth > 10) {
1576 LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
1577 return RCode::ServFail;
1578 }
1579 LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
1580
1581 set<GetBestNSAnswer> beenthere2;
1582 return doResolve(newtarget, qtype, ret, depth + 1, beenthere2);
1583 }
1584 if(lwr.d_rcode==RCode::NXDomain) {
1585 LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
1586
1587 if(d_doDNSSEC)
1588 addNXNSECS(ret, lwr.d_records);
1589
1590 return RCode::NXDomain;
1591 }
1592 if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
1593 LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
1594
1595 if(d_doDNSSEC)
1596 addNXNSECS(ret, lwr.d_records);
1597 return 0;
1598 }
1599 else if(realreferral) {
1600 LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
1601 if(sawDS) {
1602 t_sstorage->dnssecmap[newauth]=true;
1603 /* for(const auto& e : t_sstorage->dnssecmap)
1604 cout<<e.first<<' ';
1605 cout<<endl;*/
1606 }
1607 auth=newauth;
1608
1609 nameservers.clear();
1610 for (auto const &nameserver : nsset) {
1611 if (d_wantsRPZ) {
1612 d_appliedPolicy = luaconfsLocal->dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
1613 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1614 LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1615 return -2;
1616 }
1617 }
1618 nameservers.insert({nameserver, {{}, false}});
1619 }
1620 LOG("looping to them"<<endl);
1621 break;
1622 }
1623 else if(!tns->empty()) { // means: not OOB, OOB == empty
1624 goto wasLame;
1625 }
1626 }
1627 }
1628 return -1;
1629 }
1630
1631 boost::optional<Netmask> SyncRes::getEDNSSubnetMask(const ComboAddress& local, const DNSName&dn, const ComboAddress& rem)
1632 {
1633 boost::optional<Netmask> result;
1634 ComboAddress trunc;
1635 uint8_t bits;
1636 if(d_incomingECSFound) {
1637 if (d_incomingECS->source.getBits() == 0) {
1638 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0 */
1639 return result;
1640 }
1641 trunc = d_incomingECS->source.getMaskedNetwork();
1642 bits = d_incomingECS->source.getBits();
1643 }
1644 else if(!local.isIPv4() || local.sin4.sin_addr.s_addr) { // detect unset 'requestor'
1645 trunc = local;
1646 bits = local.isIPv4() ? 32 : 128;
1647 }
1648 else {
1649 /* nothing usable */
1650 return result;
1651 }
1652
1653 if(s_ednsdomains.check(dn) || s_ednssubnets.match(rem)) {
1654 bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit));
1655 trunc.truncate(bits);
1656 return boost::optional<Netmask>(Netmask(trunc, bits));
1657 }
1658
1659 return result;
1660 }
1661
1662 void SyncRes::parseEDNSSubnetWhitelist(const std::string& wlist)
1663 {
1664 vector<string> parts;
1665 stringtok(parts, wlist, ",; ");
1666 for(const auto& a : parts) {
1667 try {
1668 s_ednssubnets.addMask(Netmask(a));
1669 }
1670 catch(...) {
1671 s_ednsdomains.add(DNSName(a));
1672 }
1673 }
1674 }
1675
1676 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
1677 int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret)
1678 {
1679 struct timeval now;
1680 gettimeofday(&now, 0);
1681
1682 SyncRes sr(now);
1683 int res = sr.beginResolve(qname, QType(qtype), qclass, ret);
1684
1685 return res;
1686 }
1687
1688 #include "validate-recursor.hh"
1689
1690 int SyncRes::getRootNS(struct timeval now, asyncresolve_t asyncCallback) {
1691 SyncRes sr(now);
1692 sr.setDoEDNS0(true);
1693 sr.setNoCache();
1694 sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off);
1695 sr.setAsyncCallback(asyncCallback);
1696
1697 vector<DNSRecord> ret;
1698 int res=-1;
1699 try {
1700 res=sr.beginResolve(g_rootdnsname, QType(QType::NS), 1, ret);
1701 if (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate) {
1702 ResolveContext ctx;
1703 auto state = validateRecords(ctx, ret);
1704 if (state == Bogus)
1705 throw PDNSException("Got Bogus validation result for .|NS");
1706 }
1707 return res;
1708 }
1709 catch(PDNSException& e)
1710 {
1711 L<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
1712 }
1713
1714 catch(std::exception& e)
1715 {
1716 L<<Logger::Error<<"Failed to update . records, got an exception: "<<e.what()<<endl;
1717 }
1718
1719 catch(...)
1720 {
1721 L<<Logger::Error<<"Failed to update . records, got an exception"<<endl;
1722 }
1723 if(!res) {
1724 L<<Logger::Notice<<"Refreshed . records"<<endl;
1725 }
1726 else
1727 L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
1728 return res;
1729 }