]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsbackend.hh
Merge pull request #9080 from omoerbeek/coverity-1401969-sqllite
[thirdparty/pdns.git] / pdns / dnsbackend.hh
1 /*
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 */
22 #pragma once
23
24 class DNSPacket;
25
26 #include "utility.hh"
27 #include <string>
28 #include <vector>
29 #include <map>
30 #include <sys/types.h>
31 #include "pdnsexception.hh"
32 #include <set>
33 #include <iostream>
34 #include <sys/socket.h>
35 #include <dirent.h>
36 #include "misc.hh"
37 #include "qtype.hh"
38 #include "dns.hh"
39 #include <vector>
40 #include "namespaces.hh"
41 #include "comment.hh"
42 #include "dnsname.hh"
43 #include "dnsrecords.hh"
44 #include "iputils.hh"
45
46 class DNSBackend;
47 struct DomainInfo
48 {
49 DomainInfo() : last_check(0), backend(NULL), id(0), notified_serial(0), serial(0), kind(DomainInfo::Native) {}
50
51 DNSName zone;
52 time_t last_check;
53 string account;
54 vector<ComboAddress> masters;
55 DNSBackend *backend;
56
57 uint32_t id;
58 uint32_t notified_serial;
59
60 uint32_t serial;
61 enum DomainKind : uint8_t { Master, Slave, Native } kind;
62
63 bool operator<(const DomainInfo& rhs) const
64 {
65 return zone < rhs.zone;
66 }
67
68 const char *getKindString() const
69 {
70 return DomainInfo::getKindString(kind);
71 }
72
73 static const char *getKindString(enum DomainKind kind)
74 {
75 const char *kinds[]={"Master", "Slave", "Native"};
76 return kinds[kind];
77 }
78
79 static DomainKind stringToKind(const string& kind)
80 {
81 if(pdns_iequals(kind,"SLAVE"))
82 return DomainInfo::Slave;
83 else if(pdns_iequals(kind,"MASTER"))
84 return DomainInfo::Master;
85 else
86 return DomainInfo::Native;
87 }
88
89 bool isMaster(const ComboAddress& ip) const
90 {
91 for( const auto& master: masters) {
92 if(ComboAddress::addressOnlyEqual()(ip, master))
93 return true;
94 }
95 return false;
96 }
97
98 };
99
100 struct TSIGKey {
101 DNSName name;
102 DNSName algorithm;
103 std::string key;
104 };
105
106 class DNSPacket;
107
108 //! This virtual base class defines the interface for backends for PowerDNS.
109 /** To create a backend, inherit from this class and implement functions for all virtual methods.
110 Methods should not throw an exception if they are sure they did not find the requested data. However,
111 if an error occurred which prevented them temporarily from performing a lockup, they should throw a DBException,
112 which will cause the nameserver to send out a ServFail or take other evasive action. Probably only locking
113 issues should lead to DBExceptions.
114
115 More serious errors, which may indicate that the database connection is hosed, or a configuration error occurred, should
116 lead to the throwing of an PDNSException. This exception will fall straight through the UeberBackend and the PacketHandler
117 and be caught by the Distributor, which will delete your DNSBackend instance and spawn a new one.
118 */
119 class DNSBackend
120 {
121 public:
122 //! lookup() initiates a lookup. A lookup without results should not throw!
123 virtual void lookup(const QType &qtype, const DNSName &qdomain, int zoneId=-1, DNSPacket *pkt_p=nullptr)=0;
124 virtual bool get(DNSResourceRecord &)=0; //!< retrieves one DNSResource record, returns false if no more were available
125 virtual bool get(DNSZoneRecord &r);
126
127 //! Initiates a list of the specified domain
128 /** Once initiated, DNSResourceRecord objects can be retrieved using get(). Should return false
129 if the backend does not consider itself responsible for the id passed.
130 \param domain_id ID of which a list is requested
131 */
132 virtual bool list(const DNSName &target, int domain_id, bool include_disabled=false)=0;
133
134 virtual ~DNSBackend(){};
135
136 //! fills the soadata struct with the SOA details. Returns false if there is no SOA.
137 virtual bool getSOA(const DNSName &name, SOAData &soadata);
138
139 virtual bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)
140 {
141 return false;
142 }
143
144 virtual bool listSubZone(const DNSName &zone, int domain_id)
145 {
146 return false;
147 }
148
149 // the DNSSEC related (getDomainMetadata has broader uses too)
150 bool isDnssecDomainMetadata (const string& name) {
151 return (name == "PRESIGNED" || name == "NSEC3PARAM" || name == "NSEC3NARROW");
152 }
153 virtual bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta) { return false; };
154 virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) { return false; }
155 virtual bool getDomainMetadataOne(const DNSName& name, const std::string& kind, std::string& value)
156 {
157 std::vector<std::string> meta;
158 if (getDomainMetadata(name, kind, meta)) {
159 if(!meta.empty()) {
160 value = *meta.begin();
161 return true;
162 }
163 }
164 return false;
165 }
166
167 virtual bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) {return false;}
168 virtual bool setDomainMetadataOne(const DNSName& name, const std::string& kind, const std::string& value)
169 {
170 const std::vector<std::string> meta(1, value);
171 return setDomainMetadata(name, kind, meta);
172 }
173
174
175 virtual void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false) { }
176
177 /** Determines if we are authoritative for a zone, and at what level */
178 virtual bool getAuth(const DNSName &target, SOAData *sd);
179
180 struct KeyData {
181 std::string content;
182 unsigned int id;
183 unsigned int flags;
184 bool active;
185 bool published;
186 };
187
188 virtual bool getDomainKeys(const DNSName& name, std::vector<KeyData>& keys) { return false;}
189 virtual bool removeDomainKey(const DNSName& name, unsigned int id) { return false; }
190 virtual bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id){ return false; }
191 virtual bool activateDomainKey(const DNSName& name, unsigned int id) { return false; }
192 virtual bool deactivateDomainKey(const DNSName& name, unsigned int id) { return false; }
193 virtual bool publishDomainKey(const DNSName& name, unsigned int id) { return false; }
194 virtual bool unpublishDomainKey(const DNSName& name, unsigned int id) { return false; }
195
196 virtual bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) { return false; }
197 virtual bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) { return false; }
198 virtual bool deleteTSIGKey(const DNSName& name) { return false; }
199 virtual bool getTSIGKeys(std::vector< struct TSIGKey > &keys) { return false; }
200
201 virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after)
202 {
203 std::cerr<<"Default beforeAndAfterAbsolute called!"<<std::endl;
204 abort();
205 return false;
206 }
207
208 virtual bool getBeforeAndAfterNames(uint32_t id, const DNSName& zonename, const DNSName& qname, DNSName& before, DNSName& after);
209
210 virtual bool updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype=QType::ANY)
211 {
212 return false;
213 }
214
215 virtual bool updateEmptyNonTerminals(uint32_t domain_id, set<DNSName>& insert, set<DNSName>& erase, bool remove)
216 {
217 return false;
218 }
219
220 virtual bool doesDNSSEC()
221 {
222 return false;
223 }
224
225 // end DNSSEC
226
227 // comments support
228 virtual bool listComments(uint32_t domain_id)
229 {
230 return false; // unsupported by this backend
231 }
232
233 virtual bool getComment(Comment& comment)
234 {
235 return false;
236 }
237
238 virtual void feedComment(const Comment& comment)
239 {
240 }
241
242 virtual bool replaceComments(const uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<Comment>& comments)
243 {
244 return false;
245 }
246
247 //! returns true if master ip is master for domain name.
248 //! starts the transaction for updating domain qname (FIXME: what is id?)
249 virtual bool startTransaction(const DNSName &qname, int id=-1)
250 {
251 return false;
252 }
253
254 //! commits the transaction started by startTransaction
255 virtual bool commitTransaction()
256 {
257 return false;
258 }
259
260 //! aborts the transaction started by strartTransaction, should leave state unaltered
261 virtual bool abortTransaction()
262 {
263 return false;
264 }
265
266 virtual void reload()
267 {
268 }
269
270 virtual void rediscover(string* status=0)
271 {
272 }
273
274 //! feeds a record to a zone, needs a call to startTransaction first
275 virtual bool feedRecord(const DNSResourceRecord &rr, const DNSName &ordername, bool ordernameIsNSEC3=false)
276 {
277 return false; // no problem!
278 }
279 virtual bool feedEnts(int domain_id, map<DNSName,bool> &nonterm)
280 {
281 return false;
282 }
283 virtual bool feedEnts3(int domain_id, const DNSName &domain, map<DNSName,bool> &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow)
284 {
285 return false;
286 }
287
288 //! if this returns true, DomainInfo di contains information about the domain
289 virtual bool getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial=true)
290 {
291 return false;
292 }
293 //! slave capable backends should return a list of slaves that should be rechecked for staleness
294 virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains)
295 {
296 }
297
298 //! get a list of IP addresses that should also be notified for a domain
299 virtual void alsoNotifies(const DNSName &domain, set<string> *ips)
300 {
301 }
302
303 //! get list of domains that have been changed since their last notification to slaves
304 virtual void getUpdatedMasters(vector<DomainInfo>* domains)
305 {
306 }
307
308 //! Called by PowerDNS to inform a backend that a domain has been checked for freshness
309 virtual void setFresh(uint32_t domain_id)
310 {
311
312 }
313 //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to slaves
314 virtual void setNotified(uint32_t id, uint32_t serial)
315 {
316 }
317
318 //! Called when the Master of a domain should be changed
319 virtual bool setMaster(const DNSName &domain, const string &ip)
320 {
321 return false;
322 }
323
324 //! Called when the Kind of a domain should be changed (master -> native and similar)
325 virtual bool setKind(const DNSName &domain, const DomainInfo::DomainKind kind)
326 {
327 return false;
328 }
329
330 //! Called when the Account of a domain should be changed
331 virtual bool setAccount(const DNSName &domain, const string &account)
332 {
333 return false;
334 }
335
336 //! Can be called to seed the getArg() function with a prefix
337 void setArgPrefix(const string &prefix);
338
339 //! determine if ip is a supermaster or a domain
340 virtual bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
341 {
342 return false;
343 }
344
345 //! called by PowerDNS to create a new domain
346 virtual bool createDomain(const DNSName &domain)
347 {
348 return false;
349 }
350
351 //! called by PowerDNS to create a slave record for a superMaster
352 virtual bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account)
353 {
354 return false;
355 }
356
357 //! called to delete a domain, incl. all metadata, zone contents, etc.
358 virtual bool deleteDomain(const DNSName &domain)
359 {
360 return false;
361 }
362
363 virtual string directBackendCmd(const string &query)
364 {
365 return "directBackendCmd not supported for this backend\n";
366 }
367
368 //! Search for records, returns true if search was done successfully.
369 virtual bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result)
370 {
371 return false;
372 }
373
374 //! Search for comments, returns true if search was done successfully.
375 virtual bool searchComments(const string &pattern, int maxResults, vector<Comment>& result)
376 {
377 return false;
378 }
379
380 const string& getPrefix() { return d_prefix; };
381 protected:
382 bool mustDo(const string &key);
383 const string &getArg(const string &key);
384 int getArgAsNum(const string &key);
385
386 private:
387 string d_prefix;
388 };
389
390 class BackendFactory
391 {
392 public:
393 BackendFactory(const string &name) : d_name(name) {}
394 virtual ~BackendFactory(){}
395 virtual DNSBackend *make(const string &suffix)=0;
396 virtual DNSBackend *makeMetadataOnly(const string &suffix)
397 {
398 return this->make(suffix);
399 }
400 virtual void declareArguments(const string &suffix=""){}
401 const string &getName() const;
402
403 protected:
404 void declare(const string &suffix, const string &param, const string &explanation, const string &value);
405
406 private:
407 const string d_name;
408 };
409
410 class BackendMakerClass
411 {
412 public:
413 void report(BackendFactory *bf);
414 void launch(const string &instr);
415 vector<DNSBackend *>all(bool skipBIND=false);
416 void load(const string &module);
417 int numLauncheable();
418 vector<string> getModules();
419
420 private:
421 void load_all();
422 typedef map<string,BackendFactory *>d_repository_t;
423 d_repository_t d_repository;
424 vector<pair<string,string> >d_instances;
425 };
426
427 extern BackendMakerClass &BackendMakers();
428
429 //! Exception that can be thrown by a DNSBackend to indicate a failure
430 class DBException : public PDNSException
431 {
432 public:
433 DBException(const string &reason_) : PDNSException(reason_){}
434 };
435
436 /** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */
437 void fillSOAData(const string &content, SOAData &data);
438 // same but more karmic
439 void fillSOAData(const DNSZoneRecord& in, SOAData& data);
440 // the reverse
441 std::shared_ptr<DNSRecordContent> makeSOAContent(const SOAData& sd);