]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/ueberbackend.cc
rec: Update new b-root-server.net addresses in built-in hints.
[thirdparty/pdns.git] / pdns / ueberbackend.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <boost/archive/binary_iarchive.hpp>
26 #include <boost/archive/binary_oarchive.hpp>
27
28 #include "auth-querycache.hh"
29 #include "auth-zonecache.hh"
30 #include "utility.hh"
31
32
33 #include <dlfcn.h>
34 #include <string>
35 #include <map>
36 #include <sys/types.h>
37 #include <sstream>
38 #include <cerrno>
39 #include <iostream>
40 #include <sstream>
41 #include <functional>
42
43 #include "dns.hh"
44 #include "arguments.hh"
45 #include "dnsbackend.hh"
46 #include "ueberbackend.hh"
47 #include "dnspacket.hh"
48 #include "logger.hh"
49 #include "statbag.hh"
50
51 extern StatBag S;
52
53 LockGuarded<vector<UeberBackend *>> UeberBackend::d_instances;
54
55 // initially we are blocked
56 bool UeberBackend::d_go=false;
57 bool UeberBackend::s_doANYLookupsOnly=false;
58 std::mutex UeberBackend::d_mut;
59 std::condition_variable UeberBackend::d_cond;
60 AtomicCounter* UeberBackend::s_backendQueries = nullptr;
61
62 //! Loads a module and reports it to all UeberBackend threads
63 bool UeberBackend::loadmodule(const string &name)
64 {
65 g_log<<Logger::Warning <<"Loading '"<<name<<"'" << endl;
66
67 void *dlib=dlopen(name.c_str(), RTLD_NOW);
68
69 if(dlib == nullptr) {
70 g_log<<Logger::Error <<"Unable to load module '"<<name<<"': "<<dlerror() << endl;
71 return false;
72 }
73
74 return true;
75 }
76
77 bool UeberBackend::loadModules(const vector<string>& modules, const string& path)
78 {
79 for (const auto& module: modules) {
80 bool res;
81 if (module.find('.')==string::npos) {
82 res = UeberBackend::loadmodule(path+"/lib"+module+"backend.so");
83 } else if (module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) {
84 // absolute or current path
85 res = UeberBackend::loadmodule(module);
86 } else {
87 res = UeberBackend::loadmodule(path+"/"+module);
88 }
89
90 if (res == false) {
91 return false;
92 }
93 }
94 return true;
95 }
96
97 void UeberBackend::go()
98 {
99 if (::arg().mustDo("consistent-backends")) {
100 s_doANYLookupsOnly = true;
101 }
102
103 S.declare("backend-queries", "Number of queries sent to the backend(s)");
104 s_backendQueries = S.getPointer("backend-queries");
105
106 {
107 std::unique_lock<std::mutex> l(d_mut);
108 d_go = true;
109 }
110 d_cond.notify_all();
111 }
112
113 bool UeberBackend::getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial)
114 {
115 for(auto backend : backends)
116 if(backend->getDomainInfo(domain, di, getSerial))
117 return true;
118 return false;
119 }
120
121 bool UeberBackend::createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account)
122 {
123 for(DNSBackend* mydb : backends) {
124 if (mydb->createDomain(domain, kind, masters, account)) {
125 return true;
126 }
127 }
128 return false;
129 }
130
131 bool UeberBackend::doesDNSSEC()
132 {
133 for(auto* db : backends) {
134 if(db->doesDNSSEC())
135 return true;
136 }
137 return false;
138 }
139
140 bool UeberBackend::addDomainKey(const DNSName& name, const DNSBackend::KeyData& key, int64_t& id)
141 {
142 id = -1;
143 for(DNSBackend* db : backends) {
144 if(db->addDomainKey(name, key, id))
145 return true;
146 }
147 return false;
148 }
149 bool UeberBackend::getDomainKeys(const DNSName& name, std::vector<DNSBackend::KeyData>& keys)
150 {
151 for(DNSBackend* db : backends) {
152 if(db->getDomainKeys(name, keys))
153 return true;
154 }
155 return false;
156 }
157
158 bool UeberBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
159 {
160 for(DNSBackend* db : backends) {
161 if(db->getAllDomainMetadata(name, meta))
162 return true;
163 }
164 return false;
165 }
166
167 bool UeberBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
168 {
169 for(DNSBackend* db : backends) {
170 if(db->getDomainMetadata(name, kind, meta))
171 return true;
172 }
173 return false;
174 }
175
176 bool UeberBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::string& meta)
177 {
178 bool ret;
179 meta.clear();
180 std::vector<string> tmp;
181 if ((ret = getDomainMetadata(name, kind, tmp)) && !tmp.empty()) {
182 meta = *tmp.begin();
183 }
184 return ret;
185 }
186
187 bool UeberBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
188 {
189 for(DNSBackend* db : backends) {
190 if(db->setDomainMetadata(name, kind, meta))
191 return true;
192 }
193 return false;
194 }
195
196 bool UeberBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::string& meta)
197 {
198 std::vector<string> tmp;
199 if (!meta.empty()) {
200 tmp.push_back(meta);
201 }
202 return setDomainMetadata(name, kind, tmp);
203 }
204
205 bool UeberBackend::activateDomainKey(const DNSName& name, unsigned int id)
206 {
207 for(DNSBackend* db : backends) {
208 if(db->activateDomainKey(name, id))
209 return true;
210 }
211 return false;
212 }
213
214 bool UeberBackend::deactivateDomainKey(const DNSName& name, unsigned int id)
215 {
216 for(DNSBackend* db : backends) {
217 if(db->deactivateDomainKey(name, id))
218 return true;
219 }
220 return false;
221 }
222
223 bool UeberBackend::publishDomainKey(const DNSName& name, unsigned int id)
224 {
225 for(DNSBackend* db : backends) {
226 if(db->publishDomainKey(name, id))
227 return true;
228 }
229 return false;
230 }
231
232 bool UeberBackend::unpublishDomainKey(const DNSName& name, unsigned int id)
233 {
234 for(DNSBackend* db : backends) {
235 if(db->unpublishDomainKey(name, id))
236 return true;
237 }
238 return false;
239 }
240
241
242 bool UeberBackend::removeDomainKey(const DNSName& name, unsigned int id)
243 {
244 for(DNSBackend* db : backends) {
245 if(db->removeDomainKey(name, id))
246 return true;
247 }
248 return false;
249 }
250
251
252
253 void UeberBackend::reload()
254 {
255 for (auto & backend : backends)
256 {
257 backend->reload();
258 }
259 }
260
261 void UeberBackend::updateZoneCache() {
262 if (!g_zoneCache.isEnabled()) {
263 return;
264 }
265
266 vector<std::tuple<DNSName, int>> zone_indices;
267 g_zoneCache.setReplacePending();
268
269 for (vector<DNSBackend*>::iterator i = backends.begin(); i != backends.end(); ++i )
270 {
271 vector<DomainInfo> zones;
272 (*i)->getAllDomains(&zones, false, true);
273 for(auto& di: zones) {
274 zone_indices.emplace_back(std::move(di.zone), (int)di.id); // this cast should not be necessary
275 }
276 }
277 g_zoneCache.replace(zone_indices);
278 }
279
280 void UeberBackend::rediscover(string *status)
281 {
282 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
283 {
284 string tmpstr;
285 ( *i )->rediscover(&tmpstr);
286 if(status)
287 *status+=tmpstr + (i!=backends.begin() ? "\n" : "");
288 }
289
290 updateZoneCache();
291 }
292
293
294 void UeberBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
295 {
296 for (auto & backend : backends)
297 {
298 backend->getUnfreshSlaveInfos( domains );
299 }
300 }
301
302 void UeberBackend::getUpdatedMasters(vector<DomainInfo>& domains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes)
303 {
304 for (auto & backend : backends)
305 {
306 backend->getUpdatedMasters(domains, catalogs, catalogHashes);
307 }
308 }
309
310 bool UeberBackend::inTransaction()
311 {
312 for (auto* b : backends )
313 {
314 if(b->inTransaction())
315 return true;
316 }
317 return false;
318 }
319
320 bool UeberBackend::getAuth(const DNSName &target, const QType& qtype, SOAData* sd, bool cachedOk)
321 {
322 // A backend can respond to our authority request with the 'best' match it
323 // has. For example, when asked for a.b.c.example.com. it might respond with
324 // com. We then store that and keep querying the other backends in case one
325 // of them has a more specific zone but don't bother asking this specific
326 // backend again for b.c.example.com., c.example.com. and example.com.
327 // If a backend has no match it may respond with an empty qname.
328 bool found = false;
329 int cstat;
330 DNSName shorter(target);
331 vector<pair<size_t, SOAData> > bestmatch (backends.size(), pair(target.wirelength()+1, SOAData()));
332 do {
333 int zoneId{-1};
334 if(cachedOk && g_zoneCache.isEnabled()) {
335 if (g_zoneCache.getEntry(shorter, zoneId)) {
336 // Zone exists in zone cache, directly look up SOA.
337 DNSZoneRecord zr;
338 lookup(QType(QType::SOA), shorter, zoneId, nullptr);
339 if (!get(zr)) {
340 DLOG(g_log << Logger::Info << "Backend returned no SOA for zone '" << shorter.toLogString() << "', which it reported as existing " << endl);
341 continue;
342 }
343 if (zr.dr.d_name != shorter) {
344 throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '"+zr.dr.d_name.toLogString()+"' is not equal to looked up zone '"+shorter.toLogString()+"'");
345 }
346 // fill sd
347 sd->qname = zr.dr.d_name;
348 try {
349 fillSOAData(zr, *sd);
350 }
351 catch (...) {
352 g_log << Logger::Warning << "Backend returned a broken SOA for zone '" << shorter.toLogString() << "'" << endl;
353 while (get(zr))
354 ;
355 continue;
356 }
357 if (backends.size() == 1) {
358 sd->db = *backends.begin();
359 }
360 else {
361 sd->db = nullptr;
362 }
363 // leave database handle in a consistent state
364 while (get(zr))
365 ;
366 goto found;
367 }
368 // zone does not exist, try again with shorter name
369 continue;
370 }
371
372 d_question.qtype = QType::SOA;
373 d_question.qname = shorter;
374 d_question.zoneId = zoneId;
375
376 // Check cache
377 if(cachedOk && (d_cache_ttl || d_negcache_ttl)) {
378 cstat = cacheHas(d_question,d_answers);
379
380 if(cstat == 1 && !d_answers.empty() && d_cache_ttl) {
381 DLOG(g_log<<Logger::Error<<"has pos cache entry: "<<shorter<<endl);
382 fillSOAData(d_answers[0], *sd);
383
384 if (backends.size() == 1) {
385 sd->db = *backends.begin();
386 } else {
387 sd->db = nullptr;
388 }
389 sd->qname = shorter;
390 goto found;
391 } else if(cstat == 0 && d_negcache_ttl) {
392 DLOG(g_log<<Logger::Error<<"has neg cache entry: "<<shorter<<endl);
393 continue;
394 }
395 }
396
397 // Check backends
398 {
399 vector<DNSBackend *>::const_iterator i = backends.begin();
400 vector<pair<size_t, SOAData> >::iterator j = bestmatch.begin();
401 for(; i != backends.end() && j != bestmatch.end(); ++i, ++j) {
402
403 DLOG(g_log<<Logger::Error<<"backend: "<<i-backends.begin()<<", qname: "<<shorter<<endl);
404
405 if(j->first < shorter.wirelength()) {
406 DLOG(g_log<<Logger::Error<<"skipped, we already found a shorter best match in this backend: "<<j->second.qname<<endl);
407 continue;
408 } else if(j->first == shorter.wirelength()) {
409 DLOG(g_log<<Logger::Error<<"use shorter best match: "<<j->second.qname<<endl);
410 *sd = j->second;
411 break;
412 } else {
413 DLOG(g_log<<Logger::Error<<"lookup: "<<shorter<<endl);
414 if((*i)->getAuth(shorter, sd)) {
415 DLOG(g_log<<Logger::Error<<"got: "<<sd->qname<<endl);
416 if(!sd->qname.empty() && !shorter.isPartOf(sd->qname)) {
417 throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '"+sd->qname.toLogString()+"' is not part of '"+shorter.toLogString()+"'");
418 }
419 j->first = sd->qname.wirelength();
420 j->second = *sd;
421 if(sd->qname == shorter) {
422 break;
423 }
424 } else {
425 DLOG(g_log<<Logger::Error<<"no match for: "<<shorter<<endl);
426 }
427 }
428 }
429
430 // Add to cache
431 if(i == backends.end()) {
432 if(d_negcache_ttl) {
433 DLOG(g_log<<Logger::Error<<"add neg cache entry:"<<shorter<<endl);
434 d_question.qname=shorter;
435 addNegCache(d_question);
436 }
437 continue;
438 } else if(d_cache_ttl) {
439 DLOG(g_log<<Logger::Error<<"add pos cache entry: "<<sd->qname<<endl);
440 d_question.qtype = QType::SOA;
441 d_question.qname = sd->qname;
442 d_question.zoneId = zoneId;
443
444 DNSZoneRecord rr;
445 rr.dr.d_name = sd->qname;
446 rr.dr.d_type = QType::SOA;
447 rr.dr.setContent(makeSOAContent(*sd));
448 rr.dr.d_ttl = sd->ttl;
449 rr.domain_id = sd->domain_id;
450
451 addCache(d_question, {rr});
452 }
453 }
454
455 found:
456 if(found == (qtype == QType::DS) || target != shorter) {
457 DLOG(g_log<<Logger::Error<<"found: "<<sd->qname<<endl);
458 return true;
459 } else {
460 DLOG(g_log<<Logger::Error<<"chasing next: "<<sd->qname<<endl);
461 found = true;
462 }
463
464 } while(shorter.chopOff());
465 return found;
466 }
467
468 bool UeberBackend::getSOAUncached(const DNSName &domain, SOAData &sd)
469 {
470 d_question.qtype=QType::SOA;
471 d_question.qname=domain;
472 d_question.zoneId=-1;
473
474 for(auto backend : backends)
475 if(backend->getSOA(domain, sd)) {
476 if(domain != sd.qname) {
477 throw PDNSException("getSOA() returned an SOA for the wrong zone. Question: '"+domain.toLogString()+"', answer: '"+sd.qname.toLogString()+"'");
478 }
479 if(d_cache_ttl) {
480 DNSZoneRecord rr;
481 rr.dr.d_name = sd.qname;
482 rr.dr.d_type = QType::SOA;
483 rr.dr.setContent(makeSOAContent(sd));
484 rr.dr.d_ttl = sd.ttl;
485 rr.domain_id = sd.domain_id;
486
487 addCache(d_question, {rr});
488
489 }
490 return true;
491 }
492
493 if(d_negcache_ttl)
494 addNegCache(d_question);
495 return false;
496 }
497
498 bool UeberBackend::superMasterAdd(const AutoPrimary &primary)
499 {
500 for(auto backend : backends)
501 if(backend->superMasterAdd(primary))
502 return true;
503 return false;
504 }
505
506 bool UeberBackend::autoPrimaryRemove(const AutoPrimary &primary)
507 {
508 for(auto backend : backends)
509 if(backend->autoPrimaryRemove(primary))
510 return true;
511 return false;
512 }
513
514 bool UeberBackend::autoPrimariesList(std::vector<AutoPrimary>& primaries)
515 {
516 for(auto backend : backends)
517 if(backend->autoPrimariesList(primaries))
518 return true;
519 return false;
520 }
521
522 bool UeberBackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
523 {
524 for(auto backend : backends)
525 if(backend->superMasterBackend(ip, domain, nsset, nameserver, account, db))
526 return true;
527 return false;
528 }
529
530 UeberBackend::UeberBackend(const string &pname)
531 {
532 {
533 d_instances.lock()->push_back(this); // report to the static list of ourself
534 }
535
536 d_negcached=false;
537 d_cached=false;
538 d_cache_ttl = ::arg().asNum("query-cache-ttl");
539 d_negcache_ttl = ::arg().asNum("negquery-cache-ttl");
540 d_qtype = 0;
541 d_stale = false;
542
543 backends=BackendMakers().all(pname=="key-only");
544 }
545
546 static void del(DNSBackend* d)
547 {
548 delete d;
549 }
550
551 void UeberBackend::cleanup()
552 {
553 {
554 auto instances = d_instances.lock();
555 remove(instances->begin(), instances->end(), this);
556 instances->resize(instances->size()-1);
557 }
558
559 for_each(backends.begin(),backends.end(),del);
560 }
561
562 // returns -1 for miss, 0 for negative match, 1 for hit
563 int UeberBackend::cacheHas(const Question &q, vector<DNSZoneRecord> &rrs)
564 {
565 extern AuthQueryCache QC;
566
567 if(!d_cache_ttl && ! d_negcache_ttl) {
568 return -1;
569 }
570
571 rrs.clear();
572 // g_log<<Logger::Warning<<"looking up: '"<<q.qname+"'|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
573
574 bool ret=QC.getEntry(q.qname, q.qtype, rrs, q.zoneId); // think about lowercasing here
575 if(!ret) {
576 return -1;
577 }
578 if(rrs.empty()) // negatively cached
579 return 0;
580
581 return 1;
582 }
583
584 void UeberBackend::addNegCache(const Question &q)
585 {
586 extern AuthQueryCache QC;
587 if(!d_negcache_ttl)
588 return;
589 // 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!
590 QC.insert(q.qname, q.qtype, vector<DNSZoneRecord>(), d_negcache_ttl, q.zoneId);
591 }
592
593 void UeberBackend::addCache(const Question &q, vector<DNSZoneRecord> &&rrs)
594 {
595 extern AuthQueryCache QC;
596
597 if(!d_cache_ttl)
598 return;
599
600 for(const auto& rr : rrs) {
601 if (rr.scopeMask)
602 return;
603 }
604
605 QC.insert(q.qname, q.qtype, std::move(rrs), d_cache_ttl, q.zoneId);
606 }
607
608 void UeberBackend::alsoNotifies(const DNSName &domain, set<string> *ips)
609 {
610 for (auto & backend : backends)
611 backend->alsoNotifies(domain,ips);
612 }
613
614 UeberBackend::~UeberBackend()
615 {
616 DLOG(g_log<<Logger::Error<<"UeberBackend destructor called, removing ourselves from instances, and deleting our backends"<<endl);
617 cleanup();
618 }
619
620 // this handle is more magic than most
621 void UeberBackend::lookup(const QType &qtype,const DNSName &qname, int zoneId, DNSPacket *pkt_p)
622 {
623 if(d_stale) {
624 g_log<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl;
625 throw PDNSException("We are stale, please recycle");
626 }
627
628 DLOG(g_log<<"UeberBackend received question for "<<qtype<<" of "<<qname<<endl);
629 if (!d_go) {
630 g_log<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl;
631 std::unique_lock<std::mutex> l(d_mut);
632 d_cond.wait(l, []{ return d_go == true; });
633 g_log<<Logger::Error<<"Broadcast received, unblocked"<<endl;
634 }
635
636 d_qtype=qtype.getCode();
637
638 d_handle.i=0;
639 d_handle.qtype=s_doANYLookupsOnly ? QType::ANY : qtype;
640 d_handle.qname=qname;
641 d_handle.zoneId=zoneId;
642 d_handle.pkt_p=pkt_p;
643
644 if(!backends.size()) {
645 g_log<<Logger::Error<<"No database backends available - unable to answer questions."<<endl;
646 d_stale=true; // please recycle us!
647 throw PDNSException("We are stale, please recycle");
648 }
649 else {
650 d_question.qtype=d_handle.qtype;
651 d_question.qname=qname;
652 d_question.zoneId=d_handle.zoneId;
653
654 int cstat=cacheHas(d_question, d_answers);
655 if(cstat<0) { // nothing
656 // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): uncached"<<endl;
657 d_negcached=d_cached=false;
658 d_answers.clear();
659 (d_handle.d_hinterBackend=backends[d_handle.i++])->lookup(d_handle.qtype, d_handle.qname, d_handle.zoneId, d_handle.pkt_p);
660 ++(*s_backendQueries);
661 }
662 else if(cstat==0) {
663 // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): NEGcached"<<endl;
664 d_negcached=true;
665 d_cached=false;
666 d_answers.clear();
667 }
668 else {
669 // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): CACHED"<<endl;
670 d_negcached=false;
671 d_cached=true;
672 d_cachehandleiter = d_answers.begin();
673 }
674 }
675
676 d_handle.parent=this;
677 }
678
679 void UeberBackend::getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled)
680 {
681 for (auto & backend : backends)
682 {
683 backend->getAllDomains(domains, getSerial, include_disabled);
684 }
685 }
686
687 bool UeberBackend::get(DNSZoneRecord &rr)
688 {
689 // cout<<"UeberBackend::get(DNSZoneRecord) called"<<endl;
690 if(d_negcached) {
691 return false;
692 }
693
694 if(d_cached) {
695 while(d_cachehandleiter != d_answers.end()) {
696 rr=*d_cachehandleiter++;;
697 if((d_qtype == QType::ANY || rr.dr.d_type == d_qtype)) {
698 return true;
699 }
700 }
701 return false;
702 }
703
704 while(d_handle.get(rr)) {
705 rr.dr.d_place=DNSResourceRecord::ANSWER;
706 d_answers.push_back(rr);
707 if((d_qtype == QType::ANY || rr.dr.d_type == d_qtype)) {
708 return true;
709 }
710 }
711
712 // cout<<"end of ueberbackend get, seeing if we should cache"<<endl;
713 if(d_answers.empty()) {
714 // cout<<"adding negcache"<<endl;
715 addNegCache(d_question);
716 }
717 else {
718 // cout<<"adding query cache"<<endl;
719 addCache(d_question, std::move(d_answers));
720 }
721 d_answers.clear();
722 return false;
723 }
724
725 // TSIG
726 //
727 bool UeberBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
728 {
729 for (auto* b : backends) {
730 if (b->setTSIGKey(name, algorithm, content)) {
731 return true;
732 }
733 }
734 return false;
735 }
736
737 bool UeberBackend::getTSIGKey(const DNSName& name, DNSName& algorithm, string& content)
738 {
739 algorithm.clear();
740 content.clear();
741
742 for (auto* b : backends) {
743 if (b->getTSIGKey(name, algorithm, content)) {
744 break;
745 }
746 }
747 return (!algorithm.empty() && !content.empty());
748 }
749
750 bool UeberBackend::getTSIGKeys(std::vector<struct TSIGKey>& keys)
751 {
752 keys.clear();
753
754 for (auto* b : backends) {
755 if (b->getTSIGKeys(keys)) {
756 return true;
757 }
758 }
759 return false;
760 }
761
762 bool UeberBackend::deleteTSIGKey(const DNSName& name)
763 {
764 for (auto* b : backends) {
765 if (b->deleteTSIGKey(name)) {
766 return true;
767 }
768 }
769 return false;
770 }
771
772 // API Search
773 //
774 bool UeberBackend::searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result)
775 {
776 bool rc = false;
777 for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && i != backends.end(); ++i )
778 if ((*i)->searchRecords(pattern, maxResults - result.size(), result)) rc = true;
779 return rc;
780 }
781
782 bool UeberBackend::searchComments(const string& pattern, int maxResults, vector<Comment>& result)
783 {
784 bool rc = false;
785 for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<Comment>::size_type>(maxResults) && i != backends.end(); ++i )
786 if ((*i)->searchComments(pattern, maxResults - result.size(), result)) rc = true;
787 return rc;
788 }
789
790 AtomicCounter UeberBackend::handle::instances(0);
791
792 UeberBackend::handle::handle()
793 {
794 // g_log<<Logger::Warning<<"Handle instances: "<<instances<<endl;
795 ++instances;
796 parent=nullptr;
797 d_hinterBackend=nullptr;
798 pkt_p=nullptr;
799 i=0;
800 zoneId = -1;
801 }
802
803 UeberBackend::handle::~handle()
804 {
805 --instances;
806 }
807
808 bool UeberBackend::handle::get(DNSZoneRecord &r)
809 {
810 DLOG(g_log << "Ueber get() was called for a "<<qtype<<" record" << endl);
811 bool isMore=false;
812 while(d_hinterBackend && !(isMore=d_hinterBackend->get(r))) { // this backend out of answers
813 if(i<parent->backends.size()) {
814 DLOG(g_log<<"Backend #"<<i<<" of "<<parent->backends.size()
815 <<" out of answers, taking next"<<endl);
816
817 d_hinterBackend=parent->backends[i++];
818 d_hinterBackend->lookup(qtype,qname,zoneId,pkt_p);
819 ++(*s_backendQueries);
820 }
821 else
822 break;
823
824 DLOG(g_log<<"Now asking backend #"<<i<<endl);
825 }
826
827 if(!isMore && i==parent->backends.size()) {
828 DLOG(g_log<<"UeberBackend reached end of backends"<<endl);
829 return false;
830 }
831
832 DLOG(g_log<<"Found an answering backend - will not try another one"<<endl);
833 i=parent->backends.size(); // don't go on to the next backend
834 return true;
835 }