]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsbackend.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "dnsbackend.hh"
27 #include "arguments.hh"
28 #include "ueberbackend.hh"
31 #include <sys/types.h>
32 #include "pdns/packetcache.hh"
33 #include "dnspacket.hh"
36 // this has to be somewhere central, and not in a file that requires Lua
37 // this is so the geoipbackend can set this pointer if loaded for lua-record.cc
38 std::function
<std::string(const std::string
&, int)> g_getGeo
;
40 bool DNSBackend::getAuth(const DNSName
&target
, SOAData
*sd
)
42 return this->getSOA(target
, *sd
);
45 void DNSBackend::setArgPrefix(const string
&prefix
)
50 bool DNSBackend::mustDo(const string
&key
)
52 return arg().mustDo(d_prefix
+"-"+key
);
55 const string
&DNSBackend::getArg(const string
&key
)
57 return arg()[d_prefix
+"-"+key
];
60 int DNSBackend::getArgAsNum(const string
&key
)
62 return arg().asNum(d_prefix
+"-"+key
);
65 void BackendFactory::declare(const string
&suffix
, const string
¶m
, const string
&help
, const string
&value
)
67 string fullname
=d_name
+suffix
+"-"+param
;
68 arg().set(fullname
,help
)=value
;
71 const string
&BackendFactory::getName() const
76 BackendMakerClass
&BackendMakers()
78 static BackendMakerClass bmc
;
82 void BackendMakerClass::report(BackendFactory
*bf
)
84 d_repository
[bf
->getName()]=bf
;
88 vector
<string
> BackendMakerClass::getModules()
92 // copy(d_repository.begin(), d_repository.end(),back_inserter(ret));
93 for(d_repository_t::const_iterator i
=d_repository
.begin();i
!=d_repository
.end();++i
)
94 ret
.push_back(i
->first
);
98 void BackendMakerClass::load_all()
100 // TODO: Implement this?
101 DIR *dir
=opendir(arg()["module-dir"].c_str());
103 g_log
<<Logger::Error
<<"Unable to open module directory '"<<arg()["module-dir"]<<"'"<<endl
;
106 struct dirent
*entry
;
107 while((entry
=readdir(dir
))) {
108 if(!strncmp(entry
->d_name
,"lib",3) &&
109 strlen(entry
->d_name
)>13 &&
110 !strcmp(entry
->d_name
+strlen(entry
->d_name
)-10,"backend.so"))
116 void BackendMakerClass::load(const string
&module
)
120 if(module
.find(".")==string::npos
)
121 res
=UeberBackend::loadmodule(arg()["module-dir"]+"/lib"+module
+"backend.so");
122 else if(module
[0]=='/' || (module
[0]=='.' && module
[1]=='/') || (module
[0]=='.' && module
[1]=='.')) // absolute or current path
123 res
=UeberBackend::loadmodule(module
);
125 res
=UeberBackend::loadmodule(arg()["module-dir"]+"/"+module
);
128 g_log
<<Logger::Error
<<"DNSBackend unable to load module in "<<module
<<endl
;
133 void BackendMakerClass::launch(const string
&instr
)
136 // throw ArgException("Not launching any backends - nameserver won't function");
138 vector
<string
> parts
;
139 stringtok(parts
,instr
,", ");
141 for (const auto part
: parts
)
142 if (count(parts
.begin(), parts
.end(), part
) > 1)
143 throw ArgException("Refusing to launch multiple backends with the same name '" + part
+ "', verify all 'launch' statements in your configuration");
145 for(vector
<string
>::const_iterator i
=parts
.begin();i
!=parts
.end();++i
) {
146 const string
&part
=*i
;
149 vector
<string
>pparts
;
150 stringtok(pparts
,part
,": ");
155 if(d_repository
.find(module
)==d_repository
.end()) {
156 // this is *so* userfriendly
158 if(d_repository
.find(module
)==d_repository
.end())
159 throw ArgException("Trying to launch unknown backend '"+module
+"'");
161 d_repository
[module
]->declareArguments(name
);
162 d_instances
.push_back(make_pair(module
,name
));
166 int BackendMakerClass::numLauncheable()
168 return d_instances
.size();
171 vector
<DNSBackend
*>BackendMakerClass::all(bool metadataOnly
)
173 vector
<DNSBackend
*>ret
;
174 if(d_instances
.empty())
175 throw PDNSException("No database backends configured for launch, unable to function");
178 for(vector
<pair
<string
,string
> >::const_iterator i
=d_instances
.begin();i
!=d_instances
.end();++i
) {
181 made
= d_repository
[i
->first
]->makeMetadataOnly(i
->second
);
183 made
= d_repository
[i
->first
]->make(i
->second
);
185 throw PDNSException("Unable to launch backend '"+i
->first
+"'");
190 catch(PDNSException
&ae
) {
191 g_log
<<Logger::Error
<<"Caught an exception instantiating a backend: "<<ae
.reason
<<endl
;
192 g_log
<<Logger::Error
<<"Cleaning up"<<endl
;
193 for(vector
<DNSBackend
*>::const_iterator i
=ret
.begin();i
!=ret
.end();++i
)
198 g_log
<<Logger::Error
<<"Caught an exception instantiating a backend, cleaning up"<<endl
;
199 for(vector
<DNSBackend
*>::const_iterator i
=ret
.begin();i
!=ret
.end();++i
)
207 /** getSOA() is a function that is called to get the SOA of a domain. Callers should ONLY
208 use getSOA() and not perform a lookup() themselves as backends may decide to special case
211 Returns false if there is definitely no SOA for the domain. May throw a DBException
212 to indicate that the backend is currently unable to supply an answer.
214 WARNING: This function *may* fill out the db attribute of the SOAData, but then again,
215 it may not! If you find a zero in there, you may have been handed a non-live and cached
216 answer, in which case you need to perform a getDomainInfo call!
218 \param domain Domain we want to get the SOA details of
219 \param sd SOAData which is filled with the SOA details
220 \param unmodifiedSerial bool if set, serial will be returned as stored in the backend (maybe 0)
222 bool DNSBackend::getSOA(const DNSName
&domain
, SOAData
&sd
)
224 this->lookup(QType(QType::SOA
),domain
);
226 DNSResourceRecord rr
;
231 while(this->get(rr
)) {
232 if (rr
.qtype
!= QType::SOA
) throw PDNSException("Got non-SOA record when asking for SOA");
234 fillSOAData(rr
.content
, sd
);
235 sd
.domain_id
=rr
.domain_id
;
242 if(!sd
.nameserver
.countLabels())
243 sd
.nameserver
= DNSName(arg()["default-soa-name"]);
245 if(!sd
.hostmaster
.countLabels()) {
246 if (!arg().isEmpty("default-soa-mail")) {
247 sd
.hostmaster
= DNSName(arg()["default-soa-mail"]);
248 // attodot(sd.hostmaster); FIXME400
251 sd
.hostmaster
=DNSName("hostmaster")+domain
;
258 bool DNSBackend::get(DNSZoneRecord
& dzr
)
260 // cout<<"DNSBackend::get(DNSZoneRecord&) called - translating into DNSResourceRecord query"<<endl;
261 DNSResourceRecord rr
;
265 dzr
.domain_id
= rr
.domain_id
;
266 dzr
.scopeMask
= rr
.scopeMask
;
267 if(rr
.qtype
.getCode() == QType::TXT
&& !rr
.content
.empty() && rr
.content
[0]!='"')
268 rr
.content
= "\""+ rr
.content
+ "\"";
269 if(rr
.qtype
.getCode() == QType::SOA
) {
271 dzr
.dr
= DNSRecord(rr
);
273 vector
<string
> parts
;
274 stringtok(parts
, rr
.content
, " \t");
276 rr
.content
= arg()["default-soa-name"];
278 rr
.content
+= " " +arg()["default-soa-mail"];
282 rr
.content
+= " " + ::arg()["soa-refresh-default"];
284 rr
.content
+= " " + ::arg()["soa-retry-default"];
286 rr
.content
+= " " + ::arg()["soa-expire-default"];
288 rr
.content
+= " " + ::arg()["soa-minimum-ttl"];
289 dzr
.dr
= DNSRecord(rr
);
294 dzr
.dr
= DNSRecord(rr
);
297 while(this->get(rr
));
304 bool DNSBackend::getBeforeAndAfterNames(uint32_t id
, const DNSName
& zonename
, const DNSName
& qname
, DNSName
& before
, DNSName
& after
)
307 bool ret
= this->getBeforeAndAfterNamesAbsolute(id
, qname
.makeRelative(zonename
).makeLowerCase(), unhashed
, before
, after
);
308 DNSName lczonename
= zonename
.makeLowerCase();
309 before
+= lczonename
;
314 void fillSOAData(const DNSZoneRecord
& in
, SOAData
& sd
)
316 sd
.domain_id
= in
.domain_id
;
317 sd
.ttl
= in
.dr
.d_ttl
;
319 auto src
=getRR
<SOARecordContent
>(in
.dr
);
320 sd
.nameserver
= src
->d_mname
;
321 sd
.hostmaster
= src
->d_rname
;
322 sd
.serial
= src
->d_st
.serial
;
323 sd
.refresh
= src
->d_st
.refresh
;
324 sd
.retry
= src
->d_st
.retry
;
325 sd
.expire
= src
->d_st
.expire
;
326 sd
.default_ttl
= src
->d_st
.minimum
;
329 std::shared_ptr
<DNSRecordContent
> makeSOAContent(const SOAData
& sd
)
332 st
.serial
= sd
.serial
;
333 st
.refresh
= sd
.refresh
;
335 st
.expire
= sd
.expire
;
336 st
.minimum
= sd
.default_ttl
;
337 return std::make_shared
<SOARecordContent
>(sd
.nameserver
, sd
.hostmaster
, st
);
341 void fillSOAData(const string
&content
, SOAData
&data
)
343 // content consists of fields separated by spaces:
344 // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
346 // fill out data with some plausible defaults:
347 // 10800 3600 604800 3600
349 stringtok(parts
,content
);
350 int pleft
=parts
.size();
352 // cout<<"'"<<content<<"'"<<endl;
355 data
.nameserver
=DNSName(parts
[0]);
358 data
.hostmaster
=DNSName(attodot(parts
[1])); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl
361 data
.serial
= pleft
> 2 ? pdns_stou(parts
[2]) : 0;
363 data
.refresh
= pleft
> 3 ? pdns_stou(parts
[3])
364 : ::arg().asNum("soa-refresh-default");
366 data
.retry
= pleft
> 4 ? pdns_stou(parts
[4].c_str())
367 : ::arg().asNum("soa-retry-default");
369 data
.expire
= pleft
> 5 ? pdns_stou(parts
[5].c_str())
370 : ::arg().asNum("soa-expire-default");
372 data
.default_ttl
= pleft
> 6 ? pdns_stou(parts
[6].c_str())
373 : ::arg().asNum("soa-minimum-ttl");
375 catch(const std::out_of_range
& oor
) {
376 throw PDNSException("Out of range exception parsing "+content
);