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