• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

3.09
/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 primary;
48
  bool force;
49
  enum RequestPriority : uint8_t
50
  {
51
    PdnsControl,
52
    Api,
53
    Notify,
54
    SerialRefresh,
55
    SignaturesRefresh
56
  };
57
  std::pair<RequestPriority, uint64_t> priorityAndOrder;
58
  bool operator<(const SuckRequest& b) const
59
  {
48✔
60
    return std::tie(domain, primary) < std::tie(b.domain, b.primary);
48✔
61
  }
48✔
62
};
63

64
struct IDTag
65
{
66
};
67

68
using UniQueue = multi_index_container<
69
  SuckRequest,
70
  indexed_by<
71
    ordered_unique<member<SuckRequest, std::pair<SuckRequest::RequestPriority, uint64_t>, &SuckRequest::priorityAndOrder>>,
72
    ordered_unique<tag<IDTag>, identity<SuckRequest>>>>;
73
using domains_by_name_t = UniQueue::index<IDTag>::type;
74

75
class NotificationQueue
76
{
77
public:
78
  void add(const DNSName& domain, const string& ipstring, time_t delay = 0)
79
  {
×
80
    const ComboAddress ipaddress(ipstring);
×
81
    add(domain, ipaddress, delay);
×
82
  }
×
83

84
  void add(const DNSName& domain, const ComboAddress& ipaddress, time_t delay = 0)
85
  {
×
86
    NotificationRequest nr;
×
87
    nr.domain = domain;
×
88
    nr.ip = ipaddress.toStringWithPort();
×
89
    nr.attempts = 0;
×
90
    nr.id = dns_random_uint16();
×
91
    nr.next = time(nullptr) + delay;
×
92

×
93
    d_nqueue.push_back(nr);
×
94
  }
×
95

96
  bool removeIf(const ComboAddress& remote, uint16_t id, const DNSName& domain)
97
  {
×
98
    for (auto i = d_nqueue.begin(); i != d_nqueue.end(); ++i) {
×
99
      ComboAddress stQueued{i->ip};
×
100
      if (i->id == id && stQueued == remote && i->domain == domain) {
×
101
        d_nqueue.erase(i);
×
102
        return true;
×
103
      }
×
104
    }
×
105
    return false;
×
106
  }
×
107

108
  bool getOne(DNSName& domain, string& ip, uint16_t* id, bool& purged)
109
  {
×
110
    for (d_nqueue_t::iterator i = d_nqueue.begin(); i != d_nqueue.end(); ++i)
×
111
      if (i->next <= time(nullptr)) {
×
112
        i->attempts++;
×
113
        purged = false;
×
114
        i->next = time(nullptr) + 1 + (1 << i->attempts);
×
115
        domain = i->domain;
×
116
        ip = i->ip;
×
117
        *id = i->id;
×
118
        purged = false;
×
119
        if (i->attempts > 4) {
×
120
          purged = true;
×
121
          d_nqueue.erase(i);
×
122
        }
×
123
        return true;
×
124
      }
×
125
    return false;
×
126
  }
×
127

128
  time_t earliest()
129
  {
×
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);
×
133
    return early - time(nullptr);
×
134
  }
×
135

136
  void dump();
137

138
private:
139
  struct NotificationRequest
140
  {
141
    DNSName domain;
142
    string ip;
143
    time_t next;
144
    int attempts;
145
    uint16_t id;
146
  };
147

148
  using d_nqueue_t = std::list<NotificationRequest>;
149
  d_nqueue_t d_nqueue;
150
};
151

152
struct ZoneStatus;
153

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:
160
  CommunicatorClass()
161
  {
162
    d_tickinterval = 60;
163
    d_secondarieschanged = true;
164
    d_nsock4 = -1;
165
    d_nsock6 = -1;
166
    d_preventSelfNotification = false;
167
  }
168
  time_t doNotifications(PacketHandler* P);
169
  void go();
170

171
  void drillHole(const DNSName& domain, const string& ip);
172
  bool justNotified(const DNSName& domain, const string& ip);
173
  void addSuckRequest(const DNSName& domain, const ComboAddress& primary, SuckRequest::RequestPriority, bool force = false);
174
  void addSecondaryCheckRequest(const DomainInfo& di, const ComboAddress& remote);
175
  void addTryAutoPrimaryRequest(const DNSPacket& p);
176
  void notify(const DNSName& domain, const string& ip);
177
  void mainloop();
178
  void retrievalLoopThread();
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();
182
  size_t getSuckRequestsWaiting();
183

184
private:
185
  static void loadArgsIntoSet(const char* listname, set<string>& listset);
186
  void makeNotifySockets();
187
  void queueNotifyDomain(const DomainInfo& di, UeberBackend* B);
188
  int d_nsock4, d_nsock6;
189
  LockGuarded<map<pair<DNSName, string>, time_t>> d_holes;
190

191
  void suck(const DNSName& domain, const ComboAddress& remote, bool force = false);
192
  void ixfrSuck(const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, ZoneStatus& zs, vector<DNSRecord>* axfr);
193

194
  void secondaryRefresh(PacketHandler* P);
195
  void primaryUpdateCheck(PacketHandler* P);
196
  void getUpdatedProducers(UeberBackend* B, vector<DomainInfo>& domains, const std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes);
197

198
  Semaphore d_suck_sem;
199
  Semaphore d_any_sem;
200

201
  set<string> d_alsoNotify;
202
  NetmaskGroup d_onlyNotify;
203
  NotificationQueue d_nq;
204

205
  time_t d_tickinterval;
206
  bool d_secondarieschanged;
207
  bool d_preventSelfNotification;
208
  time_t d_delayNotifications{0};
209

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;
217
    struct cmp
218
    {
219
      bool operator()(const DNSPacket& a, const DNSPacket& b) const
220
      {
×
221
        return a.qdomain < b.qdomain;
×
222
      };
×
223
    };
224

225
    std::set<DNSPacket, cmp> d_potentialautoprimaries;
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
230
    map<DNSName, pair<uint64_t, time_t>> d_failedSecondaryRefresh;
231
  };
232

233
  LockGuarded<Data> d_data;
234

235
  struct RemoveSentinel
236
  {
237
    explicit RemoveSentinel(const DNSName& dn, CommunicatorClass* cc) :
238
      d_dn(dn), d_cc(cc)
239
    {}
×
240

241
    ~RemoveSentinel()
242
    {
×
243
      try {
×
244
        d_cc->d_data.lock()->d_inprogress.erase(d_dn);
×
245
      }
×
246
      catch (...) {
×
247
      }
×
248
    }
×
249
    DNSName d_dn;
250
    CommunicatorClass* d_cc;
251
  };
252
};
253

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:
258
  vector<string> lookup(const DNSName& name, UeberBackend* b)
259
  {
×
260
    vector<string> addresses;
×
261

×
262
    this->resolve_name(&addresses, name);
×
263

×
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
×
270
    }
×
271
    return addresses;
×
272
  }
×
273

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));
×
280
    hints.ai_socktype = SOCK_DGRAM; // otherwise we get everything in triplicate (!)
×
281
    for (int n = 0; n < 2; ++n) {
×
282
      hints.ai_family = n ? AF_INET : AF_INET6;
×
283
      ComboAddress remote;
×
284
      remote.sin4.sin_family = AF_INET6;
×
285
      if (!getaddrinfo(name.toString().c_str(), 0, &hints, &res)) {
×
286
        struct addrinfo* address = res;
×
287
        do {
×
288
          if (address->ai_addrlen <= sizeof(remote)) {
×
289
            remote.setSockaddr(address->ai_addr, address->ai_addrlen);
×
290
            addresses->push_back(remote.toString());
×
291
          }
×
292
        } while ((address = address->ai_next));
×
293
        freeaddrinfo(res);
×
294
      }
×
295
    }
×
296
  }
×
297
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc