]>
Commit | Line | Data |
---|---|---|
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 | |
50 | extern StatBag S; | |
51 | ||
52 | vector<UeberBackend *>UeberBackend::instances; | |
53 | pthread_mutex_t UeberBackend::instances_lock=PTHREAD_MUTEX_INITIALIZER; | |
54 | ||
12c86877 BH |
55 | // initially we are blocked |
56 | bool UeberBackend::d_go=false; | |
57 | pthread_mutex_t UeberBackend::d_mut = PTHREAD_MUTEX_INITIALIZER; | |
58 | pthread_cond_t UeberBackend::d_cond = PTHREAD_COND_INITIALIZER; | |
59 | ||
12c86877 BH |
60 | //! Loads a module and reports it to all UeberBackend threads |
61 | bool 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 |
75 | bool 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 |
95 | void 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 | 103 | bool 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 | 111 | bool 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 |
121 | bool UeberBackend::doesDNSSEC() |
122 | { | |
123 | for(auto* db : backends) { | |
124 | if(db->doesDNSSEC()) | |
125 | return true; | |
126 | } | |
127 | return false; | |
128 | } | |
129 | ||
82cc0761 | 130 | bool 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 | 139 | bool 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 | 148 | bool 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 | 157 | bool 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 | 166 | bool 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 | 175 | bool 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 | 184 | bool 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 | ||
675fa24c | 193 | bool UeberBackend::removeDomainKey(const DNSName& name, unsigned int id) |
4496f66f | 194 | { |
ef7cd021 | 195 | for(DNSBackend* db : backends) { |
4496f66f BH |
196 | if(db->removeDomainKey(name, id)) |
197 | return true; | |
198 | } | |
199 | return false; | |
200 | } | |
201 | ||
c0273500 | 202 | |
675fa24c | 203 | bool UeberBackend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) |
78bcb858 | 204 | { |
ef7cd021 | 205 | for(DNSBackend* db : backends) { |
78bcb858 BH |
206 | if(db->getTSIGKey(name, algorithm, content)) |
207 | return true; | |
208 | } | |
209 | return false; | |
210 | } | |
211 | ||
212 | ||
675fa24c | 213 | bool UeberBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) |
6f872b78 | 214 | { |
ef7cd021 | 215 | for(DNSBackend* db : backends) { |
6f872b78 AT |
216 | if(db->setTSIGKey(name, algorithm, content)) |
217 | return true; | |
218 | } | |
219 | return false; | |
220 | } | |
221 | ||
675fa24c | 222 | bool UeberBackend::deleteTSIGKey(const DNSName& name) |
6f872b78 | 223 | { |
ef7cd021 | 224 | for(DNSBackend* db : backends) { |
6f872b78 AT |
225 | if(db->deleteTSIGKey(name)) |
226 | return true; | |
227 | } | |
228 | return false; | |
229 | } | |
230 | ||
231 | bool UeberBackend::getTSIGKeys(std::vector< struct TSIGKey > &keys) | |
232 | { | |
ef7cd021 | 233 | for(DNSBackend* db : backends) { |
6f872b78 AT |
234 | db->getTSIGKeys(keys); |
235 | } | |
236 | return true; | |
237 | } | |
238 | ||
12c86877 BH |
239 | void UeberBackend::reload() |
240 | { | |
241 | for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i ) | |
242 | { | |
243 | ( *i )->reload(); | |
244 | } | |
245 | } | |
246 | ||
973ad2b5 | 247 | void UeberBackend::rediscover(string *status) |
12c86877 | 248 | { |
20ca8e7d | 249 | |
12c86877 BH |
250 | for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i ) |
251 | { | |
973ad2b5 BH |
252 | string tmpstr; |
253 | ( *i )->rediscover(&tmpstr); | |
6242d8a4 KM |
254 | if(status) |
255 | *status+=tmpstr + (i!=backends.begin() ? "\n" : ""); | |
12c86877 BH |
256 | } |
257 | } | |
258 | ||
259 | ||
260 | void UeberBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains) | |
261 | { | |
262 | for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i ) | |
263 | { | |
264 | ( *i )->getUnfreshSlaveInfos( domains ); | |
265 | } | |
266 | } | |
267 | ||
268 | ||
269 | ||
270 | void UeberBackend::getUpdatedMasters(vector<DomainInfo>* domains) | |
271 | { | |
272 | for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i ) | |
273 | { | |
274 | ( *i )->getUpdatedMasters( domains ); | |
275 | } | |
276 | } | |
277 | ||
cec52de6 | 278 | bool UeberBackend::getAuth(const DNSName &target, const QType& qtype, SOAData* sd, bool cachedOk) |
c14bc34a | 279 | { |
942d4729 KM |
280 | // A backend can respond to our authority request with the 'best' match it |
281 | // has. For example, when asked for a.b.c.example.com. it might respond with | |
282 | // com. We then store that and keep querying the other backends in case one | |
283 | // of them has a more specific zone but don't bother asking this specific | |
284 | // backend again for b.c.example.com., c.example.com. and example.com. | |
37029707 | 285 | // If a backend has no match it may respond with an empty qname. |
942d4729 | 286 | |
5b9ac871 KM |
287 | bool found = false; |
288 | int cstat; | |
942d4729 | 289 | DNSName shorter(target); |
5b9ac871 KM |
290 | vector<pair<size_t, SOAData> > bestmatch (backends.size(), make_pair(target.wirelength()+1, SOAData())); |
291 | do { | |
292 | ||
293 | // Check cache | |
cec52de6 | 294 | if(cachedOk && (d_cache_ttl || d_negcache_ttl)) { |
5b9ac871 | 295 | d_question.qtype = QType::SOA; |
942d4729 | 296 | d_question.qname = shorter; |
5b9ac871 KM |
297 | d_question.zoneId = -1; |
298 | ||
299 | cstat = cacheHas(d_question,d_answers); | |
300 | ||
301 | if(cstat == 1 && !d_answers.empty() && d_cache_ttl) { | |
e6a9dde5 | 302 | DLOG(g_log<<Logger::Error<<"has pos cache entry: "<<shorter<<endl); |
90ba52e0 | 303 | fillSOAData(d_answers[0], *sd); |
304 | ||
5b9ac871 | 305 | sd->db = 0; |
942d4729 | 306 | sd->qname = shorter; |
5b9ac871 KM |
307 | goto found; |
308 | } else if(cstat == 0 && d_negcache_ttl) { | |
e6a9dde5 | 309 | DLOG(g_log<<Logger::Error<<"has neg cache entry: "<<shorter<<endl); |
5b9ac871 | 310 | continue; |
c14bc34a | 311 | } |
c14bc34a | 312 | } |
f70be3c3 | 313 | |
5b9ac871 KM |
314 | // Check backends |
315 | { | |
316 | vector<DNSBackend *>::const_iterator i = backends.begin(); | |
317 | vector<pair<size_t, SOAData> >::iterator j = bestmatch.begin(); | |
318 | for(; i != backends.end() && j != bestmatch.end(); ++i, ++j) { | |
319 | ||
e6a9dde5 | 320 | DLOG(g_log<<Logger::Error<<"backend: "<<i-backends.begin()<<", qname: "<<shorter<<endl); |
5b9ac871 | 321 | |
942d4729 | 322 | if(j->first < shorter.wirelength()) { |
e6a9dde5 | 323 | DLOG(g_log<<Logger::Error<<"skipped, we already found a shorter best match in this backend: "<<j->second.qname<<endl); |
5b9ac871 | 324 | continue; |
942d4729 | 325 | } else if(j->first == shorter.wirelength()) { |
e6a9dde5 | 326 | DLOG(g_log<<Logger::Error<<"use shorter best match: "<<j->second.qname<<endl); |
5b9ac871 KM |
327 | *sd = j->second; |
328 | break; | |
329 | } else { | |
e6a9dde5 | 330 | DLOG(g_log<<Logger::Error<<"lookup: "<<shorter<<endl); |
942d4729 | 331 | if((*i)->getAuth(shorter, sd)) { |
e6a9dde5 | 332 | DLOG(g_log<<Logger::Error<<"got: "<<sd->qname<<endl); |
37029707 KM |
333 | if(!shorter.isPartOf(sd->qname) && !sd->qname.empty()) { |
334 | throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '"+sd->qname.toLogString()+"' is not part of '"+shorter.toLogString()+"'"); | |
335 | } | |
5b9ac871 | 336 | j->first = sd->qname.wirelength(); |
bee25428 | 337 | j->second = *sd; |
942d4729 | 338 | if(sd->qname == shorter) { |
5b9ac871 KM |
339 | break; |
340 | } | |
341 | } else { | |
e6a9dde5 | 342 | DLOG(g_log<<Logger::Error<<"no match for: "<<shorter<<endl); |
5b9ac871 KM |
343 | } |
344 | } | |
f70be3c3 | 345 | } |
c14bc34a | 346 | |
5b9ac871 KM |
347 | // Add to cache |
348 | if(i == backends.end()) { | |
349 | if(d_negcache_ttl) { | |
e6a9dde5 | 350 | DLOG(g_log<<Logger::Error<<"add neg cache entry:"<<shorter<<endl); |
942d4729 | 351 | d_question.qname=shorter; |
5b9ac871 KM |
352 | addNegCache(d_question); |
353 | } | |
354 | continue; | |
355 | } else if(d_cache_ttl) { | |
e6a9dde5 | 356 | DLOG(g_log<<Logger::Error<<"add pos cache entry: "<<sd->qname<<endl); |
c14bc34a MZ |
357 | d_question.qtype = QType::SOA; |
358 | d_question.qname = sd->qname; | |
359 | d_question.zoneId = -1; | |
360 | ||
90ba52e0 | 361 | DNSZoneRecord rr; |
362 | rr.dr.d_name = sd->qname; | |
363 | rr.dr.d_type = QType::SOA; | |
90ba52e0 | 364 | rr.dr.d_content = makeSOAContent(*sd); |
365 | rr.dr.d_ttl = sd->ttl; | |
c14bc34a | 366 | rr.domain_id = sd->domain_id; |
90ba52e0 | 367 | |
368 | addCache(d_question, {rr}); | |
5b9ac871 | 369 | } |
c14bc34a MZ |
370 | } |
371 | ||
5b9ac871 | 372 | found: |
942d4729 | 373 | if(found == (qtype == QType::DS) || target != shorter) { |
e6a9dde5 | 374 | DLOG(g_log<<Logger::Error<<"found: "<<sd->qname<<endl); |
5b9ac871 KM |
375 | return true; |
376 | } else { | |
e6a9dde5 | 377 | DLOG(g_log<<Logger::Error<<"chasing next: "<<sd->qname<<endl); |
5b9ac871 KM |
378 | found = true; |
379 | } | |
380 | ||
942d4729 | 381 | } while(shorter.chopOff()); |
5b9ac871 | 382 | return found; |
c14bc34a MZ |
383 | } |
384 | ||
94bfa5b6 | 385 | bool UeberBackend::getSOA(const DNSName &domain, SOAData &sd) |
12c86877 BH |
386 | { |
387 | d_question.qtype=QType::SOA; | |
388 | d_question.qname=domain; | |
389 | d_question.zoneId=-1; | |
390 | ||
79ba7763 CH |
391 | int cstat=cacheHas(d_question,d_answers); |
392 | if(cstat==0) { // negative | |
393 | return false; | |
12c86877 | 394 | } |
79ba7763 | 395 | else if(cstat==1 && !d_answers.empty()) { |
90ba52e0 | 396 | fillSOAData(d_answers[0],sd); |
79ba7763 | 397 | sd.domain_id=d_answers[0].domain_id; |
90ba52e0 | 398 | sd.ttl=d_answers[0].dr.d_ttl; |
79ba7763 CH |
399 | sd.db=0; |
400 | return true; | |
401 | } | |
402 | ||
403 | // not found in neg. or pos. cache, look it up | |
76e1255a | 404 | return getSOAUncached(domain, sd); |
79ba7763 CH |
405 | } |
406 | ||
76e1255a | 407 | bool UeberBackend::getSOAUncached(const DNSName &domain, SOAData &sd) |
79ba7763 CH |
408 | { |
409 | d_question.qtype=QType::SOA; | |
410 | d_question.qname=domain; | |
411 | d_question.zoneId=-1; | |
412 | ||
12c86877 | 413 | for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i) |
76e1255a | 414 | if((*i)->getSOA(domain, sd)) { |
37029707 KM |
415 | if(domain != sd.qname) { |
416 | throw PDNSException("getSOA() returned an SOA for the wrong zone. Question: '"+domain.toLogString()+"', answer: '"+sd.qname.toLogString()+"'"); | |
417 | } | |
76e1255a | 418 | if(d_cache_ttl) { |
90ba52e0 | 419 | DNSZoneRecord rr; |
420 | rr.dr.d_name = sd.qname; | |
421 | rr.dr.d_type = QType::SOA; | |
90ba52e0 | 422 | rr.dr.d_content = makeSOAContent(sd); |
423 | rr.dr.d_ttl = sd.ttl; | |
424 | rr.domain_id = sd.domain_id; | |
425 | ||
426 | addCache(d_question, {rr}); | |
427 | ||
f1d64762 | 428 | } |
12c86877 BH |
429 | return true; |
430 | } | |
431 | ||
b87f301b KM |
432 | if(d_negcache_ttl) |
433 | addNegCache(d_question); | |
12c86877 BH |
434 | return false; |
435 | } | |
436 | ||
675fa24c | 437 | bool UeberBackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db) |
12c86877 BH |
438 | { |
439 | for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i) | |
719f9024 | 440 | if((*i)->superMasterBackend(ip, domain, nsset, nameserver, account, db)) |
12c86877 BH |
441 | return true; |
442 | return false; | |
12c86877 BH |
443 | } |
444 | ||
12c86877 BH |
445 | UeberBackend::UeberBackend(const string &pname) |
446 | { | |
12c86877 BH |
447 | pthread_mutex_lock(&instances_lock); |
448 | instances.push_back(this); // report to the static list of ourself | |
449 | pthread_mutex_unlock(&instances_lock); | |
450 | ||
51d01c80 AT |
451 | d_negcached=0; |
452 | d_ancount=0; | |
ce4a60ce | 453 | d_domain_id=-1; |
51d01c80 | 454 | d_cached=0; |
f1d64762 MZ |
455 | d_cache_ttl = ::arg().asNum("query-cache-ttl"); |
456 | d_negcache_ttl = ::arg().asNum("negquery-cache-ttl"); | |
457 | ||
ce4a60ce CH |
458 | d_tid=pthread_self(); |
459 | d_stale=false; | |
12c86877 | 460 | |
e0d84497 | 461 | backends=BackendMakers().all(pname=="key-only"); |
12c86877 BH |
462 | } |
463 | ||
12c86877 BH |
464 | void del(DNSBackend* d) |
465 | { | |
466 | delete d; | |
467 | } | |
468 | ||
469 | void UeberBackend::cleanup() | |
470 | { | |
471 | pthread_mutex_lock(&instances_lock); | |
472 | ||
473 | remove(instances.begin(),instances.end(),this); | |
474 | instances.resize(instances.size()-1); | |
475 | ||
476 | pthread_mutex_unlock(&instances_lock); | |
477 | ||
6242d8a4 | 478 | for_each(backends.begin(),backends.end(),del); |
12c86877 BH |
479 | } |
480 | ||
cb433f9c | 481 | // returns -1 for miss, 0 for negative match, 1 for hit |
90ba52e0 | 482 | int UeberBackend::cacheHas(const Question &q, vector<DNSZoneRecord> &rrs) |
12c86877 | 483 | { |
bf269e28 | 484 | extern AuthQueryCache QC; |
12c86877 | 485 | |
f1d64762 | 486 | if(!d_cache_ttl && ! d_negcache_ttl) { |
12c86877 BH |
487 | return -1; |
488 | } | |
489 | ||
a3b6f8d0 | 490 | rrs.clear(); |
e6a9dde5 | 491 | // g_log<<Logger::Warning<<"looking up: '"<<q.qname+"'|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl; |
cf71f03f | 492 | |
bf269e28 | 493 | bool ret=QC.getEntry(q.qname, q.qtype, rrs, q.zoneId); // think about lowercasing here |
12c86877 | 494 | if(!ret) { |
12c86877 BH |
495 | return -1; |
496 | } | |
a3b6f8d0 | 497 | if(rrs.empty()) // negatively cached |
12c86877 | 498 | return 0; |
cb433f9c | 499 | |
12c86877 BH |
500 | return 1; |
501 | } | |
502 | ||
503 | void UeberBackend::addNegCache(const Question &q) | |
504 | { | |
bf269e28 | 505 | extern AuthQueryCache QC; |
f1d64762 | 506 | if(!d_negcache_ttl) |
12c86877 | 507 | return; |
ee5e1751 | 508 | // 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 | 509 | QC.insert(q.qname, q.qtype, vector<DNSZoneRecord>(), d_negcache_ttl, q.zoneId); |
12c86877 BH |
510 | } |
511 | ||
90ba52e0 | 512 | void UeberBackend::addCache(const Question &q, const vector<DNSZoneRecord> &rrs) |
12c86877 | 513 | { |
bf269e28 | 514 | extern AuthQueryCache QC; |
46c6efbe | 515 | |
f1d64762 | 516 | if(!d_cache_ttl) |
12c86877 | 517 | return; |
f1d64762 MZ |
518 | |
519 | unsigned int store_ttl = d_cache_ttl; | |
90ba52e0 | 520 | for(const auto& rr : rrs) { |
521 | if (rr.dr.d_ttl < d_cache_ttl) | |
522 | store_ttl = rr.dr.d_ttl; | |
429ae4cb | 523 | if (rr.scopeMask) |
524 | return; | |
525 | } | |
526 | ||
bf269e28 | 527 | QC.insert(q.qname, q.qtype, rrs, store_ttl, q.zoneId); |
12c86877 BH |
528 | } |
529 | ||
675fa24c | 530 | void UeberBackend::alsoNotifies(const DNSName &domain, set<string> *ips) |
27d94a79 BH |
531 | { |
532 | for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i ) | |
533 | (*i)->alsoNotifies(domain,ips); | |
534 | } | |
12c86877 BH |
535 | |
536 | UeberBackend::~UeberBackend() | |
537 | { | |
e6a9dde5 | 538 | DLOG(g_log<<Logger::Error<<"UeberBackend destructor called, removing ourselves from instances, and deleting our backends"<<endl); |
12c86877 BH |
539 | cleanup(); |
540 | } | |
541 | ||
542 | // this handle is more magic than most | |
675fa24c | 543 | void UeberBackend::lookup(const QType &qtype,const DNSName &qname, DNSPacket *pkt_p, int zoneId) |
12c86877 | 544 | { |
ce4a60ce | 545 | if(d_stale) { |
e6a9dde5 | 546 | g_log<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl; |
3f81d239 | 547 | throw PDNSException("We are stale, please recycle"); |
12c86877 BH |
548 | } |
549 | ||
e6a9dde5 | 550 | DLOG(g_log<<"UeberBackend received question for "<<qtype.getName()<<" of "<<qname<<endl); |
12c86877 BH |
551 | if(!d_go) { |
552 | pthread_mutex_lock(&d_mut); | |
553 | while (d_go==false) { | |
e6a9dde5 | 554 | g_log<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl; |
12c86877 | 555 | pthread_cond_wait(&d_cond, &d_mut); |
e6a9dde5 | 556 | g_log<<Logger::Error<<"Broadcast received, unblocked"<<endl; |
12c86877 BH |
557 | } |
558 | pthread_mutex_unlock(&d_mut); | |
559 | } | |
560 | ||
ce4a60ce | 561 | d_domain_id=zoneId; |
c27c8d96 | 562 | |
12c86877 BH |
563 | d_handle.i=0; |
564 | d_handle.qtype=qtype; | |
565 | d_handle.qname=qname; | |
566 | d_handle.pkt_p=pkt_p; | |
567 | d_ancount=0; | |
568 | ||
569 | if(!backends.size()) { | |
e6a9dde5 | 570 | g_log<<Logger::Error<<"No database backends available - unable to answer questions."<<endl; |
ce4a60ce | 571 | d_stale=true; // please recycle us! |
3f81d239 | 572 | throw PDNSException("We are stale, please recycle"); |
12c86877 BH |
573 | } |
574 | else { | |
6242d8a4 KM |
575 | d_question.qtype=qtype; |
576 | d_question.qname=qname; | |
577 | d_question.zoneId=zoneId; | |
578 | int cstat=cacheHas(d_question, d_answers); | |
579 | if(cstat<0) { // nothing | |
aa7b2405 | 580 | // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): uncached"<<endl; |
6242d8a4 KM |
581 | d_negcached=d_cached=false; |
582 | d_answers.clear(); | |
583 | (d_handle.d_hinterBackend=backends[d_handle.i++])->lookup(qtype, qname,pkt_p,zoneId); | |
584 | } | |
585 | else if(cstat==0) { | |
aa7b2405 | 586 | // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): NEGcached"<<endl; |
6242d8a4 KM |
587 | d_negcached=true; |
588 | d_cached=false; | |
589 | d_answers.clear(); | |
590 | } | |
591 | else { | |
aa7b2405 | 592 | // cout<<"UeberBackend::lookup("<<qname<<"|"<<DNSRecordContent::NumberToType(qtype.getCode())<<"): CACHED"<<endl; |
6242d8a4 KM |
593 | d_negcached=false; |
594 | d_cached=true; | |
595 | d_cachehandleiter = d_answers.begin(); | |
596 | } | |
12c86877 BH |
597 | } |
598 | ||
599 | d_handle.parent=this; | |
12c86877 BH |
600 | } |
601 | ||
cea26350 | 602 | void UeberBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled) { |
1325e8a2 PD |
603 | for (vector<DNSBackend*>::iterator i = backends.begin(); i != backends.end(); ++i ) |
604 | { | |
cea26350 | 605 | (*i)->getAllDomains(domains, include_disabled); |
1325e8a2 PD |
606 | } |
607 | } | |
608 | ||
90ba52e0 | 609 | bool UeberBackend::get(DNSZoneRecord &rr) |
12c86877 | 610 | { |
aa7b2405 | 611 | // cout<<"UeberBackend::get(DNSZoneRecord) called"<<endl; |
12c86877 BH |
612 | if(d_negcached) { |
613 | return false; | |
614 | } | |
615 | ||
616 | if(d_cached) { | |
cb433f9c BH |
617 | if(d_cachehandleiter != d_answers.end()) { |
618 | rr=*d_cachehandleiter++;; | |
619 | return true; | |
620 | } | |
621 | return false; | |
12c86877 | 622 | } |
12c86877 | 623 | if(!d_handle.get(rr)) { |
aa7b2405 | 624 | // cout<<"end of ueberbackend get, seeing if we should cache"<<endl; |
625 | if(!d_ancount && d_handle.qname.countLabels()) {// don't cache axfr | |
16925355 | 626 | // cout<<"adding negcache"<<endl; |
12c86877 | 627 | addNegCache(d_question); |
aa7b2405 | 628 | } |
629 | else { | |
630 | // cout<<"adding query cache"<<endl; | |
631 | addCache(d_question, d_answers); | |
632 | } | |
cb433f9c | 633 | d_answers.clear(); |
12c86877 BH |
634 | return false; |
635 | } | |
cb433f9c BH |
636 | d_ancount++; |
637 | d_answers.push_back(rr); | |
12c86877 BH |
638 | return true; |
639 | } | |
640 | ||
9f8e226e AT |
641 | bool UeberBackend::searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result) |
642 | { | |
643 | bool rc = false; | |
644 | for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && i != backends.end(); ++i ) | |
645 | if ((*i)->searchRecords(pattern, maxResults - result.size(), result)) rc = true; | |
646 | return rc; | |
647 | } | |
648 | ||
649 | bool UeberBackend::searchComments(const string& pattern, int maxResults, vector<Comment>& result) | |
650 | { | |
651 | bool rc = false; | |
652 | for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<Comment>::size_type>(maxResults) && i != backends.end(); ++i ) | |
653 | if ((*i)->searchComments(pattern, maxResults - result.size(), result)) rc = true; | |
654 | return rc; | |
655 | } | |
12c86877 | 656 | |
16f7d28d | 657 | AtomicCounter UeberBackend::handle::instances(0); |
12c86877 BH |
658 | |
659 | UeberBackend::handle::handle() | |
660 | { | |
e6a9dde5 | 661 | // g_log<<Logger::Warning<<"Handle instances: "<<instances<<endl; |
16f7d28d | 662 | ++instances; |
457d7c72 AT |
663 | parent=NULL; |
664 | d_hinterBackend=NULL; | |
665 | pkt_p=NULL; | |
666 | i=0; | |
12c86877 BH |
667 | } |
668 | ||
669 | UeberBackend::handle::~handle() | |
670 | { | |
16f7d28d | 671 | --instances; |
12c86877 BH |
672 | } |
673 | ||
90ba52e0 | 674 | bool UeberBackend::handle::get(DNSZoneRecord &r) |
12c86877 | 675 | { |
e6a9dde5 | 676 | DLOG(g_log << "Ueber get() was called for a "<<qtype.getName()<<" record" << endl); |
12c86877 BH |
677 | bool isMore=false; |
678 | while(d_hinterBackend && !(isMore=d_hinterBackend->get(r))) { // this backend out of answers | |
679 | if(i<parent->backends.size()) { | |
e6a9dde5 | 680 | DLOG(g_log<<"Backend #"<<i<<" of "<<parent->backends.size() |
4957a608 | 681 | <<" out of answers, taking next"<<endl); |
12c86877 BH |
682 | |
683 | d_hinterBackend=parent->backends[i++]; | |
ce4a60ce | 684 | d_hinterBackend->lookup(qtype,qname,pkt_p,parent->d_domain_id); |
12c86877 BH |
685 | } |
686 | else | |
687 | break; | |
688 | ||
e6a9dde5 | 689 | DLOG(g_log<<"Now asking backend #"<<i<<endl); |
12c86877 BH |
690 | } |
691 | ||
692 | if(!isMore && i==parent->backends.size()) { | |
e6a9dde5 | 693 | DLOG(g_log<<"UeberBackend reached end of backends"<<endl); |
12c86877 BH |
694 | return false; |
695 | } | |
696 | ||
e6a9dde5 | 697 | DLOG(g_log<<"Found an answering backend - will not try another one"<<endl); |
12c86877 BH |
698 | i=parent->backends.size(); // don't go on to the next backend |
699 | return true; | |
700 | } |