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