]>
Commit | Line | Data |
---|---|---|
12c86877 | 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 | */ | |
e8c59f2d | 22 | #pragma once |
12c86877 | 23 | |
973ad2b5 BH |
24 | class DNSPacket; |
25 | ||
12c86877 BH |
26 | #include "utility.hh" |
27 | #include <string> | |
28 | #include <vector> | |
29 | #include <map> | |
30 | #include <sys/types.h> | |
5c409fa2 | 31 | #include "pdnsexception.hh" |
973ad2b5 | 32 | #include <set> |
702b226d | 33 | #include <iostream> |
76473b92 KM |
34 | #include <sys/socket.h> |
35 | #include <dirent.h> | |
76979e74 | 36 | #include "misc.hh" |
12c86877 BH |
37 | #include "qtype.hh" |
38 | #include "dns.hh" | |
e5b11b2f | 39 | #include <vector> |
10f4eea8 | 40 | #include "namespaces.hh" |
6cc98ddf | 41 | #include "comment.hh" |
675fa24c | 42 | #include "dnsname.hh" |
28e2e78e | 43 | #include "dnsrecords.hh" |
a2dfc9ea | 44 | #include "iputils.hh" |
76979e74 | 45 | |
12c86877 BH |
46 | class DNSBackend; |
47 | struct DomainInfo | |
48 | { | |
f82ed9fc | 49 | DomainInfo() : last_check(0), backend(NULL), id(0), notified_serial(0), serial(0), kind(DomainInfo::Native) {} |
52ff1db1 | 50 | |
675fa24c | 51 | DNSName zone; |
12c86877 | 52 | time_t last_check; |
8ffb7a9b | 53 | string account; |
d622042f | 54 | vector<ComboAddress> masters; |
12c86877 | 55 | DNSBackend *backend; |
52ff1db1 PL |
56 | |
57 | uint32_t id; | |
58 | uint32_t notified_serial; | |
59 | ||
60 | uint32_t serial; | |
61 | enum DomainKind : uint8_t { Master, Slave, Native } kind; | |
7f3d870e BH |
62 | |
63 | bool operator<(const DomainInfo& rhs) const | |
64 | { | |
65 | return zone < rhs.zone; | |
66 | } | |
ec10217f CH |
67 | |
68 | const char *getKindString() const | |
76979e74 CH |
69 | { |
70 | return DomainInfo::getKindString(kind); | |
71 | } | |
72 | ||
73 | static const char *getKindString(enum DomainKind kind) | |
ec10217f CH |
74 | { |
75 | const char *kinds[]={"Master", "Slave", "Native"}; | |
76 | return kinds[kind]; | |
77 | } | |
76979e74 CH |
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 | ||
2f538e82 | 89 | bool isMaster(const ComboAddress& ip) const |
a2dfc9ea KM |
90 | { |
91 | for( const auto& master: masters) { | |
f43e6a40 | 92 | if(ComboAddress::addressOnlyEqual()(ip, master)) |
a2dfc9ea KM |
93 | return true; |
94 | } | |
95 | return false; | |
96 | } | |
97 | ||
12c86877 BH |
98 | }; |
99 | ||
6f872b78 | 100 | struct TSIGKey { |
675fa24c PD |
101 | DNSName name; |
102 | DNSName algorithm; | |
6f872b78 AT |
103 | std::string key; |
104 | }; | |
105 | ||
12c86877 | 106 | class DNSPacket; |
bdc9f8d2 | 107 | |
35520716 | 108 | //! This virtual base class defines the interface for backends for PowerDNS. |
bdc9f8d2 BH |
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 | |
3f81d239 | 116 | lead to the throwing of an PDNSException. This exception will fall straight through the UeberBackend and the PacketHandler |
bdc9f8d2 BH |
117 | and be caught by the Distributor, which will delete your DNSBackend instance and spawn a new one. |
118 | */ | |
12c86877 BH |
119 | class DNSBackend |
120 | { | |
121 | public: | |
bdc9f8d2 | 122 | //! lookup() initiates a lookup. A lookup without results should not throw! |
acb61e0a | 123 | virtual void lookup(const QType &qtype, const DNSName &qdomain, int zoneId=-1, DNSPacket *pkt_p=nullptr)=0; |
bdc9f8d2 | 124 | virtual bool get(DNSResourceRecord &)=0; //!< retrieves one DNSResource record, returns false if no more were available |
90ba52e0 | 125 | virtual bool get(DNSZoneRecord &r); |
702b226d | 126 | |
bdc9f8d2 BH |
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 | */ | |
675fa24c | 132 | virtual bool list(const DNSName &target, int domain_id, bool include_disabled=false)=0; |
12c86877 BH |
133 | |
134 | virtual ~DNSBackend(){}; | |
135 | ||
bdc9f8d2 | 136 | //! fills the soadata struct with the SOA details. Returns false if there is no SOA. |
76e1255a | 137 | virtual bool getSOA(const DNSName &name, SOAData &soadata); |
d07fc616 | 138 | |
675fa24c | 139 | virtual bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset) |
8bbb6f36 BH |
140 | { |
141 | return false; | |
142 | } | |
143 | ||
675fa24c | 144 | virtual bool listSubZone(const DNSName &zone, int domain_id) |
6a323f63 RA |
145 | { |
146 | return false; | |
147 | } | |
148 | ||
4aafcb39 | 149 | // the DNSSEC related (getDomainMetadata has broader uses too) |
ad34750d KM |
150 | bool isDnssecDomainMetadata (const string& name) { |
151 | return (name == "PRESIGNED" || name == "NSEC3PARAM" || name == "NSEC3NARROW"); | |
152 | } | |
675fa24c PD |
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) | |
d29d5db7 CH |
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 | ||
675fa24c PD |
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) | |
d29d5db7 CH |
169 | { |
170 | const std::vector<std::string> meta(1, value); | |
171 | return setDomainMetadata(name, kind, meta); | |
172 | } | |
173 | ||
4aafcb39 | 174 | |
cea26350 | 175 | virtual void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false) { } |
1325e8a2 | 176 | |
c14bc34a | 177 | /** Determines if we are authoritative for a zone, and at what level */ |
cec52de6 | 178 | virtual bool getAuth(const DNSName &target, SOAData *sd); |
c14bc34a | 179 | |
4aafcb39 | 180 | struct KeyData { |
eda140fa | 181 | std::string content; |
4aafcb39 BH |
182 | unsigned int id; |
183 | unsigned int flags; | |
184 | bool active; | |
33918299 | 185 | bool published; |
4aafcb39 BH |
186 | }; |
187 | ||
9c1c5d49 | 188 | virtual bool getDomainKeys(const DNSName& name, std::vector<KeyData>& keys) { return false;} |
675fa24c | 189 | virtual bool removeDomainKey(const DNSName& name, unsigned int id) { return false; } |
82cc0761 | 190 | virtual bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id){ return false; } |
675fa24c PD |
191 | virtual bool activateDomainKey(const DNSName& name, unsigned int id) { return false; } |
192 | virtual bool deactivateDomainKey(const DNSName& name, unsigned int id) { return false; } | |
33918299 RG |
193 | virtual bool publishDomainKey(const DNSName& name, unsigned int id) { return false; } |
194 | virtual bool unpublishDomainKey(const DNSName& name, unsigned int id) { return false; } | |
8ab63616 | 195 | |
675fa24c PD |
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; } | |
6f872b78 | 199 | virtual bool getTSIGKeys(std::vector< struct TSIGKey > &keys) { return false; } |
78bcb858 | 200 | |
29e0008a | 201 | virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) |
4aafcb39 BH |
202 | { |
203 | std::cerr<<"Default beforeAndAfterAbsolute called!"<<std::endl; | |
204 | abort(); | |
205 | return false; | |
206 | } | |
207 | ||
675fa24c | 208 | virtual bool getBeforeAndAfterNames(uint32_t id, const DNSName& zonename, const DNSName& qname, DNSName& before, DNSName& after); |
4aafcb39 | 209 | |
96e63d77 | 210 | virtual bool updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype=QType::ANY) |
4aafcb39 BH |
211 | { |
212 | return false; | |
213 | } | |
214 | ||
96e63d77 | 215 | virtual bool updateEmptyNonTerminals(uint32_t domain_id, set<DNSName>& insert, set<DNSName>& erase, bool remove) |
c2df797e PD |
216 | { |
217 | return false; | |
218 | } | |
219 | ||
ece45ffb PD |
220 | virtual bool doesDNSSEC() |
221 | { | |
222 | return false; | |
223 | } | |
224 | ||
4aafcb39 BH |
225 | // end DNSSEC |
226 | ||
6cc98ddf CH |
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 | ||
675fa24c | 242 | virtual bool replaceComments(const uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<Comment>& comments) |
6cc98ddf CH |
243 | { |
244 | return false; | |
245 | } | |
246 | ||
bdc9f8d2 | 247 | //! returns true if master ip is master for domain name. |
bdc9f8d2 | 248 | //! starts the transaction for updating domain qname (FIXME: what is id?) |
675fa24c | 249 | virtual bool startTransaction(const DNSName &qname, int id=-1) |
12c86877 BH |
250 | { |
251 | return false; | |
252 | } | |
253 | ||
bdc9f8d2 | 254 | //! commits the transaction started by startTransaction |
12c86877 BH |
255 | virtual bool commitTransaction() |
256 | { | |
257 | return false; | |
258 | } | |
259 | ||
bdc9f8d2 | 260 | //! aborts the transaction started by strartTransaction, should leave state unaltered |
12c86877 BH |
261 | virtual bool abortTransaction() |
262 | { | |
263 | return false; | |
264 | } | |
265 | ||
266 | virtual void reload() | |
267 | { | |
268 | } | |
269 | ||
973ad2b5 | 270 | virtual void rediscover(string* status=0) |
12c86877 BH |
271 | { |
272 | } | |
273 | ||
bdc9f8d2 | 274 | //! feeds a record to a zone, needs a call to startTransaction first |
3bb3f561 | 275 | virtual bool feedRecord(const DNSResourceRecord &rr, const DNSName &ordername, bool ordernameIsNSEC3=false) |
12c86877 BH |
276 | { |
277 | return false; // no problem! | |
278 | } | |
675fa24c | 279 | virtual bool feedEnts(int domain_id, map<DNSName,bool> &nonterm) |
f9cf6d92 KM |
280 | { |
281 | return false; | |
282 | } | |
28e2e78e | 283 | virtual bool feedEnts3(int domain_id, const DNSName &domain, map<DNSName,bool> &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) |
f9cf6d92 KM |
284 | { |
285 | return false; | |
286 | } | |
287 | ||
bdc9f8d2 | 288 | //! if this returns true, DomainInfo di contains information about the domain |
47bddbb7 | 289 | virtual bool getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial=true) |
12c86877 BH |
290 | { |
291 | return false; | |
292 | } | |
bdc9f8d2 | 293 | //! slave capable backends should return a list of slaves that should be rechecked for staleness |
12c86877 BH |
294 | virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains) |
295 | { | |
296 | } | |
297 | ||
bdc9f8d2 | 298 | //! get a list of IP addresses that should also be notified for a domain |
675fa24c | 299 | virtual void alsoNotifies(const DNSName &domain, set<string> *ips) |
12c86877 BH |
300 | { |
301 | } | |
bdc9f8d2 BH |
302 | |
303 | //! get list of domains that have been changed since their last notification to slaves | |
12c86877 BH |
304 | virtual void getUpdatedMasters(vector<DomainInfo>* domains) |
305 | { | |
306 | } | |
bdc9f8d2 BH |
307 | |
308 | //! Called by PowerDNS to inform a backend that a domain has been checked for freshness | |
092f210a | 309 | virtual void setFresh(uint32_t domain_id) |
12c86877 BH |
310 | { |
311 | ||
312 | } | |
bdc9f8d2 | 313 | //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to slaves |
092f210a | 314 | virtual void setNotified(uint32_t id, uint32_t serial) |
12c86877 BH |
315 | { |
316 | } | |
317 | ||
6d58359c | 318 | //! Called when the Master of a domain should be changed |
675fa24c | 319 | virtual bool setMaster(const DNSName &domain, const string &ip) |
6d58359c CH |
320 | { |
321 | return false; | |
322 | } | |
323 | ||
324 | //! Called when the Kind of a domain should be changed (master -> native and similar) | |
675fa24c | 325 | virtual bool setKind(const DNSName &domain, const DomainInfo::DomainKind kind) |
6d58359c CH |
326 | { |
327 | return false; | |
328 | } | |
329 | ||
79532aa7 | 330 | //! Called when the Account of a domain should be changed |
675fa24c | 331 | virtual bool setAccount(const DNSName &domain, const string &account) |
79532aa7 CH |
332 | { |
333 | return false; | |
334 | } | |
335 | ||
bdc9f8d2 | 336 | //! Can be called to seed the getArg() function with a prefix |
12c86877 | 337 | void setArgPrefix(const string &prefix); |
bdc9f8d2 BH |
338 | |
339 | //! determine if ip is a supermaster or a domain | |
675fa24c | 340 | virtual bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db) |
12c86877 BH |
341 | { |
342 | return false; | |
343 | } | |
bdc9f8d2 | 344 | |
487cf033 | 345 | //! called by PowerDNS to create a new domain |
675fa24c | 346 | virtual bool createDomain(const DNSName &domain) |
487cf033 CH |
347 | { |
348 | return false; | |
349 | } | |
350 | ||
bdc9f8d2 | 351 | //! called by PowerDNS to create a slave record for a superMaster |
675fa24c | 352 | virtual bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account) |
12c86877 BH |
353 | { |
354 | return false; | |
355 | } | |
356 | ||
44e62984 | 357 | //! called to delete a domain, incl. all metadata, zone contents, etc. |
675fa24c | 358 | virtual bool deleteDomain(const DNSName &domain) |
44e62984 CH |
359 | { |
360 | return false; | |
361 | } | |
362 | ||
f641c3b7 PD |
363 | virtual string directBackendCmd(const string &query) |
364 | { | |
365 | return "directBackendCmd not supported for this backend\n"; | |
366 | } | |
367 | ||
9f8e226e AT |
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 | ||
ece1aa0b | 380 | const string& getPrefix() { return d_prefix; }; |
12c86877 BH |
381 | protected: |
382 | bool mustDo(const string &key); | |
383 | const string &getArg(const string &key); | |
384 | int getArgAsNum(const string &key); | |
12c86877 BH |
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; | |
2717b8b3 BH |
396 | virtual DNSBackend *makeMetadataOnly(const string &suffix) |
397 | { | |
398 | return this->make(suffix); | |
399 | } | |
12c86877 BH |
400 | virtual void declareArguments(const string &suffix=""){} |
401 | const string &getName() const; | |
402 | ||
403 | protected: | |
404 | void declare(const string &suffix, const string ¶m, 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); | |
e0d84497 | 415 | vector<DNSBackend *>all(bool skipBIND=false); |
12c86877 BH |
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 | ||
bdc9f8d2 | 429 | //! Exception that can be thrown by a DNSBackend to indicate a failure |
3f81d239 | 430 | class DBException : public PDNSException |
cc3afe25 BH |
431 | { |
432 | public: | |
dd079764 | 433 | DBException(const string &reason_) : PDNSException(reason_){} |
cc3afe25 BH |
434 | }; |
435 | ||
ceea1ba6 | 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); | |
90ba52e0 | 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); |