]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/communicator.hh
Replace include guard ifdef/define with pragma once
[thirdparty/pdns.git] / pdns / communicator.hh
CommitLineData
12c86877 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 */
e8c59f2d 22#pragma once
12c86877
BH
23#include <pthread.h>
24#include <string>
25#include <semaphore.h>
26#include <queue>
27#include <list>
f1a8bee5 28#include <limits>
dbcb3066
BH
29#include <boost/multi_index_container.hpp>
30#include <boost/multi_index/identity.hpp>
31#include <boost/multi_index/sequenced_index.hpp>
32using namespace boost::multi_index;
1258abe0 33
76473b92
KM
34#include <unistd.h>
35#include <fcntl.h>
36#include <netdb.h>
1258abe0 37
12c86877
BH
38#include "lock.hh"
39#include "packethandler.hh"
40
10f4eea8 41#include "namespaces.hh"
d2116c15 42#include "dns_random.hh"
12c86877
BH
43
44struct SuckRequest
45{
5fca2e23 46 DNSName domain;
d622042f 47 ComboAddress master;
dbcb3066
BH
48 bool operator<(const SuckRequest& b) const
49 {
50 return tie(domain, master) < tie(b.domain, b.master);
51 }
12c86877
BH
52};
53
dbcb3066
BH
54struct IDTag{};
55
56typedef multi_index_container<
57 SuckRequest,
58 indexed_by<
59 sequenced<>,
60 ordered_unique<tag<IDTag>, identity<SuckRequest> >
61 >
62> UniQueue;
a71bee29 63typedef UniQueue::index<IDTag>::type domains_by_name_t;
dbcb3066 64
12c86877
BH
65class NotificationQueue
66{
67public:
5fca2e23 68 void add(const DNSName &domain, const string &ip)
12c86877 69 {
3c8a7112
KM
70 const ComboAddress caIp(ip);
71
1258abe0
BH
72 NotificationRequest nr;
73 nr.domain = domain;
3c8a7112 74 nr.ip = caIp.toStringWithPort();
1258abe0 75 nr.attempts = 0;
a410b176 76 nr.id = dns_random_uint16();
1258abe0 77 nr.next = time(0);
12c86877
BH
78
79 d_nqueue.push_back(nr);
80 }
3c8a7112 81
5fca2e23 82 bool removeIf(const string &remote, uint16_t id, const DNSName &domain)
12c86877 83 {
3c8a7112
KM
84 ServiceTuple stRemote, stQueued;
85 parseService(remote, stRemote);
86
a71bee29 87 for(d_nqueue_t::iterator i=d_nqueue.begin(); i!=d_nqueue.end(); ++i) {
3c8a7112
KM
88 parseService(i->ip, stQueued);
89 if(i->id==id && stQueued.host == stRemote.host && i->domain==domain) {
4957a608
BH
90 d_nqueue.erase(i);
91 return true;
12c86877
BH
92 }
93 }
94 return false;
95 }
96
5fca2e23 97 bool getOne(DNSName &domain, string &ip, uint16_t *id, bool &purged)
12c86877
BH
98 {
99 for(d_nqueue_t::iterator i=d_nqueue.begin();i!=d_nqueue.end();++i)
100 if(i->next <= time(0)) {
4957a608
BH
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;
12c86877
BH
113 }
114 return false;
115 }
3c8a7112 116
12c86877
BH
117 time_t earliest()
118 {
10f4eea8 119 time_t early=std::numeric_limits<time_t>::max() - 1;
12c86877
BH
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 }
3c8a7112 124
2d00c43d 125 void dump();
3c8a7112 126
12c86877
BH
127private:
128 struct NotificationRequest
129 {
5fca2e23 130 DNSName domain;
12c86877 131 string ip;
1c514700 132 time_t next;
12c86877 133 int attempts;
092f210a 134 uint16_t id;
12c86877
BH
135 };
136
a71bee29 137 typedef std::list<NotificationRequest> d_nqueue_t;
12c86877
BH
138 d_nqueue_t d_nqueue;
139
140};
141
3e7dcee6 142struct ZoneStatus;
143
12c86877
BH
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
147class CommunicatorClass
148{
149public:
150 CommunicatorClass()
151 {
152 pthread_mutex_init(&d_lock,0);
153 pthread_mutex_init(&d_holelock,0);
dbcb3066 154
12c86877 155 d_tickinterval=60;
bd11bd1d 156 d_masterschanged=d_slaveschanged=true;
50d471ea
AT
157 d_nsock4 = -1;
158 d_nsock6 = -1;
50d471ea 159 d_preventSelfNotification = false;
12c86877 160 }
3497eb18 161 time_t doNotifications(PacketHandler *P);
dbcb3066
BH
162 void go();
163
164
5fca2e23
PD
165 void drillHole(const DNSName &domain, const string &ip);
166 bool justNotified(const DNSName &domain, const string &ip);
d622042f 167 void addSuckRequest(const DNSName &domain, const ComboAddress& master);
7f3d870e 168 void addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote);
c2826d2e 169 void addTrySuperMasterRequest(const DNSPacket& p);
5fca2e23 170 void notify(const DNSName &domain, const string &ip);
12c86877 171 void mainloop();
dbcb3066 172 void retrievalLoopThread();
3497eb18 173 void sendNotification(int sock, const DNSName &domain, const ComboAddress& remote, uint16_t id, UeberBackend* B);
a71bee29 174
12c86877
BH
175 static void *launchhelper(void *p)
176 {
177 static_cast<CommunicatorClass *>(p)->mainloop();
178 return 0;
179 }
dbcb3066
BH
180 static void *retrieveLaunchhelper(void *p)
181 {
182 static_cast<CommunicatorClass *>(p)->retrievalLoopThread();
183 return 0;
184 }
3497eb18 185 bool notifyDomain(const DNSName &domain, UeberBackend* B);
12c86877 186private:
e8940583 187 void loadArgsIntoSet(const char *listname, set<string> &listset);
0c01dd7c 188 void makeNotifySockets();
abcd36a1 189 void queueNotifyDomain(const DomainInfo& di, UeberBackend* B);
0c01dd7c 190 int d_nsock4, d_nsock6;
675fa24c 191 map<pair<DNSName,string>,time_t>d_holes;
12c86877 192 pthread_mutex_t d_holelock;
d622042f 193 void suck(const DNSName &domain, const ComboAddress& remote);
c2826d2e 194 void ixfrSuck(const DNSName &domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, std::unique_ptr<AuthLua4>& pdl,
3e7dcee6 195 ZoneStatus& zs, vector<DNSRecord>* axfr);
cd189f24 196
12c86877
BH
197 void slaveRefresh(PacketHandler *P);
198 void masterUpdateCheck(PacketHandler *P);
199 pthread_mutex_t d_lock;
dbcb3066
BH
200
201 UniQueue d_suckdomains;
3e7dcee6 202 set<DNSName> d_inprogress;
dbcb3066 203
12c86877
BH
204 Semaphore d_suck_sem;
205 Semaphore d_any_sem;
88c0425a 206 time_t d_tickinterval;
7f3d870e 207 set<DomainInfo> d_tocheck;
02980dc2 208 struct cmp {
385b86f6 209 bool operator()(const DNSPacket& a, const DNSPacket& b) const {
02980dc2 210 return a.qdomain < b.qdomain;
211 };
212 };
213
214 std::set<DNSPacket, cmp> d_potentialsupermasters;
215
24d3239e 216 set<string> d_alsoNotify;
cf58746e
PL
217 NotificationQueue d_nq;
218 NetmaskGroup d_onlyNotify;
cf58746e
PL
219 bool d_masterschanged, d_slaveschanged;
220 bool d_preventSelfNotification;
3e7dcee6 221
b239dfba
PL
222 // Used to keep some state on domains that failed their freshness checks.
223 // uint64_t == counter of the number of failures (increased by 1 every consecutive slave-cycle-interval that the domain fails)
224 // time_t == wait at least until this time before attempting a new check
225 map<DNSName, pair<uint64_t, time_t> > d_failedSlaveRefresh;
226
3e7dcee6 227 struct RemoveSentinel
228 {
229 explicit RemoveSentinel(const DNSName& dn, CommunicatorClass* cc) : d_dn(dn), d_cc(cc)
230 {}
231
232 ~RemoveSentinel()
233 {
737a287f
RG
234 try {
235 Lock l(&d_cc->d_lock);
236 d_cc->d_inprogress.erase(d_dn);
237 }
238 catch(...) {
239 }
3e7dcee6 240 }
241 DNSName d_dn;
242 CommunicatorClass* d_cc;
243};
244
12c86877
BH
245};
246
ef03cc09 247// class that one day might be more than a function to help you get IP addresses for a nameserver
248class FindNS
249{
250public:
35b942fe 251 vector<string> lookup(const DNSName &name, UeberBackend *b)
ef03cc09 252 {
253 vector<string> addresses;
254
255 this->resolve_name(&addresses, name);
256
2a642697 257 if(b) {
acb61e0a 258 b->lookup(QType(QType::ANY),name,-1);
c079ae34
PD
259 DNSZoneRecord rr;
260 while(b->get(rr))
261 if(rr.dr.d_type == QType::A || rr.dr.d_type==QType::AAAA)
262 addresses.push_back(rr.dr.d_content->getZoneRepresentation()); // SOL if you have a CNAME for an NS
2a642697 263 }
ef03cc09 264 return addresses;
265 }
266
ef03cc09 267private:
268 void resolve_name(vector<string>* addresses, const DNSName& name)
269 {
270 struct addrinfo* res;
271 struct addrinfo hints;
272 memset(&hints, 0, sizeof(hints));
d259e496 273 hints.ai_socktype = SOCK_DGRAM; // otherwise we get everything in triplicate (!)
ef03cc09 274 for(int n = 0; n < 2; ++n) {
275 hints.ai_family = n ? AF_INET : AF_INET6;
276 ComboAddress remote;
277 remote.sin4.sin_family = AF_INET6;
278 if(!getaddrinfo(name.toString().c_str(), 0, &hints, &res)) {
279 struct addrinfo* address = res;
280 do {
a683e8bd 281 if (address->ai_addrlen <= sizeof(remote)) {
d38e2ba9 282 remote.setSockaddr(address->ai_addr, address->ai_addrlen);
a683e8bd
RG
283 addresses->push_back(remote.toString());
284 }
ef03cc09 285 } while((address = address->ai_next));
286 freeaddrinfo(res);
287 }
288 }
289 }
290};