root/trunk/pdns/pdns/backends/bind/bindbackend2.cc @ 180

Revision 180, 21.6 KB (checked in by ahu, 10 years ago)

lots of fixes, axfp ldap support, ldap ttl support, spurious debugging
output removed

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2002-2003  PowerDNS.COM BV
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published by the Free Software Foundation;
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
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17*/
18// $Id: bindbackend2.cc,v 1.4 2003/08/22 13:33:31 ahu Exp $
19#include <errno.h>
20#include <string>
21#include <map>
22#include <set>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26
27using namespace std;
28
29#include "dns.hh"
30#include "dnsbackend.hh"
31#include "bindbackend2.hh"
32#include "dnspacket.hh"
33
34#include "zoneparser.hh"
35#include "bindparser.hh"
36#include "logger.hh"
37#include "arguments.hh"
38#include "huffman.hh"
39#include "qtype.hh"
40#include "misc.hh"
41#include "dynlistener.hh"
42#include "lock.hh"
43using namespace std;
44
45/** new scheme of things:
46    we have zone-id map
47    a zone-id has a vector of DNSResourceRecords */
48
49map<string,int> Bind2Backend::s_name_id_map;
50map<u_int32_t,BB2DomainInfo* > Bind2Backend::s_id_zone_map;
51int Bind2Backend::s_first=1;
52pthread_mutex_t Bind2Backend::s_startup_lock=PTHREAD_MUTEX_INITIALIZER;
53
54/* when a query comes in, we find the most appropriate zone and answer from that */
55
56BB2DomainInfo::BB2DomainInfo()
57{
58  d_loaded=false;
59  d_last_check=0;
60  d_checknow=false;
61  d_rwlock=new pthread_rwlock_t;
62  d_status="Seen in bind configuration";
63  d_confcount=0;
64  //  cout<<"Generated a new bbdomaininfo: "<<(void*)d_rwlock<<"/"<<getpid()<<endl;
65  pthread_rwlock_init(d_rwlock,0);
66}
67
68void BB2DomainInfo::setCheckInterval(time_t seconds)
69{
70  d_checkinterval=seconds;
71}
72
73bool BB2DomainInfo::current()
74{
75  if(d_checknow)
76    return false;
77
78  if(!d_checknow && !d_checkinterval || (time(0)-d_lastcheck<d_checkinterval) || d_filename.empty())
79    return true;
80
81  return (getCtime()==d_ctime);
82}
83
84time_t BB2DomainInfo::getCtime()
85{
86  struct stat buf;
87 
88  if(d_filename.empty() || stat(d_filename.c_str(),&buf)<0)
89    return 0; 
90  d_lastcheck=time(0);
91  return buf.st_ctime;
92}
93
94void BB2DomainInfo::setCtime()
95{
96  struct stat buf;
97  if(stat(d_filename.c_str(),&buf)<0)
98    return; 
99  d_ctime=buf.st_ctime;
100}
101
102void Bind2Backend::setNotified(u_int32_t id, u_int32_t serial)
103{
104  s_id_zone_map[id]->d_lastnotified=serial;
105}
106
107void Bind2Backend::setFresh(u_int32_t domain_id)
108{
109  s_id_zone_map[domain_id]->d_last_check=time(0);
110}
111
112bool Bind2Backend::startTransaction(const string &qname, int id)
113{
114
115  BB2DomainInfo &bbd=*s_id_zone_map[d_transaction_id=id];
116  d_transaction_tmpname=bbd.d_filename+"."+itoa(random());
117  d_of=new ofstream(d_transaction_tmpname.c_str());
118  if(!*d_of) {
119    throw DBException("Unable to open temporary zonefile '"+d_transaction_tmpname+"': "+stringerror());
120    unlink(d_transaction_tmpname.c_str());
121    delete d_of;
122    d_of=0;
123  }
124 
125  *d_of<<"; Written by PowerDNS, don't edit!"<<endl;
126  *d_of<<"; Zone '"+bbd.d_name+"' retrieved from master "<<bbd.d_master<<endl<<"; at "<<nowTime()<<endl;
127  bbd.lock();
128
129  return true;
130}
131
132bool Bind2Backend::commitTransaction()
133{
134  delete d_of;
135  d_of=0;
136  if(rename(d_transaction_tmpname.c_str(),s_id_zone_map[d_transaction_id]->d_filename.c_str())<0)
137    throw DBException("Unable to commit (rename to: '"+s_id_zone_map[d_transaction_id]->d_filename+"') AXFRed zone: "+stringerror());
138
139
140  queueReload(s_id_zone_map[d_transaction_id]);
141  s_id_zone_map[d_transaction_id]->unlock();
142  d_transaction_id=0;
143
144  return true;
145}
146
147bool Bind2Backend::abortTransaction()
148{
149  if(d_transaction_id) {
150    s_id_zone_map[d_transaction_id]->unlock();
151    delete d_of;
152    d_of=0;
153    unlink(d_transaction_tmpname.c_str());
154    d_transaction_id=0;
155  }
156
157  return true;
158}
159
160bool Bind2Backend::feedRecord(const DNSResourceRecord &r)
161{
162  string qname=r.qname;
163  string domain=s_id_zone_map[d_transaction_id]->d_name;
164
165  if(!stripDomainSuffix(&qname,domain)) 
166    throw DBException("out-of-zone data '"+qname+"' during AXFR of zone '"+domain+"'");
167
168  string content=r.content;
169
170  // SOA needs stripping too! XXX FIXME
171  switch(r.qtype.getCode()) {
172  case QType::TXT:
173    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t\""<<r.content<<"\""<<endl;
174    break;
175  case QType::MX:
176    if(!stripDomainSuffix(&content,domain))
177      content+=".";
178    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<r.priority<<"\t"<<content<<endl;
179    break;
180  case QType::CNAME:
181  case QType::NS:
182    if(!stripDomainSuffix(&content,domain))
183      content+=".";
184    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<content<<endl;
185    break;
186  default:
187    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<r.content<<endl;
188    break;
189  }
190
191  return true;
192}
193
194void Bind2Backend::getUpdatedMasters(vector<DomainInfo> *changedDomains)
195{
196  SOAData soadata;
197  for(map<u_int32_t,BB2DomainInfo*>::iterator i=s_id_zone_map.begin();i!=s_id_zone_map.end();++i) {
198    if(!i->second->d_master.empty())
199      continue;
200    soadata.serial=0;
201    try {
202      getSOA(i->second->d_name,soadata); // we might not *have* a SOA yet
203    }
204    catch(...){}
205    DomainInfo di;
206    di.id=i->first;
207    di.serial=soadata.serial;
208    di.zone=i->second->d_name;
209    di.last_check=i->second->d_last_check;
210    di.backend=this;
211    di.kind=DomainInfo::Master;
212    if(!i->second->d_lastnotified)            // don't do notification storm on startup
213      i->second->d_lastnotified=soadata.serial;
214    else
215      if(soadata.serial!=i->second->d_lastnotified)
216        changedDomains->push_back(di);
217   
218  }
219}
220
221void Bind2Backend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
222{
223  for(map<u_int32_t,BB2DomainInfo*>::const_iterator i=s_id_zone_map.begin();i!=s_id_zone_map.end();++i) {
224    if(i->second->d_master.empty())
225      continue;
226    DomainInfo sd;
227    sd.id=i->first;
228    sd.zone=i->second->d_name;
229    sd.master=i->second->d_master;
230    sd.last_check=i->second->d_last_check;
231    sd.backend=this;
232    sd.kind=DomainInfo::Slave;
233    SOAData soadata;
234    soadata.serial=0;
235    soadata.refresh=0;
236    soadata.serial=0;
237    soadata.db=(DNSBackend *)-1; // not sure if this is useful, inhibits any caches that might be around
238    try {
239      getSOA(i->second->d_name,soadata); // we might not *have* a SOA yet
240    }
241    catch(...){}
242    sd.serial=soadata.serial;
243    if(sd.last_check+soadata.refresh<(unsigned int)time(0))
244      unfreshDomains->push_back(sd);   
245  }
246}
247
248bool Bind2Backend::getDomainInfo(const string &domain, DomainInfo &di)
249{
250  for(map<u_int32_t,BB2DomainInfo*>::const_iterator i=s_id_zone_map.begin();i!=s_id_zone_map.end();++i) {
251    if(i->second->d_name==domain) {
252      di.id=i->first;
253      di.zone=domain;
254      di.master=i->second->d_master;
255      di.last_check=i->second->d_last_check;
256      di.backend=this;
257      di.kind=i->second->d_master.empty() ? DomainInfo::Master : DomainInfo::Slave;
258      di.serial=0;
259      try {
260        SOAData sd;
261        sd.serial=0;
262       
263        getSOA(i->second->d_name,sd); // we might not *have* a SOA yet
264        di.serial=sd.serial;
265      }
266      catch(...){}
267
268      return true;
269    }
270  }
271  return false;
272}
273
274
275static string canonic(string ret)
276{
277  string::iterator i;
278
279  for(i=ret.begin();
280      i!=ret.end();
281      ++i)
282    ; // *i=*i; //tolower(*i);
283
284
285  if(*(i-1)=='.')
286    ret.resize(i-ret.begin()-1);
287  return ret;
288}
289
290map<unsigned int, BB2DomainInfo*> nbbds;
291/** This function adds a record to a domain with a certain id. */
292void Bind2Backend::insert(int id, const string &qnameu, const string &qtype, const string &content, int ttl=300, int prio=25)
293{
294  DNSResourceRecord rr;
295  rr.domain_id=id;
296  rr.qname=canonic(qnameu);
297  rr.qtype=qtype;
298  rr.content=content;
299  rr.ttl=ttl;
300  rr.priority=prio;
301  nbbds[id]->d_records->push_back(rr);
302}
303
304
305static Bind2Backend *us;
306
307void Bind2Backend::reload()
308{
309  for(map<u_int32_t,BB2DomainInfo*>::iterator i=us->s_id_zone_map.begin();i!=us->s_id_zone_map.end();++i) 
310    i->second->d_checknow=true;
311}
312
313string Bind2Backend::DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid)
314{
315  ostringstream ret;
316  bool doReload=false;
317  for(map<u_int32_t,BB2DomainInfo*>::iterator j=us->s_id_zone_map.begin();j!=us->s_id_zone_map.end();++j) {
318    doReload=false;
319    if(parts.size()==1)
320      doReload=true;
321    else 
322      for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i)                 // O(N) badness XXX FIXME
323        if(*i==j->second->d_name) {
324          doReload=true;
325          break;
326        }
327   
328    if(doReload) {
329      j->second->lock();
330
331      us->queueReload(j->second);
332      j->second->unlock();
333      ret<<j->second->d_name<< (j->second->d_loaded ? "": "[rejected]") <<"\t"<<j->second->d_status<<"\n";
334    }
335    doReload=false;
336  }
337       
338  return ret.str();
339}
340
341
342string Bind2Backend::DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid)
343{
344  string ret;
345  bool doPrint=false;
346  for(map<u_int32_t,BB2DomainInfo*>::iterator j=us->s_id_zone_map.begin();j!=us->s_id_zone_map.end();++j) {
347    ostringstream line;
348    doPrint=false;
349    if(parts.size()==1)
350      doPrint=true;
351    else 
352      for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i)                 // O(N) badness XXX FIXME
353        if(*i==j->second->d_name) {
354          doPrint=true;
355          break;
356        }
357   
358    if(doPrint)
359      line<<j->second->d_name<< (j->second->d_loaded ? "": "[rejected]") <<"\t"<<j->second->d_status<<"\n";
360    doPrint=false;
361    ret+=line.str();
362  }
363       
364  return ret;
365}
366
367
368string Bind2Backend::DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid)
369{
370  ostringstream ret;
371  for(map<u_int32_t,BB2DomainInfo*>::iterator j=us->s_id_zone_map.begin();j!=us->s_id_zone_map.end();++j) 
372    if(!j->second->d_loaded)
373      ret<<j->second->d_name<<"\t"<<j->second->d_status<<endl;
374       
375  return ret.str();
376}
377
378static void callback(unsigned int domain_id, const string &domain, const string &qtype, const string &content, int ttl, int prio)
379{
380  us->insert(domain_id,domain,qtype,content,ttl,prio);
381}
382
383
384
385Bind2Backend::Bind2Backend(const string &suffix)
386{
387#if __GNUC__ >= 3
388    ios_base::sync_with_stdio(false);
389#endif
390  d_logprefix="[bind2"+suffix+"backend]";
391  setArgPrefix("bind2"+suffix);
392  Lock l(&s_startup_lock);
393
394  d_transaction_id=0;
395  if(!s_first) {
396    return;
397  }
398   
399  s_first=0;
400 
401  if(mustDo("example-zones")) {
402    insert(0,"www.example.com","A","1.2.3.4");
403    insert(0,"example.com","SOA","ns1.example.com hostmaster.example.com");
404    insert(0,"example.com","NS","ns1.example.com",86400);
405    insert(0,"example.com","NS","ns2.example.com",86400);
406    insert(0,"example.com","MX","mail.example.com",3600,25);
407    insert(0,"example.com","MX","mail1.example.com",3600,25);
408    insert(0,"mail.example.com","A","4.3.2.1");
409    insert(0,"mail1.example.com","A","5.4.3.2");
410    insert(0,"ns1.example.com","A","4.3.2.1");
411    insert(0,"ns2.example.com","A","5.4.3.2");
412     
413    for(int i=0;i<1000;i++)
414      insert(0,"host-"+itoa(i)+".example.com","A","2.3.4.5");
415
416    s_id_zone_map[0]=new BB2DomainInfo;
417    BB2DomainInfo &bbd=*s_id_zone_map[0];
418    bbd.d_name="example.com";
419    bbd.d_filename="";
420    bbd.d_id=0;
421    s_id_zone_map[0]->d_loaded=true;
422    s_id_zone_map[0]->d_status="parsed into memory at "+nowTime();
423  }
424 
425  loadConfig();
426 
427
428  extern DynListener *dl;
429  us=this;
430  dl->registerFunc("BIND2-RELOAD-NOW", &DLReloadNowHandler);
431  dl->registerFunc("BIND2-DOMAIN-STATUS", &DLDomStatusHandler);
432  dl->registerFunc("BIND2-LIST-REJECTS", &DLListRejectsHandler);
433}
434
435
436void Bind2Backend::rediscover(string *status)
437{
438  loadConfig(status);
439}
440
441void Bind2Backend::loadConfig(string* status)
442{
443  static int domain_id=1;
444  nbbds.clear();
445  if(!getArg("config").empty()) {
446    BindParser BP;
447    try {
448      BP.parse(getArg("config"));
449    }
450    catch(AhuException &ae) {
451      L<<Logger::Error<<"Error parsing bind configuration: "<<ae.reason<<endl;
452      throw;
453    }
454   
455    ZoneParser ZP;
456     
457    vector<BindDomainInfo> domains=BP.getDomains();
458   
459    us=this;
460
461    ZP.setDirectory(BP.getDirectory());
462    ZP.setCallback(&callback); 
463    L<<Logger::Warning<<d_logprefix<<" Parsing "<<domains.size()<<" domain(s), will report when done"<<endl;
464   
465    int rejected=0;
466    int newdomains=0;
467
468    for(vector<BindDomainInfo>::const_iterator i=domains.begin();
469        i!=domains.end();
470        ++i)
471      {
472        BB2DomainInfo *bbd=0;
473        if(i->type!="master" && i->type!="slave") {
474          L<<Logger::Warning<<d_logprefix<<" Warning! Skipping '"<<i->type<<"' zone '"<<i->name<<"'"<<endl;
475          continue;
476        }
477        map<unsigned int, BB2DomainInfo*>::const_iterator j=s_id_zone_map.begin();
478        for(;j!=s_id_zone_map.end();++j)
479          if(j->second->d_name==i->name) {
480            bbd=j->second;
481            break;
482          }
483        if(j==s_id_zone_map.end()) { // entirely new
484          bbd=new BB2DomainInfo;
485          bbd->d_records=new vector<DNSResourceRecord>;
486         
487          bbd->d_id=domain_id++;
488          s_name_id_map[i->name]=bbd->d_id;
489          bbd->setCheckInterval(getArgAsNum("check-interval"));
490          bbd->d_lastnotified=0;
491          bbd->d_loaded=false;
492        }
493
494        bbd->d_name=i->name;
495        bbd->d_filename=i->filename;
496        bbd->d_master=i->master;
497       
498        nbbds[bbd->d_id]=bbd; 
499        if(!bbd->d_loaded) {
500          L<<Logger::Info<<d_logprefix<<" parsing '"<<i->name<<"' from file '"<<i->filename<<"'"<<endl;
501         
502          try {
503            ZP.parse(i->filename,i->name,bbd->d_id); // calls callback for us
504            nbbds[bbd->d_id]->setCtime();
505            nbbds[bbd->d_id]->d_loaded=true;          // does this perform locking for us?
506            nbbds[bbd->d_id]->d_status="parsed into memory at "+nowTime();
507           
508          }
509          catch(AhuException &ae) {
510            ostringstream msg;
511            msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.reason;
512
513            if(status)
514              *status+=msg.str();
515            nbbds[bbd->d_id]->d_status=msg.str();
516            L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
517            rejected++;
518          }
519        }
520        /*
521        vector<vector<BBResourceRecord> *>&tmp=d_zone_id_map[bbd.d_id];  // shrink trick
522        vector<vector<BBResourceRecord> *>(tmp).swap(tmp);
523        */
524      }
525
526
527    int remdomains=0;
528    set<string> oldnames, newnames;
529    for(map<unsigned int, BB2DomainInfo*>::const_iterator j=s_id_zone_map.begin();j!=s_id_zone_map.end();++j) {
530      oldnames.insert(j->second->d_name);
531    }
532    for(map<unsigned int, BB2DomainInfo*>::const_iterator j=nbbds.begin();j!=nbbds.end();++j) {
533      newnames.insert(j->second->d_name);
534    }
535
536    vector<string> diff;
537    set_difference(oldnames.begin(), oldnames.end(), newnames.begin(), newnames.end(), back_inserter(diff));
538    remdomains=diff.size();
539    for(vector<string>::const_iterator k=diff.begin();k!=diff.end();++k) {
540      delete s_id_zone_map[s_name_id_map[*k]]->d_records;
541      delete s_id_zone_map[s_name_id_map[*k]];
542      s_name_id_map.erase(*k);
543      L<<Logger::Error<<"Removed: "<<*k<<endl;
544    }
545
546    for(map<unsigned int, BB2DomainInfo*>::iterator j=s_id_zone_map.begin();j!=s_id_zone_map.end();++j) { // O(N*M)
547      for(vector<string>::const_iterator k=diff.begin();k!=diff.end();++k)
548        if(j->second->d_name==*k) {
549          L<<Logger::Error<<"Removing records from zone '"<<j->second->d_name<<"' from memory"<<endl;
550          j->second->lock();
551          j->second->d_loaded=false;
552          nukeZoneRecords(j->second);
553          j->second->unlock(); 
554          break;
555        }
556    }
557
558    vector<string> diff2;
559    set_difference(newnames.begin(), newnames.end(), oldnames.begin(), oldnames.end(), back_inserter(diff2));
560    newdomains=diff2.size();
561
562    s_id_zone_map.swap(nbbds); // commit
563    ostringstream msg;
564    msg<<" Done parsing domains, "<<rejected<<" rejected, "<<newdomains<<" new, "<<remdomains<<" removed"; 
565    if(status)
566      *status=msg.str();
567
568    L<<Logger::Error<<d_logprefix<<msg.str()<<endl;
569    //   L<<Logger::Info<<d_logprefix<<" Number of hash buckets: "<<d_qnames.bucket_count()<<", number of entries: "<<d_qnames.size()<< endl;
570  }
571}
572
573/** nuke all records from memory, keep bbd intact though. Must be called with bbd lock held already! */
574void Bind2Backend::nukeZoneRecords(BB2DomainInfo *bbd)
575{
576  bbd->d_loaded=0; // block further access
577  bbd->d_records->clear();
578}
579
580/** Must be called with bbd locked already. Will not be unlocked on return, is your own problem.
581    Does not throw errors or anything, may update d_status however */
582
583
584void Bind2Backend::queueReload(BB2DomainInfo *bbd)
585{
586  nbbds.clear();
587
588  // we reload *now* for the time being
589  //cout<<"unlock domain"<<endl;
590  bbd->unlock();
591  //cout<<"lock it again"<<endl;
592
593  bbd->lock();
594  try {
595    nukeZoneRecords(bbd);
596   
597    ZoneParser ZP;
598    us=this;
599    ZP.setCallback(&callback); 
600
601    nbbds[bbd->d_id]=s_id_zone_map[bbd->d_id];
602    ZP.parse(bbd->d_filename,bbd->d_name,bbd->d_id);
603    s_id_zone_map[bbd->d_id]=nbbds[bbd->d_id];
604
605    bbd->setCtime();
606    // and raise d_loaded again!
607    bbd->d_loaded=1;
608    bbd->d_checknow=0;
609    bbd->d_status="parsed into memory at "+nowTime();
610    L<<Logger::Warning<<"Zone '"<<bbd->d_name<<"' ("<<bbd->d_filename<<") reloaded"<<endl;
611  }
612  catch(AhuException &ae) {
613    ostringstream msg;
614    msg<<" error at "+nowTime()+" parsing '"<<bbd->d_name<<"' from file '"<<bbd->d_filename<<"': "<<ae.reason;
615    bbd->d_status=msg.str();
616  }
617}
618
619void Bind2Backend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int zoneId )
620{
621  d_handle=new Bind2Backend::handle;
622  d_handle->d_records=new vector<DNSResourceRecord>; // WRONG
623  //  cout<<"Lookup! for "<<qname<<endl;
624  string domain=qname;
625  while(!s_name_id_map.count(domain) && chopOff(domain));
626
627  if(!s_name_id_map.count(domain)) {
628    //    cout<<"no such domain: '"<<qname<<"'"<<endl;
629    d_handle->d_iter=d_handle->d_records->end();  // WRONG
630    d_handle->d_list=false;
631    d_handle->d_bbd=0;
632    return;
633  }
634  unsigned int id=s_name_id_map[domain];
635
636  //  cout<<"domain: '"<<domain<<"', id="<<id<<endl;
637 
638
639  DLOG(L<<"Bind2Backend constructing handle for search for "<<qtype.getName()<<" for "<<
640       qname<<endl);
641
642  d_handle->qname=qname;
643  d_handle->parent=this;
644  d_handle->qtype=qtype;
645  string compressed=toLower(qname);
646  d_handle->d_records=s_id_zone_map[id]->d_records;
647  d_handle->d_bbd=0;
648  if(!d_handle->d_records->empty()) {
649    BB2DomainInfo& bbd=*s_id_zone_map[id];
650    if(!bbd.d_loaded) {
651      delete d_handle;
652      throw DBException("Zone temporarily not available (file missing, or master dead)"); // fuck
653    }
654
655    if(!bbd.tryRLock()) {
656      L<<Logger::Warning<<"Can't get read lock on zone '"<<bbd.d_name<<"'"<<endl;
657      delete d_handle;
658      throw DBException("Temporarily unavailable due to a zone lock"); // fuck
659    }
660     
661
662    if(!bbd.current()) {
663      L<<Logger::Warning<<"Zone '"<<bbd.d_name<<"' ("<<bbd.d_filename<<") needs reloading"<<endl;
664      queueReload(&bbd);
665    }
666    d_handle->d_bbd=&bbd;
667  }
668  else {
669    DLOG(L<<"Query with no results"<<endl);
670  }
671  d_handle->d_iter=d_handle->d_records->begin();
672  d_handle->d_list=false;
673}
674
675Bind2Backend::handle::handle()
676{
677  d_bbd=0;
678  count=0;
679}
680
681bool Bind2Backend::get(DNSResourceRecord &r)
682{
683  if(!d_handle->get(r)) {
684    delete d_handle;
685    d_handle=0;
686    return false;
687  }
688  return true;
689}
690
691bool Bind2Backend::handle::get(DNSResourceRecord &r)
692{
693  if(d_list)
694    return get_list(r);
695  else
696    return get_normal(r);
697}
698
699bool Bind2Backend::handle::get_normal(DNSResourceRecord &r)
700{
701  DLOG(L << "Bind2Backend get() was called for "<<qtype.getName() << " record  for "<<
702       qname<<"- "<<d_records->size()<<" available!"<<endl);
703 
704  while(d_iter!=d_records->end() && (d_iter->qname!=qname || !(qtype=="ANY" || (d_iter)->qtype==qtype))) {
705    DLOG(L<<Logger::Warning<<"Skipped "<<qname<<"/"<<QType(d_iter->qtype).getName()<<": '"<<d_iter->content<<"'"<<endl);
706    d_iter++;
707  }
708  if(d_iter==d_records->end()) { // we've reached the end
709    if(d_bbd) {
710      d_bbd->unlock();
711      d_bbd=0;
712    }
713    return false;
714  }
715  DLOG(L << "Bind2Backend get() returning a rr with a "<<QType(d_iter->qtype).getCode()<<endl);
716
717  r.qname=qname; // fill this in
718 
719  r.content=(d_iter)->content;
720  r.domain_id=(d_iter)->domain_id;
721  r.qtype=(d_iter)->qtype;
722  r.ttl=(d_iter)->ttl;
723  r.priority=(d_iter)->priority;
724  d_iter++;
725
726  return true;
727}
728
729bool Bind2Backend::list(const string &target, int id)
730{
731  // cout<<"List of id "<<id<<" requested"<<endl;
732  if(!s_id_zone_map.count(id))
733    return false;
734
735  d_handle=new Bind2Backend::handle;
736  DLOG(L<<"Bind2Backend constructing handle for list of "<<id<<endl);
737
738  d_handle->d_qname_iter=s_id_zone_map[id]->d_records->begin();
739  d_handle->d_qname_end=s_id_zone_map[id]->d_records->end();   // iter now points to a vector of pointers to vector<BBResourceRecords>
740
741  d_handle->parent=this;
742  d_handle->id=id;
743  d_handle->d_list=true;
744  return true;
745
746}
747
748bool Bind2Backend::handle::get_list(DNSResourceRecord &r)
749{
750  if(d_qname_iter!=d_qname_end) {
751    r=*d_qname_iter;
752    d_qname_iter++;
753    return true;
754  }
755  return false;
756
757}
758
759bool Bind2Backend::isMaster(const string &name, const string &ip)
760{
761  for(map<u_int32_t,BB2DomainInfo*>::iterator j=us->s_id_zone_map.begin();j!=us->s_id_zone_map.end();++j) 
762    if(j->second->d_name==name)
763      return j->second->d_master==ip;
764  return false;
765}
766
767class Bind2Factory : public BackendFactory
768{
769   public:
770      Bind2Factory() : BackendFactory("bind2") {}
771
772      void declareArguments(const string &suffix="")
773      {
774         declare(suffix,"config","Location of named.conf","");
775         declare(suffix,"example-zones","Install example zones","no");
776         declare(suffix,"check-interval","Interval for zonefile changes","0");
777      }
778
779      DNSBackend *make(const string &suffix="")
780      {
781         return new Bind2Backend(suffix);
782      }
783};
784
785//! Magic class that is activated when the dynamic library is loaded
786class Bind2Loader
787{
788public:
789  Bind2Loader()
790  {
791    BackendMakers().report(new Bind2Factory);
792    L<<Logger::Notice<<"[Bind2Backend] This is the bind backend version "VERSION" ("__DATE__", "__TIME__") reporting"<<endl;
793  }
794};
795static Bind2Loader bind2loader;
Note: See TracBrowser for help on using the browser.