]>
Commit | Line | Data |
---|---|---|
444ca1fe | 1 | /* |
12471842 PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
69ab97d1 | 22 | |
870a0fe4 AT |
23 | #ifdef HAVE_CONFIG_H |
24 | #include "config.h" | |
25 | #endif | |
b532a4b1 BH |
26 | #include <errno.h> |
27 | #include <string> | |
b532a4b1 BH |
28 | #include <set> |
29 | #include <sys/types.h> | |
30 | #include <sys/stat.h> | |
31 | #include <unistd.h> | |
f404b863 | 32 | #include <fstream> |
82f7b3cc | 33 | #include <fcntl.h> |
f404b863 | 34 | #include <sstream> |
82cc6877 | 35 | #include <boost/algorithm/string.hpp> |
e0e48a7a | 36 | #include <system_error> |
fa8fd4d2 | 37 | |
e53a4bf6 KM |
38 | #include "pdns/dnsseckeeper.hh" |
39 | #include "pdns/dnssecinfra.hh" | |
40 | #include "pdns/base32.hh" | |
41 | #include "pdns/namespaces.hh" | |
e53a4bf6 KM |
42 | #include "pdns/dns.hh" |
43 | #include "pdns/dnsbackend.hh" | |
b532a4b1 | 44 | #include "bindbackend2.hh" |
e53a4bf6 KM |
45 | #include "pdns/dnspacket.hh" |
46 | #include "pdns/zoneparser-tng.hh" | |
47 | #include "pdns/bindparserclasses.hh" | |
48 | #include "pdns/logger.hh" | |
49 | #include "pdns/arguments.hh" | |
50 | #include "pdns/qtype.hh" | |
51 | #include "pdns/misc.hh" | |
52 | #include "pdns/dynlistener.hh" | |
53 | #include "pdns/lock.hh" | |
54 | #include "pdns/namespaces.hh" | |
b532a4b1 | 55 | |
d8f47a4a | 56 | /* |
57 | All instances of this backend share one s_state, which is indexed by zone name and zone id. | |
58 | The s_state is protected by a read/write lock, and the goal it to only interact with it briefly. | |
59 | When a query comes in, we take a read lock and COPY the best zone to answer from s_state (BB2DomainInfo object) | |
60 | All answers are served from this copy. | |
61 | ||
62 | To interact with s_state, use safeGetBBDomainInfo (search on name or id), safePutBBDomainInfo (to update) | |
63 | or safeRemoveBBDomainInfo. These all lock as they should. | |
64 | ||
65 | Several functions need to traverse s_state to get data for the rest of PowerDNS. When doing so, | |
66 | you need to manually take the s_state_lock (read). | |
67 | ||
68 | Parsing zones happens with parseZone(), which fills a BB2DomainInfo object. This can then be stored with safePutBBDomainInfo. | |
69 | ||
70 | Finally, the BB2DomainInfo contains all records as a LookButDontTouch object. This makes sure you only look, but don't touch, since | |
71 | the records might be in use in other places. | |
72 | */ | |
b532a4b1 | 73 | |
f08339e3 | 74 | Bind2Backend::state_t Bind2Backend::s_state; |
b532a4b1 | 75 | int Bind2Backend::s_first=1; |
17c2b1a8 | 76 | bool Bind2Backend::s_ignore_broken_records=false; |
d10f9034 | 77 | |
b755d50a | 78 | pthread_rwlock_t Bind2Backend::s_state_lock=PTHREAD_RWLOCK_INITIALIZER; |
d8f47a4a | 79 | pthread_mutex_t Bind2Backend::s_supermaster_config_lock=PTHREAD_MUTEX_INITIALIZER; // protects writes to config file |
b755d50a | 80 | pthread_mutex_t Bind2Backend::s_startup_lock=PTHREAD_MUTEX_INITIALIZER; |
10635124 | 81 | string Bind2Backend::s_binddirectory; |
2717b8b3 | 82 | |
b532a4b1 BH |
83 | BB2DomainInfo::BB2DomainInfo() |
84 | { | |
85 | d_loaded=false; | |
c36285d0 | 86 | d_lastcheck=0; |
b532a4b1 | 87 | d_checknow=false; |
d10f9034 | 88 | d_status="Unknown"; |
b532a4b1 BH |
89 | } |
90 | ||
91 | void BB2DomainInfo::setCheckInterval(time_t seconds) | |
92 | { | |
93 | d_checkinterval=seconds; | |
94 | } | |
95 | ||
96 | bool BB2DomainInfo::current() | |
97 | { | |
aaf2e4a4 | 98 | if(d_checknow) { |
b532a4b1 | 99 | return false; |
aaf2e4a4 | 100 | } |
b532a4b1 | 101 | |
c36285d0 BH |
102 | if(!d_checkinterval) |
103 | return true; | |
104 | ||
aaf2e4a4 | 105 | if(time(0) - d_lastcheck < d_checkinterval) |
c36285d0 BH |
106 | return true; |
107 | ||
108 | if(d_filename.empty()) | |
b532a4b1 BH |
109 | return true; |
110 | ||
111 | return (getCtime()==d_ctime); | |
112 | } | |
113 | ||
114 | time_t BB2DomainInfo::getCtime() | |
115 | { | |
116 | struct stat buf; | |
117 | ||
118 | if(d_filename.empty() || stat(d_filename.c_str(),&buf)<0) | |
119 | return 0; | |
120 | d_lastcheck=time(0); | |
121 | return buf.st_ctime; | |
122 | } | |
123 | ||
124 | void BB2DomainInfo::setCtime() | |
125 | { | |
126 | struct stat buf; | |
127 | if(stat(d_filename.c_str(),&buf)<0) | |
128 | return; | |
129 | d_ctime=buf.st_ctime; | |
130 | } | |
131 | ||
a1c4d85c | 132 | bool Bind2Backend::safeGetBBDomainInfo(int id, BB2DomainInfo* bbd) |
133 | { | |
134 | ReadLock rl(&s_state_lock); | |
135 | state_t::const_iterator iter = s_state.find(id); | |
136 | if(iter == s_state.end()) | |
137 | return false; | |
138 | *bbd=*iter; | |
139 | return true; | |
140 | } | |
141 | ||
c77d4725 | 142 | bool Bind2Backend::safeGetBBDomainInfo(const DNSName& name, BB2DomainInfo* bbd) |
a1c4d85c | 143 | { |
144 | ReadLock rl(&s_state_lock); | |
145 | typedef state_t::index<NameTag>::type nameindex_t; | |
146 | nameindex_t& nameindex = boost::multi_index::get<NameTag>(s_state); | |
147 | ||
148 | nameindex_t::const_iterator iter = nameindex.find(name); | |
149 | if(iter == nameindex.end()) | |
150 | return false; | |
151 | *bbd=*iter; | |
152 | return true; | |
153 | } | |
154 | ||
c77d4725 | 155 | bool Bind2Backend::safeRemoveBBDomainInfo(const DNSName& name) |
6b947ad5 | 156 | { |
157 | WriteLock rl(&s_state_lock); | |
158 | typedef state_t::index<NameTag>::type nameindex_t; | |
159 | nameindex_t& nameindex = boost::multi_index::get<NameTag>(s_state); | |
160 | ||
161 | nameindex_t::iterator iter = nameindex.find(name); | |
162 | if(iter == nameindex.end()) | |
163 | return false; | |
164 | nameindex.erase(iter); | |
165 | return true; | |
166 | } | |
167 | ||
a1c4d85c | 168 | void Bind2Backend::safePutBBDomainInfo(const BB2DomainInfo& bbd) |
169 | { | |
170 | WriteLock rl(&s_state_lock); | |
171 | replacing_insert(s_state, bbd); | |
172 | } | |
173 | ||
092f210a | 174 | void Bind2Backend::setNotified(uint32_t id, uint32_t serial) |
b532a4b1 | 175 | { |
f08339e3 | 176 | BB2DomainInfo bbd; |
7295dc0b AT |
177 | if (!safeGetBBDomainInfo(id, &bbd)) |
178 | return; | |
f08339e3 | 179 | bbd.d_lastnotified = serial; |
b755d50a | 180 | safePutBBDomainInfo(bbd); |
b532a4b1 BH |
181 | } |
182 | ||
092f210a | 183 | void Bind2Backend::setFresh(uint32_t domain_id) |
b532a4b1 | 184 | { |
f08339e3 | 185 | BB2DomainInfo bbd; |
186 | if(safeGetBBDomainInfo(domain_id, &bbd)) { | |
187 | bbd.d_lastcheck=time(0); | |
b755d50a | 188 | safePutBBDomainInfo(bbd); |
f1cf0678 | 189 | } |
f1cf0678 BH |
190 | } |
191 | ||
675fa24c | 192 | bool Bind2Backend::startTransaction(const DNSName &qname, int id) |
b532a4b1 | 193 | { |
340a213e BH |
194 | if(id < 0) { |
195 | d_transaction_tmpname.clear(); | |
196 | d_transaction_id=id; | |
89cb3e71 | 197 | return false; |
340a213e | 198 | } |
c919b27e CH |
199 | if(id == 0) { |
200 | throw DBException("domain_id 0 is invalid for this backend."); | |
201 | } | |
c99d9120 | 202 | |
f08339e3 | 203 | d_transaction_id=id; |
204 | BB2DomainInfo bbd; | |
205 | if(safeGetBBDomainInfo(id, &bbd)) { | |
206 | d_transaction_tmpname=bbd.d_filename+"."+itoa(random()); | |
7cfe0cc3 | 207 | d_of=std::unique_ptr<ofstream>(new ofstream(d_transaction_tmpname.c_str())); |
f08339e3 | 208 | if(!*d_of) { |
f08339e3 | 209 | unlink(d_transaction_tmpname.c_str()); |
7cfe0cc3 | 210 | d_of.reset(); |
10464f03 | 211 | throw DBException("Unable to open temporary zonefile '"+d_transaction_tmpname+"': "+stringerror()); |
f08339e3 | 212 | } |
213 | ||
214 | *d_of<<"; Written by PowerDNS, don't edit!"<<endl; | |
97b019d0 | 215 | *d_of<<"; Zone '"<<bbd.d_name<<"' retrieved from master "<<endl<<"; at "<<nowTime()<<endl; // insert master info here again |
f08339e3 | 216 | |
217 | return true; | |
b532a4b1 | 218 | } |
f08339e3 | 219 | return false; |
220 | } | |
b532a4b1 | 221 | |
b532a4b1 BH |
222 | bool Bind2Backend::commitTransaction() |
223 | { | |
340a213e | 224 | if(d_transaction_id < 0) |
89cb3e71 | 225 | return false; |
7cfe0cc3 | 226 | d_of.reset(); |
d10f9034 | 227 | |
f08339e3 | 228 | BB2DomainInfo bbd; |
229 | if(safeGetBBDomainInfo(d_transaction_id, &bbd)) { | |
230 | if(rename(d_transaction_tmpname.c_str(), bbd.d_filename.c_str())<0) | |
231 | throw DBException("Unable to commit (rename to: '" + bbd.d_filename+"') AXFRed zone: "+stringerror()); | |
aaf2e4a4 | 232 | queueReloadAndStore(bbd.d_id); |
f08339e3 | 233 | } |
016e4ae9 | 234 | |
b532a4b1 BH |
235 | d_transaction_id=0; |
236 | ||
237 | return true; | |
238 | } | |
239 | ||
240 | bool Bind2Backend::abortTransaction() | |
241 | { | |
c919b27e CH |
242 | // -1 = dnssec speciality |
243 | // 0 = invalid transact | |
244 | // >0 = actual transaction | |
245 | if(d_transaction_id > 0) { | |
b532a4b1 | 246 | unlink(d_transaction_tmpname.c_str()); |
7cfe0cc3 | 247 | d_of.reset(); |
b532a4b1 BH |
248 | d_transaction_id=0; |
249 | } | |
250 | ||
251 | return true; | |
252 | } | |
253 | ||
c9b43446 | 254 | bool Bind2Backend::feedRecord(const DNSResourceRecord &rr, const DNSName &ordername) |
b532a4b1 | 255 | { |
f08339e3 | 256 | BB2DomainInfo bbd; |
7295dc0b AT |
257 | if (!safeGetBBDomainInfo(d_transaction_id, &bbd)) |
258 | return false; | |
f08339e3 | 259 | |
6b205e29 RG |
260 | string qname; |
261 | string name = bbd.d_name.toString(); | |
262 | if (bbd.d_name.empty()) { | |
263 | qname = rr.qname.toString(); | |
264 | } | |
265 | else if (rr.qname.isPartOf(bbd.d_name)) { | |
266 | if (rr.qname == bbd.d_name) { | |
267 | qname = "@"; | |
268 | } | |
269 | else { | |
270 | DNSName relName = rr.qname.makeRelative(bbd.d_name); | |
271 | qname = relName.toStringNoDot(); | |
272 | } | |
273 | } | |
274 | else { | |
97b019d0 | 275 | throw DBException("out-of-zone data '"+rr.qname.toLogString()+"' during AXFR of zone '"+bbd.d_name.toLogString()+"'"); |
6b205e29 | 276 | } |
b532a4b1 | 277 | |
aa6d2045 KM |
278 | shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)); |
279 | string content = drc->getZoneRepresentation(); | |
b532a4b1 | 280 | |
69ab97d1 | 281 | // SOA needs stripping too! XXX FIXME - also, this should not be here I think |
54ec6012 | 282 | switch(rr.qtype.getCode()) { |
b532a4b1 | 283 | case QType::MX: |
f7fc87e6 | 284 | case QType::SRV: |
b532a4b1 | 285 | case QType::CNAME: |
165e5695 | 286 | case QType::DNAME: |
54ec6012 | 287 | case QType::NS: |
aa6d2045 | 288 | stripDomainSuffix(&content, name); |
73e924ea | 289 | // fallthrough |
b532a4b1 | 290 | default: |
7cfe0cc3 RG |
291 | if (d_of && *d_of) { |
292 | *d_of<<qname<<"\t"<<rr.ttl<<"\t"<<rr.qtype.getName()<<"\t"<<content<<endl; | |
293 | } | |
b532a4b1 | 294 | } |
b532a4b1 BH |
295 | return true; |
296 | } | |
297 | ||
298 | void Bind2Backend::getUpdatedMasters(vector<DomainInfo> *changedDomains) | |
299 | { | |
c7287b67 | 300 | vector<DomainInfo> consider; |
9215e60f | 301 | { |
302 | ReadLock rl(&s_state_lock); | |
9215e60f | 303 | |
304 | for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { | |
078023c1 | 305 | if(i->d_kind != DomainInfo::Master && this->alsoNotify.empty() && i->d_also_notify.empty()) |
2336e762 KM |
306 | continue; |
307 | ||
9215e60f | 308 | DomainInfo di; |
309 | di.id=i->d_id; | |
9215e60f | 310 | di.zone=i->d_name; |
311 | di.last_check=i->d_lastcheck; | |
2336e762 | 312 | di.notified_serial=i->d_lastnotified; |
9215e60f | 313 | di.backend=this; |
314 | di.kind=DomainInfo::Master; | |
2336e762 | 315 | consider.push_back(di); |
fbdca370 | 316 | } |
9215e60f | 317 | } |
c7287b67 | 318 | |
319 | SOAData soadata; | |
ef7cd021 | 320 | for(DomainInfo& di : consider) { |
c7287b67 | 321 | soadata.serial=0; |
322 | try { | |
323 | this->getSOA(di.zone, soadata); // we might not *have* a SOA yet, but this might trigger a load of it | |
324 | } | |
2336e762 KM |
325 | catch(...) { |
326 | continue; | |
327 | } | |
328 | if(di.notified_serial != soadata.serial) { | |
329 | BB2DomainInfo bbd; | |
330 | if(safeGetBBDomainInfo(di.id, &bbd)) { | |
331 | bbd.d_lastnotified=soadata.serial; | |
332 | safePutBBDomainInfo(bbd); | |
333 | } | |
334 | if(di.notified_serial) { // don't do notification storm on startup | |
335 | di.serial=soadata.serial; | |
336 | changedDomains->push_back(di); | |
337 | } | |
c7287b67 | 338 | } |
b532a4b1 BH |
339 | } |
340 | } | |
341 | ||
f08339e3 | 342 | void Bind2Backend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled) |
343 | { | |
1325e8a2 PD |
344 | SOAData soadata; |
345 | ||
d695df1a AT |
346 | // prevent deadlock by using getSOA() later on |
347 | { | |
348 | ReadLock rl(&s_state_lock); | |
349 | ||
350 | for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { | |
351 | DomainInfo di; | |
352 | di.id=i->d_id; | |
353 | di.zone=i->d_name; | |
354 | di.last_check=i->d_lastcheck; | |
bc67ec22 | 355 | di.kind=i->d_kind; |
a222f04e | 356 | di.masters=i->d_masters; |
d695df1a AT |
357 | di.backend=this; |
358 | domains->push_back(di); | |
359 | }; | |
360 | } | |
99d6d7f6 | 361 | |
ef7cd021 | 362 | for(DomainInfo &di : *domains) { |
99d6d7f6 CH |
363 | // do not corrupt di if domain supplied by another backend. |
364 | if (di.backend != this) | |
365 | continue; | |
d695df1a | 366 | this->getSOA(di.zone, soadata); |
1325e8a2 | 367 | di.serial=soadata.serial; |
1325e8a2 PD |
368 | } |
369 | } | |
370 | ||
b532a4b1 BH |
371 | void Bind2Backend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains) |
372 | { | |
d695df1a AT |
373 | vector<DomainInfo> domains; |
374 | { | |
375 | ReadLock rl(&s_state_lock); | |
376 | for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { | |
bc67ec22 | 377 | if(i->d_kind != DomainInfo::Slave) |
d695df1a AT |
378 | continue; |
379 | DomainInfo sd; | |
380 | sd.id=i->d_id; | |
381 | sd.zone=i->d_name; | |
382 | sd.masters=i->d_masters; | |
383 | sd.last_check=i->d_lastcheck; | |
384 | sd.backend=this; | |
385 | sd.kind=DomainInfo::Slave; | |
386 | domains.push_back(sd); | |
387 | } | |
388 | } | |
389 | ||
ef7cd021 | 390 | for(DomainInfo &sd : domains) { |
b532a4b1 | 391 | SOAData soadata; |
b532a4b1 BH |
392 | soadata.refresh=0; |
393 | soadata.serial=0; | |
b532a4b1 | 394 | try { |
d695df1a | 395 | getSOA(sd.zone,soadata); // we might not *have* a SOA yet |
b532a4b1 BH |
396 | } |
397 | catch(...){} | |
398 | sd.serial=soadata.serial; | |
d8f47a4a | 399 | if(sd.last_check+soadata.refresh < (unsigned int)time(0)) |
b532a4b1 BH |
400 | unfreshDomains->push_back(sd); |
401 | } | |
402 | } | |
403 | ||
c77d4725 | 404 | bool Bind2Backend::getDomainInfo(const DNSName& domain, DomainInfo &di) |
b532a4b1 | 405 | { |
79ff9306 | 406 | BB2DomainInfo bbd; |
407 | if(!safeGetBBDomainInfo(domain, &bbd)) | |
408 | return false; | |
b532a4b1 | 409 | |
79ff9306 | 410 | di.id=bbd.d_id; |
411 | di.zone=domain; | |
412 | di.masters=bbd.d_masters; | |
413 | di.last_check=bbd.d_lastcheck; | |
414 | di.backend=this; | |
bc67ec22 | 415 | di.kind=bbd.d_kind; |
79ff9306 | 416 | di.serial=0; |
417 | try { | |
418 | SOAData sd; | |
419 | sd.serial=0; | |
420 | ||
421 | getSOA(bbd.d_name,sd); // we might not *have* a SOA yet | |
422 | di.serial=sd.serial; | |
b532a4b1 | 423 | } |
79ff9306 | 424 | catch(...){} |
425 | ||
426 | return true; | |
b532a4b1 BH |
427 | } |
428 | ||
c77d4725 | 429 | void Bind2Backend::alsoNotifies(const DNSName& domain, set<string> *ips) |
27d94a79 | 430 | { |
27d94a79 BH |
431 | // combine global list with local list |
432 | for(set<string>::iterator i = this->alsoNotify.begin(); i != this->alsoNotify.end(); i++) { | |
433 | (*ips).insert(*i); | |
434 | } | |
a1c4d85c | 435 | ReadLock rl(&s_state_lock); |
f08339e3 | 436 | for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { |
69c887a2 | 437 | if(i->d_name == domain) { |
f08339e3 | 438 | for(set<string>::iterator it = i->d_also_notify.begin(); it != i->d_also_notify.end(); it++) { |
27d94a79 BH |
439 | (*ips).insert(*it); |
440 | } | |
441 | return; | |
442 | } | |
443 | } | |
444 | } | |
b532a4b1 | 445 | |
a1c4d85c | 446 | // only parses, does NOT add to s_state! |
4ce10aea | 447 | void Bind2Backend::parseZoneFile(BB2DomainInfo *bbd) |
40126001 PB |
448 | { |
449 | NSEC3PARAMRecordContent ns3pr; | |
aebddbd2 KM |
450 | bool nsec3zone; |
451 | if (d_hybrid) { | |
452 | DNSSECKeeper dk; | |
453 | nsec3zone=dk.getNSEC3PARAM(bbd->d_name, &ns3pr); | |
454 | } else | |
455 | nsec3zone=getNSEC3PARAM(bbd->d_name, &ns3pr); | |
aaf2e4a4 | 456 | |
457 | bbd->d_records = shared_ptr<recordstorage_t>(new recordstorage_t()); | |
40126001 PB |
458 | |
459 | ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory); | |
460 | DNSResourceRecord rr; | |
461 | string hashed; | |
b755d50a | 462 | while(zpt.get(rr)) { |
40126001 PB |
463 | if(rr.qtype.getCode() == QType::NSEC || rr.qtype.getCode() == QType::NSEC3) |
464 | continue; // we synthesise NSECs on demand | |
465 | ||
444ca1fe | 466 | insertRecord(*bbd, rr.qname, rr.qtype, rr.content, rr.ttl, ""); |
40126001 | 467 | } |
444ca1fe | 468 | fixupOrderAndAuth(*bbd, nsec3zone, ns3pr); |
f08339e3 | 469 | doEmptyNonTerminals(*bbd, nsec3zone, ns3pr); |
40126001 | 470 | bbd->setCtime(); |
47fee74f | 471 | bbd->d_loaded=true; |
aaf2e4a4 | 472 | bbd->d_checknow=false; |
40126001 PB |
473 | bbd->d_status="parsed into memory at "+nowTime(); |
474 | } | |
475 | ||
7c696097 | 476 | /** THIS IS AN INTERNAL FUNCTION! It does moadnsparser prio impedance matching |
04361e50 | 477 | Much of the complication is due to the efforts to benefit from std::string reference counting copy on write semantics */ |
c77d4725 | 478 | void Bind2Backend::insertRecord(BB2DomainInfo& bb2, const DNSName &qname, const QType &qtype, const string &content, int ttl, const std::string& hashed, bool *auth) |
b532a4b1 | 479 | { |
d9367e79 | 480 | Bind2DNSRecord bdr; |
f08339e3 | 481 | shared_ptr<recordstorage_t> records = bb2.d_records.getWRITABLE(); |
c77d4725 | 482 | bdr.qname=qname; |
79ff9306 | 483 | |
5e6880ce BH |
484 | if(bb2.d_name.empty()) |
485 | ; | |
c77d4725 AT |
486 | else if(bdr.qname.isPartOf(bb2.d_name)) |
487 | bdr.qname = bdr.qname.makeRelative(bb2.d_name); | |
c3b85638 | 488 | else { |
97b019d0 | 489 | string msg = "Trying to insert non-zone data, name='"+bdr.qname.toLogString()+"', qtype="+qtype.getName()+", zone='"+bb2.d_name.toLogString()+"'"; |
0eeca6c0 | 490 | if(s_ignore_broken_records) { |
e6a9dde5 | 491 | g_log<<Logger::Warning<<msg<< " ignored" << endl; |
c3b85638 PB |
492 | return; |
493 | } | |
494 | else | |
495 | throw PDNSException(msg); | |
496 | } | |
9b145472 | 497 | |
c77d4725 | 498 | // bdr.qname.swap(bdr.qname); |
ced82662 | 499 | |
f08339e3 | 500 | if(!records->empty() && bdr.qname==boost::prior(records->end())->qname) |
501 | bdr.qname=boost::prior(records->end())->qname; | |
ced82662 | 502 | |
dc1fb060 | 503 | bdr.qname=bdr.qname; |
874300a8 | 504 | bdr.qtype=qtype.getCode(); |
82cc6877 | 505 | bdr.content=content; |
772e8b10 | 506 | bdr.nsec3hash = hashed; |
b5baefaf | 507 | |
90f27487 KM |
508 | if (auth) // Set auth on empty non-terminals |
509 | bdr.auth=*auth; | |
fe5ecd7e KM |
510 | else |
511 | bdr.auth=true; | |
82cc6877 | 512 | |
9b145472 | 513 | bdr.ttl=ttl; |
f08339e3 | 514 | records->insert(bdr); |
b532a4b1 BH |
515 | } |
516 | ||
b532a4b1 BH |
517 | string Bind2Backend::DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid) |
518 | { | |
519 | ostringstream ret; | |
b532a4b1 | 520 | |
d10f9034 | 521 | for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) { |
f08339e3 | 522 | BB2DomainInfo bbd; |
0b9da0f5 PL |
523 | DNSName zone(*i); |
524 | if(safeGetBBDomainInfo(zone, &bbd)) { | |
2717b8b3 | 525 | Bind2Backend bb2; |
aaf2e4a4 | 526 | bb2.queueReloadAndStore(bbd.d_id); |
7295dc0b AT |
527 | if (!safeGetBBDomainInfo(zone, &bbd)) // Read the *new* domain status |
528 | ret << *i << ": [missing]\n"; | |
529 | else | |
530 | ret<< *i << ": "<< (bbd.d_wasRejectedLastReload ? "[rejected]": "") <<"\t"<<bbd.d_status<<"\n"; | |
b532a4b1 | 531 | } |
d10f9034 BH |
532 | else |
533 | ret<< *i << " no such domain\n"; | |
534 | } | |
e9dd48f9 | 535 | if(ret.str().empty()) |
04361e50 | 536 | ret<<"no domains reloaded"; |
b532a4b1 BH |
537 | return ret.str(); |
538 | } | |
539 | ||
540 | ||
541 | string Bind2Backend::DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid) | |
542 | { | |
d10f9034 | 543 | ostringstream ret; |
3be60e6e | 544 | |
d10f9034 BH |
545 | if(parts.size() > 1) { |
546 | for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) { | |
f08339e3 | 547 | BB2DomainInfo bbd; |
b873e23a | 548 | if(safeGetBBDomainInfo(DNSName(*i), &bbd)) { |
c77d4725 | 549 | ret<< *i << ": "<< (bbd.d_loaded ? "": "[rejected]") <<"\t"<<bbd.d_status<<"\n"; |
d10f9034 BH |
550 | } |
551 | else | |
4957a608 | 552 | ret<< *i << " no such domain\n"; |
d10f9034 | 553 | } |
b532a4b1 | 554 | } |
f08339e3 | 555 | else { |
556 | ReadLock rl(&s_state_lock); | |
557 | for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { | |
97b019d0 | 558 | ret<< i->d_name << ": "<< (i->d_loaded ? "": "[rejected]") <<"\t"<<i->d_status<<"\n"; |
f08339e3 | 559 | } |
560 | } | |
d10f9034 BH |
561 | |
562 | if(ret.str().empty()) | |
563 | ret<<"no domains passed"; | |
564 | ||
565 | return ret.str(); | |
b532a4b1 BH |
566 | } |
567 | ||
b532a4b1 BH |
568 | string Bind2Backend::DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid) |
569 | { | |
570 | ostringstream ret; | |
a1c4d85c | 571 | ReadLock rl(&s_state_lock); |
f08339e3 | 572 | for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { |
573 | if(!i->d_loaded) | |
97b019d0 | 574 | ret<<i->d_name<<"\t"<<i->d_status<<endl; |
f08339e3 | 575 | } |
b532a4b1 BH |
576 | return ret.str(); |
577 | } | |
578 | ||
a31fe060 PB |
579 | string Bind2Backend::DLAddDomainHandler(const vector<string>&parts, Utility::pid_t ppid) |
580 | { | |
581 | if(parts.size() < 3) | |
1c8fd613 | 582 | return "ERROR: Domain name and zone filename are required"; |
a31fe060 | 583 | |
c77d4725 | 584 | DNSName domainname(parts[1]); |
a31fe060 | 585 | const string &filename = parts[2]; |
f08339e3 | 586 | BB2DomainInfo bbd; |
587 | if(safeGetBBDomainInfo(domainname, &bbd)) | |
a31fe060 | 588 | return "Already loaded"; |
c0475277 PL |
589 | |
590 | if (!boost::starts_with(filename, "/") && ::arg()["chroot"].empty()) | |
97b019d0 | 591 | return "Unable to load zone " + domainname.toLogString() + " from " + filename + " as the filename is not absolute."; |
c0475277 PL |
592 | |
593 | struct stat buf; | |
594 | if (stat(filename.c_str(), &buf) != 0) | |
97b019d0 | 595 | return "Unable to load zone " + domainname.toLogString() + " from " + filename + ": " + strerror(errno); |
c0475277 | 596 | |
d8f47a4a | 597 | Bind2Backend bb2; // createdomainentry needs access to our configuration |
b755d50a | 598 | bbd=bb2.createDomainEntry(domainname, filename); |
a31fe060 PB |
599 | bbd.d_filename=filename; |
600 | bbd.d_checknow=true; | |
601 | bbd.d_loaded=true; | |
602 | bbd.d_lastcheck=0; | |
603 | bbd.d_status="parsing into memory"; | |
f08339e3 | 604 | |
b755d50a | 605 | safePutBBDomainInfo(bbd); |
a31fe060 | 606 | |
e6a9dde5 | 607 | g_log<<Logger::Warning<<"Zone "<<domainname<< " loaded"<<endl; |
97b019d0 | 608 | return "Loaded zone " + domainname.toLogString() + " from " + filename; |
a31fe060 PB |
609 | } |
610 | ||
2717b8b3 | 611 | Bind2Backend::Bind2Backend(const string &suffix, bool loadZones) |
b532a4b1 | 612 | { |
0f310932 AT |
613 | d_getAllDomainMetadataQuery_stmt = NULL; |
614 | d_getDomainMetadataQuery_stmt = NULL; | |
615 | d_deleteDomainMetadataQuery_stmt = NULL; | |
616 | d_insertDomainMetadataQuery_stmt = NULL; | |
617 | d_getDomainKeysQuery_stmt = NULL; | |
618 | d_deleteDomainKeyQuery_stmt = NULL; | |
619 | d_insertDomainKeyQuery_stmt = NULL; | |
9c6c256f | 620 | d_GetLastInsertedKeyIdQuery_stmt = NULL; |
0f310932 AT |
621 | d_activateDomainKeyQuery_stmt = NULL; |
622 | d_deactivateDomainKeyQuery_stmt = NULL; | |
623 | d_getTSIGKeyQuery_stmt = NULL; | |
624 | d_setTSIGKeyQuery_stmt = NULL; | |
625 | d_deleteTSIGKeyQuery_stmt = NULL; | |
626 | d_getTSIGKeysQuery_stmt = NULL; | |
627 | ||
d7dbeca9 | 628 | setArgPrefix("bind"+suffix); |
17c2b1a8 | 629 | d_logprefix="[bind"+suffix+"backend]"; |
aebddbd2 | 630 | d_hybrid=mustDo("hybrid"); |
17c2b1a8 PB |
631 | s_ignore_broken_records=mustDo("ignore-broken-records"); |
632 | ||
aebddbd2 KM |
633 | if (!loadZones && d_hybrid) |
634 | return; | |
635 | ||
b532a4b1 | 636 | Lock l(&s_startup_lock); |
2717b8b3 | 637 | |
b532a4b1 | 638 | d_transaction_id=0; |
2717b8b3 | 639 | setupDNSSEC(); |
b532a4b1 BH |
640 | if(!s_first) { |
641 | return; | |
642 | } | |
2717b8b3 | 643 | |
2717b8b3 BH |
644 | if(loadZones) { |
645 | loadConfig(); | |
646 | s_first=0; | |
647 | } | |
648 | ||
b532a4b1 | 649 | extern DynListener *dl; |
17384177 PD |
650 | dl->registerFunc("BIND-RELOAD-NOW", &DLReloadNowHandler, "bindbackend: reload domains", "<domains>"); |
651 | dl->registerFunc("BIND-DOMAIN-STATUS", &DLDomStatusHandler, "bindbackend: list status of all domains", "[domains]"); | |
652 | dl->registerFunc("BIND-LIST-REJECTS", &DLListRejectsHandler, "bindbackend: list rejected domains"); | |
a31fe060 | 653 | dl->registerFunc("BIND-ADD-ZONE", &DLAddDomainHandler, "bindbackend: add zone", "<domain> <filename>"); |
b532a4b1 BH |
654 | } |
655 | ||
2a95d1df | 656 | Bind2Backend::~Bind2Backend() |
0f310932 | 657 | { freeStatements(); } // deallocate statements |
2a95d1df | 658 | |
b532a4b1 BH |
659 | void Bind2Backend::rediscover(string *status) |
660 | { | |
10635124 | 661 | loadConfig(status); |
b532a4b1 | 662 | } |
82f7b3cc | 663 | |
a3047110 BH |
664 | void Bind2Backend::reload() |
665 | { | |
f08339e3 | 666 | WriteLock rwl(&s_state_lock); |
b755d50a | 667 | for(state_t::iterator i = s_state.begin(); i != s_state.end() ; ++i) { |
6a347650 | 668 | i->d_checknow=true; // being a bit cheeky here, don't index state_t on this (mutable) |
f08339e3 | 669 | } |
82f7b3cc | 670 | } |
81c43517 | 671 | |
444ca1fe | 672 | void Bind2Backend::fixupOrderAndAuth(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr) |
81c43517 | 673 | { |
444ca1fe | 674 | shared_ptr<recordstorage_t> records = bbd.d_records.getWRITABLE(); |
444ca1fe KM |
675 | |
676 | bool skip; | |
677 | DNSName shorter; | |
678 | set<DNSName> nssets, dssets; | |
679 | ||
680 | for(const auto& bdr: *records) { | |
681 | if(!bdr.qname.isRoot() && bdr.qtype == QType::NS) | |
682 | nssets.insert(bdr.qname); | |
683 | else if(bdr.qtype == QType::DS) | |
684 | dssets.insert(bdr.qname); | |
21a0a2ae | 685 | } |
81c43517 | 686 | |
444ca1fe KM |
687 | for(auto iter = records->begin(); iter != records->end(); iter++) { |
688 | skip = false; | |
689 | shorter = iter->qname; | |
690 | ||
691 | if (!iter->qname.isRoot() && shorter.chopOff() && !iter->qname.isRoot()) { | |
692 | do { | |
693 | if(nssets.count(shorter)) { | |
694 | skip = true; | |
695 | break; | |
696 | } | |
697 | } while(shorter.chopOff() && !iter->qname.isRoot()); | |
698 | } | |
699 | ||
700 | iter->auth = (!skip && (iter->qtype == QType::DS || iter->qtype == QType::RRSIG || !nssets.count(iter->qname))); | |
701 | ||
702 | if(!skip && nsec3zone && iter->qtype != QType::RRSIG && (iter->auth || (iter->qtype == QType::NS && !ns3pr.d_flags) || dssets.count(iter->qname))) { | |
703 | Bind2DNSRecord bdr = *iter; | |
704 | bdr.nsec3hash = toBase32Hex(hashQNameWithSalt(ns3pr, bdr.qname+bbd.d_name)); | |
705 | records->replace(iter, bdr); | |
706 | } | |
707 | ||
97b019d0 | 708 | // cerr<<iter->qname<<"\t"<<QType(iter->qtype).getName()<<"\t"<<iter->nsec3hash<<"\t"<<iter->auth<<endl; |
81c43517 BH |
709 | } |
710 | } | |
711 | ||
f08339e3 | 712 | void Bind2Backend::doEmptyNonTerminals(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr) |
b5baefaf | 713 | { |
9353b710 | 714 | shared_ptr<const recordstorage_t> records = bbd.d_records.get(); |
444ca1fe KM |
715 | |
716 | bool auth; | |
717 | DNSName shorter; | |
c77d4725 AT |
718 | set<DNSName> qnames; |
719 | map<DNSName, bool> nonterm; | |
b5baefaf PD |
720 | |
721 | uint32_t maxent = ::arg().asNum("max-ent-entries"); | |
722 | ||
c77d4725 | 723 | for(const auto& bdr : *records) |
dc1fb060 | 724 | qnames.insert(bdr.qname); |
b5baefaf | 725 | |
c77d4725 | 726 | for(const auto& bdr : *records) { |
90f27487 KM |
727 | |
728 | if (!bdr.auth && bdr.qtype == QType::NS) | |
444ca1fe | 729 | auth = (!nsec3zone || !ns3pr.d_flags); |
90f27487 | 730 | else |
444ca1fe | 731 | auth = bdr.auth; |
b5baefaf | 732 | |
444ca1fe | 733 | shorter = bdr.qname; |
c77d4725 | 734 | while(shorter.chopOff()) |
b5baefaf | 735 | { |
54c9247e | 736 | if(!qnames.count(shorter)) |
b5baefaf PD |
737 | { |
738 | if(!(maxent)) | |
739 | { | |
e6a9dde5 | 740 | g_log<<Logger::Error<<"Zone '"<<bbd.d_name<<"' has too many empty non terminals."<<endl; |
444ca1fe | 741 | return; |
b5baefaf | 742 | } |
90f27487 KM |
743 | |
744 | if (!nonterm.count(shorter)) { | |
c77d4725 | 745 | nonterm.insert(pair<DNSName, bool>(shorter, auth)); |
90f27487 KM |
746 | --maxent; |
747 | } else if (auth) | |
444ca1fe | 748 | nonterm[shorter] = true; |
b5baefaf PD |
749 | } |
750 | } | |
b5baefaf PD |
751 | } |
752 | ||
753 | DNSResourceRecord rr; | |
444ca1fe KM |
754 | rr.qtype = "#0"; |
755 | rr.content = ""; | |
756 | rr.ttl = 0; | |
757 | for(auto& nt : nonterm) | |
b5baefaf | 758 | { |
444ca1fe KM |
759 | string hashed; |
760 | rr.qname = nt.first + bbd.d_name; | |
761 | if(nsec3zone && nt.second) | |
762 | hashed = toBase32Hex(hashQNameWithSalt(ns3pr, rr.qname)); | |
c77d4725 | 763 | insertRecord(bbd, rr.qname, rr.qtype, rr.content, rr.ttl, hashed, &nt.second); |
444ca1fe KM |
764 | |
765 | // cerr<<rr.qname<<"\t"<<rr.qtype.getName()<<"\t"<<hashed<<"\t"<<nt.second<<endl; | |
b5baefaf PD |
766 | } |
767 | } | |
768 | ||
b532a4b1 BH |
769 | void Bind2Backend::loadConfig(string* status) |
770 | { | |
771 | static int domain_id=1; | |
d9367e79 | 772 | |
b532a4b1 BH |
773 | if(!getArg("config").empty()) { |
774 | BindParser BP; | |
775 | try { | |
776 | BP.parse(getArg("config")); | |
777 | } | |
3f81d239 | 778 | catch(PDNSException &ae) { |
e6a9dde5 | 779 | g_log<<Logger::Error<<"Error parsing bind configuration: "<<ae.reason<<endl; |
23d15cf1 | 780 | throw; |
b532a4b1 | 781 | } |
b532a4b1 BH |
782 | |
783 | vector<BindDomainInfo> domains=BP.getDomains(); | |
27d94a79 BH |
784 | this->alsoNotify = BP.getAlsoNotify(); |
785 | ||
10635124 | 786 | s_binddirectory=BP.getDirectory(); |
874300a8 | 787 | // ZP.setDirectory(d_binddirectory); |
04361e50 | 788 | |
e6a9dde5 | 789 | g_log<<Logger::Warning<<d_logprefix<<" Parsing "<<domains.size()<<" domain(s), will report when done"<<endl; |
b532a4b1 | 790 | |
c77d4725 | 791 | set<DNSName> oldnames, newnames; |
6b947ad5 | 792 | { |
793 | ReadLock rl(&s_state_lock); | |
ef7cd021 | 794 | for(const BB2DomainInfo& bbd : s_state) { |
6b947ad5 | 795 | oldnames.insert(bbd.d_name); |
796 | } | |
797 | } | |
b532a4b1 BH |
798 | int rejected=0; |
799 | int newdomains=0; | |
800 | ||
82f7b3cc BH |
801 | struct stat st; |
802 | ||
803 | for(vector<BindDomainInfo>::iterator i=domains.begin(); i!=domains.end(); ++i) | |
804 | { | |
c36285d0 | 805 | if(stat(i->filename.c_str(), &st) == 0) { |
4957a608 BH |
806 | i->d_dev = st.st_dev; |
807 | i->d_ino = st.st_ino; | |
c36285d0 | 808 | } |
82f7b3cc BH |
809 | } |
810 | ||
811 | sort(domains.begin(), domains.end()); // put stuff in inode order | |
b532a4b1 | 812 | for(vector<BindDomainInfo>::const_iterator i=domains.begin(); |
4957a608 BH |
813 | i!=domains.end(); |
814 | ++i) | |
b532a4b1 | 815 | { |
6808f3b5 | 816 | if (!(i->hadFileDirective)) { |
e6a9dde5 | 817 | g_log<<Logger::Warning<<d_logprefix<<" Zone '"<<i->name<<"' has no 'file' directive set in "<<getArg("config")<<endl; |
6808f3b5 PL |
818 | rejected++; |
819 | continue; | |
820 | } | |
821 | ||
1cab5f51 | 822 | if(i->type == "") |
e6a9dde5 | 823 | g_log<<Logger::Notice<<d_logprefix<<" Zone '"<<i->name<<"' has no type specified, assuming 'native'"<<endl; |
1cab5f51 | 824 | if(i->type!="master" && i->type!="slave" && i->type != "native" && i->type != "") { |
e6a9dde5 | 825 | g_log<<Logger::Warning<<d_logprefix<<" Warning! Skipping zone '"<<i->name<<"' because type '"<<i->type<<"' is invalid"<<endl; |
83e34d08 | 826 | rejected++; |
4957a608 BH |
827 | continue; |
828 | } | |
829 | ||
f08339e3 | 830 | BB2DomainInfo bbd; |
e0e48a7a | 831 | bool isNew = false; |
4957a608 | 832 | |
f08339e3 | 833 | if(!safeGetBBDomainInfo(i->name, &bbd)) { |
e0e48a7a | 834 | isNew = true; |
f08339e3 | 835 | bbd.d_id=domain_id++; |
836 | bbd.setCheckInterval(getArgAsNum("check-interval")); | |
837 | bbd.d_lastnotified=0; | |
838 | bbd.d_loaded=false; | |
4957a608 BH |
839 | } |
840 | ||
4957a608 | 841 | // overwrite what we knew about the domain |
c77d4725 | 842 | bbd.d_name=i->name; |
f08339e3 | 843 | bool filenameChanged = (bbd.d_filename!=i->filename); |
844 | bbd.d_filename=i->filename; | |
845 | bbd.d_masters=i->masters; | |
846 | bbd.d_also_notify=i->alsoNotify; | |
ff0a23c2 | 847 | |
bc67ec22 PL |
848 | bbd.d_kind = DomainInfo::Native; |
849 | if (i->type == "master") | |
850 | bbd.d_kind = DomainInfo::Master; | |
851 | if (i->type == "slave") | |
852 | bbd.d_kind = DomainInfo::Slave; | |
853 | ||
ff0a23c2 | 854 | newnames.insert(bbd.d_name); |
f08339e3 | 855 | if(filenameChanged || !bbd.d_loaded || !bbd.current()) { |
e6a9dde5 | 856 | g_log<<Logger::Info<<d_logprefix<<" parsing '"<<i->name<<"' from file '"<<i->filename<<"'"<<endl; |
d4d9ea3c | 857 | |
4957a608 | 858 | try { |
f08339e3 | 859 | parseZoneFile(&bbd); |
4957a608 | 860 | } |
3f81d239 | 861 | catch(PDNSException &ae) { |
4957a608 | 862 | ostringstream msg; |
97b019d0 | 863 | msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.reason; |
4957a608 BH |
864 | |
865 | if(status) | |
866 | *status+=msg.str(); | |
f08339e3 | 867 | bbd.d_status=msg.str(); |
868 | ||
e6a9dde5 | 869 | g_log<<Logger::Warning<<d_logprefix<<msg.str()<<endl; |
4957a608 BH |
870 | rejected++; |
871 | } | |
e0e48a7a | 872 | catch(std::system_error &ae) { |
4957a608 | 873 | ostringstream msg; |
e0e48a7a PL |
874 | if (ae.code().value() == ENOENT && isNew && i->type == "slave") |
875 | msg<<" error at "+nowTime()<<" no file found for new slave domain '"<<i->name<<"'. Has not been AXFR'd yet"; | |
876 | else | |
877 | msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.what(); | |
4957a608 BH |
878 | |
879 | if(status) | |
880 | *status+=msg.str(); | |
f08339e3 | 881 | bbd.d_status=msg.str(); |
e6a9dde5 | 882 | g_log<<Logger::Warning<<d_logprefix<<msg.str()<<endl; |
4957a608 BH |
883 | rejected++; |
884 | } | |
05070089 CH |
885 | catch(std::exception &ae) { |
886 | ostringstream msg; | |
887 | msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.what(); | |
888 | ||
889 | if(status) | |
890 | *status+=msg.str(); | |
891 | bbd.d_status=msg.str(); | |
892 | ||
e6a9dde5 | 893 | g_log<<Logger::Warning<<d_logprefix<<msg.str()<<endl; |
05070089 CH |
894 | rejected++; |
895 | } | |
d8f47a4a | 896 | safePutBBDomainInfo(bbd); |
ff0a23c2 | 897 | |
4957a608 | 898 | } |
b532a4b1 | 899 | } |
c77d4725 | 900 | vector<DNSName> diff; |
f08339e3 | 901 | |
b532a4b1 | 902 | set_difference(oldnames.begin(), oldnames.end(), newnames.begin(), newnames.end(), back_inserter(diff)); |
ff0a23c2 | 903 | unsigned int remdomains=diff.size(); |
6b947ad5 | 904 | |
c77d4725 | 905 | for(const DNSName& name: diff) { |
6b947ad5 | 906 | safeRemoveBBDomainInfo(name); |
907 | } | |
cecc5075 | 908 | |
04361e50 | 909 | // count number of entirely new domains |
6b947ad5 | 910 | diff.clear(); |
911 | set_difference(newnames.begin(), newnames.end(), oldnames.begin(), oldnames.end(), back_inserter(diff)); | |
912 | newdomains=diff.size(); | |
e9dd48f9 | 913 | |
b532a4b1 BH |
914 | ostringstream msg; |
915 | msg<<" Done parsing domains, "<<rejected<<" rejected, "<<newdomains<<" new, "<<remdomains<<" removed"; | |
916 | if(status) | |
917 | *status=msg.str(); | |
918 | ||
e6a9dde5 | 919 | g_log<<Logger::Error<<d_logprefix<<msg.str()<<endl; |
b532a4b1 BH |
920 | } |
921 | } | |
922 | ||
aaf2e4a4 | 923 | void Bind2Backend::queueReloadAndStore(unsigned int id) |
b532a4b1 | 924 | { |
aaf2e4a4 | 925 | BB2DomainInfo bbold; |
b532a4b1 | 926 | try { |
aaf2e4a4 | 927 | if(!safeGetBBDomainInfo(id, &bbold)) |
928 | return; | |
4ce10aea RG |
929 | BB2DomainInfo bbnew(bbold); |
930 | parseZoneFile(&bbnew); | |
931 | bbnew.d_checknow=false; | |
932 | bbnew.d_wasRejectedLastReload=false; | |
933 | safePutBBDomainInfo(bbnew); | |
e6a9dde5 | 934 | g_log<<Logger::Warning<<"Zone '"<<bbnew.d_name<<"' ("<<bbnew.d_filename<<") reloaded"<<endl; |
b532a4b1 | 935 | } |
3f81d239 | 936 | catch(PDNSException &ae) { |
c733e4d5 | 937 | ostringstream msg; |
97b019d0 | 938 | msg<<" error at "+nowTime()+" parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.reason; |
e6a9dde5 | 939 | g_log<<Logger::Warning<<" error parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.reason<<endl; |
aaf2e4a4 | 940 | bbold.d_status=msg.str(); |
c539d857 | 941 | bbold.d_wasRejectedLastReload=true; |
aaf2e4a4 | 942 | safePutBBDomainInfo(bbold); |
c733e4d5 | 943 | } |
5172cb78 | 944 | catch(std::exception &ae) { |
b532a4b1 | 945 | ostringstream msg; |
97b019d0 | 946 | msg<<" error at "+nowTime()+" parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.what(); |
e6a9dde5 | 947 | g_log<<Logger::Warning<<" error parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.what()<<endl; |
aaf2e4a4 | 948 | bbold.d_status=msg.str(); |
c539d857 | 949 | bbold.d_wasRejectedLastReload=true; |
aaf2e4a4 | 950 | safePutBBDomainInfo(bbold); |
b532a4b1 BH |
951 | } |
952 | } | |
953 | ||
29e0008a | 954 | bool Bind2Backend::findBeforeAndAfterUnhashed(BB2DomainInfo& bbd, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) |
8e16b978 | 955 | { |
f08339e3 | 956 | shared_ptr<const recordstorage_t> records = bbd.d_records.get(); |
8e16b978 | 957 | |
eec59416 KM |
958 | // for(const auto& record: *records) |
959 | // cerr<<record.qname<<"\t"<<makeHexDump(record.qname.toDNSString())<<endl; | |
27045410 | 960 | |
eec59416 | 961 | recordstorage_t::const_iterator iterBefore, iterAfter; |
8e16b978 | 962 | |
eec59416 | 963 | iterBefore = iterAfter = records->upper_bound(qname.makeLowerCase()); |
52be7b52 | 964 | |
eec59416 KM |
965 | if(iterBefore != records->begin()) |
966 | --iterBefore; | |
967 | while((!iterBefore->auth && iterBefore->qtype != QType::NS) || !iterBefore->qtype) | |
968 | --iterBefore; | |
29e0008a | 969 | before=iterBefore->qname; |
f3c18f9d | 970 | |
eec59416 KM |
971 | if(iterAfter == records->end()) { |
972 | iterAfter = records->begin(); | |
8e16b978 | 973 | } else { |
eec59416 KM |
974 | while((!iterAfter->auth && iterAfter->qtype != QType::NS) || !iterAfter->qtype) { |
975 | ++iterAfter; | |
976 | if(iterAfter == records->end()) { | |
977 | iterAfter = records->begin(); | |
f3c18f9d PD |
978 | break; |
979 | } | |
980 | } | |
8e16b978 | 981 | } |
29e0008a | 982 | after = iterAfter->qname; |
8e16b978 | 983 | |
8e16b978 | 984 | return true; |
8e16b978 | 985 | } |
9b145472 | 986 | |
29e0008a | 987 | bool Bind2Backend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) |
772e8b10 | 988 | { |
f08339e3 | 989 | BB2DomainInfo bbd; |
7295dc0b AT |
990 | if (!safeGetBBDomainInfo(id, &bbd)) |
991 | return false; | |
f08339e3 | 992 | |
772e8b10 | 993 | NSEC3PARAMRecordContent ns3pr; |
eec59416 | 994 | |
aebddbd2 KM |
995 | bool nsec3zone; |
996 | if (d_hybrid) { | |
997 | DNSSECKeeper dk; | |
eec59416 | 998 | nsec3zone=dk.getNSEC3PARAM(bbd.d_name, &ns3pr); |
aebddbd2 | 999 | } else |
eec59416 | 1000 | nsec3zone=getNSEC3PARAM(bbd.d_name, &ns3pr); |
aebddbd2 KM |
1001 | |
1002 | if(!nsec3zone) { | |
29e0008a | 1003 | return findBeforeAndAfterUnhashed(bbd, qname, unhashed, before, after); |
772e8b10 BH |
1004 | } |
1005 | else { | |
94364112 | 1006 | auto& hashindex=boost::multi_index::get<NSEC3Tag>(*bbd.d_records.getWRITABLE()); |
27045410 | 1007 | |
eec59416 KM |
1008 | // for(auto iter = first; iter != hashindex.end(); iter++) |
1009 | // cerr<<iter->nsec3hash<<endl; | |
1010 | ||
94364112 | 1011 | auto first = hashindex.upper_bound(""); |
eec59416 | 1012 | auto iter = hashindex.upper_bound(qname.toStringNoDot()); |
27045410 | 1013 | |
444ca1fe KM |
1014 | if (iter == hashindex.end()) { |
1015 | --iter; | |
29e0008a KM |
1016 | before = DNSName(iter->nsec3hash); |
1017 | after = DNSName(first->nsec3hash); | |
444ca1fe | 1018 | } else { |
29e0008a | 1019 | after = DNSName(iter->nsec3hash); |
444ca1fe KM |
1020 | if (iter != first) |
1021 | --iter; | |
1022 | else | |
1023 | iter = --hashindex.end(); | |
29e0008a | 1024 | before = DNSName(iter->nsec3hash); |
772e8b10 | 1025 | } |
444ca1fe | 1026 | unhashed = iter->qname+bbd.d_name; |
27045410 | 1027 | |
772e8b10 BH |
1028 | return true; |
1029 | } | |
1030 | } | |
1031 | ||
675fa24c | 1032 | void Bind2Backend::lookup(const QType &qtype, const DNSName &qname, DNSPacket *pkt_p, int zoneId ) |
b532a4b1 | 1033 | { |
95c22a8f | 1034 | d_handle.reset(); |
c77d4725 | 1035 | DNSName domain(qname); |
69ab97d1 | 1036 | |
702156df | 1037 | static bool mustlog=::arg().mustDo("query-logging"); |
70524e9a | 1038 | if(mustlog) |
e6a9dde5 | 1039 | g_log<<Logger::Warning<<"Lookup for '"<<qtype.getName()<<"' of '"<<domain<<"' within zoneID "<<zoneId<<endl; |
b755d50a | 1040 | bool found=false; |
1041 | BB2DomainInfo bbd; | |
c77d4725 | 1042 | |
98b9845f RG |
1043 | do { |
1044 | found = safeGetBBDomainInfo(domain, &bbd); | |
1045 | } while ((!found || (zoneId != (int)bbd.d_id && zoneId != -1)) && domain.chopOff()); | |
b532a4b1 | 1046 | |
b755d50a | 1047 | if(!found) { |
70524e9a | 1048 | if(mustlog) |
e6a9dde5 | 1049 | g_log<<Logger::Warning<<"Found no authoritative zone for "<<qname<<endl; |
7b308b7e | 1050 | d_handle.d_list=false; |
b532a4b1 BH |
1051 | return; |
1052 | } | |
b755d50a | 1053 | |
70524e9a | 1054 | if(mustlog) |
e6a9dde5 | 1055 | g_log<<Logger::Warning<<"Found a zone '"<<domain<<"' (with id " << bbd.d_id<<") that might contain data "<<endl; |
70524e9a | 1056 | |
b755d50a | 1057 | d_handle.id=bbd.d_id; |
7b308b7e | 1058 | |
e6a9dde5 | 1059 | DLOG(g_log<<"Bind2Backend constructing handle for search for "<<qtype.getName()<<" for "<< |
f43c4448 | 1060 | qname<<endl); |
9b145472 | 1061 | |
5e6880ce BH |
1062 | if(domain.empty()) |
1063 | d_handle.qname=qname; | |
c77d4725 AT |
1064 | else if(qname.isPartOf(domain)) |
1065 | d_handle.qname=qname.makeRelative(domain); // strip domain name | |
945a9ad4 | 1066 | |
7b308b7e | 1067 | d_handle.qtype=qtype; |
c77d4725 | 1068 | d_handle.domain=domain; |
b755d50a | 1069 | |
ab9e6a6c BH |
1070 | if(!bbd.d_loaded) { |
1071 | d_handle.reset(); | |
97b019d0 | 1072 | throw DBException("Zone for '"+bbd.d_name.toLogString()+"' in '"+bbd.d_filename+"' temporarily not available (file missing, or master dead)"); // fsck |
b532a4b1 | 1073 | } |
ab9e6a6c BH |
1074 | |
1075 | if(!bbd.current()) { | |
e6a9dde5 | 1076 | g_log<<Logger::Warning<<"Zone '"<<bbd.d_name<<"' ("<<bbd.d_filename<<") needs reloading"<<endl; |
aaf2e4a4 | 1077 | queueReloadAndStore(bbd.d_id); |
9353b710 | 1078 | if (!safeGetBBDomainInfo(domain, &bbd)) |
97b019d0 | 1079 | throw DBException("Zone '"+bbd.d_name.toLogString()+"' ("+bbd.d_filename+") gone after reload"); // if we don't throw here, we crash for some reason |
b532a4b1 | 1080 | } |
ced82662 | 1081 | |
f08339e3 | 1082 | d_handle.d_records = bbd.d_records.get(); |
ab9e6a6c BH |
1083 | |
1084 | if(d_handle.d_records->empty()) | |
e6a9dde5 | 1085 | DLOG(g_log<<"Query with no results"<<endl); |
38e655b6 | 1086 | |
702156df | 1087 | d_handle.mustlog = mustlog; |
94364112 | 1088 | |
1089 | auto& hashedidx = boost::multi_index::get<UnorderedNameTag>(*d_handle.d_records); | |
1090 | auto range = hashedidx.equal_range(d_handle.qname); | |
ced82662 BH |
1091 | |
1092 | if(range.first==range.second) { | |
7b308b7e | 1093 | d_handle.d_list=false; |
76faefcf | 1094 | d_handle.d_iter = d_handle.d_end_iter = range.first; |
ced82662 BH |
1095 | return; |
1096 | } | |
1097 | else { | |
7b308b7e BH |
1098 | d_handle.d_iter=range.first; |
1099 | d_handle.d_end_iter=range.second; | |
ced82662 BH |
1100 | } |
1101 | ||
7b308b7e | 1102 | d_handle.d_list=false; |
b532a4b1 BH |
1103 | } |
1104 | ||
1105 | Bind2Backend::handle::handle() | |
1106 | { | |
38e655b6 | 1107 | mustlog=false; |
b532a4b1 BH |
1108 | } |
1109 | ||
1110 | bool Bind2Backend::get(DNSResourceRecord &r) | |
1111 | { | |
702156df BH |
1112 | if(!d_handle.d_records) { |
1113 | if(d_handle.mustlog) | |
e6a9dde5 | 1114 | g_log<<Logger::Warning<<"There were no answers"<<endl; |
69ab97d1 | 1115 | return false; |
702156df | 1116 | } |
69ab97d1 | 1117 | |
7b308b7e | 1118 | if(!d_handle.get(r)) { |
702156df | 1119 | if(d_handle.mustlog) |
e6a9dde5 | 1120 | g_log<<Logger::Warning<<"End of answers"<<endl; |
69ab97d1 | 1121 | |
702156df | 1122 | d_handle.reset(); |
69ab97d1 | 1123 | |
b532a4b1 BH |
1124 | return false; |
1125 | } | |
c1d02c0d | 1126 | if(d_handle.mustlog) |
e6a9dde5 | 1127 | g_log<<Logger::Warning<<"Returning: '"<<r.qtype.getName()<<"' of '"<<r.qname<<"', content: '"<<r.content<<"'"<<endl; |
b532a4b1 BH |
1128 | return true; |
1129 | } | |
1130 | ||
1131 | bool Bind2Backend::handle::get(DNSResourceRecord &r) | |
1132 | { | |
1133 | if(d_list) | |
1134 | return get_list(r); | |
1135 | else | |
1136 | return get_normal(r); | |
1137 | } | |
1138 | ||
a3047110 BH |
1139 | void Bind2Backend::handle::reset() |
1140 | { | |
1141 | d_records.reset(); | |
1142 | qname.clear(); | |
1143 | mustlog=false; | |
1144 | } | |
1145 | ||
8e16b978 | 1146 | //#define DLOG(x) x |
b532a4b1 BH |
1147 | bool Bind2Backend::handle::get_normal(DNSResourceRecord &r) |
1148 | { | |
e6a9dde5 | 1149 | DLOG(g_log << "Bind2Backend get() was called for "<<qtype.getName() << " record for '"<< |
f43c4448 | 1150 | qname<<"' - "<<d_records->size()<<" available in total!"<<endl); |
b532a4b1 | 1151 | |
ced82662 | 1152 | if(d_iter==d_end_iter) { |
ced82662 BH |
1153 | return false; |
1154 | } | |
9b145472 | 1155 | |
ced82662 | 1156 | while(d_iter!=d_end_iter && !(qtype.getCode()==QType::ANY || (d_iter)->qtype==qtype.getCode())) { |
e6a9dde5 | 1157 | DLOG(g_log<<Logger::Warning<<"Skipped "<<qname<<"/"<<QType(d_iter->qtype).getName()<<": '"<<d_iter->content<<"'"<<endl); |
b532a4b1 BH |
1158 | d_iter++; |
1159 | } | |
ced82662 | 1160 | if(d_iter==d_end_iter) { |
b532a4b1 BH |
1161 | return false; |
1162 | } | |
e6a9dde5 | 1163 | DLOG(g_log << "Bind2Backend get() returning a rr with a "<<QType(d_iter->qtype).getCode()<<endl); |
b532a4b1 | 1164 | |
c77d4725 | 1165 | r.qname=qname.empty() ? domain : (qname+domain); |
ced82662 BH |
1166 | r.domain_id=id; |
1167 | r.content=(d_iter)->content; | |
9b145472 | 1168 | // r.domain_id=(d_iter)->domain_id; |
b532a4b1 BH |
1169 | r.qtype=(d_iter)->qtype; |
1170 | r.ttl=(d_iter)->ttl; | |
8e16b978 | 1171 | |
2717b8b3 | 1172 | //if(!d_iter->auth && r.qtype.getCode() != QType::A && r.qtype.getCode()!=QType::AAAA && r.qtype.getCode() != QType::NS) |
97b019d0 | 1173 | // cerr<<"Warning! Unauth response for qtype "<< r.qtype.getName() << " for '"<<r.qname<<"'"<<endl; |
8e16b978 BH |
1174 | r.auth = d_iter->auth; |
1175 | ||
b532a4b1 BH |
1176 | d_iter++; |
1177 | ||
1178 | return true; | |
1179 | } | |
1180 | ||
c77d4725 | 1181 | bool Bind2Backend::list(const DNSName& target, int id, bool include_disabled) |
b532a4b1 | 1182 | { |
b755d50a | 1183 | BB2DomainInfo bbd; |
1184 | ||
1185 | if(!safeGetBBDomainInfo(id, &bbd)) | |
b532a4b1 BH |
1186 | return false; |
1187 | ||
e9dd48f9 | 1188 | d_handle.reset(); |
e6a9dde5 | 1189 | DLOG(g_log<<"Bind2Backend constructing handle for list of "<<id<<endl); |
b532a4b1 | 1190 | |
b755d50a | 1191 | d_handle.d_records=bbd.d_records.get(); // give it a copy, which will stay around |
d9367e79 BH |
1192 | d_handle.d_qname_iter= d_handle.d_records->begin(); |
1193 | d_handle.d_qname_end=d_handle.d_records->end(); // iter now points to a vector of pointers to vector<BBResourceRecords> | |
b532a4b1 | 1194 | |
7b308b7e | 1195 | d_handle.id=id; |
8fa54203 | 1196 | d_handle.domain=bbd.d_name; |
7b308b7e | 1197 | d_handle.d_list=true; |
b532a4b1 | 1198 | return true; |
b532a4b1 BH |
1199 | } |
1200 | ||
1201 | bool Bind2Backend::handle::get_list(DNSResourceRecord &r) | |
1202 | { | |
1203 | if(d_qname_iter!=d_qname_end) { | |
dc1fb060 | 1204 | r.qname=d_qname_iter->qname.empty() ? domain : (d_qname_iter->qname+domain); |
7b308b7e BH |
1205 | r.domain_id=id; |
1206 | r.content=(d_qname_iter)->content; | |
1207 | r.qtype=(d_qname_iter)->qtype; | |
1208 | r.ttl=(d_qname_iter)->ttl; | |
8e16b978 | 1209 | r.auth = d_qname_iter->auth; |
b532a4b1 BH |
1210 | d_qname_iter++; |
1211 | return true; | |
1212 | } | |
1213 | return false; | |
b532a4b1 BH |
1214 | } |
1215 | ||
c77d4725 | 1216 | bool Bind2Backend::isMaster(const DNSName& name, const string &ip) |
b532a4b1 | 1217 | { |
b755d50a | 1218 | BB2DomainInfo bbd; |
1219 | if(!safeGetBBDomainInfo(name, &bbd)) | |
1220 | return false; | |
1221 | ||
bc67ec22 PL |
1222 | if(bbd.d_kind != DomainInfo::Slave) |
1223 | return false; | |
1224 | ||
b755d50a | 1225 | for(vector<string>::const_iterator iter = bbd.d_masters.begin(); iter != bbd.d_masters.end(); ++iter) |
1226 | if(*iter==ip) | |
1227 | return true; | |
1228 | ||
b532a4b1 BH |
1229 | return false; |
1230 | } | |
1231 | ||
c77d4725 | 1232 | bool Bind2Backend::superMasterBackend(const string &ip, const DNSName& domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db) |
f404b863 BH |
1233 | { |
1234 | // Check whether we have a configfile available. | |
1235 | if (getArg("supermaster-config").empty()) | |
1236 | return false; | |
1237 | ||
9e04108d | 1238 | ifstream c_if(getArg("supermasters").c_str(), std::ios::in); // this was nocreate? |
f404b863 | 1239 | if (!c_if) { |
e6a9dde5 | 1240 | g_log << Logger::Error << "Unable to open supermasters file for read: " << stringerror() << endl; |
f404b863 BH |
1241 | return false; |
1242 | } | |
1243 | ||
1244 | // Format: | |
1245 | // <ip> <accountname> | |
1246 | string line, sip, saccount; | |
1247 | while (getline(c_if, line)) { | |
9e04108d | 1248 | std::istringstream ii(line); |
f404b863 BH |
1249 | ii >> sip; |
1250 | if (sip == ip) { | |
1251 | ii >> saccount; | |
1252 | break; | |
1253 | } | |
1254 | } | |
1255 | c_if.close(); | |
1256 | ||
1257 | if (sip != ip) // ip not found in authorization list - reject | |
1258 | return false; | |
1259 | ||
1260 | // ip authorized as supermaster - accept | |
1261 | *db = this; | |
1262 | if (saccount.length() > 0) | |
1263 | *account = saccount.c_str(); | |
1264 | ||
1265 | return true; | |
1266 | } | |
1267 | ||
c77d4725 | 1268 | BB2DomainInfo Bind2Backend::createDomainEntry(const DNSName& domain, const string &filename) |
f404b863 | 1269 | { |
a31fe060 | 1270 | int newid=1; |
b755d50a | 1271 | { // Find a free zone id nr. |
1272 | ReadLock rl(&s_state_lock); | |
1273 | if (!s_state.empty()) { | |
1274 | newid = s_state.rbegin()->d_id+1; | |
1275 | } | |
a31fe060 PB |
1276 | } |
1277 | ||
b755d50a | 1278 | BB2DomainInfo bbd; |
a31fe060 PB |
1279 | bbd.d_id = newid; |
1280 | bbd.d_records = shared_ptr<recordstorage_t >(new recordstorage_t); | |
1281 | bbd.d_name = domain; | |
1282 | bbd.setCheckInterval(getArgAsNum("check-interval")); | |
1283 | bbd.d_filename = filename; | |
a31fe060 PB |
1284 | return bbd; |
1285 | } | |
1286 | ||
c77d4725 | 1287 | bool Bind2Backend::createSlaveDomain(const string &ip, const DNSName& domain, const string &nameserver, const string &account) |
f404b863 | 1288 | { |
c77d4725 | 1289 | string filename = getArg("supermaster-destdir")+'/'+domain.toStringNoDot(); |
f404b863 | 1290 | |
e6a9dde5 | 1291 | g_log << Logger::Warning << d_logprefix |
97b019d0 | 1292 | << " Writing bind config zone statement for superslave zone '" << domain |
f404b863 | 1293 | << "' from supermaster " << ip << endl; |
8168957d PB |
1294 | |
1295 | { | |
1296 | Lock l2(&s_supermaster_config_lock); | |
f404b863 | 1297 | |
8168957d PB |
1298 | ofstream c_of(getArg("supermaster-config").c_str(), std::ios::app); |
1299 | if (!c_of) { | |
e6a9dde5 | 1300 | g_log << Logger::Error << "Unable to open supermaster configfile for append: " << stringerror() << endl; |
8168957d PB |
1301 | throw DBException("Unable to open supermaster configfile for append: "+stringerror()); |
1302 | } | |
1303 | ||
1304 | c_of << endl; | |
3cd692b3 | 1305 | c_of << "# Superslave zone '" << domain.toString() << "' (added: " << nowTime() << ") (account: " << account << ')' << endl; |
c77d4725 | 1306 | c_of << "zone \"" << domain.toStringNoDot() << "\" {" << endl; |
8168957d PB |
1307 | c_of << "\ttype slave;" << endl; |
1308 | c_of << "\tfile \"" << filename << "\";" << endl; | |
1309 | c_of << "\tmasters { " << ip << "; };" << endl; | |
1310 | c_of << "};" << endl; | |
1311 | c_of.close(); | |
f404b863 | 1312 | } |
8168957d | 1313 | |
c77d4725 | 1314 | BB2DomainInfo bbd = createDomainEntry(domain, filename); |
bc67ec22 | 1315 | bbd.d_kind = DomainInfo::Slave; |
e5b11b2f | 1316 | bbd.d_masters.push_back(ip); |
b755d50a | 1317 | safePutBBDomainInfo(bbd); |
f404b863 BH |
1318 | return true; |
1319 | } | |
1320 | ||
69abb9b6 AT |
1321 | bool Bind2Backend::searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result) |
1322 | { | |
1323 | SimpleMatch sm(pattern,true); | |
1324 | static bool mustlog=::arg().mustDo("query-logging"); | |
1325 | if(mustlog) | |
e6a9dde5 | 1326 | g_log<<Logger::Warning<<"Search for pattern '"<<pattern<<"'"<<endl; |
69abb9b6 AT |
1327 | |
1328 | { | |
1329 | ReadLock rl(&s_state_lock); | |
1330 | ||
1331 | for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { | |
1332 | BB2DomainInfo h; | |
1333 | safeGetBBDomainInfo(i->d_id, &h); | |
2010ac95 | 1334 | shared_ptr<const recordstorage_t> rhandle = h.d_records.get(); |
69abb9b6 | 1335 | |
2010ac95 | 1336 | for(recordstorage_t::const_iterator ri = rhandle->begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && ri != rhandle->end(); ri++) { |
69abb9b6 AT |
1337 | DNSName name = ri->qname.empty() ? i->d_name : (ri->qname+i->d_name); |
1338 | if (sm.match(name) || sm.match(ri->content)) { | |
1339 | DNSResourceRecord r; | |
1340 | r.qname=name; | |
1341 | r.domain_id=i->d_id; | |
1342 | r.content=ri->content; | |
1343 | r.qtype=ri->qtype; | |
1344 | r.ttl=ri->ttl; | |
1345 | r.auth = ri->auth; | |
1346 | result.push_back(r); | |
1347 | } | |
1348 | } | |
1349 | } | |
1350 | } | |
1351 | ||
1352 | return true; | |
1353 | } | |
1354 | ||
b532a4b1 BH |
1355 | class Bind2Factory : public BackendFactory |
1356 | { | |
1357 | public: | |
d7dbeca9 | 1358 | Bind2Factory() : BackendFactory("bind") {} |
b532a4b1 BH |
1359 | |
1360 | void declareArguments(const string &suffix="") | |
1361 | { | |
fb484267 | 1362 | declare(suffix,"ignore-broken-records","Ignore records that are out-of-bound for the zone.","no"); |
b2e52bc5 PB |
1363 | declare(suffix,"config","Location of named.conf",""); |
1364 | declare(suffix,"check-interval","Interval for zonefile changes","0"); | |
1365 | declare(suffix,"supermaster-config","Location of (part of) named.conf where pdns can write zone-statements to",""); | |
1366 | declare(suffix,"supermasters","List of IP-addresses of supermasters",""); | |
1367 | declare(suffix,"supermaster-destdir","Destination directory for newly added slave zones",::arg()["config-dir"]); | |
1368 | declare(suffix,"dnssec-db","Filename to store & access our DNSSEC metadatabase, empty for none", ""); | |
aebddbd2 | 1369 | declare(suffix,"hybrid","Store DNSSEC metadata in other backend","no"); |
b532a4b1 BH |
1370 | } |
1371 | ||
1372 | DNSBackend *make(const string &suffix="") | |
1373 | { | |
1374 | return new Bind2Backend(suffix); | |
1375 | } | |
2717b8b3 BH |
1376 | |
1377 | DNSBackend *makeMetadataOnly(const string &suffix="") | |
1378 | { | |
1379 | return new Bind2Backend(suffix, false); | |
1380 | } | |
b532a4b1 BH |
1381 | }; |
1382 | ||
1383 | //! Magic class that is activated when the dynamic library is loaded | |
1384 | class Bind2Loader | |
1385 | { | |
1386 | public: | |
1387 | Bind2Loader() | |
1388 | { | |
1389 | BackendMakers().report(new Bind2Factory); | |
e6a9dde5 | 1390 | g_log << Logger::Info << "[bind2backend] This is the bind backend version " << VERSION |
5e6a3d93 PL |
1391 | #ifndef REPRODUCIBLE |
1392 | << " (" __DATE__ " " __TIME__ ")" | |
1393 | #endif | |
1394 | << " reporting" << endl; | |
b532a4b1 BH |
1395 | } |
1396 | }; | |
1397 | static Bind2Loader bind2loader; |