]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/communicator.hh
yolocommit, but it does track a zone. Once.
[thirdparty/pdns.git] / pdns / communicator.hh
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
dbcb3066 3 Copyright (C) 2002-2010 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
22dc646a
BH
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
f782fe38
MH
8
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12c86877
BH
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877
BH
21*/
22#ifndef PDNS_COMMUNICATOR_HH
23#define PDNS_COMMUNICATOR_HH
24
25#include <pthread.h>
26#include <string>
27#include <semaphore.h>
28#include <queue>
29#include <list>
f1a8bee5 30#include <limits>
dbcb3066
BH
31#include <boost/multi_index_container.hpp>
32#include <boost/multi_index/identity.hpp>
33#include <boost/multi_index/sequenced_index.hpp>
34using namespace boost::multi_index;
1258abe0 35
76473b92
KM
36#include <unistd.h>
37#include <fcntl.h>
38#include <netdb.h>
1258abe0 39
12c86877
BH
40#include "lock.hh"
41#include "packethandler.hh"
42
10f4eea8 43#include "namespaces.hh"
12c86877
BH
44
45struct SuckRequest
46{
5fca2e23 47 DNSName domain;
12c86877 48 string master;
cd189f24 49 uint32_t currentSerial;
dbcb3066
BH
50 bool operator<(const SuckRequest& b) const
51 {
52 return tie(domain, master) < tie(b.domain, b.master);
53 }
12c86877
BH
54};
55
dbcb3066
BH
56struct IDTag{};
57
58typedef multi_index_container<
59 SuckRequest,
60 indexed_by<
61 sequenced<>,
62 ordered_unique<tag<IDTag>, identity<SuckRequest> >
63 >
64> UniQueue;
a71bee29 65typedef UniQueue::index<IDTag>::type domains_by_name_t;
dbcb3066 66
12c86877
BH
67class NotificationQueue
68{
69public:
5fca2e23 70 void add(const DNSName &domain, const string &ip)
12c86877 71 {
3c8a7112
KM
72 const ComboAddress caIp(ip);
73
1258abe0
BH
74 NotificationRequest nr;
75 nr.domain = domain;
3c8a7112 76 nr.ip = caIp.toStringWithPort();
1258abe0
BH
77 nr.attempts = 0;
78 nr.id = Utility::random()%0xffff;
79 nr.next = time(0);
12c86877
BH
80
81 d_nqueue.push_back(nr);
82 }
3c8a7112 83
5fca2e23 84 bool removeIf(const string &remote, uint16_t id, const DNSName &domain)
12c86877 85 {
3c8a7112
KM
86 ServiceTuple stRemote, stQueued;
87 parseService(remote, stRemote);
88
a71bee29 89 for(d_nqueue_t::iterator i=d_nqueue.begin(); i!=d_nqueue.end(); ++i) {
3c8a7112
KM
90 parseService(i->ip, stQueued);
91 if(i->id==id && stQueued.host == stRemote.host && i->domain==domain) {
4957a608
BH
92 d_nqueue.erase(i);
93 return true;
12c86877
BH
94 }
95 }
96 return false;
97 }
98
5fca2e23 99 bool getOne(DNSName &domain, string &ip, uint16_t *id, bool &purged)
12c86877
BH
100 {
101 for(d_nqueue_t::iterator i=d_nqueue.begin();i!=d_nqueue.end();++i)
102 if(i->next <= time(0)) {
4957a608
BH
103 i->attempts++;
104 purged=false;
105 i->next=time(0)+1+(1<<i->attempts);
106 domain=i->domain;
107 ip=i->ip;
108 *id=i->id;
109 purged=false;
110 if(i->attempts>4) {
111 purged=true;
112 d_nqueue.erase(i);
113 }
114 return true;
12c86877
BH
115 }
116 return false;
117 }
3c8a7112 118
12c86877
BH
119 time_t earliest()
120 {
10f4eea8 121 time_t early=std::numeric_limits<time_t>::max() - 1;
12c86877
BH
122 for(d_nqueue_t::const_iterator i=d_nqueue.begin();i!=d_nqueue.end();++i)
123 early=min(early,i->next);
124 return early-time(0);
125 }
3c8a7112 126
2d00c43d 127 void dump();
3c8a7112 128
12c86877
BH
129private:
130 struct NotificationRequest
131 {
5fca2e23 132 DNSName domain;
12c86877 133 string ip;
1c514700 134 time_t next;
12c86877 135 int attempts;
092f210a 136 uint16_t id;
12c86877
BH
137 };
138
a71bee29 139 typedef std::list<NotificationRequest> d_nqueue_t;
12c86877
BH
140 d_nqueue_t d_nqueue;
141
142};
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
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;
159 d_havepriosuckrequest = false;
160 d_preventSelfNotification = false;
12c86877 161 }
88c0425a 162 time_t doNotifications();
dbcb3066
BH
163 void go();
164
165
5fca2e23
PD
166 void drillHole(const DNSName &domain, const string &ip);
167 bool justNotified(const DNSName &domain, const string &ip);
cd189f24 168 void addSuckRequest(const DNSName &domain, const string &master, uint32_t curser);
7f3d870e 169 void addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote);
7108e055 170 void addTrySuperMasterRequest(DNSPacket *p);
5fca2e23 171 void notify(const DNSName &domain, const string &ip);
12c86877 172 void mainloop();
dbcb3066 173 void retrievalLoopThread();
5fca2e23 174 void sendNotification(int sock, const DNSName &domain, const ComboAddress& remote, uint16_t id);
a71bee29 175
12c86877
BH
176 static void *launchhelper(void *p)
177 {
178 static_cast<CommunicatorClass *>(p)->mainloop();
179 return 0;
180 }
dbcb3066
BH
181 static void *retrieveLaunchhelper(void *p)
182 {
183 static_cast<CommunicatorClass *>(p)->retrievalLoopThread();
184 return 0;
185 }
5fca2e23 186 bool notifyDomain(const DNSName &domain);
12c86877 187private:
0c01dd7c 188 void makeNotifySockets();
5fca2e23 189 void queueNotifyDomain(const DNSName &domain, 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;
dbcb3066 193 void launchRetrievalThreads();
cd189f24 194 void suck(const DNSName &domain, const string &remote, uint32_t* curser);
195 void ixfrSuck(const DNSName &domain, const string &remote, uint32_t curser);
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;
202
12c86877
BH
203 Semaphore d_suck_sem;
204 Semaphore d_any_sem;
88c0425a 205 time_t d_tickinterval;
7f3d870e 206 set<DomainInfo> d_tocheck;
7108e055 207 vector<DNSPacket> d_potentialsupermasters;
24d3239e 208 set<string> d_alsoNotify;
cf58746e
PL
209 NotificationQueue d_nq;
210 NetmaskGroup d_onlyNotify;
211 bool d_havepriosuckrequest;
212 bool d_masterschanged, d_slaveschanged;
213 bool d_preventSelfNotification;
12c86877
BH
214};
215
ef03cc09 216// class that one day might be more than a function to help you get IP addresses for a nameserver
217class FindNS
218{
219public:
220 vector<string> lookup(const DNSName &name, DNSBackend *b)
221 {
222 vector<string> addresses;
223
224 this->resolve_name(&addresses, name);
225
2a642697
PD
226 if(b) {
227 b->lookup(QType(QType::ANY),name);
228 DNSResourceRecord rr;
229 while(b->get(rr))
230 if(rr.qtype.getCode() == QType::A || rr.qtype.getCode()==QType::AAAA)
231 addresses.push_back(rr.content); // SOL if you have a CNAME for an NS
232 }
ef03cc09 233 return addresses;
234 }
235
236 vector<string> lookup(const DNSName &name, UeberBackend *b)
237 {
238 vector<string> addresses;
239
240 this->resolve_name(&addresses, name);
241
2a642697
PD
242 if(b) {
243 b->lookup(QType(QType::ANY),name);
244 DNSResourceRecord rr;
245 while(b->get(rr))
246 if(rr.qtype.getCode() == QType::A || rr.qtype.getCode()==QType::AAAA)
247 addresses.push_back(rr.content); // SOL if you have a CNAME for an NS
248 }
ef03cc09 249 return addresses;
250 }
251
252private:
253 void resolve_name(vector<string>* addresses, const DNSName& name)
254 {
255 struct addrinfo* res;
256 struct addrinfo hints;
257 memset(&hints, 0, sizeof(hints));
258
259 for(int n = 0; n < 2; ++n) {
260 hints.ai_family = n ? AF_INET : AF_INET6;
261 ComboAddress remote;
262 remote.sin4.sin_family = AF_INET6;
263 if(!getaddrinfo(name.toString().c_str(), 0, &hints, &res)) {
264 struct addrinfo* address = res;
265 do {
a683e8bd
RG
266 if (address->ai_addrlen <= sizeof(remote)) {
267 memcpy(&remote, address->ai_addr, address->ai_addrlen);
268 addresses->push_back(remote.toString());
269 }
ef03cc09 270 } while((address = address->ai_next));
271 freeaddrinfo(res);
272 }
273 }
274 }
275};
276
277
12c86877 278#endif