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