2
2
PowerDNS Versatile Database Driven Nameserver
3
Copyright (C) 2002-2005 PowerDNS.COM BV
3
Copyright (C) 2002-2007 PowerDNS.COM BV
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
14
14
You should have received a copy of the GNU General Public License
15
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
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
49
50
on start of query, we find the best zone to answer from
52
Bind2Backend::name_id_map_t Bind2Backend::s_name_id_map;
54
53
// this map contains BB2DomainInfo structs, each of which contains a *pointer* to domain data
55
Bind2Backend::id_zone_map_t Bind2Backend::s_id_zone_map, Bind2Backend::s_staging_zone_map;
57
/* the model is that everything works from the s_id_zone_map, which is left alone most of the time.
59
Any updates which might fail, build a new zone map in s_staging_zone_map
60
Then we swap atomically, and clear the copy.
62
Zone id's are kept constant so s_name_id_map doesn't need to be updated, except on removal or addition.
54
shared_ptr<Bind2Backend::State> Bind2Backend::s_state;
56
/* the model is that all our state hides in s_state. This State instance consists of the id_zone_map, which contains all our zone information, indexed by id.
57
Then there is the name_id_map, which allows us to map a query to a zone id.
59
The s_state is never written to, and it is a reference counted shared_ptr. Any function which needs to access the state
60
should do so by making a shared_ptr copy of it, and do all its work on that copy.
62
When I said s_state is never written to, I lied. No elements are ever added to it, or removed from it.
63
Its values however may be changed, but not the keys.
65
When it is necessary to change the State, a deep copy is made, which is changed. Afterwards,
66
the s_state pointer is made to point to the new State.
68
Anybody who is currently accessing the original holds a reference counted handle (shared_ptr) to it, which means it will stay around
69
To save memory, we hold the records as a shared_ptr as well.
71
Changes made to s_state directly should take the s_state_lock, so as to prevent writing to a stale copy.
65
74
int Bind2Backend::s_first=1;
67
76
pthread_mutex_t Bind2Backend::s_startup_lock=PTHREAD_MUTEX_INITIALIZER;
68
pthread_mutex_t Bind2Backend::s_zonemap_lock=PTHREAD_MUTEX_INITIALIZER;
77
pthread_mutex_t Bind2Backend::s_state_lock=PTHREAD_MUTEX_INITIALIZER;
78
string Bind2Backend::s_binddirectory;
70
79
/* when a query comes in, we find the most appropriate zone and answer from that */
72
81
BB2DomainInfo::BB2DomainInfo()
77
86
d_status="Unknown";
114
129
void Bind2Backend::setNotified(uint32_t id, uint32_t serial)
116
s_id_zone_map[id].d_lastnotified=serial;
131
Lock l(&s_state_lock);
132
s_state->id_zone_map[id].d_lastnotified=serial;
119
135
void Bind2Backend::setFresh(uint32_t domain_id)
121
s_id_zone_map[domain_id].d_last_check=time(0);
137
Lock l(&s_state_lock);
138
s_state->id_zone_map[domain_id].d_lastcheck=time(0);
124
141
bool Bind2Backend::startTransaction(const string &qname, int id)
126
BB2DomainInfo &bbd=s_id_zone_map[d_transaction_id=id];
143
shared_ptr<State> state = s_state; // is only read from
145
const BB2DomainInfo &bbd=state->id_zone_map[d_transaction_id=id];
127
147
d_transaction_tmpname=bbd.d_filename+"."+itoa(random());
128
148
d_of=new ofstream(d_transaction_tmpname.c_str());
146
if(rename(d_transaction_tmpname.c_str(),s_id_zone_map[d_transaction_id].d_filename.c_str())<0)
147
throw DBException("Unable to commit (rename to: '"+s_id_zone_map[d_transaction_id].d_filename+"') AXFRed zone: "+stringerror());
150
queueReload(&s_id_zone_map[d_transaction_id]);
166
shared_ptr<State> state = s_state;
168
// this might fail if s_state was cycled during the AXFR
169
if(rename(d_transaction_tmpname.c_str(), state->id_zone_map[d_transaction_id].d_filename.c_str())<0)
170
throw DBException("Unable to commit (rename to: '" + state->id_zone_map[d_transaction_id].d_filename+"') AXFRed zone: "+stringerror());
172
queueReload(&state->id_zone_map[d_transaction_id]);
152
174
d_transaction_id=0;
169
191
bool Bind2Backend::feedRecord(const DNSResourceRecord &r)
171
193
string qname=r.qname;
172
string domain=s_id_zone_map[d_transaction_id].d_name;
195
const shared_ptr<State> state = s_state;
196
string domain = state->id_zone_map[d_transaction_id].d_name;
174
198
if(!stripDomainSuffix(&qname,domain))
175
199
throw DBException("out-of-zone data '"+qname+"' during AXFR of zone '"+domain+"'");
179
203
// SOA needs stripping too! XXX FIXME - also, this should not be here I think
180
204
switch(r.qtype.getCode()) {
182
*d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t\""<<r.content<<"\""<<endl;
185
if(!stripDomainSuffix(&content,domain))
206
if(!stripDomainSuffix(&content, domain))
187
209
*d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<r.priority<<"\t"<<content<<endl;
189
211
case QType::CNAME:
191
if(!stripDomainSuffix(&content,domain))
213
if(!stripDomainSuffix(&content, domain))
193
215
*d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<content<<endl;
203
225
void Bind2Backend::getUpdatedMasters(vector<DomainInfo> *changedDomains)
206
for(id_zone_map_t::iterator i=s_id_zone_map.begin();i!=s_id_zone_map.end();++i) {
207
if(!i->second.d_master.empty())
229
// Lock l(&s_state_lock); // we don't really change the zone map, just flip a bit
231
for(id_zone_map_t::iterator i = s_state->id_zone_map.begin(); i != s_state->id_zone_map.end() ; ++i) {
232
if(!i->second.d_masters.empty())
209
234
soadata.serial=0;
211
getSOA(i->second.d_name,soadata); // we might not *have* a SOA yet
236
this->getSOA(i->second.d_name, soadata); // we might not *have* a SOA yet, but this might trigger a load of it
216
241
di.serial=soadata.serial;
217
242
di.zone=i->second.d_name;
218
di.last_check=i->second.d_last_check;
243
di.last_check=i->second.d_lastcheck;
220
245
di.kind=DomainInfo::Master;
221
246
if(!i->second.d_lastnotified) // don't do notification storm on startup
229
254
void Bind2Backend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
231
for(id_zone_map_t::const_iterator i=s_id_zone_map.begin();i!=s_id_zone_map.end();++i) {
232
if(i->second.d_master.empty())
256
shared_ptr<State> state = s_state;
257
for(id_zone_map_t::const_iterator i = state->id_zone_map.begin(); i != state->id_zone_map.end() ; ++i) {
258
if(i->second.d_masters.empty())
236
262
sd.zone=i->second.d_name;
237
sd.master=i->second.d_master;
238
sd.last_check=i->second.d_last_check;
263
sd.masters=i->second.d_masters;
264
sd.last_check=i->second.d_lastcheck;
240
266
sd.kind=DomainInfo::Slave;
256
282
bool Bind2Backend::getDomainInfo(const string &domain, DomainInfo &di)
258
for(id_zone_map_t::const_iterator i=s_id_zone_map.begin();i!=s_id_zone_map.end();++i) {
284
shared_ptr<State> state = s_state;
285
for(id_zone_map_t::const_iterator i = state->id_zone_map.begin(); i != state->id_zone_map.end() ; ++i) {
259
286
if(i->second.d_name==domain) {
262
di.master=i->second.d_master;
263
di.last_check=i->second.d_last_check;
289
di.masters=i->second.d_masters;
290
di.last_check=i->second.d_lastcheck;
265
di.kind=i->second.d_master.empty() ? DomainInfo::Master : DomainInfo::Slave;
292
di.kind=i->second.d_masters.empty() ? DomainInfo::Master : DomainInfo::Slave;
299
static Bind2Backend *us;
301
static void InsertionCallback(unsigned int domain_id, const string &domain, const string &qtype, const string &content, int ttl, int prio)
303
us->insert(domain_id, domain, qtype, content, ttl, prio);
306
326
set<string> contents;
308
/** This function adds a record to a domain with a certain id.
328
/** THIS IS AN INTERNAL FUNCTION! It does moadnsparser prio impedence matching
329
This function adds a record to a domain with a certain id.
309
330
Much of the complication is due to the efforts to benefit from std::string reference counting copy on write semantics */
310
void Bind2Backend::insert(int id, const string &qnameu, const string &qtype, const string &content, int ttl=300, int prio=25)
331
void Bind2Backend::insert(shared_ptr<State> stage, int id, const string &qnameu, const QType &qtype, const string &content, int ttl=300, int prio=25)
333
BB2DomainInfo bb2 = stage->id_zone_map[id];
312
334
Bind2DNSRecord bdr;
314
BB2DomainInfo& bb2=s_staging_zone_map[id];
316
vector<Bind2DNSRecord>& records=*bb2.d_records;
336
vector<Bind2DNSRecord>& records=*bb2.d_records;
318
338
bdr.qname=toLower(canonic(qnameu));
319
339
if(bdr.qname==toLower(bb2.d_name))
321
341
else if(bdr.qname.length() > bb2.d_name.length())
322
342
bdr.qname.resize(bdr.qname.length() - (bb2.d_name.length() + 1));
324
throw AhuException("Trying to insert non-zone data, name='"+bdr.qname+"', zone='"+s_staging_zone_map[id].d_name+"'");
344
throw AhuException("Trying to insert non-zone data, name='"+bdr.qname+"', zone='" + s_state->id_zone_map[id].d_name+"'");
326
346
bdr.qname.swap(bdr.qname);
328
348
if(!records.empty() && bdr.qname==(records.end()-1)->qname)
329
349
bdr.qname=(records.end()-1)->qname;
331
bdr.qtype=QType(qtype.c_str()).getCode();
332
bdr.content=canonic(content); // I think this is wrong, the zoneparser should not come up with . terminated stuff XXX FIXME
351
bdr.qtype=qtype.getCode();
354
if(bdr.qtype == QType::MX || bdr.qtype == QType::SRV) {
355
prio=atoi(bdr.content.c_str());
357
string::size_type pos = bdr.content.find_first_not_of("0123456789");
358
if(pos != string::npos)
359
erase_head(bdr.content, pos);
360
trim_left(bdr.content);
363
if(bdr.qtype==QType::CNAME || bdr.qtype==QType::MX || bdr.qtype==QType::NS || bdr.qtype==QType::AFSDB)
364
bdr.content=canonic(bdr.content); // I think this is wrong, the zoneparser should not come up with . terminated stuff XXX FIXME
333
366
set<string>::const_iterator i=contents.find(bdr.content);
334
367
if(i!=contents.end())
341
374
bdr.priority=prio;
343
376
records.push_back(bdr);
346
379
void Bind2Backend::reload()
348
for(id_zone_map_t::iterator i=us->s_id_zone_map.begin();i!=us->s_id_zone_map.end();++i)
381
Lock l(&s_state_lock);
382
for(id_zone_map_t::iterator i = s_state->id_zone_map.begin(); i != s_state->id_zone_map.end(); ++i)
349
383
i->second.d_checknow=true;
352
386
string Bind2Backend::DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid)
388
shared_ptr<State> state = s_state;
354
389
ostringstream ret;
356
391
for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) {
357
if(s_name_id_map.count(*i)) {
358
BB2DomainInfo& bbd=s_id_zone_map[s_name_id_map[*i]];
392
if(state->name_id_map.count(*i)) {
393
BB2DomainInfo& bbd=state->id_zone_map[state->name_id_map[*i]];
360
us->queueReload(&bbd);
361
396
ret<< *i << ": "<< (bbd.d_loaded ? "": "[rejected]") <<"\t"<<bbd.d_status<<"\n";
372
407
string Bind2Backend::DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid)
374
409
ostringstream ret;
410
shared_ptr<State> state = s_state;;
375
412
if(parts.size() > 1) {
376
413
for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) {
377
if(s_name_id_map.count(*i)) {
378
BB2DomainInfo& bbd=s_id_zone_map[s_name_id_map[*i]];
414
if(state->name_id_map.count(*i)) {
415
BB2DomainInfo& bbd=state->id_zone_map[state->name_id_map[*i]]; // XXX s_name_id_map needs trick as well
379
416
ret<< *i << ": "<< (bbd.d_loaded ? "": "[rejected]") <<"\t"<<bbd.d_status<<"\n";
396
433
string Bind2Backend::DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid)
435
shared_ptr<State> state = s_state;
398
437
ostringstream ret;
399
for(id_zone_map_t::iterator j=us->s_id_zone_map.begin();j!=us->s_id_zone_map.end();++j)
438
for(id_zone_map_t::iterator j = state->id_zone_map.begin(); j != state->id_zone_map.end(); ++j)
400
439
if(!j->second.d_loaded)
401
440
ret<<j->second.d_name<<"\t"<<j->second.d_status<<endl;
403
442
return ret.str();
407
445
Bind2Backend::Bind2Backend(const string &suffix)
409
447
#if __GNUC__ >= 3
459
s_state = shared_ptr<State>(new State);
425
462
extern DynListener *dl;
427
463
dl->registerFunc("BIND-RELOAD-NOW", &DLReloadNowHandler);
428
464
dl->registerFunc("BIND-DOMAIN-STATUS", &DLDomStatusHandler);
429
465
dl->registerFunc("BIND-LIST-REJECTS", &DLListRejectsHandler);
468
Bind2Backend::~Bind2Backend()
432
473
void Bind2Backend::rediscover(string *status)
434
475
loadConfig(status);
478
static void prefetchFile(const std::string& fname)
484
fd=open(fname.c_str(), O_RDONLY);
488
posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
437
492
void Bind2Backend::loadConfig(string* status)
439
494
// Interference with createSlaveDomain()
440
Lock l(&s_zonemap_lock);
495
Lock l(&s_state_lock);
442
497
static int domain_id=1;
443
s_staging_zone_map.clear();
499
shared_ptr<State> staging = shared_ptr<State>(new State);
444
501
if(!getArg("config").empty()) {
450
507
L<<Logger::Error<<"Error parsing bind configuration: "<<ae.reason<<endl;
456
511
vector<BindDomainInfo> domains=BP.getDomains();
460
d_binddirectory=BP.getDirectory();
461
ZP.setDirectory(d_binddirectory);
462
ZP.setCallback(&InsertionCallback);
513
s_binddirectory=BP.getDirectory();
514
// ZP.setDirectory(d_binddirectory);
464
516
L<<Logger::Warning<<d_logprefix<<" Parsing "<<domains.size()<<" domain(s), will report when done"<<endl;
467
519
int newdomains=0;
521
// random_shuffle(domains.begin(), domains.end());
524
for(vector<BindDomainInfo>::iterator i=domains.begin(); i!=domains.end(); ++i)
526
if(stat(i->filename.c_str(), &st) == 0) {
527
i->d_dev = st.st_dev;
528
i->d_ino = st.st_ino;
532
sort(domains.begin(), domains.end()); // put stuff in inode order
469
534
for(vector<BindDomainInfo>::const_iterator i=domains.begin();
470
535
i!=domains.end();
478
543
BB2DomainInfo* bbd=0;
480
if(!s_name_id_map.count(i->name)) { // is it fully new?
481
bbd=&s_staging_zone_map[domain_id];
545
if(!s_state->name_id_map.count(i->name)) { // is it fully new?
546
bbd=&staging->id_zone_map[domain_id];
482
547
bbd->d_id=domain_id++;
483
s_name_id_map[i->name]=bbd->d_id;
485
549
// this isn't necessary, we do this on the actual load
486
550
// bbd->d_records=shared_ptr<vector<Bind2DNSRecord> > (new vector<Bind2DNSRecord>);
490
554
bbd->d_loaded=false;
492
556
else { // no, we knew about it already
493
s_staging_zone_map[s_name_id_map[i->name]]=s_id_zone_map[s_name_id_map[i->name]];
494
bbd=&s_staging_zone_map[s_name_id_map[i->name]];
557
staging->id_zone_map[s_state->name_id_map[i->name]] = s_state->id_zone_map[s_state->name_id_map[i->name]]; // these should all be read-only on s_state
558
bbd = &staging->id_zone_map[s_state->name_id_map[i->name]];
561
staging->name_id_map[i->name]=bbd->d_id; // fill out name -> id map
498
563
// overwrite what we knew about the domain
499
564
bbd->d_name=i->name;
500
565
bbd->d_filename=i->filename;
501
bbd->d_master=i->master;
566
bbd->d_masters=i->masters;
503
568
if(!bbd->d_loaded || !bbd->current()) {
504
L<<Logger::Info<<d_logprefix<<" parsing '"<<i->name<<"' from file '"<<i->filename<<"'"<<endl;
569
// L<<Logger::Info<<d_logprefix<<" parsing '"<<i->name<<"' from file '"<<i->filename<<"'"<<endl;
507
// we need to allocate a new vector so we don't kill the original
572
// we need to allocate a new vector so we don't kill the original, which is still in use!
508
573
bbd->d_records=shared_ptr<vector<Bind2DNSRecord> > (new vector<Bind2DNSRecord>);
510
ZP.parse(i->filename, i->name, bbd->d_id); // calls callback for us
511
L<<Logger::Info<<d_logprefix<<" sorting '"<<i->name<<"'"<<endl;
513
sort(s_staging_zone_map[bbd->d_id].d_records->begin(), s_staging_zone_map[bbd->d_id].d_records->end());
515
s_staging_zone_map[bbd->d_id].setCtime();
516
s_staging_zone_map[bbd->d_id].d_loaded=true;
517
s_staging_zone_map[bbd->d_id].d_status="parsed into memory at "+nowTime();
575
ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
576
DNSResourceRecord rr;
578
insert(staging, bbd->d_id, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority);
581
// ZP.parse(i->filename, i->name, bbd->d_id); // calls callback for us
582
// L<<Logger::Info<<d_logprefix<<" sorting '"<<i->name<<"'"<<endl;
584
sort(staging->id_zone_map[bbd->d_id].d_records->begin(), staging->id_zone_map[bbd->d_id].d_records->end());
586
staging->id_zone_map[bbd->d_id].setCtime();
587
staging->id_zone_map[bbd->d_id].d_loaded=true;
588
staging->id_zone_map[bbd->d_id].d_status="parsed into memory at "+nowTime();
519
590
contents.clear();
520
// s_staging_zone_map[bbd->d_id].d_records->swap(*s_staging_zone_map[bbd->d_id].d_records);
591
// s_stage->id_zone_map[bbd->d_id].d_records->swap(*s_staging_zone_map[bbd->d_id].d_records);
522
593
catch(AhuException &ae) {
523
594
ostringstream msg;
527
598
*status+=msg.str();
528
s_staging_zone_map[bbd->d_id].d_status=msg.str();
599
staging->id_zone_map[bbd->d_id].d_status=msg.str();
600
L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
603
catch(exception &ae) {
605
msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.what();
609
staging->id_zone_map[bbd->d_id].d_status=msg.str();
529
610
L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
539
620
// figure out which domains were new and which vanished
540
621
int remdomains=0;
541
622
set<string> oldnames, newnames;
542
for(id_zone_map_t::const_iterator j=s_id_zone_map.begin();j!=s_id_zone_map.end();++j) {
623
for(id_zone_map_t::const_iterator j=s_state->id_zone_map.begin();j != s_state->id_zone_map.end();++j) {
543
624
oldnames.insert(j->second.d_name);
545
for(id_zone_map_t::const_iterator j=s_staging_zone_map.begin();j!=s_staging_zone_map.end();++j) {
626
for(id_zone_map_t::const_iterator j=staging->id_zone_map.begin(); j!= staging->id_zone_map.end(); ++j) {
546
627
newnames.insert(j->second.d_name);
549
630
vector<string> diff;
550
631
set_difference(oldnames.begin(), oldnames.end(), newnames.begin(), newnames.end(), back_inserter(diff));
551
632
remdomains=diff.size();
553
635
// remove domains from the *name* map, delete their pointer
554
636
for(vector<string>::const_iterator k=diff.begin();k!=diff.end(); ++k) {
555
637
L<<Logger::Error<<"Removing domain: "<<*k<<endl;
556
s_name_id_map.erase(*k);
638
s_state->name_id_map.erase(*k);
559
// now remove from the s_id_zone_map
560
for(id_zone_map_t::iterator j=s_id_zone_map.begin();j!=s_id_zone_map.end();++j) { // O(N*M)
641
// now remove from the s_state->id_zone_map
642
for(id_zone_map_t::iterator j=s_state->id_zone_map.begin();j!=s_state->id_zone_map.end();++j) { // O(N*M)
561
643
for(vector<string>::const_iterator k=diff.begin();k!=diff.end();++k)
562
644
if(j->second.d_name==*k) {
563
645
L<<Logger::Error<<"Removing records from zone '"<<j->second.d_name<<"' from memory"<<endl;
572
655
// count number of entirely new domains
573
656
vector<string> diff2;
574
657
set_difference(newnames.begin(), newnames.end(), oldnames.begin(), oldnames.end(), back_inserter(diff2));
575
658
newdomains=diff2.size();
577
s_id_zone_map.swap(s_staging_zone_map); // commit
578
s_staging_zone_map.clear(); // and cleanup
660
s_state.swap(staging); // and boy do we hope this is a threadsafe operation!
581
663
ostringstream msg;
591
673
void Bind2Backend::nukeZoneRecords(BB2DomainInfo *bbd)
593
675
bbd->d_loaded=0; // block further access
594
bbd->d_records->clear(); // empty the vector of Bind2DNSRecords
676
bbd->d_records = shared_ptr<vector<Bind2DNSRecord> > (new vector<Bind2DNSRecord>);
598
680
void Bind2Backend::queueReload(BB2DomainInfo *bbd)
600
Lock l(&s_zonemap_lock);
682
Lock l(&s_state_lock);
602
s_staging_zone_map.clear();
684
shared_ptr<State> staging(new State);
604
686
// we reload *now* for the time being
607
nukeZoneRecords(bbd);
612
ZP.setDirectory(d_binddirectory);
613
ZP.setCallback(&InsertionCallback);
615
s_staging_zone_map[bbd->d_id]=s_id_zone_map[bbd->d_id];
616
s_staging_zone_map[bbd->d_id].d_records=shared_ptr<vector<Bind2DNSRecord> > (new vector<Bind2DNSRecord>); // nuke it
618
ZP.parse(bbd->d_filename, bbd->d_name, bbd->d_id);
620
sort(s_staging_zone_map[bbd->d_id].d_records->begin(), s_staging_zone_map[bbd->d_id].d_records->end());
621
s_staging_zone_map[bbd->d_id].setCtime();
689
nukeZoneRecords(bbd); // ? do we need this?
690
staging->id_zone_map[bbd->d_id]=s_state->id_zone_map[bbd->d_id];
691
staging->id_zone_map[bbd->d_id].d_records=shared_ptr<vector<Bind2DNSRecord> > (new vector<Bind2DNSRecord>); // nuke it
693
ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory);
694
DNSResourceRecord rr;
696
insert(staging, bbd->d_id, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority);
699
sort(staging->id_zone_map[bbd->d_id].d_records->begin(), staging->id_zone_map[bbd->d_id].d_records->end());
700
staging->id_zone_map[bbd->d_id].setCtime();
623
702
contents.clear();
625
s_id_zone_map[bbd->d_id]=s_staging_zone_map[bbd->d_id]; // move over
704
s_state->id_zone_map[bbd->d_id]=staging->id_zone_map[bbd->d_id]; // move over
628
707
// and raise d_loaded again!
656
740
string domain=toLower(qname);
658
bool mustlog=arg().mustDo("query-logging");
742
bool mustlog=::arg().mustDo("query-logging");
660
744
L<<Logger::Warning<<"Lookup for '"<<qtype.getName()<<"' of '"<<domain<<"'"<<endl;
662
while(!s_name_id_map.count(domain) && chopOff(domain));
664
name_id_map_t::const_iterator iditer=s_name_id_map.find(domain);
666
if(iditer==s_name_id_map.end()) {
746
shared_ptr<State> state = s_state;
748
while(!state->name_id_map.count(domain) && chopOff(domain));
750
name_id_map_t::const_iterator iditer=state->name_id_map.find(domain);
752
if(iditer==state->name_id_map.end()) {
668
754
L<<Logger::Warning<<"Found no authoritative zone for "<<qname<<endl;
669
755
d_handle.d_list=false;
681
767
if(strcasecmp(qname.c_str(),domain.c_str()))
682
768
d_handle.qname=qname.substr(0,qname.size()-domain.length()-1); // strip domain name
684
d_handle.parent=this;
685
770
d_handle.qtype=qtype;
686
771
d_handle.domain=qname.substr(qname.size()-domain.length());
688
d_handle.d_records=s_id_zone_map[iditer->second].d_records; // give it a copy
689
if(!d_handle.d_records->empty()) {
690
BB2DomainInfo& bbd=s_id_zone_map[iditer->second];
693
throw DBException("Zone temporarily not available (file missing, or master dead)"); // fsck
773
BB2DomainInfo& bbd = state->id_zone_map[iditer->second];
776
throw DBException("Zone for '"+bbd.d_name+"' in '"+bbd.d_filename+"' temporarily not available (file missing, or master dead)"); // fsck
697
L<<Logger::Warning<<"Zone '"<<bbd.d_name<<"' ("<<bbd.d_filename<<") needs reloading"<<endl;
699
d_handle.d_records=s_id_zone_map[iditer->second].d_records; // give it a *fresh* copy
780
L<<Logger::Warning<<"Zone '"<<bbd.d_name<<"' ("<<bbd.d_filename<<") needs reloading"<<endl;
781
queueReload(&bbd); // how can this be safe - ok, everybody should have their own reference counted copy of 'records'
785
d_handle.d_records = state->id_zone_map[iditer->second].d_records; // give it a reference counted copy
787
if(d_handle.d_records->empty())
703
788
DLOG(L<<"Query with no results"<<endl);
706
790
pair<vector<Bind2DNSRecord>::const_iterator, vector<Bind2DNSRecord>::const_iterator> range;
736
821
if(!d_handle.get(r)) {
737
822
d_handle.reset();
739
if(arg().mustDo("query-logging"))
824
if(::arg().mustDo("query-logging"))
740
825
L<<"End of answers"<<endl;
744
if(arg().mustDo("query-logging"))
745
L<<"Returning: '"<<r.qtype.getName()<<"' of '"<<r.qname<<"', content: '"<<r.content<<"'"<<endl;
830
L<<Logger::Warning<<"Returning: '"<<r.qtype.getName()<<"' of '"<<r.qname<<"', content: '"<<r.content<<"', prio: "<<r.priority<<endl;
787
872
bool Bind2Backend::list(const string &target, int id)
789
if(!s_id_zone_map.count(id))
874
shared_ptr<State> state = s_state;
875
if(!state->id_zone_map.count(id))
792
878
d_handle.reset();
793
879
DLOG(L<<"Bind2Backend constructing handle for list of "<<id<<endl);
795
d_handle.d_qname_iter=s_id_zone_map[id].d_records->begin();
796
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
d_handle.d_records=s_id_zone_map[id].d_records; // give it a copy --- WHY??? XXX FIXME
800
d_handle.parent=this;
881
d_handle.d_records=state->id_zone_map[id].d_records; // give it a copy, which will stay around
882
d_handle.d_qname_iter= d_handle.d_records->begin();
883
d_handle.d_qname_end=d_handle.d_records->end(); // iter now points to a vector of pointers to vector<BBResourceRecords>
802
886
d_handle.d_list=true;
823
907
bool Bind2Backend::isMaster(const string &name, const string &ip)
825
for(id_zone_map_t::iterator j=us->s_id_zone_map.begin();j!=us->s_id_zone_map.end();++j)
826
if(j->second.d_name==name)
827
return j->second.d_master==ip;
909
for(id_zone_map_t::iterator j=s_state->id_zone_map.begin();j!=s_state->id_zone_map.end();++j) {
910
if(j->second.d_name==name) {
911
for(vector<string>::const_iterator iter = j->second.d_masters.begin(); iter != j->second.d_masters.end(); ++iter)
894
982
// Find a free zone id nr.
896
if (!s_id_zone_map.empty()) {
897
id_zone_map_t::reverse_iterator i = s_id_zone_map.rbegin();
984
if (!s_state->id_zone_map.empty()) {
985
id_zone_map_t::reverse_iterator i = s_state->id_zone_map.rbegin();
898
986
newid = i->second.d_id + 1;
901
BB2DomainInfo &bbd = s_id_zone_map[newid];
989
BB2DomainInfo &bbd = s_state->id_zone_map[newid];
903
991
bbd.d_records = shared_ptr<vector<Bind2DNSRecord> >(new vector<Bind2DNSRecord>);
904
992
bbd.d_name = domain;
905
993
bbd.setCheckInterval(getArgAsNum("check-interval"));
994
bbd.d_masters.push_back(ip);
907
995
bbd.d_filename = filename;
909
s_name_id_map[domain] = bbd.d_id;
997
s_state->name_id_map[domain] = bbd.d_id;
919
1007
void declareArguments(const string &suffix="")
921
1009
declare(suffix,"config","Location of named.conf","");
922
declare(suffix,"example-zones","Install example zones","no");
1010
// declare(suffix,"example-zones","Install example zones","no");
923
1011
declare(suffix,"check-interval","Interval for zonefile changes","0");
924
1012
declare(suffix,"supermaster-config","Location of (part of) named.conf where pdns can write zone-statements to","");
925
1013
declare(suffix,"supermasters","List of IP-addresses of supermasters","");
926
declare(suffix,"supermaster-destdir","Destination directory for newly added slave zones",arg()["config-dir"]);
1014
declare(suffix,"supermaster-destdir","Destination directory for newly added slave zones",::arg()["config-dir"]);
929
1017
DNSBackend *make(const string &suffix="")