]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsbackend.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2005 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
7 as published by the Free Software Foundation
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
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.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "dnsbackend.hh"
24 #include "arguments.hh"
25 #include "ueberbackend.hh"
28 #include <sys/types.h>
29 #include "dnspacket.hh"
32 string
DNSBackend::getRemote(DNSPacket
*p
)
34 return p
->getRemote();
37 bool DNSBackend::getRemote(DNSPacket
*p
, struct sockaddr
*sa
, Utility::socklen_t
*len
)
39 if(p
->d_remote
.getSocklen() < *len
)
41 *len
=p
->d_remote
.getSocklen();
42 memcpy(sa
,&p
->d_remote
,*len
);
46 void DNSBackend::setArgPrefix(const string
&prefix
)
51 bool DNSBackend::mustDo(const string
&key
)
53 return arg().mustDo(d_prefix
+"-"+key
);
56 const string
&DNSBackend::getArg(const string
&key
)
58 return arg()[d_prefix
+"-"+key
];
61 int DNSBackend::getArgAsNum(const string
&key
)
63 return arg().asNum(d_prefix
+"-"+key
);
66 void BackendFactory::declare(const string
&suffix
, const string
¶m
, const string
&help
, const string
&value
)
68 string fullname
=d_name
+suffix
+"-"+param
;
69 arg().set(fullname
,help
)=value
;
72 const string
&BackendFactory::getName() const
77 BackendMakerClass
&BackendMakers()
79 static BackendMakerClass bmc
;
83 void BackendMakerClass::report(BackendFactory
*bf
)
85 d_repository
[bf
->getName()]=bf
;
89 vector
<string
> BackendMakerClass::getModules()
93 // copy(d_repository.begin(), d_repository.end(),back_inserter(ret));
94 for(d_repository_t::const_iterator i
=d_repository
.begin();i
!=d_repository
.end();++i
)
95 ret
.push_back(i
->first
);
99 void BackendMakerClass::load_all()
101 // TODO: Implement this?
102 DIR *dir
=opendir(arg()["module-dir"].c_str());
104 L
<<Logger::Error
<<"Unable to open module directory '"<<arg()["module-dir"]<<"'"<<endl
;
107 struct dirent
*entry
;
108 while((entry
=readdir(dir
))) {
109 if(!strncmp(entry
->d_name
,"lib",3) &&
110 strlen(entry
->d_name
)>13 &&
111 !strcmp(entry
->d_name
+strlen(entry
->d_name
)-10,"backend.so"))
117 void BackendMakerClass::load(const string
&module
)
121 if(module
.find(".")==string::npos
)
122 res
=UeberBackend::loadmodule(arg()["module-dir"]+"/lib"+module
+"backend.so");
123 else if(module
[0]=='/' || (module
[0]=='.' && module
[1]=='/') || (module
[0]=='.' && module
[1]=='.')) // absolute or current path
124 res
=UeberBackend::loadmodule(module
);
126 res
=UeberBackend::loadmodule(arg()["module-dir"]+"/"+module
);
129 L
<<Logger::Error
<<"dnsbackend unable to load module in "<<module
<<endl
;
134 void BackendMakerClass::launch(const string
&instr
)
137 // throw ArgException("Not launching any backends - nameserver won't function");
139 vector
<string
> parts
;
140 stringtok(parts
,instr
,", ");
142 for(vector
<string
>::const_iterator i
=parts
.begin();i
!=parts
.end();++i
) {
143 const string
&part
=*i
;
146 vector
<string
>pparts
;
147 stringtok(pparts
,part
,": ");
152 if(d_repository
.find(module
)==d_repository
.end()) {
153 // this is *so* userfriendly
155 if(d_repository
.find(module
)==d_repository
.end())
156 throw ArgException("Trying to launch unknown backend '"+module
+"'");
158 d_repository
[module
]->declareArguments(name
);
159 d_instances
.push_back(make_pair(module
,name
));
163 int BackendMakerClass::numLauncheable()
165 return d_instances
.size();
168 vector
<DNSBackend
*>BackendMakerClass::all(bool metadataOnly
)
170 vector
<DNSBackend
*>ret
;
171 if(d_instances
.empty())
172 throw PDNSException("No database backends configured for launch, unable to function");
175 for(vector
<pair
<string
,string
> >::const_iterator i
=d_instances
.begin();i
!=d_instances
.end();++i
) {
178 made
= d_repository
[i
->first
]->makeMetadataOnly(i
->second
);
180 made
= d_repository
[i
->first
]->make(i
->second
);
182 throw PDNSException("Unable to launch backend '"+i
->first
+"'");
187 catch(PDNSException
&ae
) {
188 L
<<Logger::Error
<<"Caught an exception instantiating a backend: "<<ae
.reason
<<endl
;
189 L
<<Logger::Error
<<"Cleaning up"<<endl
;
190 for(vector
<DNSBackend
*>::const_iterator i
=ret
.begin();i
!=ret
.end();++i
)
195 L
<<Logger::Error
<<"Caught an exception instantiating a backend, cleaning up"<<endl
;
196 for(vector
<DNSBackend
*>::const_iterator i
=ret
.begin();i
!=ret
.end();++i
)
204 /** getSOA() is a function that is called to get the SOA of a domain. Callers should ONLY
205 use getSOA() and not perform a lookup() themselves as backends may decide to special case
208 Returns false if there is definitely no SOA for the domain. May throw a DBException
209 to indicate that the backend is currently unable to supply an answer.
211 WARNING: This function *may* fill out the db attribute of the SOAData, but then again,
212 it may not! If you find a zero in there, you may have been handed a non-live and cached
213 answer, in which case you need to perform a getDomainInfo call!
215 \param domain Domain we want to get the SOA details of
216 \param sd SOAData which is filled with the SOA details
218 bool DNSBackend::getSOA(const string
&domain
, SOAData
&sd
, DNSPacket
*p
)
220 this->lookup(QType(QType::SOA
),domain
,p
);
222 DNSResourceRecord rr
;
227 while(this->get(rr
)) {
229 fillSOAData(rr
.content
, sd
);
230 sd
.domain_id
=rr
.domain_id
;
232 sd
.scopeMask
= rr
.scopeMask
;
238 if(sd
.nameserver
.empty())
239 sd
.nameserver
=arg()["default-soa-name"];
241 if(sd
.hostmaster
.empty()) {
242 if (!arg().isEmpty("default-soa-mail")) {
243 sd
.hostmaster
=arg()["default-soa-mail"];
244 attodot(sd
.hostmaster
);
247 sd
.hostmaster
="hostmaster."+domain
;
250 if(!sd
.serial
) { // magic time!
251 DLOG(L
<<Logger::Warning
<<"Doing soa serialnumber autocalculation for "<<rr
.qname
<<endl
);
254 if (calculateSOASerial(domain
, sd
, serial
)) {
256 //DLOG(L<<"autocalculated soa serialnumber for "<<rr.qname<<" is "<<newest<<endl);
258 DLOG(L
<<"soa serialnumber calculation failed for "<<rr
.qname
<<endl
);
266 bool DNSBackend::getBeforeAndAfterNames(uint32_t id
, const std::string
& zonename
, const std::string
& qname
, std::string
& before
, std::string
& after
)
268 string lcqname
=toLower(qname
);
269 string lczonename
=toLower(zonename
);
270 lcqname
=makeRelative(lcqname
, lczonename
);
272 lcqname
=labelReverse(lcqname
);
274 bool ret
= this->getBeforeAndAfterNamesAbsolute(id
, lcqname
, dnc
, before
, after
);
276 before
=dotConcat(labelReverse(before
), lczonename
);
277 after
=dotConcat(labelReverse(after
), lczonename
);
282 * Calculates a SOA serial for the zone and stores it in the third
283 * argument. Returns false if calculation is not possible for some
284 * reason (in this case, the third argument is not inspected). If it
285 * returns true, the value returned in the third argument will be set
288 * \param domain The name of the domain
289 * \param sd Information about the SOA record already available
290 * \param serial Output parameter. Only inspected when we return true
292 bool DNSBackend::calculateSOASerial(const string
& domain
, const SOAData
& sd
, time_t& serial
)
294 // we do this by listing the domain and taking the maximum last modified timestamp
299 if(!(this->list(domain
, sd
.domain_id
))) {
300 DLOG(L
<<Logger::Warning
<<"Backend error trying to determine magic serial number of zone '"<<domain
<<"'"<<endl
);
304 while(this->get(i
)) {
305 if(i
.last_modified
>newest
)
306 newest
=i
.last_modified
;
309 serial
=newest
; // +arg().asNum("soa-serial-offset");