]>
Commit | Line | Data |
---|---|---|
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> | |
32 | using 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 | |
44 | struct 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 |
64 | struct IDTag |
65 | { | |
66 | }; | |
dbcb3066 | 67 | |
937cd921 | 68 | using 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>>>>; |
73 | using domains_by_name_t = UniQueue::index<IDTag>::type; | |
dbcb3066 | 74 | |
12c86877 BH |
75 | class NotificationQueue |
76 | { | |
77 | public: | |
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 |
138 | private: |
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 | 152 | struct 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 | ||
157 | class CommunicatorClass | |
158 | { | |
159 | public: | |
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 | 184 | private: |
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 |
255 | class FindNS | |
256 | { | |
257 | public: | |
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 | 274 | private: |
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 | }; |