]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/communicator.hh
Merge pull request #14277 from Habbie/geoip-cxxfs-lib
[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;
d525b58b 47 ComboAddress primary;
65ebb951 48 bool force;
2dff6ed5
CHB
49 enum RequestPriority : uint8_t
50 {
51 PdnsControl,
52 Api,
53 Notify,
54 SerialRefresh,
55 SignaturesRefresh
56 };
472429fb 57 std::pair<RequestPriority, uint64_t> priorityAndOrder;
dbcb3066
BH
58 bool operator<(const SuckRequest& b) const
59 {
d525b58b 60 return std::tie(domain, primary) < std::tie(b.domain, b.primary);
dbcb3066 61 }
12c86877
BH
62};
63
2dff6ed5
CHB
64struct IDTag
65{
66};
dbcb3066 67
937cd921 68using UniQueue = multi_index_container<
dbcb3066
BH
69 SuckRequest,
70 indexed_by<
2dff6ed5 71 ordered_unique<member<SuckRequest, std::pair<SuckRequest::RequestPriority, uint64_t>, &SuckRequest::priorityAndOrder>>,
937cd921
CHB
72 ordered_unique<tag<IDTag>, identity<SuckRequest>>>>;
73using domains_by_name_t = UniQueue::index<IDTag>::type;
dbcb3066 74
12c86877
BH
75class NotificationQueue
76{
77public:
937cd921 78 void add(const DNSName& domain, const string& ipstring, time_t delay = 0)
12c86877 79 {
937cd921 80 const ComboAddress ipaddress(ipstring);
146ada65
CHB
81 add(domain, ipaddress, delay);
82 }
3c8a7112 83
146ada65
CHB
84 void add(const DNSName& domain, const ComboAddress& ipaddress, time_t delay = 0)
85 {
1258abe0 86 NotificationRequest nr;
2dff6ed5 87 nr.domain = domain;
937cd921 88 nr.ip = ipaddress.toStringWithPort();
1258abe0 89 nr.attempts = 0;
2dff6ed5
CHB
90 nr.id = dns_random_uint16();
91 nr.next = time(nullptr) + delay;
12c86877
BH
92
93 d_nqueue.push_back(nr);
94 }
3c8a7112 95
bd6223db 96 bool removeIf(const ComboAddress& remote, uint16_t id, const DNSName& domain)
12c86877 97 {
bd6223db 98 for (auto i = d_nqueue.begin(); i != d_nqueue.end(); ++i) {
792548c4
FM
99 ComboAddress stQueued{i->ip};
100 if (i->id == id && stQueued == remote && i->domain == domain) {
4957a608
BH
101 d_nqueue.erase(i);
102 return true;
12c86877
BH
103 }
104 }
105 return false;
106 }
107
2dff6ed5 108 bool getOne(DNSName& domain, string& ip, uint16_t* id, bool& purged)
12c86877 109 {
2dff6ed5 110 for (d_nqueue_t::iterator i = d_nqueue.begin(); i != d_nqueue.end(); ++i)
937cd921 111 if (i->next <= time(nullptr)) {
4957a608 112 i->attempts++;
2dff6ed5 113 purged = false;
937cd921 114 i->next = time(nullptr) + 1 + (1 << i->attempts);
2dff6ed5
CHB
115 domain = i->domain;
116 ip = i->ip;
117 *id = i->id;
118 purged = false;
119 if (i->attempts > 4) {
120 purged = true;
4957a608
BH
121 d_nqueue.erase(i);
122 }
123 return true;
12c86877
BH
124 }
125 return false;
126 }
3c8a7112 127
12c86877
BH
128 time_t earliest()
129 {
2dff6ed5
CHB
130 time_t early = std::numeric_limits<time_t>::max() - 1;
131 for (d_nqueue_t::const_iterator i = d_nqueue.begin(); i != d_nqueue.end(); ++i)
132 early = min(early, i->next);
937cd921 133 return early - time(nullptr);
12c86877 134 }
3c8a7112 135
2d00c43d 136 void dump();
3c8a7112 137
12c86877
BH
138private:
139 struct NotificationRequest
140 {
5fca2e23 141 DNSName domain;
12c86877 142 string ip;
1c514700 143 time_t next;
12c86877 144 int attempts;
092f210a 145 uint16_t id;
12c86877
BH
146 };
147
937cd921 148 using d_nqueue_t = std::list<NotificationRequest>;
12c86877 149 d_nqueue_t d_nqueue;
12c86877
BH
150};
151
3e7dcee6 152struct ZoneStatus;
153
12c86877
BH
154/** this class contains a thread that communicates with other nameserver and does housekeeping.
155 Initially, it is notified only of zones that need to be pulled in because they have been updated. */
156
157class CommunicatorClass
158{
159public:
de42d2df 160 CommunicatorClass()
12c86877 161 {
2dff6ed5 162 d_tickinterval = 60;
c02c999b 163 d_secondarieschanged = true;
50d471ea
AT
164 d_nsock4 = -1;
165 d_nsock6 = -1;
50d471ea 166 d_preventSelfNotification = false;
12c86877 167 }
2dff6ed5 168 time_t doNotifications(PacketHandler* P);
dbcb3066 169 void go();
de42d2df 170
2dff6ed5
CHB
171 void drillHole(const DNSName& domain, const string& ip);
172 bool justNotified(const DNSName& domain, const string& ip);
d525b58b 173 void addSuckRequest(const DNSName& domain, const ComboAddress& primary, SuckRequest::RequestPriority, bool force = false);
c02c999b 174 void addSecondaryCheckRequest(const DomainInfo& di, const ComboAddress& remote);
d525b58b 175 void addTryAutoPrimaryRequest(const DNSPacket& p);
2dff6ed5 176 void notify(const DNSName& domain, const string& ip);
12c86877 177 void mainloop();
dbcb3066 178 void retrievalLoopThread();
2dff6ed5
CHB
179 void sendNotification(int sock, const DNSName& domain, const ComboAddress& remote, uint16_t id, UeberBackend* B);
180 bool notifyDomain(const DNSName& domain, UeberBackend* B);
181 vector<pair<DNSName, ComboAddress>> getSuckRequests();
c0cc8543 182 size_t getSuckRequestsWaiting();
2dff6ed5 183
12c86877 184private:
937cd921 185 static void loadArgsIntoSet(const char* listname, set<string>& listset);
0c01dd7c 186 void makeNotifySockets();
abcd36a1 187 void queueNotifyDomain(const DomainInfo& di, UeberBackend* B);
0c01dd7c 188 int d_nsock4, d_nsock6;
2dff6ed5 189 LockGuarded<map<pair<DNSName, string>, time_t>> d_holes;
01e96795 190
2dff6ed5 191 void suck(const DNSName& domain, const ComboAddress& remote, bool force = false);
a445dac8 192 void ixfrSuck(const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, ZoneStatus& zs, vector<DNSRecord>* axfr);
cd189f24 193
c02c999b 194 void secondaryRefresh(PacketHandler* P);
d525b58b 195 void primaryUpdateCheck(PacketHandler* P);
ddeea7a6 196 void getUpdatedProducers(UeberBackend* B, vector<DomainInfo>& domains, const std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes);
01e96795 197
12c86877
BH
198 Semaphore d_suck_sem;
199 Semaphore d_any_sem;
02980dc2 200
24d3239e 201 set<string> d_alsoNotify;
cf58746e 202 NetmaskGroup d_onlyNotify;
01e96795
RG
203 NotificationQueue d_nq;
204
205 time_t d_tickinterval;
c02c999b 206 bool d_secondarieschanged;
cf58746e 207 bool d_preventSelfNotification;
7bd9b307 208 time_t d_delayNotifications{0};
3e7dcee6 209
01e96795
RG
210 struct Data
211 {
212 uint64_t d_sorthelper{0};
213 UniQueue d_suckdomains;
214 set<DNSName> d_inprogress;
215
216 set<DomainInfo> d_tocheck;
2dff6ed5
CHB
217 struct cmp
218 {
219 bool operator()(const DNSPacket& a, const DNSPacket& b) const
220 {
01e96795
RG
221 return a.qdomain < b.qdomain;
222 };
223 };
224
d525b58b 225 std::set<DNSPacket, cmp> d_potentialautoprimaries;
01e96795
RG
226
227 // Used to keep some state on domains that failed their freshness checks.
228 // uint64_t == counter of the number of failures (increased by 1 every consecutive slave-cycle-interval that the domain fails)
229 // time_t == wait at least until this time before attempting a new check
c02c999b 230 map<DNSName, pair<uint64_t, time_t>> d_failedSecondaryRefresh;
01e96795
RG
231 };
232
233 LockGuarded<Data> d_data;
b239dfba 234
3e7dcee6 235 struct RemoveSentinel
236 {
2dff6ed5
CHB
237 explicit RemoveSentinel(const DNSName& dn, CommunicatorClass* cc) :
238 d_dn(dn), d_cc(cc)
3e7dcee6 239 {}
de42d2df 240
3e7dcee6 241 ~RemoveSentinel()
242 {
737a287f 243 try {
01e96795 244 d_cc->d_data.lock()->d_inprogress.erase(d_dn);
737a287f 245 }
2dff6ed5 246 catch (...) {
737a287f 247 }
3e7dcee6 248 }
249 DNSName d_dn;
250 CommunicatorClass* d_cc;
2dff6ed5 251 };
12c86877
BH
252};
253
ef03cc09 254// class that one day might be more than a function to help you get IP addresses for a nameserver
255class FindNS
256{
257public:
2dff6ed5 258 vector<string> lookup(const DNSName& name, UeberBackend* b)
ef03cc09 259 {
260 vector<string> addresses;
261
262 this->resolve_name(&addresses, name);
de42d2df 263
2dff6ed5
CHB
264 if (b) {
265 b->lookup(QType(QType::ANY), name, -1);
266 DNSZoneRecord rr;
267 while (b->get(rr))
268 if (rr.dr.d_type == QType::A || rr.dr.d_type == QType::AAAA)
269 addresses.push_back(rr.dr.getContent()->getZoneRepresentation()); // SOL if you have a CNAME for an NS
2a642697 270 }
ef03cc09 271 return addresses;
272 }
273
ef03cc09 274private:
275 void resolve_name(vector<string>* addresses, const DNSName& name)
276 {
277 struct addrinfo* res;
278 struct addrinfo hints;
279 memset(&hints, 0, sizeof(hints));
d259e496 280 hints.ai_socktype = SOCK_DGRAM; // otherwise we get everything in triplicate (!)
2dff6ed5 281 for (int n = 0; n < 2; ++n) {
ef03cc09 282 hints.ai_family = n ? AF_INET : AF_INET6;
283 ComboAddress remote;
284 remote.sin4.sin_family = AF_INET6;
2dff6ed5 285 if (!getaddrinfo(name.toString().c_str(), 0, &hints, &res)) {
ef03cc09 286 struct addrinfo* address = res;
287 do {
a683e8bd 288 if (address->ai_addrlen <= sizeof(remote)) {
d38e2ba9 289 remote.setSockaddr(address->ai_addr, address->ai_addrlen);
a683e8bd
RG
290 addresses->push_back(remote.toString());
291 }
2dff6ed5 292 } while ((address = address->ai_next));
ef03cc09 293 freeaddrinfo(res);
294 }
295 }
296 }
297};