2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 PowerDNS.COM BV
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;
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.
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
18 // $Id: bindbackend.cc,v 1.9 2002/12/20 16:12:06 ahu Exp $
23 #include <sys/types.h>
30 #include "dnsbackend.hh"
31 #include "bindbackend.hh"
32 #include "dnspacket.hh"
34 #include "zoneparser.hh"
35 #include "bindparser.hh"
37 #include "arguments.hh"
41 #include "dynlistener.hh"
46 cmap_t
BindBackend::d_qnames
;
47 map
<int,vector
<vector
<BBResourceRecord
>* > > BindBackend::d_zone_id_map
;
48 set
<string
> BindBackend::s_contents
;
49 HuffmanCodec
BindBackend::s_hc
;
51 map
<unsigned int,BBDomainInfo
> BindBackend::d_bbds
;
53 int BindBackend::s_first
=1;
54 pthread_mutex_t
BindBackend::s_startup_lock
=PTHREAD_MUTEX_INITIALIZER
;
56 BBDomainInfo::BBDomainInfo()
61 d_rwlock
=new pthread_rwlock_t
;
62 d_status
="Seen in bind configuration";
64 //cout<<"Generated a new bbdomaininfo: "<<(void*)d_rwlock<<"/"<<getpid()<<endl;
65 pthread_rwlock_init(d_rwlock
,0);
68 void BBDomainInfo::setCheckInterval(time_t seconds
)
70 d_checkinterval
=seconds
;
73 bool BBDomainInfo::current()
78 if(!d_checknow
&& !d_checkinterval
|| (time(0)-d_lastcheck
<d_checkinterval
) || d_filename
.empty())
81 return (getCtime()==d_ctime
);
84 time_t BBDomainInfo::getCtime()
88 if(d_filename
.empty() || stat(d_filename
.c_str(),&buf
)<0)
94 void BBDomainInfo::setCtime()
97 if(stat(d_filename
.c_str(),&buf
)<0)
102 void BindBackend::setNotified(u_int32_t id
, u_int32_t serial
)
104 d_bbds
[id
].d_lastnotified
=serial
;
107 void BindBackend::setFresh(u_int32_t domain_id
)
109 d_bbds
[domain_id
].d_last_check
=time(0);
112 bool BindBackend::startTransaction(const string
&qname
, int id
)
114 BBDomainInfo
&bbd
=d_bbds
[d_transaction_id
=id
];
115 d_transaction_tmpname
=bbd
.d_filename
+"."+itoa(random());
116 d_of
=new ofstream(d_transaction_tmpname
.c_str());
118 throw DBException("Unable to open temporary zonefile '"+d_transaction_tmpname
+"': "+stringerror());
119 unlink(d_transaction_tmpname
.c_str());
124 *d_of
<<"; Written by PowerDNS, don't edit!"<<endl
;
125 *d_of
<<"; Zone '"+bbd
.d_name
+"' retrieved from master "<<bbd
.d_master
<<endl
<<"; at "<<nowTime()<<endl
;
130 bool BindBackend::commitTransaction()
134 if(rename(d_transaction_tmpname
.c_str(),d_bbds
[d_transaction_id
].d_filename
.c_str())<0)
135 throw DBException("Unable to commit (rename to: '"+d_bbds
[d_transaction_id
].d_filename
+"') AXFRed zone: "+stringerror());
137 queueReload(&d_bbds
[d_transaction_id
]);
138 d_bbds
[d_transaction_id
].unlock();
142 bool BindBackend::abortTransaction()
146 unlink(d_transaction_tmpname
.c_str());
152 bool BindBackend::feedRecord(const DNSResourceRecord
&r
)
154 string qname
=r
.qname
;
155 string domain
=d_bbds
[d_transaction_id
].d_name
;
157 if(!stripDomainSuffix(&qname
,domain
))
158 throw DBException("out-of-zone data '"+qname
+"' during AXFR of zone '"+domain
+"'");
160 string content
=r
.content
;
162 // SOA needs stripping too! XXX FIXME
163 switch(r
.qtype
.getCode()) {
165 *d_of
<<qname
<<"\t"<<r
.ttl
<<"\t"<<r
.qtype
.getName()<<"\t\""<<r
.content
<<"\""<<endl
;
168 if(!stripDomainSuffix(&content
,domain
))
170 *d_of
<<qname
<<"\t"<<r
.ttl
<<"\t"<<r
.qtype
.getName()<<"\t"<<r
.priority
<<"\t"<<content
<<endl
;
174 if(!stripDomainSuffix(&content
,domain
))
176 *d_of
<<qname
<<"\t"<<r
.ttl
<<"\t"<<r
.qtype
.getName()<<"\t"<<content
<<endl
;
179 *d_of
<<qname
<<"\t"<<r
.ttl
<<"\t"<<r
.qtype
.getName()<<"\t"<<r
.content
<<endl
;
186 void BindBackend::getUpdatedMasters(vector
<DomainInfo
> *changedDomains
)
189 for(map
<u_int32_t
,BBDomainInfo
>::iterator i
=d_bbds
.begin();i
!=d_bbds
.end();++i
) {
190 if(!i
->second
.d_master
.empty())
194 getSOA(i
->second
.d_name
,soadata
); // we might not *have* a SOA yet
199 di
.serial
=soadata
.serial
;
200 di
.zone
=i
->second
.d_name
;
201 di
.last_check
=i
->second
.d_last_check
;
203 di
.kind
=DomainInfo::Master
;
204 if(!i
->second
.d_lastnotified
) // don't do notification storm on startup
205 i
->second
.d_lastnotified
=soadata
.serial
;
207 if(soadata
.serial
!=i
->second
.d_lastnotified
)
208 changedDomains
->push_back(di
);
213 void BindBackend::getUnfreshSlaveInfos(vector
<DomainInfo
> *unfreshDomains
)
215 for(map
<u_int32_t
,BBDomainInfo
>::const_iterator i
=d_bbds
.begin();i
!=d_bbds
.end();++i
) {
216 if(i
->second
.d_master
.empty())
220 sd
.zone
=i
->second
.d_name
;
221 sd
.master
=i
->second
.d_master
;
222 sd
.last_check
=i
->second
.d_last_check
;
224 sd
.kind
=DomainInfo::Slave
;
231 getSOA(i
->second
.d_name
,soadata
); // we might not *have* a SOA yet
234 sd
.serial
=soadata
.serial
;
235 if(sd
.last_check
+soadata
.refresh
<(unsigned int)time(0))
236 unfreshDomains
->push_back(sd
);
240 bool BindBackend::getDomainInfo(const string
&domain
, DomainInfo
&di
)
242 for(map
<u_int32_t
,BBDomainInfo
>::const_iterator i
=d_bbds
.begin();i
!=d_bbds
.end();++i
) {
243 if(i
->second
.d_name
==domain
) {
246 di
.master
=i
->second
.d_master
;
247 di
.last_check
=i
->second
.d_last_check
;
249 di
.kind
=i
->second
.d_master
.empty() ? DomainInfo::Master
: DomainInfo::Slave
;
253 getSOA(i
->second
.d_name
,sd
); // we might not *have* a SOA yet
265 static string
canonic(string ret
)
272 *i
=*i
; //tolower(*i);
276 ret
.resize(i
-ret
.begin()-1);
280 /** This function adds a record to a domain with a certain id. */
281 void BindBackend::insert(int id
, const string
&qnameu
, const string
&qtype
, const string
&content
, int ttl
=300, int prio
=25)
284 static unsigned int len
;
285 static unsigned int ulen
;
287 if(!((s_count
++)%10000))
288 cerr
<<"\r"<<s_count
-1<<", "<<s_contents
.size()<<" different contents, "<<d_qnames
.size()<<" different qnames, "<<len
/1000000<<"MB, saved: "<<
292 s_hc
.encode(toLower(canonic(qnameu
)),compressed
);
293 // string(compressed).swap(compressed);
294 // cout<<"saved: "<<qnameu.size()-compressed.size()<<endl;
296 vector
<BBResourceRecord
>::const_iterator i
;
298 if(d_qnames
[compressed
].empty()) { // NEW! NEW! NEW! in de top 40!
299 d_zone_id_map
[id
].push_back(&d_qnames
[compressed
]);
300 i
=d_qnames
[compressed
].end();
303 for(i
=d_qnames
[compressed
].begin();i
!=d_qnames
[compressed
].end();++i
)
304 if(((i
)->qtype
==QType::chartocode(qtype
.c_str())))
305 if((*(i
)->content
==canonic(content
)))
308 // never saw this specific name/type/content triple before
309 if(i
==d_qnames
[compressed
].end()) {
310 BBResourceRecord v
=resourceMaker(id
,qtype
,canonic(content
),ttl
,prio
);
311 v
.qnameptr
=&d_qnames
.find(compressed
)->first
;
312 len
+=compressed
.size();
314 d_qnames
[compressed
].push_back(v
);
316 d_qnames
[compressed
].reserve(0);
317 // vector<BBResourceRecord>&tmp=d_qnames[compressed];
318 // vector<BBResourceRecord>(tmp).swap(tmp);
326 /** Helper function that creates a BBResourceRecord and does s_content housekeeping */
327 BBResourceRecord
BindBackend::resourceMaker(int id
, const string
&qtype
, const string
&content
, int ttl
, int prio
)
329 BBResourceRecord make
;
333 make
.qtype
=QType::chartocode(qtype
.c_str());
335 throw AhuException("Unknown qtype '"+qtype
+"'");
337 set
<string
>::const_iterator i
=s_contents
.find(content
);
338 if(i
==s_contents
.end()) {
339 s_contents
.insert(content
);
340 i
=s_contents
.find(content
);
348 static BindBackend
*us
;
350 void BindBackend::reload()
352 for(map
<u_int32_t
,BBDomainInfo
>::iterator i
=us
->d_bbds
.begin();i
!=us
->d_bbds
.end();++i
)
353 i
->second
.d_checknow
=true;
356 string
BindBackend::DLReloadNowHandler(const vector
<string
>&parts
, Utility::pid_t ppid
)
360 for(map
<u_int32_t
,BBDomainInfo
>::iterator j
=us
->d_bbds
.begin();j
!=us
->d_bbds
.end();++j
) {
365 for(vector
<string
>::const_iterator i
=parts
.begin()+1;i
<parts
.end();++i
) // O(N) badness XXX FIXME
366 if(*i
==j
->second
.d_name
) {
374 us
->queueReload(&j
->second
);
376 ret
<<j
->second
.d_name
<< (j
->second
.d_loaded
? "": "[rejected]") <<"\t"<<j
->second
.d_status
<<"\n";
385 string
BindBackend::DLDomStatusHandler(const vector
<string
>&parts
, Utility::pid_t ppid
)
389 for(map
<u_int32_t
,BBDomainInfo
>::iterator j
=us
->d_bbds
.begin();j
!=us
->d_bbds
.end();++j
) {
394 for(vector
<string
>::const_iterator i
=parts
.begin()+1;i
<parts
.end();++i
) // O(N) badness XXX FIXME
395 if(*i
==j
->second
.d_name
) {
401 ret
<<j
->second
.d_name
<< (j
->second
.d_loaded
? "": "[rejected]") <<"\t"<<j
->second
.d_status
<<"\n";
409 string
BindBackend::DLListRejectsHandler(const vector
<string
>&parts
, Utility::pid_t ppid
)
412 for(map
<u_int32_t
,BBDomainInfo
>::iterator j
=us
->d_bbds
.begin();j
!=us
->d_bbds
.end();++j
)
413 if(!j
->second
.d_loaded
)
414 ret
<<j
->second
.d_name
<<"\t"<<j
->second
.d_status
<<endl
;
419 static void callback(unsigned int domain_id
, const string
&domain
, const string
&qtype
, const string
&content
, int ttl
, int prio
)
421 us
->insert(domain_id
,domain
,qtype
,content
,ttl
,prio
);
426 BindBackend::BindBackend(const string
&suffix
)
428 d_logprefix
="[bind"+suffix
+"backend]";
429 setArgPrefix("bind"+suffix
);
430 Lock
l(&s_startup_lock
);
437 if(!mustDo("enable-huffman"))
438 s_hc
.passthrough(true);
440 if(mustDo("example-zones")) {
441 insert(0,"www.example.com","A","1.2.3.4");
442 insert(0,"example.com","SOA","ns1.example.com hostmaster.example.com");
443 insert(0,"example.com","NS","ns1.example.com",86400);
444 insert(0,"example.com","NS","ns2.example.com",86400);
445 insert(0,"example.com","MX","mail.example.com",3600,25);
446 insert(0,"example.com","MX","mail1.example.com",3600,25);
447 insert(0,"mail.example.com","A","4.3.2.1");
448 insert(0,"mail1.example.com","A","5.4.3.2");
449 insert(0,"ns1.example.com","A","4.3.2.1");
450 insert(0,"ns2.example.com","A","5.4.3.2");
452 for(int i
=0;i
<1000;i
++)
453 insert(0,"host-"+itoa(i
)+".example.com","A","2.3.4.5");
456 bbd
.d_name
="example.com";
460 d_bbds
[0].d_loaded
=true;
461 d_bbds
[0].d_status
="parsed into memory at "+nowTime();
467 extern DynListener
*dl
;
469 dl
->registerFunc("BIND-RELOAD-NOW", &DLReloadNowHandler
);
470 dl
->registerFunc("BIND-DOMAIN-STATUS", &DLDomStatusHandler
);
471 dl
->registerFunc("BIND-LIST-REJECTS", &DLListRejectsHandler
);
475 void BindBackend::rediscover(string
*status
)
480 void BindBackend::loadConfig(string
* status
)
482 static int domain_id
=1;
484 if(!getArg("config").empty()) {
487 BP
.parse(getArg("config"));
489 catch(AhuException
&ae
) {
490 L
<<Logger::Error
<<"Error parsing bind configuration: "<<ae
.reason
<<endl
;
496 vector
<BindDomainInfo
> domains
=BP
.getDomains();
500 ZP
.setDirectory(BP
.getDirectory());
501 ZP
.setCallback(&callback
);
502 L
<<Logger::Warning
<<d_logprefix
<<" Parsing "<<domains
.size()<<" domain(s), will report when done"<<endl
;
507 map
<unsigned int, BBDomainInfo
> nbbds
;
509 for(vector
<BindDomainInfo
>::const_iterator i
=domains
.begin();
514 if(i
->type
!="master" && i
->type
!="slave") {
515 L
<<Logger::Warning
<<d_logprefix
<<" Warning! Skipping '"<<i
->type
<<"' zone '"<<i
->name
<<"'"<<endl
;
518 map
<unsigned int, BBDomainInfo
>::const_iterator j
=d_bbds
.begin();
519 for(;j
!=d_bbds
.end();++j
)
520 if(j
->second
.d_name
==i
->name
) {
524 if(j
==d_bbds
.end()) { // entirely new
525 bbd
.d_id
=domain_id
++;
527 bbd
.setCheckInterval(getArgAsNum("check-interval"));
528 bbd
.d_lastnotified
=0;
533 bbd
.d_filename
=i
->filename
;
534 bbd
.d_master
=i
->master
;
538 L
<<Logger::Info
<<d_logprefix
<<" parsing '"<<i
->name
<<"' from file '"<<i
->filename
<<"'"<<endl
;
541 ZP
.parse(i
->filename
,i
->name
,bbd
.d_id
); // calls callback for us
542 nbbds
[bbd
.d_id
].setCtime();
543 nbbds
[bbd
.d_id
].d_loaded
=true; // does this perform locking for us?
544 nbbds
[bbd
.d_id
].d_status
="parsed into memory at "+nowTime();
547 catch(AhuException
&ae
) {
549 msg
<<" error at "+nowTime()+" parsing '"<<i
->name
<<"' from file '"<<i
->filename
<<"': "<<ae
.reason
;
552 nbbds
[bbd
.d_id
].d_status
=msg
.str();
553 L
<<Logger::Warning
<<d_logprefix
<<msg
.str()<<endl
;
558 vector
<vector
<BBResourceRecord
> *>&tmp
=d_zone_id_map
[bbd
.d_id
]; // shrink trick
559 vector
<vector
<BBResourceRecord
> *>(tmp
).swap(tmp
);
564 set
<string
> oldnames
, newnames
;
565 for(map
<unsigned int, BBDomainInfo
>::const_iterator j
=d_bbds
.begin();j
!=d_bbds
.end();++j
) {
566 oldnames
.insert(j
->second
.d_name
);
568 for(map
<unsigned int, BBDomainInfo
>::const_iterator j
=nbbds
.begin();j
!=nbbds
.end();++j
) {
569 newnames
.insert(j
->second
.d_name
);
573 set_difference(oldnames
.begin(), oldnames
.end(), newnames
.begin(), newnames
.end(), back_inserter(diff
));
574 remdomains
=diff
.size();
575 for(vector
<string
>::const_iterator k
=diff
.begin();k
!=diff
.end();++k
)
576 L
<<Logger::Error
<<"Removed: "<<*k
<<endl
;
578 for(map
<unsigned int, BBDomainInfo
>::iterator j
=d_bbds
.begin();j
!=d_bbds
.end();++j
) { // O(N*M)
579 for(vector
<string
>::const_iterator k
=diff
.begin();k
!=diff
.end();++k
)
580 if(j
->second
.d_name
==*k
) {
581 L
<<Logger::Error
<<"Removing records from zone '"<<j
->second
.d_name
<<"' from memory"<<endl
;
583 j
->second
.d_loaded
=false;
584 nukeZoneRecords(&j
->second
);
590 vector
<string
> diff2
;
591 set_difference(newnames
.begin(), newnames
.end(), oldnames
.begin(), oldnames
.end(), back_inserter(diff2
));
592 newdomains
=diff2
.size();
594 d_bbds
.swap(nbbds
); // commit
596 msg
<<" Done parsing domains, "<<rejected
<<" rejected, "<<newdomains
<<" new, "<<remdomains
<<" removed";
600 L
<<Logger::Error
<<d_logprefix
<<msg
.str()<<endl
;
601 L
<<Logger::Info
<<d_logprefix
<<" Number of hash buckets: "<<d_qnames
.bucket_count()<<", number of entries: "<<d_qnames
.size()<< endl
;
605 /** nuke all records from memory, keep bbd intact though. Must be called with bbd lock held already! */
606 void BindBackend::nukeZoneRecords(BBDomainInfo
*bbd
)
608 bbd
->d_loaded
=0; // block further access
610 // this emtpies all d_qnames vectors belonging to this domain. We find these vectors via d_zone_id_map
611 for(vector
<vector
<BBResourceRecord
> *>::iterator i
=d_zone_id_map
[bbd
->d_id
].begin();
612 i
!=d_zone_id_map
[bbd
->d_id
].end();++i
) {
616 // empty our d_zone_id_map of the references to the now empty vectors (which are not gone from d_qnames, btw)
617 d_zone_id_map
[bbd
->d_id
].clear();
620 /** Must be called with bbd locked already. Will not be unlocked on return, is your own problem.
621 Does not throw errors or anything, may update d_status however */
624 void BindBackend::queueReload(BBDomainInfo
*bbd
)
626 // we reload *now* for the time being
627 //cout<<"unlock domain"<<endl;
629 //cout<<"lock it again"<<endl;
633 nukeZoneRecords(bbd
);
637 ZP
.setCallback(&callback
);
638 ZP
.parse(bbd
->d_filename
,bbd
->d_name
,bbd
->d_id
);
640 // and raise d_loaded again!
643 bbd
->d_status
="parsed into memory at "+nowTime();
644 L
<<Logger::Warning
<<"Zone '"<<bbd
->d_name
<<"' ("<<bbd
->d_filename
<<") reloaded"<<endl
;
646 catch(AhuException
&ae
) {
648 msg
<<" error at "+nowTime()+" parsing '"<<bbd
->d_name
<<"' from file '"<<bbd
->d_filename
<<"': "<<ae
.reason
;
649 bbd
->d_status
=msg
.str();
653 void BindBackend::lookup(const QType
&qtype
,const string
&qname
, DNSPacket
*pkt_p
, int zoneId
)
655 d_handle
=new BindBackend::handle
;
656 DLOG(L
<<"BindBackend constructing handle for search for "<<qtype
.getName()<<" for "<<
659 d_handle
->qname
=qname
;
660 d_handle
->parent
=this;
661 d_handle
->qtype
=qtype
;
663 s_hc
.encode(toLower(qname
),compressed
);
664 d_handle
->d_records
=d_qnames
[compressed
];
666 if(!d_handle
->d_records
.empty()) {
667 BBDomainInfo
& bbd
=d_bbds
[d_handle
->d_records
.begin()->domain_id
];
670 throw DBException("Zone temporarily not available (file missing, or master dead)"); // fuck
673 if(!bbd
.tryRLock()) {
674 L
<<Logger::Warning
<<"Can't get read lock on zone '"<<bbd
.d_name
<<"'"<<endl
;
676 throw DBException("Temporarily unavailable due to a zone lock"); // fuck
681 L
<<Logger::Warning
<<"Zone '"<<bbd
.d_name
<<"' ("<<bbd
.d_filename
<<") needs reloading"<<endl
;
684 d_handle
->d_bbd
=&bbd
;
687 DLOG(L
<<"Query with no results"<<endl
);
689 d_handle
->d_iter
=d_handle
->d_records
.begin();
690 d_handle
->d_list
=false;
693 BindBackend::handle::handle()
699 bool BindBackend::get(DNSResourceRecord
&r
)
701 if(!d_handle
->get(r
)) {
709 bool BindBackend::handle::get(DNSResourceRecord
&r
)
714 return get_normal(r
);
717 bool BindBackend::handle::get_normal(DNSResourceRecord
&r
)
719 DLOG(L
<< "BindBackend get() was called for "<<qtype
.getName() << " record for "<<
720 qname
<<"- "<<d_records
.size()<<" available!"<<endl
);
723 while(d_iter
!=d_records
.end() && !(qtype
=="ANY" || (d_iter
)->qtype
==QType(qtype
).getCode())) {
724 DLOG(L
<<"Skipped "<<qname
<<"/"<<QType(d_iter
->qtype
).getName()<<": '"<<*d_iter
->content
<<"'"<<endl
);
727 if(d_iter
==d_records
.end()) { // we've reached the end
735 DLOG(L
<< "BindBackend get() returning a rr with a "<<QType(d_iter
->qtype
).getCode()<<endl
);
737 r
.qname
=qname
; // fill this in
739 r
.content
=*(d_iter
)->content
;
740 r
.domain_id
=(d_iter
)->domain_id
;
741 r
.qtype
=(d_iter
)->qtype
;
743 r
.priority
=(d_iter
)->priority
;
749 bool BindBackend::list(int id
)
751 d_handle
=new BindBackend::handle
;
752 DLOG(L
<<"BindBackend constructing handle for list of "<<id
<<endl
);
754 d_handle
->d_qname_iter
=d_zone_id_map
[id
].begin();
755 d_handle
->d_qname_end
=d_zone_id_map
[id
].end(); // iter now points to a vector of pointers to vector<BBResourceRecords>
756 d_handle
->d_riter
=(*(d_handle
->d_qname_iter
))->begin();
757 d_handle
->d_rend
=(*(d_handle
->d_qname_iter
))->end();
759 d_handle
->parent
=this;
761 d_handle
->d_list
=true;
765 // naam -> naamnummer
766 // naamnummer -> vector<BBResourceRecords>, BBResourceRecord bevat ook een pointer naar
768 bool BindBackend::handle::get_list(DNSResourceRecord
&r
)
770 DLOG(L
<< "BindBackend get_list()"<<endl
);
772 while(d_riter
==d_rend
) {
773 DLOG(L
<<"Starting new record"<<endl
);
775 if(d_qname_iter
==d_qname_end
) { // we've reached the end of recordsets for this id
776 DLOG(L
<<"Really stop!"<<endl
);
779 d_riter
=(*(d_qname_iter
))->begin();
780 d_rend
=(*(d_qname_iter
))->end();
782 // d_riter points to a pointer to BBResourceRecord
784 // r.qname=qname; // fill this in HOW?!
786 r
.qname
=parent
->s_hc
.decode(*d_riter
->qnameptr
);
788 r
.content
=*(d_riter
)->content
;
789 r
.domain_id
=(d_riter
)->domain_id
;
790 r
.qtype
=(d_riter
)->qtype
;
791 r
.ttl
=(d_riter
)->ttl
;
792 r
.priority
=(d_riter
)->priority
;
797 class BindFactory
: public BackendFactory
800 BindFactory() : BackendFactory("bind") {}
802 void declareArguments(const string
&suffix
="")
804 declare(suffix
,"config","Location of named.conf","");
805 declare(suffix
,"example-zones","Install example zones","no");
806 declare(suffix
,"enable-huffman","Enable huffman compression","no");
807 declare(suffix
,"check-interval","Interval for zonefile changes","0");
810 DNSBackend
*make(const string
&suffix
="")
812 return new BindBackend(suffix
);
817 //! Magic class that is activated when the dynamic library is loaded
823 BackendMakers().report(new BindFactory
);
824 L
<<Logger::Notice
<<"[BindBackend] This is the bind backend version "VERSION
" ("__DATE__
", "__TIME__
") reporting"<<endl
;
827 static BindLoader bindloader
;