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