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 <pthread.h> 24 #include <string> 25 #include <semaphore.h> 26 #include <queue> 27 #include <list> 28 #include <limits> 29 #include <boost/multi_index_container.hpp> 30 #include <boost/multi_index/identity.hpp> 31 #include <boost/multi_index/sequenced_index.hpp> 32 using namespace boost::multi_index; 33 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <netdb.h> 37 38 #include "lock.hh" 39 #include "packethandler.hh" 40 41 #include "namespaces.hh" 42 #include "dns_random.hh" 43 44 struct SuckRequest 45 { 46 DNSName domain; 47 ComboAddress master; 48 bool force; 49 enum RequestPriority : uint8_t { PdnsControl, Api, Notify, SerialRefresh, SignaturesRefresh }; 50 std::pair<RequestPriority, uint64_t> priorityAndOrder; operator <SuckRequest51 bool operator<(const SuckRequest& b) const 52 { 53 return tie(domain, master) < tie(b.domain, b.master); 54 } 55 }; 56 57 struct IDTag{}; 58 59 typedef multi_index_container< 60 SuckRequest, 61 indexed_by< 62 ordered_unique<member<SuckRequest,std::pair<SuckRequest::RequestPriority,uint64_t>,&SuckRequest::priorityAndOrder>>, 63 ordered_unique<tag<IDTag>, identity<SuckRequest> > 64 > 65 > UniQueue; 66 typedef UniQueue::index<IDTag>::type domains_by_name_t; 67 68 class NotificationQueue 69 { 70 public: add(const DNSName & domain,const string & ip)71 void add(const DNSName &domain, const string &ip) 72 { 73 const ComboAddress caIp(ip); 74 75 NotificationRequest nr; 76 nr.domain = domain; 77 nr.ip = caIp.toStringWithPort(); 78 nr.attempts = 0; 79 nr.id = dns_random_uint16(); 80 nr.next = time(0); 81 82 d_nqueue.push_back(nr); 83 } 84 removeIf(const string & remote,uint16_t id,const DNSName & domain)85 bool removeIf(const string &remote, uint16_t id, const DNSName &domain) 86 { 87 ServiceTuple stRemote, stQueued; 88 parseService(remote, stRemote); 89 90 for(d_nqueue_t::iterator i=d_nqueue.begin(); i!=d_nqueue.end(); ++i) { 91 parseService(i->ip, stQueued); 92 if(i->id==id && stQueued.host == stRemote.host && i->domain==domain) { 93 d_nqueue.erase(i); 94 return true; 95 } 96 } 97 return false; 98 } 99 getOne(DNSName & domain,string & ip,uint16_t * id,bool & purged)100 bool getOne(DNSName &domain, string &ip, uint16_t *id, bool &purged) 101 { 102 for(d_nqueue_t::iterator i=d_nqueue.begin();i!=d_nqueue.end();++i) 103 if(i->next <= time(0)) { 104 i->attempts++; 105 purged=false; 106 i->next=time(0)+1+(1<<i->attempts); 107 domain=i->domain; 108 ip=i->ip; 109 *id=i->id; 110 purged=false; 111 if(i->attempts>4) { 112 purged=true; 113 d_nqueue.erase(i); 114 } 115 return true; 116 } 117 return false; 118 } 119 earliest()120 time_t earliest() 121 { 122 time_t early=std::numeric_limits<time_t>::max() - 1; 123 for(d_nqueue_t::const_iterator i=d_nqueue.begin();i!=d_nqueue.end();++i) 124 early=min(early,i->next); 125 return early-time(0); 126 } 127 128 void dump(); 129 130 private: 131 struct NotificationRequest 132 { 133 DNSName domain; 134 string ip; 135 time_t next; 136 int attempts; 137 uint16_t id; 138 }; 139 140 typedef std::list<NotificationRequest> d_nqueue_t; 141 d_nqueue_t d_nqueue; 142 143 }; 144 145 struct ZoneStatus; 146 147 /** this class contains a thread that communicates with other nameserver and does housekeeping. 148 Initially, it is notified only of zones that need to be pulled in because they have been updated. */ 149 150 class CommunicatorClass 151 { 152 public: CommunicatorClass()153 CommunicatorClass() 154 { 155 d_tickinterval=60; 156 d_masterschanged=d_slaveschanged=true; 157 d_nsock4 = -1; 158 d_nsock6 = -1; 159 d_preventSelfNotification = false; 160 d_sorthelper = 0; 161 } 162 time_t doNotifications(PacketHandler *P); 163 void go(); 164 165 166 void drillHole(const DNSName &domain, const string &ip); 167 bool justNotified(const DNSName &domain, const string &ip); 168 void addSuckRequest(const DNSName &domain, const ComboAddress& master, SuckRequest::RequestPriority, bool force=false); 169 void addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote); 170 void addTrySuperMasterRequest(const DNSPacket& p); 171 void notify(const DNSName &domain, const string &ip); 172 void mainloop(); 173 void retrievalLoopThread(); 174 void sendNotification(int sock, const DNSName &domain, const ComboAddress& remote, uint16_t id, UeberBackend* B); 175 bool notifyDomain(const DNSName &domain, UeberBackend* B); 176 vector<pair<DNSName, ComboAddress> > getSuckRequests(); 177 size_t getSuckRequestsWaiting(); 178 private: 179 void loadArgsIntoSet(const char *listname, set<string> &listset); 180 void makeNotifySockets(); 181 void queueNotifyDomain(const DomainInfo& di, UeberBackend* B); 182 int d_nsock4, d_nsock6; 183 map<pair<DNSName,string>,time_t>d_holes; 184 std::mutex d_holelock; 185 void suck(const DNSName &domain, const ComboAddress& remote, bool force=false); 186 void ixfrSuck(const DNSName &domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, std::unique_ptr<AuthLua4>& pdl, 187 ZoneStatus& zs, vector<DNSRecord>* axfr); 188 189 void slaveRefresh(PacketHandler *P); 190 void masterUpdateCheck(PacketHandler *P); 191 std::mutex d_lock; 192 193 uint64_t d_sorthelper; 194 UniQueue d_suckdomains; 195 set<DNSName> d_inprogress; 196 197 Semaphore d_suck_sem; 198 Semaphore d_any_sem; 199 time_t d_tickinterval; 200 set<DomainInfo> d_tocheck; 201 struct cmp { operator ()CommunicatorClass::cmp202 bool operator()(const DNSPacket& a, const DNSPacket& b) const { 203 return a.qdomain < b.qdomain; 204 }; 205 }; 206 207 std::set<DNSPacket, cmp> d_potentialsupermasters; 208 209 set<string> d_alsoNotify; 210 NotificationQueue d_nq; 211 NetmaskGroup d_onlyNotify; 212 bool d_masterschanged, d_slaveschanged; 213 bool d_preventSelfNotification; 214 215 // Used to keep some state on domains that failed their freshness checks. 216 // uint64_t == counter of the number of failures (increased by 1 every consecutive slave-cycle-interval that the domain fails) 217 // time_t == wait at least until this time before attempting a new check 218 map<DNSName, pair<uint64_t, time_t> > d_failedSlaveRefresh; 219 220 struct RemoveSentinel 221 { RemoveSentinelCommunicatorClass::RemoveSentinel222 explicit RemoveSentinel(const DNSName& dn, CommunicatorClass* cc) : d_dn(dn), d_cc(cc) 223 {} 224 ~RemoveSentinelCommunicatorClass::RemoveSentinel225 ~RemoveSentinel() 226 { 227 try { 228 std::lock_guard<std::mutex> l(d_cc->d_lock); 229 d_cc->d_inprogress.erase(d_dn); 230 } 231 catch(...) { 232 } 233 } 234 DNSName d_dn; 235 CommunicatorClass* d_cc; 236 }; 237 238 }; 239 240 // class that one day might be more than a function to help you get IP addresses for a nameserver 241 class FindNS 242 { 243 public: lookup(const DNSName & name,UeberBackend * b)244 vector<string> lookup(const DNSName &name, UeberBackend *b) 245 { 246 vector<string> addresses; 247 248 this->resolve_name(&addresses, name); 249 250 if(b) { 251 b->lookup(QType(QType::ANY),name,-1); 252 DNSZoneRecord rr; 253 while(b->get(rr)) 254 if(rr.dr.d_type == QType::A || rr.dr.d_type==QType::AAAA) 255 addresses.push_back(rr.dr.d_content->getZoneRepresentation()); // SOL if you have a CNAME for an NS 256 } 257 return addresses; 258 } 259 260 private: resolve_name(vector<string> * addresses,const DNSName & name)261 void resolve_name(vector<string>* addresses, const DNSName& name) 262 { 263 struct addrinfo* res; 264 struct addrinfo hints; 265 memset(&hints, 0, sizeof(hints)); 266 hints.ai_socktype = SOCK_DGRAM; // otherwise we get everything in triplicate (!) 267 for(int n = 0; n < 2; ++n) { 268 hints.ai_family = n ? AF_INET : AF_INET6; 269 ComboAddress remote; 270 remote.sin4.sin_family = AF_INET6; 271 if(!getaddrinfo(name.toString().c_str(), 0, &hints, &res)) { 272 struct addrinfo* address = res; 273 do { 274 if (address->ai_addrlen <= sizeof(remote)) { 275 remote.setSockaddr(address->ai_addr, address->ai_addrlen); 276 addresses->push_back(remote.toString()); 277 } 278 } while((address = address->ai_next)); 279 freeaddrinfo(res); 280 } 281 } 282 } 283 }; 284