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