]>
Commit | Line | Data |
---|---|---|
b532a4b1 | 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 | */ | |
b532a4b1 | 22 | |
680f25f8 RK |
23 | #ifndef PDNS_BINDBACKEND_HH |
24 | #define PDNS_BINDBACKEND_HH | |
25 | ||
b532a4b1 BH |
26 | #include <string> |
27 | #include <map> | |
28 | #include <set> | |
29 | #include <pthread.h> | |
30 | #include <time.h> | |
31 | #include <fstream> | |
7fff09ac | 32 | #include <mutex> |
df39b849 | 33 | #include <boost/utility.hpp> |
dd7da6cd | 34 | |
945a9ad4 BH |
35 | #include <boost/tuple/tuple.hpp> |
36 | #include <boost/tuple/tuple_comparison.hpp> | |
772e8b10 | 37 | #include <boost/multi_index_container.hpp> |
94364112 | 38 | #include <boost/multi_index/hashed_index.hpp> |
772e8b10 BH |
39 | #include <boost/multi_index/ordered_index.hpp> |
40 | #include <boost/multi_index/identity.hpp> | |
41 | #include <boost/multi_index/member.hpp> | |
82f7b3cc BH |
42 | #include <sys/types.h> |
43 | #include <sys/stat.h> | |
44 | #include <unistd.h> | |
f08339e3 | 45 | #include "pdns/lock.hh" |
e53a4bf6 KM |
46 | #include "pdns/misc.hh" |
47 | #include "pdns/dnsbackend.hh" | |
e53a4bf6 | 48 | #include "pdns/namespaces.hh" |
0f310932 AT |
49 | #include "pdns/backends/gsql/ssql.hh" |
50 | ||
772e8b10 | 51 | using namespace ::boost::multi_index; |
b532a4b1 | 52 | |
e44d76b6 KM |
53 | /** |
54 | This struct is used within the Bind2Backend to store DNS information. It is | |
55 | almost identical to a DNSResourceRecord, but then a bit smaller and with | |
56 | different sorting rules, which make sure that the SOA record comes up front. | |
95c22a8f | 57 | */ |
e44d76b6 | 58 | |
9b145472 BH |
59 | struct Bind2DNSRecord |
60 | { | |
c77d4725 | 61 | DNSName qname; |
ced82662 | 62 | string content; |
772e8b10 | 63 | string nsec3hash; |
8e16b978 | 64 | uint32_t ttl; |
ced82662 | 65 | uint16_t qtype; |
b9bafae0 | 66 | mutable bool auth; |
9b145472 BH |
67 | bool operator<(const Bind2DNSRecord& rhs) const |
68 | { | |
dc1fb060 | 69 | if(qname.canonCompare(rhs.qname)) |
7b308b7e | 70 | return true; |
dc1fb060 | 71 | if(rhs.qname.canonCompare(qname)) |
7b308b7e BH |
72 | return false; |
73 | if(qtype==QType::SOA && rhs.qtype!=QType::SOA) | |
74 | return true; | |
945a9ad4 | 75 | return tie(qtype,content, ttl) < tie(rhs.qtype, rhs.content, rhs.ttl); |
9b145472 BH |
76 | } |
77 | }; | |
b532a4b1 | 78 | |
21a0a2ae BH |
79 | struct Bind2DNSCompare : std::less<Bind2DNSRecord> |
80 | { | |
81 | using std::less<Bind2DNSRecord>::operator(); | |
82 | // use operator< | |
c77d4725 | 83 | bool operator() (const DNSName& a, const Bind2DNSRecord& b) const |
dc1fb060 | 84 | {return a.canonCompare(b.qname);} |
c77d4725 | 85 | bool operator() (const Bind2DNSRecord& a, const DNSName& b) const |
dc1fb060 | 86 | {return a.qname.canonCompare(b);} |
21a0a2ae | 87 | bool operator() (const Bind2DNSRecord& a, const Bind2DNSRecord& b) const |
dc1fb060 | 88 | {return a.qname.canonCompare(b.qname);} |
c77d4725 | 89 | }; |
772e8b10 | 90 | |
94364112 | 91 | struct NSEC3Tag{}; |
92 | struct UnorderedNameTag{}; | |
772e8b10 BH |
93 | |
94 | typedef multi_index_container< | |
95 | Bind2DNSRecord, | |
96 | indexed_by < | |
e44d76b6 | 97 | ordered_non_unique<identity<Bind2DNSRecord>, Bind2DNSCompare >, |
94364112 | 98 | hashed_non_unique<tag<UnorderedNameTag>, member<Bind2DNSRecord, DNSName, &Bind2DNSRecord::qname> >, |
99 | ordered_non_unique<tag<NSEC3Tag>, member<Bind2DNSRecord, std::string, &Bind2DNSRecord::nsec3hash> > | |
772e8b10 BH |
100 | > |
101 | > recordstorage_t; | |
95c22a8f | 102 | |
f08339e3 | 103 | template <typename T> |
104 | class LookButDontTouch // : public boost::noncopyable | |
105 | { | |
106 | public: | |
7fff09ac | 107 | LookButDontTouch() |
f08339e3 | 108 | { |
f08339e3 | 109 | } |
110 | LookButDontTouch(shared_ptr<T> records) : d_records(records) | |
111 | { | |
f08339e3 | 112 | } |
113 | ||
114 | shared_ptr<const T> get() | |
115 | { | |
116 | shared_ptr<const T> ret; | |
117 | { | |
7fff09ac | 118 | std::lock_guard<std::mutex> lock(s_lock); |
f08339e3 | 119 | ret = d_records; |
120 | } | |
121 | return ret; | |
122 | } | |
123 | ||
e640604f RG |
124 | size_t getEntriesCount() const |
125 | { | |
126 | std::lock_guard<std::mutex> lock(s_lock); | |
127 | return d_records->size(); | |
128 | } | |
129 | ||
f08339e3 | 130 | private: |
7fff09ac | 131 | static std::mutex s_lock; |
f08339e3 | 132 | shared_ptr<T> d_records; |
133 | }; | |
134 | ||
135 | ||
95c22a8f | 136 | /** Class which describes all metadata of a domain for storage by the Bind2Backend, and also contains a pointer to a vector of Bind2DNSRecord's */ |
b532a4b1 BH |
137 | class BB2DomainInfo |
138 | { | |
139 | public: | |
140 | BB2DomainInfo(); | |
b532a4b1 | 141 | void setCtime(); |
b532a4b1 | 142 | bool current(); |
a3047110 BH |
143 | //! configure how often this domain should be checked for changes (on disk) |
144 | void setCheckInterval(time_t seconds); | |
e640604f RG |
145 | time_t getCheckInterval() const |
146 | { | |
147 | return d_checkinterval; | |
148 | } | |
b532a4b1 | 149 | |
c77d4725 | 150 | DNSName d_name; //!< actual name of the domain |
bc67ec22 | 151 | DomainInfo::DomainKind d_kind; //!< the kind of domain |
95c22a8f | 152 | string d_filename; //!< full absolute filename of the zone on disk |
6b6c39de | 153 | string d_status; //!< message describing status of a domain, for human consumption |
d622042f | 154 | vector<ComboAddress> d_masters; //!< IP address of the master of this domain |
27d94a79 | 155 | set<string> d_also_notify; //!< IP list of hosts to also notify |
6b6c39de | 156 | LookButDontTouch<recordstorage_t> d_records; //!< the actual records belonging to this domain |
e10d80f9 RG |
157 | time_t d_ctime{0}; //!< last known ctime of the file on disk |
158 | time_t d_lastcheck{0}; //!< last time domain was checked for freshness | |
159 | uint32_t d_lastnotified{0}; //!< Last serial number we notified our slaves of | |
6b6c39de PL |
160 | unsigned int d_id; //!< internal id of the domain |
161 | mutable bool d_checknow; //!< if this domain has been flagged for a check | |
162 | bool d_loaded; //!< if a domain is loaded | |
c539d857 | 163 | bool d_wasRejectedLastReload{false}; //!< if the domain was rejected during Bind2Backend::queueReloadAndStore |
95c22a8f | 164 | |
b532a4b1 BH |
165 | private: |
166 | time_t getCtime(); | |
167 | time_t d_checkinterval; | |
b532a4b1 | 168 | }; |
b532a4b1 | 169 | |
2717b8b3 BH |
170 | class SSQLite3; |
171 | class NSEC3PARAMRecordContent; | |
172 | ||
b755d50a | 173 | struct NameTag |
174 | {}; | |
175 | ||
b532a4b1 BH |
176 | class Bind2Backend : public DNSBackend |
177 | { | |
178 | public: | |
2717b8b3 | 179 | Bind2Backend(const string &suffix="", bool loadZones=true); |
2a95d1df | 180 | ~Bind2Backend(); |
d57d7155 KM |
181 | void getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains) override; |
182 | void getUpdatedMasters(vector<DomainInfo> *changedDomains) override; | |
47bddbb7 | 183 | bool getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial=true ) override; |
b532a4b1 | 184 | time_t getCtime(const string &fname); |
a1c4d85c | 185 | // DNSSEC |
d57d7155 | 186 | bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) override; |
acb61e0a | 187 | void lookup(const QType &, const DNSName &qdomain, int zoneId, DNSPacket *p=nullptr) override; |
d57d7155 KM |
188 | bool list(const DNSName &target, int id, bool include_disabled=false) override; |
189 | bool get(DNSResourceRecord &) override; | |
190 | void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false) override; | |
b532a4b1 BH |
191 | |
192 | static DNSBackend *maker(); | |
193 | static pthread_mutex_t s_startup_lock; | |
194 | ||
d57d7155 KM |
195 | void setFresh(uint32_t domain_id) override; |
196 | void setNotified(uint32_t id, uint32_t serial) override; | |
197 | bool startTransaction(const DNSName &qname, int id) override; | |
3bb3f561 | 198 | bool feedRecord(const DNSResourceRecord &rr, const DNSName &ordername, bool ordernameIsNSEC3=false) override; |
d57d7155 KM |
199 | bool commitTransaction() override; |
200 | bool abortTransaction() override; | |
201 | void alsoNotifies(const DNSName &domain, set<string> *ips) override; | |
202 | bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result) override; | |
27d94a79 | 203 | |
2717b8b3 | 204 | // the DNSSEC related (getDomainMetadata has broader uses too) |
d57d7155 KM |
205 | bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta) override; |
206 | bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override; | |
207 | bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) override; | |
208 | bool getDomainKeys(const DNSName& name, std::vector<KeyData>& keys) override; | |
209 | bool removeDomainKey(const DNSName& name, unsigned int id) override; | |
210 | bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id) override; | |
211 | bool activateDomainKey(const DNSName& name, unsigned int id) override; | |
212 | bool deactivateDomainKey(const DNSName& name, unsigned int id) override; | |
33918299 RG |
213 | bool publishDomainKey(const DNSName& name, unsigned int id) override; |
214 | bool unpublishDomainKey(const DNSName& name, unsigned int id) override; | |
d57d7155 KM |
215 | bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) override; |
216 | bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) override; | |
217 | bool deleteTSIGKey(const DNSName& name) override; | |
218 | bool getTSIGKeys(std::vector< struct TSIGKey > &keys) override; | |
219 | bool doesDNSSEC() override; | |
2717b8b3 BH |
220 | // end of DNSSEC |
221 | ||
f08339e3 | 222 | typedef multi_index_container < BB2DomainInfo , |
223 | indexed_by < ordered_unique<member<BB2DomainInfo, unsigned int, &BB2DomainInfo::d_id> >, | |
c77d4725 | 224 | ordered_unique<tag<NameTag>, member<BB2DomainInfo, DNSName, &BB2DomainInfo::d_name> > |
f08339e3 | 225 | > > state_t; |
226 | static state_t s_state; | |
227 | static pthread_rwlock_t s_state_lock; | |
cecc5075 | 228 | |
f08339e3 | 229 | void parseZoneFile(BB2DomainInfo *bbd); |
7b4a8993 | 230 | void rediscover(string *status=nullptr) override; |
b532a4b1 | 231 | |
f404b863 BH |
232 | |
233 | // for supermaster support | |
e217b913 | 234 | bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db) override; |
8168957d | 235 | static pthread_mutex_t s_supermaster_config_lock; |
e217b913 | 236 | bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account) override; |
a31fe060 | 237 | |
b532a4b1 | 238 | private: |
2717b8b3 | 239 | void setupDNSSEC(); |
0f310932 AT |
240 | void setupStatements(); |
241 | void freeStatements(); | |
f08339e3 | 242 | static bool safeGetBBDomainInfo(int id, BB2DomainInfo* bbd); |
b755d50a | 243 | static void safePutBBDomainInfo(const BB2DomainInfo& bbd); |
c77d4725 AT |
244 | static bool safeGetBBDomainInfo(const DNSName& name, BB2DomainInfo* bbd); |
245 | static bool safeRemoveBBDomainInfo(const DNSName& name); | |
2717b8b3 | 246 | shared_ptr<SSQLite3> d_dnssecdb; |
e44d76b6 | 247 | bool getNSEC3PARAM(const DNSName& name, NSEC3PARAMRecordContent* ns3p); |
b532a4b1 BH |
248 | class handle |
249 | { | |
250 | public: | |
251 | bool get(DNSResourceRecord &); | |
a3047110 BH |
252 | void reset(); |
253 | ||
b532a4b1 BH |
254 | handle(); |
255 | ||
f08339e3 | 256 | shared_ptr<const recordstorage_t > d_records; |
94364112 | 257 | recordstorage_t::index<UnorderedNameTag>::type::const_iterator d_iter, d_end_iter; |
258 | ||
259 | recordstorage_t::const_iterator d_qname_iter, d_qname_end; | |
260 | ||
c77d4725 AT |
261 | DNSName qname; |
262 | DNSName domain; | |
39e58bff | 263 | |
eef653be | 264 | int id; |
b532a4b1 | 265 | QType qtype; |
eef653be | 266 | bool d_list; |
38e655b6 BH |
267 | bool mustlog; |
268 | ||
b532a4b1 | 269 | private: |
b532a4b1 BH |
270 | bool get_normal(DNSResourceRecord &); |
271 | bool get_list(DNSResourceRecord &); | |
69ab97d1 BH |
272 | |
273 | void operator=(const handle& ); // don't go copying this | |
274 | handle(const handle &); | |
b532a4b1 BH |
275 | }; |
276 | ||
a59a9c23 AT |
277 | unique_ptr<SSqlStatement> d_getAllDomainMetadataQuery_stmt; |
278 | unique_ptr<SSqlStatement> d_getDomainMetadataQuery_stmt; | |
279 | unique_ptr<SSqlStatement> d_deleteDomainMetadataQuery_stmt; | |
280 | unique_ptr<SSqlStatement> d_insertDomainMetadataQuery_stmt; | |
281 | unique_ptr<SSqlStatement> d_getDomainKeysQuery_stmt; | |
282 | unique_ptr<SSqlStatement> d_deleteDomainKeyQuery_stmt; | |
283 | unique_ptr<SSqlStatement> d_insertDomainKeyQuery_stmt; | |
284 | unique_ptr<SSqlStatement> d_GetLastInsertedKeyIdQuery_stmt; | |
285 | unique_ptr<SSqlStatement> d_activateDomainKeyQuery_stmt; | |
286 | unique_ptr<SSqlStatement> d_deactivateDomainKeyQuery_stmt; | |
33918299 RG |
287 | unique_ptr<SSqlStatement> d_publishDomainKeyQuery_stmt; |
288 | unique_ptr<SSqlStatement> d_unpublishDomainKeyQuery_stmt; | |
a59a9c23 AT |
289 | unique_ptr<SSqlStatement> d_getTSIGKeyQuery_stmt; |
290 | unique_ptr<SSqlStatement> d_setTSIGKeyQuery_stmt; | |
291 | unique_ptr<SSqlStatement> d_deleteTSIGKeyQuery_stmt; | |
292 | unique_ptr<SSqlStatement> d_getTSIGKeysQuery_stmt; | |
5b15d4d3 | 293 | |
39e58bff | 294 | string d_transaction_tmpname; |
b532a4b1 | 295 | string d_logprefix; |
27d94a79 | 296 | set<string> alsoNotify; //!< this is used to store the also-notify list of interested peers. |
7cfe0cc3 | 297 | std::unique_ptr<ofstream> d_of; |
7b308b7e | 298 | handle d_handle; |
39e58bff PL |
299 | static string s_binddirectory; //!< this is used to store the 'directory' setting of the bind configuration |
300 | static int s_first; //!< this is raised on construction to prevent multiple instances of us being generated | |
301 | int d_transaction_id; | |
302 | static bool s_ignore_broken_records; | |
303 | bool d_hybrid; | |
304 | ||
0b6fa0eb | 305 | BB2DomainInfo createDomainEntry(const DNSName& domain, const string &filename); //!< does not insert in s_state |
95c22a8f | 306 | |
aaf2e4a4 | 307 | void queueReloadAndStore(unsigned int id); |
7b4a8993 RG |
308 | static bool findBeforeAndAfterUnhashed(std::shared_ptr<const recordstorage_t>& records, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after); |
309 | static void insertRecord(std::shared_ptr<recordstorage_t>& records, const DNSName& zoneName, const DNSName &qname, const QType &qtype, const string &content, int ttl, const std::string& hashed=string(), bool *auth=nullptr); | |
e217b913 | 310 | void reload() override; |
b532a4b1 | 311 | static string DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid); |
e640604f | 312 | static string DLDomExtendedStatusHandler(const vector<string>&parts, Utility::pid_t ppid); |
b532a4b1 BH |
313 | static string DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid); |
314 | static string DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid); | |
a31fe060 | 315 | static string DLAddDomainHandler(const vector<string>&parts, Utility::pid_t ppid); |
7b4a8993 RG |
316 | static void fixupOrderAndAuth(std::shared_ptr<recordstorage_t>& records, const DNSName& zoneName, bool nsec3zone, NSEC3PARAMRecordContent ns3pr); |
317 | static void doEmptyNonTerminals(std::shared_ptr<recordstorage_t>& records, const DNSName& zoneName, bool nsec3zone, NSEC3PARAMRecordContent ns3pr); | |
318 | void loadConfig(string *status=nullptr); | |
b532a4b1 | 319 | }; |
680f25f8 RK |
320 | |
321 | #endif /* PDNS_BINDBACKEND_HH */ |