]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/ueberbackend.cc
move around a lot of stuff to isolate dnssec db connectivity
[thirdparty/pdns.git] / pdns / ueberbackend.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
ba45c866 3 Copyright (C) 2005 - 2008 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
923a2384
BH
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
12c86877
BH
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 17*/
ba45c866 18#include "packetcache.hh"
12c86877 19#include "utility.hh"
c6566265
BH
20
21#ifdef HAVE_CONFIG_H
22# include "config.h"
23#endif // HAVE_CONFIG_H
24
12c86877
BH
25#include <string>
26#include <map>
27#include <sys/types.h>
28
29#include <errno.h>
30#include <iostream>
31#include <sstream>
32#include <functional>
c0273500 33#include <boost/foreach.hpp>
12c86877
BH
34
35#include "dns.hh"
36#include "arguments.hh"
37#include "dnsbackend.hh"
38#include "ueberbackend.hh"
39#include "dnspacket.hh"
40#include "logger.hh"
41#include "statbag.hh"
ba45c866 42
12c86877
BH
43
44extern StatBag S;
45
46vector<UeberBackend *>UeberBackend::instances;
47pthread_mutex_t UeberBackend::instances_lock=PTHREAD_MUTEX_INITIALIZER;
48
49sem_t UeberBackend::d_dynserialize;
50string UeberBackend::programname;
51string UeberBackend::s_status;
52
53// initially we are blocked
54bool UeberBackend::d_go=false;
55pthread_mutex_t UeberBackend::d_mut = PTHREAD_MUTEX_INITIALIZER;
56pthread_cond_t UeberBackend::d_cond = PTHREAD_COND_INITIALIZER;
57
58int UeberBackend::s_s=-1; // ?
59
731f58b8
BH
60#ifdef NEED_RTLD_NOW
61#define RTLD_NOW RTLD_LAZY
62#endif
63
12c86877
BH
64//! Loads a module and reports it to all UeberBackend threads
65bool UeberBackend::loadmodule(const string &name)
66{
67 // TODO: Implement dynamic loading?
68#if !defined(WIN32) && !defined(DARWIN)
69 void *dlib=dlopen(name.c_str(), RTLD_NOW);
70
71 if(dlib == NULL) {
72 L<<Logger::Warning <<"Unable to load module '"<<name<<"': "<<dlerror() << endl;
73 return false;
74 }
75
76 return true;
77
78#else
79 L << Logger::Warning << "This version doesn't support dynamic loading (yet)." << endl;
80 return false;
81
82#endif // WIN32
83
84}
85
86void UeberBackend::go(void)
87{
88 pthread_mutex_lock(&d_mut);
89 d_go=true;
90 pthread_cond_broadcast(&d_cond);
91 pthread_mutex_unlock(&d_mut);
92}
93
94bool UeberBackend::getDomainInfo(const string &domain, DomainInfo &di)
95{
96 for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
97 if((*i)->getDomainInfo(domain, di))
98 return true;
99 return false;
100}
101
c0273500
BH
102int UeberBackend::addDomainKey(const string& name, const KeyData& key)
103{
104 BOOST_FOREACH(DNSBackend* db, backends) {
105 if(db->addDomainKey(name, key) >= 0)
106 return true;
107 }
108 return false;
109}
110bool UeberBackend::getDomainKeys(const string& name, unsigned int kind, std::vector<KeyData>& keys)
111{
112 BOOST_FOREACH(DNSBackend* db, backends) {
113 if(db->getDomainKeys(name, kind, keys))
114 return true;
115 }
116 return false;
117}
118
119bool UeberBackend::getDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta)
120{
121 BOOST_FOREACH(DNSBackend* db, backends) {
122 if(db->getDomainMetadata(name, kind, meta))
123 return true;
124 }
125 return false;
126}
127
128bool UeberBackend::setDomainMetadata(const string& name, const std::string& kind, const std::vector<std::string>& meta)
129{
130 BOOST_FOREACH(DNSBackend* db, backends) {
131 if(db->setDomainMetadata(name, kind, meta))
132 return true;
133 }
134 return false;
135}
136
137
12c86877
BH
138void UeberBackend::reload()
139{
140 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
141 {
142 ( *i )->reload();
143 }
144}
145
973ad2b5 146void UeberBackend::rediscover(string *status)
12c86877 147{
20ca8e7d 148
12c86877
BH
149 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
150 {
973ad2b5
BH
151 string tmpstr;
152 ( *i )->rediscover(&tmpstr);
153 if(status)
154 *status+=tmpstr + (i!=backends.begin() ? "\n" : "");
12c86877
BH
155 }
156}
157
158
159void UeberBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
160{
161 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
162 {
163 ( *i )->getUnfreshSlaveInfos( domains );
164 }
165}
166
167
168
169void UeberBackend::getUpdatedMasters(vector<DomainInfo>* domains)
170{
171 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
172 {
173 ( *i )->getUpdatedMasters( domains );
174 }
175}
176
3de83124 177/** special trick - if sd.db is set to -1, the cache is ignored */
35933370 178bool UeberBackend::getSOA(const string &domain, SOAData &sd, DNSPacket *p)
12c86877
BH
179{
180 d_question.qtype=QType::SOA;
181 d_question.qname=domain;
182 d_question.zoneId=-1;
183
3de83124
BH
184 if(sd.db!=(DNSBackend *)-1) {
185 int cstat=cacheHas(d_question,d_answer);
186 if(cstat==0) {
187 return false;
188 }
189 else if(cstat==1) {
190 // ehm
34b37bbb 191 fillSOAData(d_answer.content,sd);
3de83124
BH
192 sd.domain_id=d_answer.domain_id;
193 sd.ttl=d_answer.ttl;
194 sd.db=0;
195 return true;
196 }
12c86877
BH
197 }
198
199
200 for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
35933370 201 if((*i)->getSOA(domain, sd, p)) {
12c86877
BH
202 DNSResourceRecord rr;
203 rr.qname=domain;
204 rr.qtype=QType::SOA;
34b37bbb 205 rr.content=serializeSOAData(sd);
12c86877 206 rr.ttl=sd.ttl;
12c86877
BH
207 rr.domain_id=sd.domain_id;
208 addOneCache(d_question,rr);
209 return true;
210 }
211
212 addNegCache(d_question);
213 return false;
214}
215
216bool UeberBackend::superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db)
217{
218 for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
219 if((*i)->superMasterBackend(ip,domain,nsset,account, db))
220 return true;
221 return false;
222
223}
224
225void UeberBackend::setStatus(const string &st)
226{
227 s_status=st;
228}
229
12c86877
BH
230UeberBackend::UeberBackend(const string &pname)
231{
232 programname=pname;
233 pthread_mutex_lock(&instances_lock);
234 instances.push_back(this); // report to the static list of ourself
235 pthread_mutex_unlock(&instances_lock);
236
237 tid=pthread_self();
238 stale=false;
239
240 backends=BackendMakers().all();
241}
242
243void UeberBackend::die()
244{
245 cleanup();
246 stale=true;
247}
248
249void del(DNSBackend* d)
250{
251 delete d;
252}
253
254void UeberBackend::cleanup()
255{
256 pthread_mutex_lock(&instances_lock);
257
258 remove(instances.begin(),instances.end(),this);
259 instances.resize(instances.size()-1);
260
261 pthread_mutex_unlock(&instances_lock);
262
263 for_each(backends.begin(),backends.end(),del);
264}
265
923a2384
BH
266// silly Solaris fix
267#undef PC
268
12c86877
BH
269int UeberBackend::cacheHas(const Question &q, DNSResourceRecord &rr)
270{
271 extern PacketCache PC;
dee7ba5a
BH
272 static unsigned int *qcachehit=S.getPointer("query-cache-hit");
273 static unsigned int *qcachemiss=S.getPointer("query-cache-miss");
12c86877 274
ba45c866
BH
275 static int negqueryttl=::arg().asNum("negquery-cache-ttl");
276 static int queryttl=::arg().asNum("query-cache-ttl");
cf71f03f 277
12c86877
BH
278 if(!negqueryttl && !queryttl) {
279 (*qcachemiss)++;
280 return -1;
281 }
282
283 string content;
2f24bcd2 284 // L<<Logger::Warning<<"looking up: '"<<q.qname+"'|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
cf71f03f 285
ba45c866 286 bool ret=PC.getEntry(q.qname, q.qtype, PacketCache::QUERYCACHE, content, q.zoneId); // think about lowercasing here
12c86877
BH
287
288 if(!ret) {
289 (*qcachemiss)++;
290 return -1;
291 }
12c86877 292 (*qcachehit)++;
2f24bcd2 293 if(content.empty()) // negatively cached
12c86877
BH
294 return 0;
295 rr.unSerialize(content);
296 return 1;
297}
298
299void UeberBackend::addNegCache(const Question &q)
300{
301 extern PacketCache PC;
ba45c866 302 static int negqueryttl=::arg().asNum("negquery-cache-ttl");
12c86877
BH
303 if(!negqueryttl)
304 return;
305 // L<<Logger::Warning<<"negative inserting: "<<q.qname+"|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
2f24bcd2 306 PC.insert(q.qname, q.qtype, PacketCache::QUERYCACHE, "", negqueryttl, q.zoneId);
12c86877
BH
307}
308
309void UeberBackend::addOneCache(const Question &q, const DNSResourceRecord &rr)
310{
311 extern PacketCache PC;
ba45c866 312 static int queryttl=::arg().asNum("query-cache-ttl");
12c86877
BH
313 if(!queryttl)
314 return;
2f24bcd2 315 // L<<Logger::Warning<<"inserting: "<<q.qname+"|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
ba45c866 316 PC.insert(q.qname, q.qtype, PacketCache::QUERYCACHE, rr.serialize(), queryttl, q.zoneId);
12c86877
BH
317}
318
27d94a79
BH
319void UeberBackend::alsoNotifies(const string &domain, set<string> *ips)
320{
321 for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
322 (*i)->alsoNotifies(domain,ips);
323}
12c86877
BH
324
325UeberBackend::~UeberBackend()
326{
327 DLOG(L<<Logger::Error<<"UeberBackend destructor called, removing ourselves from instances, and deleting our backends"<<endl);
328 cleanup();
329}
330
331// this handle is more magic than most
332void UeberBackend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int zoneId)
333{
334 if(stale) {
335 L<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl;
336 throw AhuException("We are stale, please recycle");
337 }
338
339 DLOG(L<<"UeberBackend received question for "<<qtype.getName()<<" of "<<qname<<endl);
340 if(!d_go) {
341 pthread_mutex_lock(&d_mut);
342 while (d_go==false) {
343 L<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl;
344 pthread_cond_wait(&d_cond, &d_mut);
345 L<<Logger::Error<<"Broadcast received, unblocked"<<endl;
346 }
347 pthread_mutex_unlock(&d_mut);
348 }
349
350 d_handle.i=0;
351 d_handle.qtype=qtype;
352 d_handle.qname=qname;
353 d_handle.pkt_p=pkt_p;
354 d_ancount=0;
355
356 if(!backends.size()) {
357 L<<Logger::Error<<Logger::NTLog<<"No database backends available - unable to answer questions."<<endl;
358 stale=true; // please recycle us!
359 throw AhuException("We are stale, please recycle");
360 }
361 else {
362 d_question.qtype=qtype;
363 d_question.qname=qname;
364 d_question.zoneId=zoneId;
365 int cstat=cacheHas(d_question,d_answer);
366 if(cstat<0) { // nothing
367 d_negcached=d_cached=false;
368 (d_handle.d_hinterBackend=backends[d_handle.i++])->lookup(qtype, qname,pkt_p,zoneId);
369 }
370 else if(cstat==0) {
371 d_negcached=true;
372 d_cached=false;
373 }
374 else {
375 d_negcached=false;
376 d_cached=true;
377 }
378 }
379
380 d_handle.parent=this;
381
382}
383
384bool UeberBackend::get(DNSResourceRecord &rr)
385{
386 if(d_negcached) {
387 return false;
388 }
389
390 if(d_cached) {
391 rr=d_answer;
392 d_negcached=true; // ugly, confusing
393 return true;
394 }
12c86877
BH
395 if(!d_handle.get(rr)) {
396 if(!d_ancount && !d_handle.qname.empty()) // don't cache axfr
397 addNegCache(d_question);
398
399 if(d_ancount==1) {
2f24bcd2 400 addOneCache(d_question, lastrr);
12c86877
BH
401 }
402
403 return false;
404 }
405
406 if(!d_ancount++) {
407 lastrr=rr;
408 }
409 return true;
410}
411
88def049 412bool UeberBackend::list(const string &target, int domain_id)
12c86877 413{
36d772ab
BH
414 L<<Logger::Error<<"UeberBackend::list called, should NEVER EVER HAPPEN"<<endl;
415 exit(1);
416 return false;
12c86877 417}
36d772ab 418
12c86877
BH
419
420int UeberBackend::handle::instances=0;
421
422UeberBackend::handle::handle()
423{
424 // L<<Logger::Warning<<"Handle instances: "<<instances<<endl;
425 instances++;
426}
427
428UeberBackend::handle::~handle()
429{
430 instances--;
431}
432
433
434
435
436
437bool UeberBackend::handle::get(DNSResourceRecord &r)
438{
439 DLOG(L << "Ueber get() was called for a "<<qtype.getName()<<" record" << endl);
440 bool isMore=false;
441 while(d_hinterBackend && !(isMore=d_hinterBackend->get(r))) { // this backend out of answers
442 if(i<parent->backends.size()) {
443 DLOG(L<<"Backend #"<<i<<" of "<<parent->backends.size()
4957a608 444 <<" out of answers, taking next"<<endl);
12c86877
BH
445
446 d_hinterBackend=parent->backends[i++];
447 d_hinterBackend->lookup(qtype,qname,pkt_p);
448 }
449 else
450 break;
451
452 DLOG(L<<"Now asking backend #"<<i<<endl);
453 }
454
455 if(!isMore && i==parent->backends.size()) {
456 DLOG(L<<"UeberBackend reached end of backends"<<endl);
457 return false;
458 }
459
460 DLOG(L<<"Found an answering backend - will not try another one"<<endl);
461 i=parent->backends.size(); // don't go on to the next backend
462 return true;
463}