]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/ueberbackend.cc
Merge pull request #8901 from rgacogne/ddist-docs-8683
[thirdparty/pdns.git] / pdns / ueberbackend.cc
CommitLineData
12c86877 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
cb433f9c
BH
25#include <boost/archive/binary_iarchive.hpp>
26#include <boost/archive/binary_oarchive.hpp>
27
bf269e28 28#include "auth-querycache.hh"
12c86877 29#include "utility.hh"
c6566265 30
c6566265 31
96349507 32#include <dlfcn.h>
12c86877
BH
33#include <string>
34#include <map>
35#include <sys/types.h>
cb433f9c 36#include <sstream>
12c86877
BH
37#include <errno.h>
38#include <iostream>
39#include <sstream>
40#include <functional>
fa8fd4d2 41
12c86877
BH
42#include "dns.hh"
43#include "arguments.hh"
44#include "dnsbackend.hh"
45#include "ueberbackend.hh"
46#include "dnspacket.hh"
47#include "logger.hh"
48#include "statbag.hh"
12c86877
BH
49
50extern StatBag S;
51
52vector<UeberBackend *>UeberBackend::instances;
53pthread_mutex_t UeberBackend::instances_lock=PTHREAD_MUTEX_INITIALIZER;
54
12c86877
BH
55// initially we are blocked
56bool UeberBackend::d_go=false;
57pthread_mutex_t UeberBackend::d_mut = PTHREAD_MUTEX_INITIALIZER;
58pthread_cond_t UeberBackend::d_cond = PTHREAD_COND_INITIALIZER;
59
12c86877
BH
60//! Loads a module and reports it to all UeberBackend threads
61bool UeberBackend::loadmodule(const string &name)
62{
e6a9dde5 63 g_log<<Logger::Warning <<"Loading '"<<name<<"'" << endl;
74caf870 64
12c86877 65 void *dlib=dlopen(name.c_str(), RTLD_NOW);
74caf870 66
12c86877 67 if(dlib == NULL) {
e6a9dde5 68 g_log<<Logger::Error <<"Unable to load module '"<<name<<"': "<<dlerror() << endl;
12c86877
BH
69 return false;
70 }
74caf870 71
12c86877 72 return true;
12c86877
BH
73}
74
d4168b30
CHB
75bool UeberBackend::loadModules(const vector<string>& modules, const string& path)
76{
77 for (const auto& module: modules) {
78 bool res;
79 if (module.find(".")==string::npos) {
80 res = UeberBackend::loadmodule(path+"/lib"+module+"backend.so");
81 } else if (module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) {
82 // absolute or current path
83 res = UeberBackend::loadmodule(module);
84 } else {
85 res = UeberBackend::loadmodule(path+"/"+module);
86 }
87
88 if (res == false) {
89 return false;
90 }
91 }
92 return true;
93}
94
12c86877
BH
95void UeberBackend::go(void)
96{
97 pthread_mutex_lock(&d_mut);
98 d_go=true;
99 pthread_cond_broadcast(&d_cond);
100 pthread_mutex_unlock(&d_mut);
101}
102
47bddbb7 103bool UeberBackend::getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial)
12c86877
BH
104{
105 for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
47bddbb7 106 if((*i)->getDomainInfo(domain, di, getSerial))
12c86877
BH
107 return true;
108 return false;
109}
110
675fa24c 111bool UeberBackend::createDomain(const DNSName &domain)
487cf033 112{
ef7cd021 113 for(DNSBackend* mydb : backends) {
487cf033 114 if(mydb->createDomain(domain)) {
487cf033
CH
115 return true;
116 }
117 }
118 return false;
119}
120
7fa35c07
KM
121bool UeberBackend::doesDNSSEC()
122{
123 for(auto* db : backends) {
124 if(db->doesDNSSEC())
125 return true;
126 }
127 return false;
128}
129
82cc0761 130bool UeberBackend::addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& id)
c0273500 131{
82cc0761 132 id = -1;
ef7cd021 133 for(DNSBackend* db : backends) {
82cc0761
BZ
134 if(db->addDomainKey(name, key, id))
135 return true;
c0273500 136 }
82cc0761 137 return false;
c0273500 138}
9c1c5d49 139bool UeberBackend::getDomainKeys(const DNSName& name, std::vector<DNSBackend::KeyData>& keys)
c0273500 140{
ef7cd021 141 for(DNSBackend* db : backends) {
9c1c5d49 142 if(db->getDomainKeys(name, keys))
c0273500
BH
143 return true;
144 }
145 return false;
146}
147
675fa24c 148bool UeberBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
ac993e0a 149{
ef7cd021 150 for(DNSBackend* db : backends) {
ac993e0a
AT
151 if(db->getAllDomainMetadata(name, meta))
152 return true;
153 }
154 return false;
155}
156
675fa24c 157bool UeberBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
c0273500 158{
ef7cd021 159 for(DNSBackend* db : backends) {
c0273500
BH
160 if(db->getDomainMetadata(name, kind, meta))
161 return true;
162 }
163 return false;
164}
165
675fa24c 166bool UeberBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
c0273500 167{
ef7cd021 168 for(DNSBackend* db : backends) {
c0273500
BH
169 if(db->setDomainMetadata(name, kind, meta))
170 return true;
171 }
172 return false;
173}
174
675fa24c 175bool UeberBackend::activateDomainKey(const DNSName& name, unsigned int id)
4496f66f 176{
ef7cd021 177 for(DNSBackend* db : backends) {
4496f66f
BH
178 if(db->activateDomainKey(name, id))
179 return true;
180 }
181 return false;
182}
183
675fa24c 184bool UeberBackend::deactivateDomainKey(const DNSName& name, unsigned int id)
4496f66f 185{
ef7cd021 186 for(DNSBackend* db : backends) {
4496f66f
BH
187 if(db->deactivateDomainKey(name, id))
188 return true;
189 }
190 return false;
191}
192
33918299
RG
193bool UeberBackend::publishDomainKey(const DNSName& name, unsigned int id)
194{
195 for(DNSBackend* db : backends) {
196 if(db->publishDomainKey(name, id))
197 return true;
198 }
199 return false;
200}
201
202bool UeberBackend::unpublishDomainKey(const DNSName& name, unsigned int id)
203{
204 for(DNSBackend* db : backends) {
205 if(db->unpublishDomainKey(name, id))
206 return true;
207 }
208 return false;
209}
210
211
675fa24c 212bool UeberBackend::removeDomainKey(const DNSName& name, unsigned int id)
4496f66f 213{
ef7cd021 214 for(DNSBackend* db : backends) {
4496f66f
BH
215 if(db->removeDomainKey(name, id))
216 return true;
217 }
218 return false;
219}
220
c0273500 221
675fa24c 222bool UeberBackend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
78bcb858 223{
ef7cd021 224 for(DNSBackend* db : backends) {
78bcb858
BH
225 if(db->getTSIGKey(name, algorithm, content))
226 return true;
227 }
228 return false;
229}
230
231
675fa24c 232bool UeberBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
6f872b78 233{
ef7cd021 234 for(DNSBackend* db : backends) {
6f872b78
AT
235 if(db->setTSIGKey(name, algorithm, content))
236 return true;
237 }
238 return false;
239}
240
675fa24c 241bool UeberBackend::deleteTSIGKey(const DNSName& name)
6f872b78 242{
ef7cd021 243 for(DNSBackend* db : backends) {
6f872b78
AT
244 if(db->deleteTSIGKey(name))
245 return true;
246 }
247 return false;
248}
249
250bool UeberBackend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
251{
ef7cd021 252 for(DNSBackend* db : backends) {
6f872b78
AT
253 db->getTSIGKeys(keys);
254 }
255 return true;
256}
257
12c86877
BH
258void UeberBackend::reload()
259{
260 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
261 {
262 ( *i )->reload();
263 }
264}
265
973ad2b5 266void UeberBackend::rediscover(string *status)
12c86877 267{
20ca8e7d 268
12c86877
BH
269 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
270 {
973ad2b5
BH
271 string tmpstr;
272 ( *i )->rediscover(&tmpstr);
6242d8a4
KM
273 if(status)
274 *status+=tmpstr + (i!=backends.begin() ? "\n" : "");
12c86877
BH
275 }
276}
277
278
279void UeberBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
280{
281 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
282 {
283 ( *i )->getUnfreshSlaveInfos( domains );
284 }
285}
286
287
288
289void UeberBackend::getUpdatedMasters(vector<DomainInfo>* domains)
290{
291 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
292 {
293 ( *i )->getUpdatedMasters( domains );
294 }
295}
296
cec52de6 297bool UeberBackend::getAuth(const DNSName &target, const QType& qtype, SOAData* sd, bool cachedOk)
c14bc34a 298{
942d4729
KM
299 // A backend can respond to our authority request with the 'best' match it
300 // has. For example, when asked for a.b.c.example.com. it might respond with
301 // com. We then store that and keep querying the other backends in case one
302 // of them has a more specific zone but don't bother asking this specific
303 // backend again for b.c.example.com., c.example.com. and example.com.
37029707 304 // If a backend has no match it may respond with an empty qname.
942d4729 305
5b9ac871
KM
306 bool found = false;
307 int cstat;
942d4729 308 DNSName shorter(target);
5b9ac871
KM
309 vector<pair<size_t, SOAData> > bestmatch (backends.size(), make_pair(target.wirelength()+1, SOAData()));
310 do {
311
312 // Check cache
cec52de6 313 if(cachedOk && (d_cache_ttl || d_negcache_ttl)) {
5b9ac871 314 d_question.qtype = QType::SOA;
942d4729 315 d_question.qname = shorter;
5b9ac871
KM
316 d_question.zoneId = -1;
317
318 cstat = cacheHas(d_question,d_answers);
319
320 if(cstat == 1 && !d_answers.empty() && d_cache_ttl) {
e6a9dde5 321 DLOG(g_log<<Logger::Error<<"has pos cache entry: "<<shorter<<endl);
90ba52e0 322 fillSOAData(d_answers[0], *sd);
323
5b9ac871 324 sd->db = 0;
942d4729 325 sd->qname = shorter;
5b9ac871
KM
326 goto found;
327 } else if(cstat == 0 && d_negcache_ttl) {
e6a9dde5 328 DLOG(g_log<<Logger::Error<<"has neg cache entry: "<<shorter<<endl);
5b9ac871 329 continue;
c14bc34a 330 }
c14bc34a 331 }
f70be3c3 332
5b9ac871
KM
333 // Check backends
334 {
335 vector<DNSBackend *>::const_iterator i = backends.begin();
336 vector<pair<size_t, SOAData> >::iterator j = bestmatch.begin();
337 for(; i != backends.end() && j != bestmatch.end(); ++i, ++j) {
338
e6a9dde5 339 DLOG(g_log<<Logger::Error<<"backend: "<<i-backends.begin()<<", qname: "<<shorter<<endl);
5b9ac871 340
942d4729 341 if(j->first < shorter.wirelength()) {
e6a9dde5 342 DLOG(g_log<<Logger::Error<<"skipped, we already found a shorter best match in this backend: "<<j->second.qname<<endl);
5b9ac871 343 continue;
942d4729 344 } else if(j->first == shorter.wirelength()) {
e6a9dde5 345 DLOG(g_log<<Logger::Error<<"use shorter best match: "<<j->second.qname<<endl);
5b9ac871
KM
346 *sd = j->second;
347 break;
348 } else {
e6a9dde5 349 DLOG(g_log<<Logger::Error<<"lookup: "<<shorter<<endl);
942d4729 350 if((*i)->getAuth(shorter, sd)) {
e6a9dde5 351 DLOG(g_log<<Logger::Error<<"got: "<<sd->qname<<endl);
41147d67 352 if(!sd->qname.empty() && !shorter.isPartOf(sd->qname)) {
37029707
KM
353 throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '"+sd->qname.toLogString()+"' is not part of '"+shorter.toLogString()+"'");
354 }
5b9ac871 355 j->first = sd->qname.wirelength();
bee25428 356 j->second = *sd;
942d4729 357 if(sd->qname == shorter) {
5b9ac871
KM
358 break;
359 }
360 } else {
e6a9dde5 361 DLOG(g_log<<Logger::Error<<"no match for: "<<shorter<<endl);
5b9ac871
KM
362 }
363 }
f70be3c3 364 }
c14bc34a 365
5b9ac871
KM
366 // Add to cache
367 if(i == backends.end()) {
368 if(d_negcache_ttl) {
e6a9dde5 369 DLOG(g_log<<Logger::Error<<"add neg cache entry:"<<shorter<<endl);
942d4729 370 d_question.qname=shorter;
5b9ac871
KM
371 addNegCache(d_question);
372 }
373 continue;
374 } else if(d_cache_ttl) {
e6a9dde5 375 DLOG(g_log<<Logger::Error<<"add pos cache entry: "<<sd->qname<<endl);
c14bc34a
MZ
376 d_question.qtype = QType::SOA;
377 d_question.qname = sd->qname;
378 d_question.zoneId = -1;
379
90ba52e0 380 DNSZoneRecord rr;
381 rr.dr.d_name = sd->qname;
382 rr.dr.d_type = QType::SOA;
90ba52e0 383 rr.dr.d_content = makeSOAContent(*sd);
384 rr.dr.d_ttl = sd->ttl;
c14bc34a 385 rr.domain_id = sd->domain_id;
90ba52e0 386
387 addCache(d_question, {rr});
5b9ac871 388 }
c14bc34a
MZ
389 }
390
5b9ac871 391found:
942d4729 392 if(found == (qtype == QType::DS) || target != shorter) {
e6a9dde5 393 DLOG(g_log<<Logger::Error<<"found: "<<sd->qname<<endl);
5b9ac871
KM
394 return true;
395 } else {
e6a9dde5 396 DLOG(g_log<<Logger::Error<<"chasing next: "<<sd->qname<<endl);
5b9ac871
KM
397 found = true;
398 }
399
942d4729 400 } while(shorter.chopOff());
5b9ac871 401 return found;
c14bc34a
MZ
402}
403
94bfa5b6 404bool UeberBackend::getSOA(const DNSName &domain, SOAData &sd)
12c86877
BH
405{
406 d_question.qtype=QType::SOA;
407 d_question.qname=domain;
408 d_question.zoneId=-1;
409
79ba7763
CH
410 int cstat=cacheHas(d_question,d_answers);
411 if(cstat==0) { // negative
412 return false;
12c86877 413 }
79ba7763 414 else if(cstat==1 && !d_answers.empty()) {
90ba52e0 415 fillSOAData(d_answers[0],sd);
79ba7763 416 sd.domain_id=d_answers[0].domain_id;
90ba52e0 417 sd.ttl=d_answers[0].dr.d_ttl;
79ba7763
CH
418 sd.db=0;
419 return true;
420 }
421
422 // not found in neg. or pos. cache, look it up
76e1255a 423 return getSOAUncached(domain, sd);
79ba7763
CH
424}
425
76e1255a 426bool UeberBackend::getSOAUncached(const DNSName &domain, SOAData &sd)
79ba7763
CH
427{
428 d_question.qtype=QType::SOA;
429 d_question.qname=domain;
430 d_question.zoneId=-1;
431
12c86877 432 for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
76e1255a 433 if((*i)->getSOA(domain, sd)) {
37029707
KM
434 if(domain != sd.qname) {
435 throw PDNSException("getSOA() returned an SOA for the wrong zone. Question: '"+domain.toLogString()+"', answer: '"+sd.qname.toLogString()+"'");
436 }
76e1255a 437 if(d_cache_ttl) {
90ba52e0 438 DNSZoneRecord rr;
439 rr.dr.d_name = sd.qname;
440 rr.dr.d_type = QType::SOA;
90ba52e0 441 rr.dr.d_content = makeSOAContent(sd);
442 rr.dr.d_ttl = sd.ttl;
443 rr.domain_id = sd.domain_id;
444
445 addCache(d_question, {rr});
446
f1d64762 447 }
12c86877
BH
448 return true;
449 }
450
b87f301b
KM
451 if(d_negcache_ttl)
452 addNegCache(d_question);
12c86877
BH
453 return false;
454}
455
675fa24c 456bool UeberBackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
12c86877
BH
457{
458 for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
719f9024 459 if((*i)->superMasterBackend(ip, domain, nsset, nameserver, account, db))
12c86877
BH
460 return true;
461 return false;
12c86877
BH
462}
463
12c86877
BH
464UeberBackend::UeberBackend(const string &pname)
465{
12c86877
BH
466 pthread_mutex_lock(&instances_lock);
467 instances.push_back(this); // report to the static list of ourself
468 pthread_mutex_unlock(&instances_lock);
469
51d01c80
AT
470 d_negcached=0;
471 d_ancount=0;
ce4a60ce 472 d_domain_id=-1;
51d01c80 473 d_cached=0;
f1d64762
MZ
474 d_cache_ttl = ::arg().asNum("query-cache-ttl");
475 d_negcache_ttl = ::arg().asNum("negquery-cache-ttl");
476
ce4a60ce
CH
477 d_tid=pthread_self();
478 d_stale=false;
12c86877 479
e0d84497 480 backends=BackendMakers().all(pname=="key-only");
12c86877
BH
481}
482
12c86877
BH
483void del(DNSBackend* d)
484{
485 delete d;
486}
487
488void UeberBackend::cleanup()
489{
490 pthread_mutex_lock(&instances_lock);
491
492 remove(instances.begin(),instances.end(),this);
493 instances.resize(instances.size()-1);
494
495 pthread_mutex_unlock(&instances_lock);
496
6242d8a4 497 for_each(backends.begin(),backends.end(),del);
12c86877
BH
498}
499
cb433f9c 500// returns -1 for miss, 0 for negative match, 1 for hit
90ba52e0 501int UeberBackend::cacheHas(const Question &q, vector<DNSZoneRecord> &rrs)
12c86877 502{
bf269e28 503 extern AuthQueryCache QC;
12c86877 504
f1d64762 505 if(!d_cache_ttl && ! d_negcache_ttl) {
12c86877
BH
506 return -1;
507 }
508
a3b6f8d0 509 rrs.clear();
e6a9dde5 510 // g_log<<Logger::Warning<<"looking up: '"<<q.qname+"'|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
cf71f03f 511
bf269e28 512 bool ret=QC.getEntry(q.qname, q.qtype, rrs, q.zoneId); // think about lowercasing here
12c86877 513 if(!ret) {
12c86877
BH
514 return -1;
515 }
a3b6f8d0 516 if(rrs.empty()) // negatively cached
12c86877 517 return 0;
cb433f9c 518
12c86877
BH
519 return 1;
520}
521
522void UeberBackend::addNegCache(const Question &q)
523{
bf269e28 524 extern AuthQueryCache QC;
f1d64762 525 if(!d_negcache_ttl)
12c86877 526 return;
ee5e1751 527 // we should also not be storing negative answers if a pipebackend does scopeMask, but we can't pass a negative scopeMask in an empty set!
bf269e28 528 QC.insert(q.qname, q.qtype, vector<DNSZoneRecord>(), d_negcache_ttl, q.zoneId);
12c86877
BH
529}
530
9bbcf03a 531void UeberBackend::addCache(const Question &q, vector<DNSZoneRecord> &&rrs)
12c86877 532{
bf269e28 533 extern AuthQueryCache QC;
46c6efbe 534
f1d64762 535 if(!d_cache_ttl)
12c86877 536 return;
f1d64762
MZ
537
538 unsigned int store_ttl = d_cache_ttl;
90ba52e0 539 for(const auto& rr : rrs) {
540 if (rr.dr.d_ttl < d_cache_ttl)
541 store_ttl = rr.dr.d_ttl;
429ae4cb 542 if (rr.scopeMask)
543 return;
544 }
545
9bbcf03a 546 QC.insert(q.qname, q.qtype, std::move(rrs), store_ttl, q.zoneId);
12c86877
BH
547}
548
675fa24c 549void UeberBackend::alsoNotifies(const DNSName &domain, set<string> *ips)
27d94a79
BH
550{
551 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
552 (*i)->alsoNotifies(domain,ips);
553}
12c86877
BH
554
555UeberBackend::~UeberBackend()
556{
e6a9dde5 557 DLOG(g_log<<Logger::Error<<"UeberBackend destructor called, removing ourselves from instances, and deleting our backends"<<endl);
12c86877
BH
558 cleanup();
559}
560
561// this handle is more magic than most
acb61e0a 562void UeberBackend::lookup(const QType &qtype,const DNSName &qname, int zoneId, DNSPacket *pkt_p)
12c86877 563{
ce4a60ce 564 if(d_stale) {
e6a9dde5 565 g_log<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl;
3f81d239 566 throw PDNSException("We are stale, please recycle");
12c86877
BH
567 }
568
e6a9dde5 569 DLOG(g_log<<"UeberBackend received question for "<<qtype.getName()<<" of "<<qname<<endl);
12c86877
BH
570 if(!d_go) {
571 pthread_mutex_lock(&d_mut);
572 while (d_go==false) {
e6a9dde5 573 g_log<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl;
12c86877 574 pthread_cond_wait(&d_cond, &d_mut);
e6a9dde5 575 g_log<<Logger::Error<<"Broadcast received, unblocked"<<endl;
12c86877
BH
576 }
577 pthread_mutex_unlock(&d_mut);
578 }
579
ce4a60ce 580 d_domain_id=zoneId;
c27c8d96 581
12c86877
BH
582 d_handle.i=0;
583 d_handle.qtype=qtype;
584 d_handle.qname=qname;
585 d_handle.pkt_p=pkt_p;
586 d_ancount=0;
587
588 if(!backends.size()) {
e6a9dde5 589 g_log<<Logger::Error<<"No database backends available - unable to answer questions."<<endl;
ce4a60ce 590 d_stale=true; // please recycle us!
3f81d239 591 throw PDNSException("We are stale, please recycle");
12c86877
BH
592 }
593 else {
6242d8a4
KM
594 d_question.qtype=qtype;
595 d_question.qname=qname;
596 d_question.zoneId=zoneId;
597 int cstat=cacheHas(d_question, d_answers);
598 if(cstat<0) { // nothing
aa7b2405 599 // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): uncached"<<endl;
6242d8a4
KM
600 d_negcached=d_cached=false;
601 d_answers.clear();
acb61e0a 602 (d_handle.d_hinterBackend=backends[d_handle.i++])->lookup(qtype, qname,zoneId,pkt_p);
6242d8a4
KM
603 }
604 else if(cstat==0) {
aa7b2405 605 // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): NEGcached"<<endl;
6242d8a4
KM
606 d_negcached=true;
607 d_cached=false;
608 d_answers.clear();
609 }
610 else {
aa7b2405 611 // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): CACHED"<<endl;
6242d8a4
KM
612 d_negcached=false;
613 d_cached=true;
614 d_cachehandleiter = d_answers.begin();
615 }
12c86877
BH
616 }
617
618 d_handle.parent=this;
12c86877
BH
619}
620
cea26350 621void UeberBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled) {
1325e8a2
PD
622 for (vector<DNSBackend*>::iterator i = backends.begin(); i != backends.end(); ++i )
623 {
cea26350 624 (*i)->getAllDomains(domains, include_disabled);
1325e8a2
PD
625 }
626}
627
90ba52e0 628bool UeberBackend::get(DNSZoneRecord &rr)
12c86877 629{
aa7b2405 630 // cout<<"UeberBackend::get(DNSZoneRecord) called"<<endl;
12c86877
BH
631 if(d_negcached) {
632 return false;
633 }
634
635 if(d_cached) {
cb433f9c
BH
636 if(d_cachehandleiter != d_answers.end()) {
637 rr=*d_cachehandleiter++;;
638 return true;
639 }
640 return false;
12c86877 641 }
12c86877 642 if(!d_handle.get(rr)) {
aa7b2405 643 // cout<<"end of ueberbackend get, seeing if we should cache"<<endl;
644 if(!d_ancount && d_handle.qname.countLabels()) {// don't cache axfr
16925355 645 // cout<<"adding negcache"<<endl;
12c86877 646 addNegCache(d_question);
aa7b2405 647 }
648 else {
649 // cout<<"adding query cache"<<endl;
9bbcf03a 650 addCache(d_question, std::move(d_answers));
aa7b2405 651 }
cb433f9c 652 d_answers.clear();
12c86877
BH
653 return false;
654 }
2ac9fd56
KM
655
656 rr.dr.d_place=DNSResourceRecord::ANSWER;
657
cb433f9c
BH
658 d_ancount++;
659 d_answers.push_back(rr);
12c86877
BH
660 return true;
661}
662
9f8e226e
AT
663bool UeberBackend::searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result)
664{
665 bool rc = false;
666 for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && i != backends.end(); ++i )
667 if ((*i)->searchRecords(pattern, maxResults - result.size(), result)) rc = true;
668 return rc;
669}
670
671bool UeberBackend::searchComments(const string& pattern, int maxResults, vector<Comment>& result)
672{
673 bool rc = false;
674 for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<Comment>::size_type>(maxResults) && i != backends.end(); ++i )
675 if ((*i)->searchComments(pattern, maxResults - result.size(), result)) rc = true;
676 return rc;
677}
12c86877 678
16f7d28d 679AtomicCounter UeberBackend::handle::instances(0);
12c86877
BH
680
681UeberBackend::handle::handle()
682{
e6a9dde5 683 // g_log<<Logger::Warning<<"Handle instances: "<<instances<<endl;
16f7d28d 684 ++instances;
457d7c72
AT
685 parent=NULL;
686 d_hinterBackend=NULL;
687 pkt_p=NULL;
688 i=0;
12c86877
BH
689}
690
691UeberBackend::handle::~handle()
692{
16f7d28d 693 --instances;
12c86877
BH
694}
695
90ba52e0 696bool UeberBackend::handle::get(DNSZoneRecord &r)
12c86877 697{
e6a9dde5 698 DLOG(g_log << "Ueber get() was called for a "<<qtype.getName()<<" record" << endl);
12c86877
BH
699 bool isMore=false;
700 while(d_hinterBackend && !(isMore=d_hinterBackend->get(r))) { // this backend out of answers
701 if(i<parent->backends.size()) {
e6a9dde5 702 DLOG(g_log<<"Backend #"<<i<<" of "<<parent->backends.size()
4957a608 703 <<" out of answers, taking next"<<endl);
12c86877
BH
704
705 d_hinterBackend=parent->backends[i++];
acb61e0a 706 d_hinterBackend->lookup(qtype,qname,parent->d_domain_id,pkt_p);
12c86877
BH
707 }
708 else
709 break;
710
e6a9dde5 711 DLOG(g_log<<"Now asking backend #"<<i<<endl);
12c86877
BH
712 }
713
714 if(!isMore && i==parent->backends.size()) {
e6a9dde5 715 DLOG(g_log<<"UeberBackend reached end of backends"<<endl);
12c86877
BH
716 return false;
717 }
718
e6a9dde5 719 DLOG(g_log<<"Found an answering backend - will not try another one"<<endl);
12c86877
BH
720 i=parent->backends.size(); // don't go on to the next backend
721 return true;
722}