~ubuntu-branches/ubuntu/maverick/pdns/maverick-updates

« back to all changes in this revision

Viewing changes to pdns/backends/bind/bindbackend2.cc

  • Committer: Bazaar Package Importer
  • Author(s): Debian PowerDNS Maintainers
  • Date: 2005-07-29 20:24:33 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050729202433-cfrk71byx0mmmbk6
Tags: 2.9.18-1
* New upstream release (Closes: #318798)
* Drop patches: 64bit-compile-fix.dpatch, addfeatures-ldapbackend.dpatch,
  amd64-compilefix.dpatch, blankout-domain-fix.dpatch,
  consistent-sql.dpatch, dosfix-ldapbackend.dpatch, fix-exit-status.dpatch,
  gpgsql-compilefix.dpatch, gsqlite-compilefix.dpatch, gsqlite-slave.dpatch,
  recursor-slowdown.patch.dpatch, typoinitscript.dpatch, zone2ldap.dpatch
  They are applied upstream.
* The ldapbackend did not properly escape all queries, allowing it to fail
  and not answer questions. (CAN-2005-2301)
* Questions from clients denied recursion could blank out answers to clients
  who are allowed recursion services, temporarily. (CAN-2005-2302)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
    PowerDNS Versatile Database Driven Nameserver
3
 
    Copyright (C) 2002-2003  PowerDNS.COM BV
 
3
    Copyright (C) 2002-2005  PowerDNS.COM BV
4
4
 
5
5
    This program is free software; you can redistribute it and/or modify
6
6
    it under the terms of the GNU General Public License version 2 as 
15
15
    along with this program; if not, write to the Free Software
16
16
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
*/
18
 
// $Id: bindbackend2.cc,v 1.6 2003/10/04 14:15:46 ahu Exp $ 
 
18
 
19
19
#include <errno.h>
20
20
#include <string>
21
21
#include <map>
37
37
#include "bindparser.hh"
38
38
#include "logger.hh"
39
39
#include "arguments.hh"
40
 
#include "huffman.hh"
41
40
#include "qtype.hh"
42
41
#include "misc.hh"
43
42
#include "dynlistener.hh"
46
45
 
47
46
/** new scheme of things:
48
47
    we have zone-id map
49
 
    a zone-id has a vector of DNSResourceRecords */
 
48
    a zone-id has a vector of DNSResourceRecords 
 
49
    on start of query, we find the best zone to answer from
 
50
*/
50
51
 
51
52
map<string,int> Bind2Backend::s_name_id_map;
52
53
map<u_int32_t,BB2DomainInfo* > Bind2Backend::s_id_zone_map;
114
115
 
115
116
bool Bind2Backend::startTransaction(const string &qname, int id)
116
117
{
117
 
 
118
118
  BB2DomainInfo &bbd=*s_id_zone_map[d_transaction_id=id];
119
119
  d_transaction_tmpname=bbd.d_filename+"."+itoa(random());
120
120
  d_of=new ofstream(d_transaction_tmpname.c_str());
170
170
 
171
171
  string content=r.content;
172
172
 
173
 
  // SOA needs stripping too! XXX FIXME
 
173
  // SOA needs stripping too! XXX FIXME - also, this should not be here I think
174
174
  switch(r.qtype.getCode()) {
175
175
  case QType::TXT:
176
176
    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t\""<<r.content<<"\""<<endl;
217
217
    else
218
218
      if(soadata.serial!=i->second->d_lastnotified)
219
219
        changedDomains->push_back(di);
220
 
    
221
220
  }
222
221
}
223
222
 
282
281
  for(i=ret.begin();
283
282
      i!=ret.end();
284
283
      ++i)
285
 
    ; // *i=*i; //tolower(*i);
 
284
    *i=tolower(*i);
286
285
 
287
286
 
288
287
  if(*(i-1)=='.')
290
289
  return ret;
291
290
}
292
291
 
 
292
 
 
293
set<string> contents;
 
294
 
293
295
map<unsigned int, BB2DomainInfo*> nbbds;
294
296
/** This function adds a record to a domain with a certain id. */
295
297
void Bind2Backend::insert(int id, const string &qnameu, const string &qtype, const string &content, int ttl=300, int prio=25)
296
298
{
297
 
  DNSResourceRecord rr;
298
 
  rr.domain_id=id;
299
 
  rr.qname=canonic(qnameu);
300
 
  rr.qtype=qtype;
301
 
  rr.content=content;
302
 
  rr.ttl=ttl;
303
 
  rr.priority=prio;
304
 
  nbbds[id]->d_records->push_back(rr);
 
299
  Bind2DNSRecord bdr;
 
300
 
 
301
  //  rr.domain_id=id;
 
302
  BB2DomainInfo* bb2=nbbds[id];
 
303
 
 
304
  vector<Bind2DNSRecord> &records=*bb2->d_records;
 
305
 
 
306
  bdr.qname=toLower(canonic(qnameu));
 
307
  if(bdr.qname==bb2->d_name)
 
308
    bdr.qname.clear();
 
309
  else if(bdr.qname.length() > bb2->d_name.length())
 
310
    bdr.qname.resize(bdr.qname.length() - (bb2->d_name.length() + 1));
 
311
  else
 
312
    throw AhuException("Trying to insert non-zone data, name='"+bdr.qname+"', zone='"+nbbds[id]->d_name+"'");
 
313
 
 
314
  bdr.qname.swap(bdr.qname);
 
315
 
 
316
  if(!records.empty() && bdr.qname==(records.end()-1)->qname)
 
317
    bdr.qname=(records.end()-1)->qname;
 
318
 
 
319
  bdr.qtype=QType(qtype.c_str()).getCode();
 
320
  bdr.content=canonic(content); // I think this is wrong, the zoneparser should not come up with . terminated stuff XXX FIXME
 
321
  set<string>::const_iterator i=contents.find(bdr.content);
 
322
  if(i!=contents.end())
 
323
   bdr.content=*i;
 
324
  else {
 
325
    contents.insert(bdr.content);
 
326
  }
 
327
 
 
328
  bdr.ttl=ttl;
 
329
 
 
330
  records.push_back(bdr);
305
331
}
306
332
 
307
333
 
383
409
  us->insert(domain_id,domain,qtype,content,ttl,prio);
384
410
}
385
411
 
386
 
 
387
 
 
388
412
Bind2Backend::Bind2Backend(const string &suffix)
389
413
{
390
414
#if __GNUC__ >= 3
401
425
   
402
426
  s_first=0;
403
427
  
404
 
  if(mustDo("example-zones")) {
405
 
    insert(0,"www.example.com","A","1.2.3.4");
406
 
    insert(0,"example.com","SOA","ns1.example.com hostmaster.example.com");
407
 
    insert(0,"example.com","NS","ns1.example.com",86400);
408
 
    insert(0,"example.com","NS","ns2.example.com",86400);
409
 
    insert(0,"example.com","MX","mail.example.com",3600,25);
410
 
    insert(0,"example.com","MX","mail1.example.com",3600,25);
411
 
    insert(0,"mail.example.com","A","4.3.2.1");
412
 
    insert(0,"mail1.example.com","A","5.4.3.2");
413
 
    insert(0,"ns1.example.com","A","4.3.2.1");
414
 
    insert(0,"ns2.example.com","A","5.4.3.2");
415
 
      
416
 
    for(int i=0;i<1000;i++)
417
 
      insert(0,"host-"+itoa(i)+".example.com","A","2.3.4.5");
418
 
 
419
 
    s_id_zone_map[0]=new BB2DomainInfo;
420
 
    BB2DomainInfo &bbd=*s_id_zone_map[0];
421
 
    bbd.d_name="example.com";
422
 
    bbd.d_filename="";
423
 
    bbd.d_id=0;
424
 
    s_id_zone_map[0]->d_loaded=true;
425
 
    s_id_zone_map[0]->d_status="parsed into memory at "+nowTime();
426
 
  }
427
 
  
428
428
  loadConfig();
429
 
  
430
429
 
431
430
  extern DynListener *dl;
432
431
  us=this;
457
456
      L<<Logger::Error<<"Error parsing bind configuration: "<<ae.reason<<endl;
458
457
      throw;
459
458
    }
460
 
    
 
459
    /*
 
460
    cout<<"sizeof Bind2DNSRecord: "<<sizeof(Bind2DNSRecord)<<endl;
 
461
    cout<<"sizeof string: "<<sizeof(string)<<endl;
 
462
    cout<<"sizeof qtype: "<<sizeof(QType)<<endl;
 
463
    */
 
464
 
461
465
    ZoneParser ZP;
462
466
      
463
467
    vector<BindDomainInfo> domains=BP.getDomains();
488
492
          }
489
493
        if(j==s_id_zone_map.end()) { // entirely new
490
494
          bbd=new BB2DomainInfo;
491
 
          bbd->d_records=new vector<DNSResourceRecord>;
 
495
          bbd->d_records=new vector<Bind2DNSRecord>;
492
496
          
493
497
          bbd->d_id=domain_id++;
494
498
          s_name_id_map[i->name]=bbd->d_id;
507
511
          
508
512
          try {
509
513
            ZP.parse(i->filename,i->name,bbd->d_id); // calls callback for us
 
514
            L<<Logger::Info<<d_logprefix<<" sorting '"<<i->name<<"'"<<endl;
 
515
            sort(nbbds[bbd->d_id]->d_records->begin(), nbbds[bbd->d_id]->d_records->end());
510
516
            nbbds[bbd->d_id]->setCtime();
511
517
            nbbds[bbd->d_id]->d_loaded=true;          // does this perform locking for us?
512
518
            nbbds[bbd->d_id]->d_status="parsed into memory at "+nowTime();
513
 
            
 
519
            //      cout<<"Had "<<contents.size()<<" different content fields, "<<nbbds[bbd->d_id]->d_records->size()<<" records, capacity: "<<
 
520
            //        nbbds[bbd->d_id]->d_records->capacity()<<endl;
 
521
            contents.clear();
 
522
            nbbds[bbd->d_id]->d_records->swap(*nbbds[bbd->d_id]->d_records);
 
523
 
514
524
          }
515
525
          catch(AhuException &ae) {
516
526
            ostringstream msg;
586
596
/** Must be called with bbd locked already. Will not be unlocked on return, is your own problem.
587
597
    Does not throw errors or anything, may update d_status however */
588
598
 
589
 
 
590
599
void Bind2Backend::queueReload(BB2DomainInfo *bbd)
591
600
{
592
601
  nbbds.clear();
622
631
  }
623
632
}
624
633
 
 
634
bool operator<(const Bind2DNSRecord &a, const string &b)
 
635
{
 
636
  return a.qname < b;
 
637
}
 
638
 
 
639
bool operator<(const string &a, const Bind2DNSRecord &b)
 
640
{
 
641
  return a < b.qname;
 
642
}
 
643
 
 
644
 
625
645
void Bind2Backend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int zoneId )
626
646
{
627
 
  d_handle=new Bind2Backend::handle;
628
 
  d_handle->d_records=new vector<DNSResourceRecord>; // WRONG
629
 
  //  cout<<"Lookup! for "<<qname<<endl;
630
 
  string domain=qname;
 
647
  d_handle.reset(); // =new Bind2Backend::handle;
 
648
 
 
649
  string domain=toLower(qname);
 
650
 
 
651
  if(arg().mustDo("query-logging"))
 
652
    L<<"Lookup for '"<<qtype.getName()<<"' of '"<<domain<<"'"<<endl;
 
653
 
631
654
  while(!s_name_id_map.count(domain) && chopOff(domain));
632
655
 
633
656
  if(!s_name_id_map.count(domain)) {
634
 
    //    cout<<"no such domain: '"<<qname<<"'"<<endl;
635
 
    d_handle->d_iter=d_handle->d_records->end();  // WRONG
636
 
    d_handle->d_list=false;
637
 
    d_handle->d_bbd=0;
 
657
    d_handle.d_list=false;
 
658
    d_handle.d_bbd=0;
638
659
    return;
639
660
  }
640
661
  unsigned int id=s_name_id_map[domain];
641
662
 
642
 
  //  cout<<"domain: '"<<domain<<"', id="<<id<<endl;
 
663
  d_handle.id=id;
643
664
  
644
 
 
645
665
  DLOG(L<<"Bind2Backend constructing handle for search for "<<qtype.getName()<<" for "<<
646
666
       qname<<endl);
647
 
 
648
 
  d_handle->qname=qname;
649
 
  d_handle->parent=this;
650
 
  d_handle->qtype=qtype;
651
 
  string compressed=toLower(qname);
652
 
  d_handle->d_records=s_id_zone_map[id]->d_records;
653
 
  d_handle->d_bbd=0;
654
 
  if(!d_handle->d_records->empty()) {
 
667
  
 
668
  if(strcasecmp(qname.c_str(),domain.c_str()))
 
669
    d_handle.qname=toLower(qname.substr(0,qname.size()-domain.length()-1)); // strip domain name
 
670
  
 
671
  d_handle.parent=this;
 
672
  d_handle.qtype=qtype;
 
673
  d_handle.domain=domain;
 
674
  d_handle.d_records=s_id_zone_map[id]->d_records; // give it a copy
 
675
  d_handle.d_bbd=0;
 
676
  if(!d_handle.d_records->empty()) {
655
677
    BB2DomainInfo& bbd=*s_id_zone_map[id];
656
678
    if(!bbd.d_loaded) {
657
 
      delete d_handle;
658
 
      throw DBException("Zone temporarily not available (file missing, or master dead)"); // fuck
 
679
      d_handle.reset();
 
680
      throw DBException("Zone temporarily not available (file missing, or master dead)"); // fsck
659
681
    }
660
682
 
661
683
    if(!bbd.tryRLock()) {
662
684
      L<<Logger::Warning<<"Can't get read lock on zone '"<<bbd.d_name<<"'"<<endl;
663
 
      delete d_handle;
664
 
      throw DBException("Temporarily unavailable due to a zone lock"); // fuck
 
685
      d_handle.reset();
 
686
      throw DBException("Temporarily unavailable due to a zone lock"); // fsck
665
687
    }
666
 
      
667
 
 
 
688
    
668
689
    if(!bbd.current()) {
669
690
      L<<Logger::Warning<<"Zone '"<<bbd.d_name<<"' ("<<bbd.d_filename<<") needs reloading"<<endl;
670
691
      queueReload(&bbd);
671
692
    }
672
 
    d_handle->d_bbd=&bbd;
 
693
    d_handle.d_bbd=&bbd;
673
694
  }
674
695
  else {
675
696
    DLOG(L<<"Query with no results"<<endl);
676
697
  }
677
 
  d_handle->d_iter=d_handle->d_records->begin();
678
 
  d_handle->d_list=false;
 
698
 
 
699
  pair<vector<Bind2DNSRecord>::const_iterator, vector<Bind2DNSRecord>::const_iterator> range;
 
700
 
 
701
  //  cout<<"starting equal range for: '"<<d_handle.qname<<"'"<<endl;
 
702
  range=equal_range(d_handle.d_records->begin(), d_handle.d_records->end(), d_handle.qname);
 
703
  
 
704
  if(range.first==range.second) {
 
705
    d_handle.d_bbd=0;
 
706
    d_handle.d_list=false;
 
707
    return;
 
708
  }
 
709
  else {
 
710
    d_handle.d_iter=range.first;
 
711
    d_handle.d_end_iter=range.second;
 
712
  }
 
713
 
 
714
  d_handle.d_list=false;
679
715
}
680
716
 
681
717
Bind2Backend::handle::handle()
682
718
{
683
719
  d_bbd=0;
 
720
  d_records=0;
684
721
  count=0;
685
722
}
686
723
 
687
724
bool Bind2Backend::get(DNSResourceRecord &r)
688
725
{
689
 
  if(!d_handle->get(r)) {
690
 
    delete d_handle;
691
 
    d_handle=0;
 
726
  if(!d_handle.d_records)
 
727
    return false;
 
728
 
 
729
  if(!d_handle.get(r)) {
 
730
    d_handle.reset();
 
731
 
 
732
    if(arg().mustDo("query-logging"))
 
733
      L<<"End of answers"<<endl;
 
734
 
692
735
    return false;
693
736
  }
 
737
  if(arg().mustDo("query-logging"))
 
738
    L<<"Returning: '"<<r.qtype.getName()<<"' of '"<<r.qname<<"', content: '"<<r.content<<"'"<<endl;
694
739
  return true;
695
740
}
696
741
 
707
752
  DLOG(L << "Bind2Backend get() was called for "<<qtype.getName() << " record  for "<<
708
753
       qname<<"- "<<d_records->size()<<" available!"<<endl);
709
754
  
710
 
  while(d_iter!=d_records->end() && (d_iter->qname!=qname || !(qtype=="ANY" || (d_iter)->qtype==qtype))) {
 
755
  if(d_iter==d_end_iter) {
 
756
    if(d_bbd) {
 
757
      d_bbd->unlock();
 
758
      d_bbd=0;
 
759
    }
 
760
    return false;
 
761
  }
 
762
 
 
763
  while(d_iter!=d_end_iter && !(qtype.getCode()==QType::ANY || (d_iter)->qtype==qtype.getCode())) {
711
764
    DLOG(L<<Logger::Warning<<"Skipped "<<qname<<"/"<<QType(d_iter->qtype).getName()<<": '"<<d_iter->content<<"'"<<endl);
712
765
    d_iter++;
713
766
  }
714
 
  if(d_iter==d_records->end()) { // we've reached the end
 
767
  if(d_iter==d_end_iter) {
715
768
    if(d_bbd) {
716
769
      d_bbd->unlock();
717
770
      d_bbd=0;
720
773
  }
721
774
  DLOG(L << "Bind2Backend get() returning a rr with a "<<QType(d_iter->qtype).getCode()<<endl);
722
775
 
723
 
  r.qname=qname; // fill this in
724
 
  
 
776
  r.qname=qname.empty() ? domain : (qname+"."+domain);
 
777
  r.domain_id=id;
725
778
  r.content=(d_iter)->content;
726
 
  r.domain_id=(d_iter)->domain_id;
 
779
  //  r.domain_id=(d_iter)->domain_id;
727
780
  r.qtype=(d_iter)->qtype;
728
781
  r.ttl=(d_iter)->ttl;
729
 
  r.priority=(d_iter)->priority;
 
782
  //  r.priority=(d_iter)->priority;
730
783
  d_iter++;
731
784
 
732
785
  return true;
734
787
 
735
788
bool Bind2Backend::list(const string &target, int id)
736
789
{
737
 
  // cout<<"List of id "<<id<<" requested"<<endl;
738
790
  if(!s_id_zone_map.count(id))
739
791
    return false;
740
792
 
741
 
  d_handle=new Bind2Backend::handle;
 
793
  d_handle.reset(); // new Bind2Backend::handle;
742
794
  DLOG(L<<"Bind2Backend constructing handle for list of "<<id<<endl);
743
795
 
744
 
  d_handle->d_qname_iter=s_id_zone_map[id]->d_records->begin();
745
 
  d_handle->d_qname_end=s_id_zone_map[id]->d_records->end();   // iter now points to a vector of pointers to vector<BBResourceRecords>
746
 
 
747
 
  d_handle->parent=this;
748
 
  d_handle->id=id;
749
 
  d_handle->d_list=true;
 
796
  d_handle.d_qname_iter=s_id_zone_map[id]->d_records->begin();
 
797
  d_handle.d_qname_end=s_id_zone_map[id]->d_records->end();   // iter now points to a vector of pointers to vector<BBResourceRecords>
 
798
 
 
799
  d_handle.d_records=s_id_zone_map[id]->d_records; // give it a copy --- WHY??? XXX FIXME
 
800
 
 
801
  d_handle.parent=this;
 
802
  d_handle.id=id;
 
803
  d_handle.d_list=true;
750
804
  return true;
751
805
 
752
806
}
754
808
bool Bind2Backend::handle::get_list(DNSResourceRecord &r)
755
809
{
756
810
  if(d_qname_iter!=d_qname_end) {
757
 
    r=*d_qname_iter;
 
811
    r.qname=d_qname_iter->qname.empty() ? domain : (d_qname_iter->qname+"."+domain);
 
812
    r.domain_id=id;
 
813
    r.content=(d_qname_iter)->content;
 
814
    r.qtype=(d_qname_iter)->qtype;
 
815
    r.ttl=(d_qname_iter)->ttl;
758
816
    d_qname_iter++;
759
817
    return true;
760
818
  }
834
892
  
835
893
  BB2DomainInfo *bbd = new BB2DomainInfo;
836
894
 
837
 
  bbd->d_records = new vector<DNSResourceRecord>;
 
895
  bbd->d_records = new vector<Bind2DNSRecord>;
838
896
  bbd->d_name = domain;
839
897
  bbd->setCheckInterval(getArgAsNum("check-interval"));
840
898
  bbd->d_master = ip;