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

PowerDNS / pdns / 15920880335

26 Jun 2025 03:30PM UTC coverage: 61.923% (-3.7%) from 65.652%
15920880335

push

github

web-flow
Merge pull request #15669 from miodvallat/serial_keyer

Increase zone serial number after zone key operations

38311 of 91850 branches covered (41.71%)

Branch coverage included in aggregate %.

27 of 29 new or added lines in 1 file covered. (93.1%)

6308 existing lines in 78 files now uncovered.

120482 of 164587 relevant lines covered (73.2%)

5965233.22 hits per line

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

77.11
/pdns/iputils.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 <string>
24
#include <sys/socket.h>
25
#include <netinet/in.h>
26
#include <arpa/inet.h>
27
#include <iostream>
28
#include <cstdio>
29
#include <functional>
30
#include "pdnsexception.hh"
31
#include "misc.hh"
32
#include <netdb.h>
33
#include <sstream>
34
#include <sys/un.h>
35

36
#include "namespaces.hh"
37

38
#ifdef __APPLE__
39
#include <libkern/OSByteOrder.h>
40

41
#define htobe16(x) OSSwapHostToBigInt16(x)
42
#define htole16(x) OSSwapHostToLittleInt16(x)
43
#define be16toh(x) OSSwapBigToHostInt16(x)
44
#define le16toh(x) OSSwapLittleToHostInt16(x)
45

46
#define htobe32(x) OSSwapHostToBigInt32(x)
47
#define htole32(x) OSSwapHostToLittleInt32(x)
48
#define be32toh(x) OSSwapBigToHostInt32(x)
49
#define le32toh(x) OSSwapLittleToHostInt32(x)
50

51
#define htobe64(x) OSSwapHostToBigInt64(x)
52
#define htole64(x) OSSwapHostToLittleInt64(x)
53
#define be64toh(x) OSSwapBigToHostInt64(x)
54
#define le64toh(x) OSSwapLittleToHostInt64(x)
55
#endif
56

57
#ifdef __sun
58

59
#define htobe16(x) BE_16(x)
60
#define htole16(x) LE_16(x)
61
#define be16toh(x) BE_IN16(&(x))
62
#define le16toh(x) LE_IN16(&(x))
63

64
#define htobe32(x) BE_32(x)
65
#define htole32(x) LE_32(x)
66
#define be32toh(x) BE_IN32(&(x))
67
#define le32toh(x) LE_IN32(&(x))
68

69
#define htobe64(x) BE_64(x)
70
#define htole64(x) LE_64(x)
71
#define be64toh(x) BE_IN64(&(x))
72
#define le64toh(x) LE_IN64(&(x))
73

74
#endif
75

76
#ifdef __FreeBSD__
77
#include <sys/endian.h>
78
#endif
79

80
#if defined(__NetBSD__) && defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
81
// The IP_PKTINFO option in NetBSD was incompatible with Linux until a
82
// change that also introduced IP_SENDSRCADDR for FreeBSD compatibility.
83
#undef IP_PKTINFO
84
#endif
85

86
union ComboAddress
87
{
88
  sockaddr_in sin4{};
89
  sockaddr_in6 sin6;
90

91
  bool operator==(const ComboAddress& rhs) const
92
  {
38,306,553✔
93
    if (std::tie(sin4.sin_family, sin4.sin_port) != std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
38,306,553✔
94
      return false;
15,535,168✔
95
    }
15,535,168✔
96
    if (sin4.sin_family == AF_INET) {
22,771,385✔
97
      return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
11,639,901✔
98
    }
11,639,901✔
99
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) == 0;
11,131,484✔
100
  }
22,771,385✔
101

102
  bool operator!=(const ComboAddress& rhs) const
103
  {
6,013,639✔
104
    return (!operator==(rhs));
6,013,639✔
105
  }
6,013,639✔
106

107
  bool operator<(const ComboAddress& rhs) const
108
  {
1,802,617✔
109
    if (sin4.sin_family == 0) {
1,802,617✔
110
      return false;
67,667✔
111
    }
67,667✔
112
    if (std::tie(sin4.sin_family, sin4.sin_port) < std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
1,734,950✔
113
      return true;
23,395✔
114
    }
23,395✔
115
    if (std::tie(sin4.sin_family, sin4.sin_port) > std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
1,711,555✔
116
      return false;
11,334✔
117
    }
11,334✔
118
    if (sin4.sin_family == AF_INET) {
1,700,257✔
119
      return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
1,112,405✔
120
    }
1,112,405✔
121
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0;
2,148,071,474✔
122
  }
1,700,221✔
123

124
  bool operator>(const ComboAddress& rhs) const
125
  {
5✔
126
    return rhs.operator<(*this);
5✔
127
  }
5✔
128

129
  struct addressPortOnlyHash
130
  {
131
    uint32_t operator()(const ComboAddress& address) const
132
    {
×
133
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
134
      if (address.sin4.sin_family == AF_INET) {
×
135
        const auto* start = reinterpret_cast<const unsigned char*>(&address.sin4.sin_addr.s_addr);
×
136
        auto tmp = burtle(start, 4, 0);
×
137
        return burtle(reinterpret_cast<const uint8_t*>(&address.sin4.sin_port), 2, tmp);
×
138
      }
×
139
      const auto* start = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
×
140
      auto tmp = burtle(start, 16, 0);
×
141
      return burtle(reinterpret_cast<const unsigned char*>(&address.sin6.sin6_port), 2, tmp);
×
142
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
143
    }
×
144
  };
145

146
  struct addressOnlyHash
147
  {
148
    uint32_t operator()(const ComboAddress& address) const
149
    {
618,938✔
150
      const unsigned char* start = nullptr;
618,938✔
151
      uint32_t len = 0;
618,938✔
152
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
153
      if (address.sin4.sin_family == AF_INET) {
618,938✔
154
        start = reinterpret_cast<const unsigned char*>(&address.sin4.sin_addr.s_addr);
617,987✔
155
        len = 4;
617,987✔
156
      }
617,987✔
157
      else {
951✔
158
        start = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
951✔
159
        len = 16;
951✔
160
      }
951✔
161
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
162
      return burtle(start, len, 0);
618,938✔
163
    }
618,938✔
164
  };
165

166
  struct addressOnlyLessThan
167
  {
168
    bool operator()(const ComboAddress& lhs, const ComboAddress& rhs) const
169
    {
18✔
170
      if (lhs.sin4.sin_family < rhs.sin4.sin_family) {
18✔
171
        return true;
1✔
172
      }
1✔
173
      if (lhs.sin4.sin_family > rhs.sin4.sin_family) {
17✔
174
        return false;
2✔
175
      }
2✔
176
      if (lhs.sin4.sin_family == AF_INET) {
15!
177
        return lhs.sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
15✔
178
      }
15✔
UNCOV
179
      return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) < 0;
×
180
    }
15✔
181
  };
182

183
  struct addressOnlyEqual
184
  {
185
    bool operator()(const ComboAddress& lhs, const ComboAddress& rhs) const
186
    {
618✔
187
      if (lhs.sin4.sin_family != rhs.sin4.sin_family) {
618!
188
        return false;
×
189
      }
×
190
      if (lhs.sin4.sin_family == AF_INET) {
618!
191
        return lhs.sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
618✔
192
      }
618✔
193
      return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) == 0;
×
194
    }
618✔
195
  };
196

197
  [[nodiscard]] socklen_t getSocklen() const
198
  {
1,685,644✔
199
    if (sin4.sin_family == AF_INET) {
1,685,644✔
200
      return sizeof(sin4);
359,693✔
201
    }
359,693✔
202
    return sizeof(sin6);
1,325,951✔
203
  }
1,685,644✔
204

205
  ComboAddress()
206
  {
109,566,772✔
207
    sin4.sin_family = AF_INET;
109,566,772✔
208
    sin4.sin_addr.s_addr = 0;
109,566,772✔
209
    sin4.sin_port = 0;
109,566,772✔
210
    sin6.sin6_scope_id = 0;
109,566,772✔
211
    sin6.sin6_flowinfo = 0;
109,566,772✔
212
  }
109,566,772✔
213

214
  ComboAddress(const struct sockaddr* socketAddress, socklen_t salen)
215
  {
14✔
216
    setSockaddr(socketAddress, salen);
14✔
217
  };
14✔
218

219
  ComboAddress(const struct sockaddr_in6* socketAddress)
220
  {
4✔
221
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
222
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in6));
4✔
223
  };
4✔
224

225
  ComboAddress(const struct sockaddr_in* socketAddress)
226
  {
2✔
227
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
228
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in));
2✔
229
  };
2✔
230

231
  void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen)
232
  {
292✔
233
    if (salen > sizeof(struct sockaddr_in6)) {
292!
234
      throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
×
235
    }
×
236
    memcpy(this, socketAddress, salen);
292✔
237
  }
292✔
238

239
  // 'port' sets a default value in case 'str' does not set a port
240
  explicit ComboAddress(const string& str, uint16_t port = 0)
241
  {
1,995,310✔
242
    memset(&sin6, 0, sizeof(sin6));
1,995,310✔
243
    sin4.sin_family = AF_INET;
1,995,310✔
244
    sin4.sin_port = 0;
1,995,310✔
245
    if (makeIPv4sockaddr(str, &sin4) != 0) {
1,995,310✔
246
      sin6.sin6_family = AF_INET6;
934,453✔
247
      if (makeIPv6sockaddr(str, &sin6) < 0) {
934,453✔
248
        throw PDNSException("Unable to convert presentation address '" + str + "'");
68✔
249
      }
68✔
250
    }
934,453✔
251
    if (sin4.sin_port == 0) { // 'str' overrides port!
1,995,242✔
252
      sin4.sin_port = htons(port);
1,721,308✔
253
    }
1,721,308✔
254
  }
1,995,242✔
255

256
  [[nodiscard]] bool isIPv6() const
257
  {
161,364,770✔
258
    return sin4.sin_family == AF_INET6;
161,364,770✔
259
  }
161,364,770✔
260
  [[nodiscard]] bool isIPv4() const
261
  {
295,591,460✔
262
    return sin4.sin_family == AF_INET;
295,591,460✔
263
  }
295,591,460✔
264

265
  [[nodiscard]] bool isMappedIPv4() const
266
  {
×
267
    if (sin4.sin_family != AF_INET6) {
×
268
      return false;
×
269
    }
×
270

271
    int iter = 0;
×
272
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
273
    const auto* ptr = reinterpret_cast<const unsigned char*>(&sin6.sin6_addr.s6_addr);
×
274
    for (iter = 0; iter < 10; ++iter) {
×
275
      if (ptr[iter] != 0) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
×
276
        return false;
×
277
      }
×
278
    }
×
279
    for (; iter < 12; ++iter) {
×
280
      if (ptr[iter] != 0xff) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
×
281
        return false;
×
282
      }
×
283
    }
×
284
    return true;
×
285
  }
×
286

287
  [[nodiscard]] bool isUnspecified() const
288
  {
1,594✔
289
    const ComboAddress unspecifiedV4("0.0.0.0:0");
1,594✔
290
    const ComboAddress unspecifiedV6("[::]:0");
1,594✔
291
    return *this == unspecifiedV4 || *this == unspecifiedV6;
1,594!
292
  }
1,594✔
293

294
  [[nodiscard]] ComboAddress mapToIPv4() const
295
  {
×
296
    if (!isMappedIPv4()) {
×
297
      throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
×
298
    }
×
299
    ComboAddress ret;
×
300
    ret.sin4.sin_family = AF_INET;
×
301
    ret.sin4.sin_port = sin4.sin_port;
×
302

303
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
304
    const auto* ptr = reinterpret_cast<const unsigned char*>(&sin6.sin6_addr.s6_addr);
×
305
    ptr += (sizeof(sin6.sin6_addr.s6_addr) - sizeof(ret.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
×
306
    memcpy(&ret.sin4.sin_addr.s_addr, ptr, sizeof(ret.sin4.sin_addr.s_addr));
×
307
    return ret;
×
308
  }
×
309

310
  [[nodiscard]] string toString() const
311
  {
1,352,874✔
312
    std::array<char, 1024> host{};
1,352,874✔
313
    if (sin4.sin_family != 0) {
1,352,878✔
314
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
315
      int retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host.data(), host.size(), nullptr, 0, NI_NUMERICHOST);
1,352,861✔
316
      if (retval == 0) {
1,352,875✔
317
        return host.data();
1,352,874✔
318
      }
1,352,874✔
319
      return "invalid " + string(gai_strerror(retval));
15,032,385,529✔
320
    }
1,352,861✔
321
    return "invalid";
2,147,483,663✔
322
  }
1,352,874✔
323

324
  //! Ignores any interface specifiers possibly available in the sockaddr data.
325
  [[nodiscard]] string toStringNoInterface() const
326
  {
4,380✔
327
    std::array<char, 1024> host{};
4,380✔
328
    if (sin4.sin_family == AF_INET) {
4,380✔
329
      const auto* ret = inet_ntop(sin4.sin_family, &sin4.sin_addr, host.data(), host.size());
3,711✔
330
      if (ret != nullptr) {
3,711!
331
        return host.data();
3,711✔
332
      }
3,711✔
333
    }
3,711✔
334
    else if (sin4.sin_family == AF_INET6) {
669!
335
      const auto* ret = inet_ntop(sin4.sin_family, &sin6.sin6_addr, host.data(), host.size());
669✔
336
      if (ret != nullptr) {
669!
337
        return host.data();
669✔
338
      }
669✔
339
    }
669✔
340
    else {
×
341
      return "invalid";
×
342
    }
×
343
    return "invalid " + stringerror();
×
344
  }
4,380✔
345

346
  [[nodiscard]] string toStringReversed() const
347
  {
70✔
348
    if (isIPv4()) {
70✔
349
      const auto address = ntohl(sin4.sin_addr.s_addr);
34✔
350
      auto aaa = (address >> 0) & 0xFF;
34✔
351
      auto bbb = (address >> 8) & 0xFF;
34✔
352
      auto ccc = (address >> 16) & 0xFF;
34✔
353
      auto ddd = (address >> 24) & 0xFF;
34✔
354
      return std::to_string(aaa) + "." + std::to_string(bbb) + "." + std::to_string(ccc) + "." + std::to_string(ddd);
34✔
355
    }
34✔
356
    const auto* addr = &sin6.sin6_addr;
36✔
357
    std::stringstream res{};
36✔
358
    res << std::hex;
36✔
359
    for (int i = 15; i >= 0; i--) {
612✔
360
      auto byte = addr->s6_addr[i]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
576✔
361
      res << ((byte >> 0) & 0xF) << ".";
576✔
362
      res << ((byte >> 4) & 0xF);
576✔
363
      if (i != 0) {
576✔
364
        res << ".";
540✔
365
      }
540✔
366
    }
576✔
367
    return res.str();
36✔
368
  }
70✔
369

370
  [[nodiscard]] string toStringWithPort() const
371
  {
14,439✔
372
    if (sin4.sin_family == AF_INET) {
14,439✔
373
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
14,225✔
374
    }
14,225✔
375
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
214✔
376
  }
14,439✔
377

378
  [[nodiscard]] string toStringWithPortExcept(int port) const
379
  {
2,761✔
380
    if (ntohs(sin4.sin_port) == port) {
2,761✔
381
      return toString();
290✔
382
    }
290✔
383
    if (sin4.sin_family == AF_INET) {
2,471✔
384
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
2,441✔
385
    }
2,441✔
386
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
30✔
387
  }
2,471✔
388

389
  [[nodiscard]] string toLogString() const
390
  {
1,718✔
391
    return toStringWithPortExcept(53);
1,718✔
392
  }
1,718✔
393

394
  [[nodiscard]] string toStructuredLogString() const
UNCOV
395
  {
×
UNCOV
396
    return toStringWithPort();
×
UNCOV
397
  }
×
398

399
  [[nodiscard]] string toByteString() const
400
  {
326✔
401
    // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
402
    if (isIPv4()) {
326✔
403
      return {reinterpret_cast<const char*>(&sin4.sin_addr.s_addr), sizeof(sin4.sin_addr.s_addr)};
309✔
404
    }
309✔
405
    return {reinterpret_cast<const char*>(&sin6.sin6_addr.s6_addr), sizeof(sin6.sin6_addr.s6_addr)};
17✔
406
    // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
407
  }
326✔
408

409
  void truncate(unsigned int bits) noexcept;
410

411
  [[nodiscard]] uint16_t getNetworkOrderPort() const noexcept
412
  {
1,025,008✔
413
    return sin4.sin_port;
1,025,008✔
414
  }
1,025,008✔
415
  [[nodiscard]] uint16_t getPort() const noexcept
416
  {
1,025,009✔
417
    return ntohs(getNetworkOrderPort());
1,025,009✔
418
  }
1,025,009✔
419
  void setPort(uint16_t port)
420
  {
291,332✔
421
    sin4.sin_port = htons(port);
291,332✔
422
  }
291,332✔
423

424
  void reset()
425
  {
744,538✔
426
    memset(&sin6, 0, sizeof(sin6));
744,538✔
427
  }
744,538✔
428

429
  //! Get the total number of address bits (either 32 or 128 depending on IP version)
430
  [[nodiscard]] uint8_t getBits() const
431
  {
94,956,822✔
432
    if (isIPv4()) {
94,956,822✔
433
      return 32;
42,913,876✔
434
    }
42,913,876✔
435
    if (isIPv6()) {
52,042,954✔
436
      return 128;
52,042,947✔
437
    }
52,042,947✔
438
    return 0;
8,589,934,588✔
439
  }
52,042,946✔
440
  /** Get the value of the bit at the provided bit index. When the index >= 0,
441
      the index is relative to the LSB starting at index zero. When the index < 0,
442
      the index is relative to the MSB starting at index -1 and counting down.
443
   */
444
  [[nodiscard]] bool getBit(int index) const
445
  {
161,992,696✔
446
    if (isIPv4()) {
161,992,696✔
447
      if (index >= 32) {
52,737,085!
448
        return false;
×
449
      }
×
450
      if (index < 0) {
52,737,091✔
451
        if (index < -32) {
40,039,174!
452
          return false;
×
453
        }
×
454
        index = 32 + index;
40,039,174✔
455
      }
40,039,174✔
456

457
      uint32_t ls_addr = ntohl(sin4.sin_addr.s_addr);
52,737,085✔
458

459
      return ((ls_addr & (1U << index)) != 0x00000000);
52,737,085✔
460
    }
52,737,085✔
461
    if (isIPv6()) {
109,255,628✔
462
      if (index >= 128) {
109,255,625!
463
        return false;
×
464
      }
×
465
      if (index < 0) {
109,255,625✔
466
        if (index < -128) {
92,477,258!
467
          return false;
×
468
        }
×
469
        index = 128 + index;
92,477,258✔
470
      }
92,477,258✔
471

472
      const auto* ls_addr = reinterpret_cast<const uint8_t*>(sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
109,255,625✔
473
      uint8_t byte_idx = index / 8;
109,255,625✔
474
      uint8_t bit_idx = index % 8;
109,255,625✔
475

476
      return ((ls_addr[15 - byte_idx] & (1U << bit_idx)) != 0x00); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
109,255,625✔
477
    }
109,255,625✔
478
    return false;
2,147,483,648✔
479
  }
109,255,611✔
480

481
  /*! Returns a comma-separated string of IP addresses
482
   *
483
   * \param c  An stl container with ComboAddresses
484
   * \param withPort  Also print the port (default true)
485
   * \param portExcept  Print the port, except when this is the port (default 53)
486
   */
487
  template <template <class...> class Container, class... Args>
488
  static string caContainerToString(const Container<ComboAddress, Args...>& container, const bool withPort = true, const uint16_t portExcept = 53)
489
  {
105✔
490
    vector<string> strs;
105✔
491
    for (const auto& address : container) {
237✔
492
      if (withPort) {
237✔
493
        strs.push_back(address.toStringWithPortExcept(portExcept));
80✔
494
        continue;
80✔
495
      }
80✔
496
      strs.push_back(address.toString());
157✔
497
    }
157✔
498
    return boost::join(strs, ",");
105✔
499
  };
105✔
500
};
501

502
union SockaddrWrapper
503
{
504
  sockaddr_in sin4{};
505
  sockaddr_in6 sin6;
506
  sockaddr_un sinun;
507

508
  [[nodiscard]] socklen_t getSocklen() const
509
  {
28✔
510
    if (sin4.sin_family == AF_INET) {
28!
511
      return sizeof(sin4);
28✔
512
    }
28✔
513
    if (sin6.sin6_family == AF_INET6) {
×
514
      return sizeof(sin6);
×
515
    }
×
516
    if (sinun.sun_family == AF_UNIX) {
×
517
      return sizeof(sinun);
×
518
    }
×
519
    return 0;
×
520
  }
×
521

522
  SockaddrWrapper()
523
  {
×
524
    sin4.sin_family = AF_INET;
×
525
    sin4.sin_addr.s_addr = 0;
×
526
    sin4.sin_port = 0;
×
527
  }
×
528

529
  SockaddrWrapper(const struct sockaddr* socketAddress, socklen_t salen)
530
  {
×
531
    setSockaddr(socketAddress, salen);
×
532
  };
×
533

534
  SockaddrWrapper(const struct sockaddr_in6* socketAddress)
535
  {
×
536
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
×
537
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in6));
×
538
  };
×
539

540
  SockaddrWrapper(const struct sockaddr_in* socketAddress)
541
  {
×
542
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
×
543
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in));
×
544
  };
×
545

546
  SockaddrWrapper(const struct sockaddr_un* socketAddress)
547
  {
×
548
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
×
549
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_un));
×
550
  };
×
551

552
  void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen)
553
  {
×
554
    if (salen > sizeof(struct sockaddr_un)) {
×
555
      throw PDNSException("ComboAddress can't handle other than sockaddr_in, sockaddr_in6 or sockaddr_un");
×
556
    }
×
557
    memcpy(this, socketAddress, salen);
×
558
  }
×
559

560
  explicit SockaddrWrapper(const string& str, uint16_t port = 0)
561
  {
89✔
562
    memset(&sinun, 0, sizeof(sinun));
89✔
563
    sin4.sin_family = AF_INET;
89✔
564
    sin4.sin_port = 0;
89✔
565
    if (str == "\"\"" || str == "''") {
89✔
566
      throw PDNSException("Stray quotation marks in address.");
10✔
567
    }
10✔
568
    if (makeIPv4sockaddr(str, &sin4) != 0) {
79✔
569
      sin6.sin6_family = AF_INET6;
45✔
570
      if (makeIPv6sockaddr(str, &sin6) < 0) {
45✔
571
        sinun.sun_family = AF_UNIX;
25✔
572
        // only attempt Unix socket address if address candidate does not contain a port
573
        if (str.find(':') != string::npos || makeUNsockaddr(str, &sinun) < 0) {
25!
574
          throw PDNSException("Unable to convert presentation address '" + str + "'");
20✔
575
        }
20✔
576
      }
25✔
577
    }
45✔
578
    if (sinun.sun_family != AF_UNIX && sin4.sin_port == 0) { // 'str' overrides port!
59✔
579
      sin4.sin_port = htons(port);
34✔
580
    }
34✔
581
  }
59✔
582

583
  [[nodiscard]] bool isIPv6() const
584
  {
×
585
    return sin4.sin_family == AF_INET6;
×
586
  }
×
587
  [[nodiscard]] bool isIPv4() const
588
  {
×
589
    return sin4.sin_family == AF_INET;
×
590
  }
×
591
  [[nodiscard]] bool isUnixSocket() const
592
  {
1,518✔
593
    return sin4.sin_family == AF_UNIX;
1,518✔
594
  }
1,518✔
595

596
  [[nodiscard]] string toString() const
597
  {
14✔
598
    if (sinun.sun_family == AF_UNIX) {
14!
599
      return sinun.sun_path;
×
600
    }
×
601
    std::array<char, 1024> host{};
14✔
602
    if (sin4.sin_family != 0) {
14!
603
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
604
      int retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host.data(), host.size(), nullptr, 0, NI_NUMERICHOST);
14✔
605
      if (retval == 0) {
14!
606
        return host.data();
14✔
607
      }
14✔
608
      return "invalid " + string(gai_strerror(retval));
×
609
    }
14✔
610
    return "invalid";
×
611
  }
14✔
612

613
  [[nodiscard]] string toStringWithPort() const
614
  {
14✔
615
    if (sinun.sun_family == AF_UNIX) {
14!
616
      return toString();
×
617
    }
×
618
    if (sin4.sin_family == AF_INET) {
14!
619
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
14✔
620
    }
14✔
621
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
×
622
  }
14✔
623

624
  void reset()
625
  {
×
626
    memset(&sinun, 0, sizeof(sinun));
×
627
  }
×
628
};
629

630
/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
631
class NetmaskException : public PDNSException
632
{
633
public:
634
  NetmaskException(const string& arg) :
635
    PDNSException(arg) {}
314✔
636
};
637

638
inline ComboAddress makeComboAddress(const string& str)
639
{
702,663✔
640
  ComboAddress address;
702,663✔
641
  address.sin4.sin_family = AF_INET;
702,663✔
642
  if (inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
702,663✔
643
    address.sin4.sin_family = AF_INET6;
339,993✔
644
    if (makeIPv6sockaddr(str, &address.sin6) < 0) {
339,993✔
645
      throw NetmaskException("Unable to convert '" + str + "' to a netmask");
314✔
646
    }
314✔
647
  }
339,993✔
648
  return address;
702,349✔
649
}
702,663✔
650

651
inline ComboAddress makeComboAddressFromRaw(uint8_t version, const char* raw, size_t len)
652
{
199✔
653
  ComboAddress address;
199✔
654

655
  if (version == 4) {
199✔
656
    address.sin4.sin_family = AF_INET;
124✔
657
    if (len != sizeof(address.sin4.sin_addr)) {
124!
658
      throw NetmaskException("invalid raw address length");
×
659
    }
×
660
    memcpy(&address.sin4.sin_addr, raw, sizeof(address.sin4.sin_addr));
124✔
661
  }
124✔
662
  else if (version == 6) {
75!
663
    address.sin6.sin6_family = AF_INET6;
75✔
664
    if (len != sizeof(address.sin6.sin6_addr)) {
75!
665
      throw NetmaskException("invalid raw address length");
×
666
    }
×
667
    memcpy(&address.sin6.sin6_addr, raw, sizeof(address.sin6.sin6_addr));
75✔
668
  }
75✔
669
  else {
×
670
    throw NetmaskException("invalid address family");
×
671
  }
×
672

673
  return address;
199✔
674
}
199✔
675

676
inline ComboAddress makeComboAddressFromRaw(uint8_t version, const string& str)
677
{
109✔
678
  return makeComboAddressFromRaw(version, str.c_str(), str.size());
109✔
679
}
109✔
680

681
/** This class represents a netmask and can be queried to see if a certain
682
    IP address is matched by this mask */
683
class Netmask
684
{
685
public:
686
  Netmask()
687
  {
5,000,550✔
688
    d_network.sin4.sin_family = 0; // disable this doing anything useful
5,000,550✔
689
    d_network.sin4.sin_port = 0; // this guarantees d_network compares identical
5,000,550✔
690
  }
5,000,550✔
691

692
  Netmask(const ComboAddress& network, uint8_t bits = 0xff) :
693
    d_network(network)
14,318,104✔
694
  {
37,342,948✔
695
    d_network.sin4.sin_port = 0;
37,342,948✔
696
    setBits(bits);
37,342,948✔
697
  }
37,342,948✔
698

699
  Netmask(const sockaddr_in* network, uint8_t bits = 0xff) :
700
    d_network(network)
701
  {
×
702
    d_network.sin4.sin_port = 0;
×
703
    setBits(bits);
×
704
  }
×
705
  Netmask(const sockaddr_in6* network, uint8_t bits = 0xff) :
706
    d_network(network)
707
  {
×
708
    d_network.sin4.sin_port = 0;
×
709
    setBits(bits);
×
710
  }
×
711
  void setBits(uint8_t value)
712
  {
38,045,290✔
713
    d_bits = d_network.isIPv4() ? std::min(value, static_cast<uint8_t>(32U)) : std::min(value, static_cast<uint8_t>(128U));
38,045,290✔
714

715
    if (d_bits < 32) {
38,045,290✔
716
      d_mask = ~(0xFFFFFFFF >> d_bits);
8,007,859✔
717
    }
8,007,859✔
718
    else {
30,037,431✔
719
      // note that d_mask is unused for IPv6
720
      d_mask = 0xFFFFFFFF;
30,037,431✔
721
    }
30,037,431✔
722

723
    if (isIPv4()) {
38,045,290✔
724
      d_network.sin4.sin_addr.s_addr = htonl(ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
15,787,644✔
725
    }
15,787,644✔
726
    else if (isIPv6()) {
22,257,652✔
727
      uint8_t bytes = d_bits / 8;
21,027,401✔
728
      auto* address = reinterpret_cast<uint8_t*>(&d_network.sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
21,027,401✔
729
      uint8_t bits = d_bits % 8;
21,027,401✔
730
      auto mask = static_cast<uint8_t>(~(0xFF >> bits));
21,027,401✔
731

732
      if (bytes < sizeof(d_network.sin6.sin6_addr.s6_addr)) {
21,027,401✔
733
        address[bytes] &= mask; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
17,070,811✔
734
      }
17,070,811✔
735

736
      for (size_t idx = bytes + 1; idx < sizeof(d_network.sin6.sin6_addr.s6_addr); ++idx) {
156,815,600✔
737
        address[idx] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
135,788,199✔
738
      }
135,788,199✔
739
    }
21,027,401✔
740
  }
38,045,290✔
741

742
  enum stringType
743
  {
744
    humanString,
745
    byteString,
746
  };
747
  //! Constructor supplies the mask, which cannot be changed
748
  Netmask(const string& mask, stringType type = humanString)
749
  {
702,681✔
750
    if (type == byteString) {
702,681✔
751
      uint8_t afi = mask.at(0);
56✔
752
      size_t len = afi == 4 ? 4 : 16;
56!
753
      uint8_t bits = mask.at(len + 1);
56✔
754

755
      d_network = makeComboAddressFromRaw(afi, mask.substr(1, len));
56✔
756

757
      setBits(bits);
56✔
758
    }
56✔
759
    else {
702,625✔
760
      pair<string, string> split = splitField(mask, '/');
702,625✔
761
      d_network = makeComboAddress(split.first);
702,625✔
762

763
      if (!split.second.empty()) {
702,625✔
764
        setBits(pdns::checked_stoi<uint8_t>(split.second));
366,351✔
765
      }
366,351✔
766
      else if (d_network.sin4.sin_family == AF_INET) {
336,274✔
767
        setBits(32);
332,468✔
768
      }
332,468✔
769
      else {
3,806✔
770
        setBits(128);
3,806✔
771
      }
3,806✔
772
    }
702,625✔
773
  }
702,681✔
774

775
  [[nodiscard]] bool match(const ComboAddress& address) const
776
  {
73✔
777
    return match(&address);
73✔
778
  }
73✔
779

780
  //! If this IP address in socket address matches
781
  bool match(const ComboAddress* address) const
782
  {
108✔
783
    if (d_network.sin4.sin_family != address->sin4.sin_family) {
108!
784
      return false;
×
785
    }
×
786
    if (d_network.sin4.sin_family == AF_INET) {
108✔
787
      return match4(htonl((unsigned int)address->sin4.sin_addr.s_addr));
78✔
788
    }
78✔
789
    if (d_network.sin6.sin6_family == AF_INET6) {
30!
790
      uint8_t bytes = d_bits / 8;
30✔
791
      uint8_t index = 0;
30✔
792
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
793
      const auto* lhs = reinterpret_cast<const uint8_t*>(&d_network.sin6.sin6_addr.s6_addr);
30✔
794
      const auto* rhs = reinterpret_cast<const uint8_t*>(&address->sin6.sin6_addr.s6_addr);
30✔
795
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
796

797
      // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
798
      for (index = 0; index < bytes; ++index) {
160✔
799
        if (lhs[index] != rhs[index]) {
140✔
800
          return false;
10✔
801
        }
10✔
802
      }
140✔
803
      // still here, now match remaining bits
804
      uint8_t bits = d_bits % 8;
20✔
805
      auto mask = static_cast<uint8_t>(~(0xFF >> bits));
20✔
806

807
      return ((lhs[index]) == (rhs[index] & mask));
20✔
808
      // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
809
    }
30✔
810
    return false;
×
811
  }
30✔
812

813
  //! If this ASCII IP address matches
814
  [[nodiscard]] bool match(const string& arg) const
815
  {
35✔
816
    ComboAddress address = makeComboAddress(arg);
35✔
817
    return match(&address);
35✔
818
  }
35✔
819

820
  //! If this IP address in native format matches
821
  [[nodiscard]] bool match4(uint32_t arg) const
822
  {
78✔
823
    return (arg & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr));
78✔
824
  }
78✔
825

826
  [[nodiscard]] string toString() const
827
  {
2,280✔
828
    return d_network.toStringNoInterface() + "/" + std::to_string((unsigned int)d_bits);
2,280✔
829
  }
2,280✔
830

831
  [[nodiscard]] string toStringNoMask() const
832
  {
1,501✔
833
    return d_network.toStringNoInterface();
1,501✔
834
  }
1,501✔
835

836
  [[nodiscard]] string toByteString() const
837
  {
86✔
838
    ostringstream tmp;
86✔
839

840
    tmp << (d_network.isIPv4() ? "\x04" : "\x06")
86✔
841
        << d_network.toByteString()
86✔
842
        << getBits();
86✔
843

844
    return tmp.str();
86✔
845
  }
86✔
846

847
  [[nodiscard]] const ComboAddress& getNetwork() const
848
  {
35,002,423✔
849
    return d_network;
35,002,423✔
850
  }
35,002,423✔
851

852
  [[nodiscard]] const ComboAddress& getMaskedNetwork() const
853
  {
34,921,180✔
854
    return getNetwork();
34,921,180✔
855
  }
34,921,180✔
856

857
  [[nodiscard]] uint8_t getBits() const
858
  {
93,718,886✔
859
    return d_bits;
93,718,886✔
860
  }
93,718,886✔
861

862
  [[nodiscard]] bool isIPv6() const
863
  {
23,327,700✔
864
    return d_network.sin6.sin6_family == AF_INET6;
23,327,700✔
865
  }
23,327,700✔
866

867
  [[nodiscard]] bool isIPv4() const
868
  {
40,492,605✔
869
    return d_network.sin4.sin_family == AF_INET;
40,492,605✔
870
  }
40,492,605✔
871

872
  bool operator<(const Netmask& rhs) const
873
  {
1,602,798✔
874
    if (empty() && !rhs.empty()) {
1,602,798✔
875
      return false;
6✔
876
    }
6✔
877
    if (!empty() && rhs.empty()) {
1,602,792✔
878
      return true;
3,124✔
879
    }
3,124✔
880
    if (d_bits > rhs.d_bits) {
1,599,668✔
881
      return true;
297,700✔
882
    }
297,700✔
883
    if (d_bits < rhs.d_bits) {
1,301,968✔
884
      return false;
154,874✔
885
    }
154,874✔
886

887
    return d_network < rhs.d_network;
1,147,094✔
888
  }
1,301,968✔
889

890
  bool operator>(const Netmask& rhs) const
891
  {
30✔
892
    return rhs.operator<(*this);
30✔
893
  }
30✔
894

895
  bool operator==(const Netmask& rhs) const
896
  {
32,080,616✔
897
    return std::tie(d_network, d_bits) == std::tie(rhs.d_network, rhs.d_bits);
32,080,616✔
898
  }
32,080,616✔
899
  bool operator!=(const Netmask& rhs) const
900
  {
4✔
901
    return !operator==(rhs);
4✔
902
  }
4✔
903

904
  [[nodiscard]] bool empty() const
905
  {
6,306,807✔
906
    return d_network.sin4.sin_family == 0;
6,306,807✔
907
  }
6,306,807✔
908

909
  //! Get normalized version of the netmask. This means that all address bits below the network bits are zero.
910
  [[nodiscard]] Netmask getNormalized() const
911
  {
34,875,203✔
912
    return {getMaskedNetwork(), d_bits};
34,875,203✔
913
  }
34,875,203✔
914
  //! Get Netmask for super network of this one (i.e. with fewer network bits)
915
  [[nodiscard]] Netmask getSuper(uint8_t bits) const
916
  {
697,670✔
917
    return {d_network, std::min(d_bits, bits)};
697,670✔
918
  }
697,670✔
919

920
  //! Get the total number of address bits for this netmask (either 32 or 128 depending on IP version)
921
  [[nodiscard]] uint8_t getFullBits() const
922
  {
1,461,425✔
923
    return d_network.getBits();
1,461,425✔
924
  }
1,461,425✔
925

926
  /** Get the value of the bit at the provided bit index. When the index >= 0,
927
      the index is relative to the LSB starting at index zero. When the index < 0,
928
      the index is relative to the MSB starting at index -1 and counting down.
929
      When the index points outside the network bits, it always yields zero.
930
   */
931
  [[nodiscard]] bool getBit(int bit) const
932
  {
132,516,419✔
933
    if (bit < -d_bits) {
132,516,419!
934
      return false;
×
935
    }
×
936
    if (bit >= 0) {
132,516,419!
937
      if (isIPv4()) {
×
938
        if (bit >= 32 || bit < (32 - d_bits)) {
×
939
          return false;
×
940
        }
×
941
      }
×
942
      if (isIPv6()) {
×
943
        if (bit >= 128 || bit < (128 - d_bits)) {
×
944
          return false;
×
945
        }
×
946
      }
×
947
    }
×
948
    return d_network.getBit(bit);
132,516,419✔
949
  }
132,516,419✔
950

951
  struct Hash
952
  {
953
    size_t operator()(const Netmask& netmask) const
954
    {
×
955
      return burtle(&netmask.d_bits, 1, ComboAddress::addressOnlyHash()(netmask.d_network));
×
956
    }
×
957
  };
958

959
private:
960
  ComboAddress d_network;
961
  uint32_t d_mask{0};
962
  uint8_t d_bits{0};
963
};
964

965
namespace std
966
{
967
template <>
968
struct hash<Netmask>
969
{
970
  auto operator()(const Netmask& netmask) const
971
  {
×
972
    return Netmask::Hash{}(netmask);
×
973
  }
×
974
};
975
}
976

977
/** Binary tree map implementation with <Netmask,T> pair.
978
 *
979
 * This is an binary tree implementation for storing attributes for IPv4 and IPv6 prefixes.
980
 * The most simple use case is simple NetmaskTree<bool> used by NetmaskGroup, which only
981
 * wants to know if given IP address is matched in the prefixes stored.
982
 *
983
 * This element is useful for anything that needs to *STORE* prefixes, and *MATCH* IP addresses
984
 * to a *LIST* of *PREFIXES*. Not the other way round.
985
 *
986
 * You can store IPv4 and IPv6 addresses to same tree, separate payload storage is kept per AFI.
987
 * Network prefixes (Netmasks) are always recorded in normalized fashion, meaning that only
988
 * the network bits are set. This is what is returned in the insert() and lookup() return
989
 * values.
990
 *
991
 * Use swap if you need to move the tree to another NetmaskTree instance, it is WAY faster
992
 * than using copy ctor or assignment operator, since it moves the nodes and tree root to
993
 * new home instead of actually recreating the tree.
994
 *
995
 * Please see NetmaskGroup for example of simple use case. Other usecases can be found
996
 * from GeoIPBackend and Sortlist, and from dnsdist.
997
 */
998
template <typename T, class K = Netmask>
999
class NetmaskTree
1000
{
1001
public:
1002
  class Iterator;
1003

1004
  using key_type = K;
1005
  using value_type = T;
1006
  using node_type = std::pair<const key_type, value_type>;
1007
  using size_type = size_t;
1008
  using iterator = class Iterator;
1009

1010
private:
1011
  /** Single node in tree, internal use only.
1012
   */
1013
  class TreeNode : boost::noncopyable
1014
  {
1015
  public:
1016
    explicit TreeNode() noexcept :
1017
      parent(nullptr), node(), assigned(false), d_bits(0)
35,352✔
1018
    {
50,251✔
1019
    }
50,251✔
1020
    explicit TreeNode(const key_type& key) :
1021
      parent(nullptr), node({key.getNormalized(), value_type()}), assigned(false), d_bits(key.getFullBits())
601,908✔
1022
    {
1,462,535✔
1023
    }
1,462,535✔
1024

1025
    //<! Makes a left leaf node with specified key.
1026
    TreeNode* make_left(const key_type& key)
1027
    {
2,315✔
1028
      d_bits = node.first.getBits();
2,315✔
1029
      left = make_unique<TreeNode>(key);
2,315✔
1030
      left->parent = this;
2,315✔
1031
      return left.get();
2,315✔
1032
    }
2,315✔
1033

1034
    //<! Makes a right leaf node with specified key.
1035
    TreeNode* make_right(const key_type& key)
1036
    {
24,720✔
1037
      d_bits = node.first.getBits();
24,720✔
1038
      right = make_unique<TreeNode>(key);
24,720✔
1039
      right->parent = this;
24,720✔
1040
      return right.get();
24,720✔
1041
    }
24,720✔
1042

1043
    //<! Splits branch at indicated bit position by inserting key
1044
    TreeNode* split(const key_type& key, int bits)
1045
    {
5,299✔
1046
      if (parent == nullptr) {
5,299!
1047
        // not to be called on the root node
1048
        throw std::logic_error(
×
1049
          "NetmaskTree::TreeNode::split(): must not be called on root node");
×
1050
      }
×
1051

1052
      // determine reference from parent
1053
      unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
5,299!
1054
      if (parent_ref.get() != this) {
5,299!
1055
        throw std::logic_error(
×
1056
          "NetmaskTree::TreeNode::split(): parent node reference is invalid");
×
1057
      }
×
1058

1059
      // create new tree node for the new key and
1060
      // attach the new node under our former parent
1061
      auto new_intermediate_node = make_unique<TreeNode>(key);
5,299✔
1062
      new_intermediate_node->d_bits = bits;
5,299✔
1063
      new_intermediate_node->parent = parent;
5,299✔
1064
      auto* new_intermediate_node_raw = new_intermediate_node.get();
5,299✔
1065

1066
      // hereafter new_intermediate points to "this"
1067
      // ie the child of the new intermediate node
1068
      std::swap(parent_ref, new_intermediate_node);
5,299✔
1069
      // and we now assign this to current_node so
1070
      // it's clear it no longer refers to the new
1071
      // intermediate node
1072
      std::unique_ptr<TreeNode> current_node = std::move(new_intermediate_node);
5,299✔
1073

1074
      // attach "this" node below the new node
1075
      // (left or right depending on bit)
1076
      // technically the raw pointer escapes the duration of the
1077
      // unique pointer, but just below we store the unique pointer
1078
      // in the parent, so it lives as long as necessary
1079
      // coverity[escape]
1080
      current_node->parent = new_intermediate_node_raw;
5,299✔
1081
      if (current_node->node.first.getBit(-1 - bits)) {
5,299✔
1082
        new_intermediate_node_raw->right = std::move(current_node);
188✔
1083
      }
188✔
1084
      else {
5,111✔
1085
        new_intermediate_node_raw->left = std::move(current_node);
5,111✔
1086
      }
5,111✔
1087

1088
      return new_intermediate_node_raw;
5,299✔
1089
    }
5,299✔
1090

1091
    //<! Forks branch for new key at indicated bit position
1092
    TreeNode* fork(const key_type& key, int bits)
1093
    {
698,180✔
1094
      if (parent == nullptr) {
698,180!
1095
        // not to be called on the root node
1096
        throw std::logic_error(
×
1097
          "NetmaskTree::TreeNode::fork(): must not be called on root node");
×
1098
      }
×
1099

1100
      // determine reference from parent
1101
      unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
698,180!
1102
      if (parent_ref.get() != this) {
698,180!
1103
        throw std::logic_error(
×
1104
          "NetmaskTree::TreeNode::fork(): parent node reference is invalid");
×
1105
      }
×
1106

1107
      // create new tree node for the branch point
1108

1109
      // the current node will now be a child of the new branch node
1110
      // (hereafter new_child1 points to "this")
1111
      unique_ptr<TreeNode> new_child1 = std::move(parent_ref);
698,180✔
1112
      // attach the branch node under our former parent
1113
      parent_ref = make_unique<TreeNode>(node.first.getSuper(bits));
698,180✔
1114
      auto* branch_node = parent_ref.get();
698,180✔
1115
      branch_node->d_bits = bits;
698,180✔
1116
      branch_node->parent = parent;
698,180✔
1117

1118
      // create second new leaf node for the new key
1119
      unique_ptr<TreeNode> new_child2 = make_unique<TreeNode>(key);
698,180✔
1120
      TreeNode* new_node = new_child2.get();
698,180✔
1121

1122
      // attach the new child nodes below the branch node
1123
      // (left or right depending on bit)
1124
      new_child1->parent = branch_node;
698,180✔
1125
      new_child2->parent = branch_node;
698,180✔
1126
      if (new_child1->node.first.getBit(-1 - bits)) {
698,180✔
1127
        branch_node->right = std::move(new_child1);
3,633✔
1128
        branch_node->left = std::move(new_child2);
3,633✔
1129
      }
3,633✔
1130
      else {
694,547✔
1131
        branch_node->right = std::move(new_child2);
694,547✔
1132
        branch_node->left = std::move(new_child1);
694,547✔
1133
      }
694,547✔
1134
      // now we have attached the new unique pointers to the tree:
1135
      // - branch_node is below its parent
1136
      // - new_child1 (ourselves) is below branch_node
1137
      // - new_child2, the new leaf node, is below branch_node as well
1138

1139
      return new_node;
698,180✔
1140
    }
698,180✔
1141

1142
    //<! Traverse left branch depth-first
1143
    TreeNode* traverse_l()
1144
    {
199,302✔
1145
      TreeNode* tnode = this;
199,302✔
1146

1147
      while (tnode->left) {
375,946!
1148
        tnode = tnode->left.get();
176,644✔
1149
      }
176,644✔
1150
      return tnode;
199,302✔
1151
    }
199,302✔
1152

1153
    //<! Traverse tree depth-first and in-order (L-N-R)
1154
    TreeNode* traverse_lnr()
1155
    {
379,065✔
1156
      TreeNode* tnode = this;
379,065✔
1157

1158
      // precondition: descended left as deep as possible
1159
      if (tnode->right) {
379,065✔
1160
        // descend right
1161
        tnode = tnode->right.get();
169,341✔
1162
        // descend left as deep as possible and return next node
1163
        return tnode->traverse_l();
169,341✔
1164
      }
169,341✔
1165

1166
      // ascend to parent
1167
      while (tnode->parent != nullptr) {
379,065✔
1168
        TreeNode* prev_child = tnode;
347,976✔
1169
        tnode = tnode->parent;
347,976✔
1170

1171
        // return this node, but only when we come from the left child branch
1172
        if (tnode->left && tnode->left.get() == prev_child) {
347,976✔
1173
          return tnode;
178,635✔
1174
        }
178,635✔
1175
      }
347,976✔
1176
      return nullptr;
31,089✔
1177
    }
209,724✔
1178

1179
    //<! Traverse only assigned nodes
1180
    TreeNode* traverse_lnr_assigned()
1181
    {
144,832✔
1182
      TreeNode* tnode = traverse_lnr();
144,832✔
1183

1184
      while (tnode != nullptr && !tnode->assigned) {
254,416!
1185
        tnode = tnode->traverse_lnr();
109,584✔
1186
      }
109,584✔
1187
      return tnode;
144,832✔
1188
    }
144,832✔
1189

1190
    unique_ptr<TreeNode> left;
1191
    unique_ptr<TreeNode> right;
1192
    TreeNode* parent;
1193

1194
    node_type node;
1195
    bool assigned; //<! Whether this node is assigned-to by the application
1196

1197
    int d_bits; //<! How many bits have been used so far
1198
  };
1199

1200
  void cleanup_tree(TreeNode* node)
1201
  {
47,278✔
1202
    // only cleanup this node if it has no children and node not assigned
1203
    if (!(node->left || node->right || node->assigned)) {
47,278!
1204
      // get parent node ptr
1205
      TreeNode* pparent = node->parent;
24,681✔
1206
      // delete this node
1207
      if (pparent) {
24,681✔
1208
        if (pparent->left.get() == node) {
24,654✔
1209
          pparent->left.reset();
3,389✔
1210
        }
3,389✔
1211
        else {
21,265✔
1212
          pparent->right.reset();
21,265✔
1213
        }
21,265✔
1214
        // now recurse up to the parent
1215
        cleanup_tree(pparent);
24,654✔
1216
      }
24,654✔
1217
    }
24,681✔
1218
  }
47,278✔
1219

1220
  void copyTree(const NetmaskTree& rhs)
1221
  {
29,961✔
1222
    try {
29,961✔
1223
      TreeNode* node = rhs.d_root.get();
29,961✔
1224
      if (node != nullptr) {
29,961!
1225
        node = node->traverse_l();
29,961✔
1226
      }
29,961✔
1227
      while (node != nullptr) {
154,610!
1228
        if (node->assigned) {
124,649!
1229
          insert(node->node.first).second = node->node.second;
64,507✔
1230
        }
64,507✔
1231
        node = node->traverse_lnr();
124,649✔
1232
      }
124,649✔
1233
    }
29,961✔
1234
    catch (const NetmaskException&) {
29,961✔
1235
      abort();
×
1236
    }
×
1237
    catch (const std::logic_error&) {
29,961✔
1238
      abort();
×
1239
    }
×
1240
  }
29,961✔
1241

1242
public:
1243
  class Iterator
1244
  {
1245
  public:
1246
    using value_type = node_type;
1247
    using reference = node_type&;
1248
    using pointer = node_type*;
1249
    using iterator_category = std::forward_iterator_tag;
1250
    using difference_type = size_type;
1251

1252
  private:
1253
    friend class NetmaskTree;
1254

1255
    const NetmaskTree* d_tree;
1256
    TreeNode* d_node;
1257

1258
    Iterator(const NetmaskTree* tree, TreeNode* node) :
1259
      d_tree(tree), d_node(node)
2,290✔
1260
    {
2,582✔
1261
    }
2,582✔
1262

1263
  public:
1264
    Iterator() :
1265
      d_tree(nullptr), d_node(nullptr) {}
×
1266

1267
    Iterator& operator++() // prefix
1268
    {
141,483✔
1269
      if (d_node == nullptr) {
141,483!
1270
        throw std::logic_error(
×
1271
          "NetmaskTree::Iterator::operator++: iterator is invalid");
×
1272
      }
×
1273
      d_node = d_node->traverse_lnr_assigned();
141,483✔
1274
      return *this;
141,483✔
1275
    }
141,483✔
1276
    Iterator operator++(int) // postfix
1277
    {
×
1278
      Iterator tmp(*this);
×
1279
      operator++();
×
1280
      return tmp;
×
1281
    }
×
1282

1283
    reference operator*()
1284
    {
78,059✔
1285
      if (d_node == nullptr) {
78,059!
1286
        throw std::logic_error(
×
1287
          "NetmaskTree::Iterator::operator*: iterator is invalid");
×
1288
      }
×
1289
      return d_node->node;
78,059✔
1290
    }
78,059✔
1291

1292
    pointer operator->()
1293
    {
328✔
1294
      if (d_node == nullptr) {
328!
1295
        throw std::logic_error(
×
1296
          "NetmaskTree::Iterator::operator->: iterator is invalid");
×
1297
      }
×
1298
      return &d_node->node;
328✔
1299
    }
328✔
1300

1301
    bool operator==(const Iterator& rhs)
1302
    {
142,774✔
1303
      return (d_tree == rhs.d_tree && d_node == rhs.d_node);
142,774!
1304
    }
142,774✔
1305
    bool operator!=(const Iterator& rhs)
1306
    {
142,774✔
1307
      return !(*this == rhs);
142,774✔
1308
    }
142,774✔
1309
  };
1310

1311
  NetmaskTree() noexcept :
1312
    d_root(new TreeNode()), d_left(nullptr)
7,063✔
1313
  {
18,139✔
1314
  }
18,139✔
1315

1316
  NetmaskTree(const NetmaskTree& rhs) :
1317
    d_root(new TreeNode()), d_left(nullptr)
28,122✔
1318
  {
29,946✔
1319
    copyTree(rhs);
29,946✔
1320
  }
29,946✔
1321

1322
  ~NetmaskTree() = default;
62,394✔
1323

1324
  NetmaskTree& operator=(const NetmaskTree& rhs)
1325
  {
15✔
1326
    if (this != &rhs) {
15!
1327
      clear();
15✔
1328
      copyTree(rhs);
15✔
1329
    }
15✔
1330
    return *this;
15✔
1331
  }
15✔
1332

1333
  NetmaskTree(NetmaskTree&&) noexcept = default;
28,458✔
1334
  NetmaskTree& operator=(NetmaskTree&&) noexcept = default;
2,973✔
1335

1336
  [[nodiscard]] iterator begin() const
1337
  {
1,236✔
1338
    return Iterator(this, d_left);
1,236✔
1339
  }
1,236✔
1340
  [[nodiscard]] iterator end() const
1341
  {
1,236✔
1342
    return Iterator(this, nullptr);
1,236✔
1343
  }
1,236✔
1344
  iterator begin()
1345
  {
55✔
1346
    return Iterator(this, d_left);
55✔
1347
  }
55✔
1348
  iterator end()
1349
  {
55✔
1350
    return Iterator(this, nullptr);
55✔
1351
  }
55✔
1352

1353
  node_type& insert(const string& mask)
1354
  {
15✔
1355
    return insert(key_type(mask));
15✔
1356
  }
15✔
1357

1358
  //<! Creates new value-pair in tree and returns it.
1359
  node_type& insert(const key_type& key)
1360
  {
765,182✔
1361
    TreeNode* node{};
765,182✔
1362
    bool is_left = true;
765,182✔
1363

1364
    // we turn left on IPv4 and right on IPv6
1365
    if (key.isIPv4()) {
765,182!
1366
      node = d_root->left.get();
393,432✔
1367
      if (node == nullptr) {
393,432✔
1368

1369
        d_root->left = make_unique<TreeNode>(key);
20,420✔
1370
        node = d_root->left.get();
20,420✔
1371
        node->assigned = true;
20,420✔
1372
        node->parent = d_root.get();
20,420✔
1373
        d_size++;
20,420✔
1374
        d_left = node;
20,420✔
1375
        return node->node;
20,420✔
1376
      }
20,420✔
1377
    }
393,432✔
1378
    else if (key.isIPv6()) {
371,750!
1379
      node = d_root->right.get();
371,750✔
1380
      if (node == nullptr) {
371,750!
1381

1382
        d_root->right = make_unique<TreeNode>(key);
13,421✔
1383
        node = d_root->right.get();
13,421✔
1384
        node->assigned = true;
13,421✔
1385
        node->parent = d_root.get();
13,421✔
1386
        d_size++;
13,421✔
1387
        if (!d_root->left) {
13,421✔
1388
          d_left = node;
19✔
1389
        }
19✔
1390
        return node->node;
13,421✔
1391
      }
13,421✔
1392
      if (d_root->left) {
358,329!
1393
        is_left = false;
358,317✔
1394
      }
358,317✔
1395
    }
358,329✔
1396
    else {
×
1397
      throw NetmaskException("invalid address family");
×
1398
    }
×
1399

1400
    // we turn left on 0 and right on 1
1401
    int bits = 0;
731,341✔
1402
    for (; bits < key.getBits(); bits++) {
32,637,038!
1403
      bool vall = key.getBit(-1 - bits);
32,630,912✔
1404

1405
      if (bits >= node->d_bits) {
32,630,912✔
1406
        // the end of the current node is reached; continue with the next
1407
        if (vall) {
4,998,384✔
1408
          if (node->left || node->assigned) {
4,844,318!
1409
            is_left = false;
4,844,318✔
1410
          }
4,844,318✔
1411
          if (!node->right) {
4,844,318!
1412
            // the right branch doesn't exist yet; attach our key here
1413
            node = node->make_right(key);
1,603✔
1414
            break;
1,603✔
1415
          }
1,603✔
1416
          node = node->right.get();
4,842,715✔
1417
        }
4,842,715✔
1418
        else {
154,066✔
1419
          if (!node->left) {
154,066✔
1420
            // the left branch doesn't exist yet; attach our key here
1421
            node = node->make_left(key);
56✔
1422
            break;
56✔
1423
          }
56✔
1424
          node = node->left.get();
154,010✔
1425
        }
154,010✔
1426
        continue;
4,996,725✔
1427
      }
4,998,384✔
1428
      if (bits >= node->node.first.getBits()) {
27,632,528✔
1429
        // the matching branch ends here, yet the key netmask has more bits; add a
1430
        // child node below the existing branch leaf.
1431
        if (vall) {
25,376!
1432
          if (node->assigned) {
23,117!
1433
            is_left = false;
23,117✔
1434
          }
23,117✔
1435
          node = node->make_right(key);
23,117✔
1436
        }
23,117✔
1437
        else {
2,259✔
1438
          node = node->make_left(key);
2,259✔
1439
        }
2,259✔
1440
        break;
25,376✔
1441
      }
25,376✔
1442
      bool valr = node->node.first.getBit(-1 - bits);
27,607,152✔
1443
      if (vall != valr) {
27,607,152✔
1444
        if (vall) {
698,180!
1445
          is_left = false;
694,547✔
1446
        }
694,547✔
1447
        // the branch matches just upto this point, yet continues in a different
1448
        // direction; fork the branch.
1449
        node = node->fork(key, bits);
698,180✔
1450
        break;
698,180✔
1451
      }
698,180✔
1452
    }
27,607,152✔
1453

1454
    if (node->node.first.getBits() > key.getBits()) {
731,341!
1455
      // key is a super-network of the matching node; split the branch and
1456
      // insert a node for the key above the matching node.
1457
      node = node->split(key, key.getBits());
5,299✔
1458
    }
5,299✔
1459

1460
    if (node->left) {
731,341!
1461
      is_left = false;
5,861✔
1462
    }
5,861✔
1463

1464
    node_type& value = node->node;
731,341✔
1465

1466
    if (!node->assigned) {
731,341!
1467
      // only increment size if not assigned before
1468
      d_size++;
730,799✔
1469
      // update the pointer to the left-most tree node
1470
      if (is_left) {
730,799✔
1471
        d_left = node;
350✔
1472
      }
350✔
1473
      node->assigned = true;
730,799✔
1474
    }
730,799✔
1475
    else {
542✔
1476
      // tree node exists for this value
1477
      if (is_left && d_left != node) {
542!
1478
        throw std::logic_error(
×
1479
          "NetmaskTree::insert(): lost track of left-most node in tree");
×
1480
      }
×
1481
    }
542✔
1482

1483
    return value;
731,341✔
1484
  }
731,341✔
1485

1486
  //<! Creates or updates value
1487
  void insert_or_assign(const key_type& mask, const value_type& value)
1488
  {
63✔
1489
    insert(mask).second = value;
63✔
1490
  }
63✔
1491

1492
  void insert_or_assign(const string& mask, const value_type& value)
1493
  {
×
1494
    insert(key_type(mask)).second = value;
×
1495
  }
×
1496

1497
  //<! check if given key is present in TreeMap
1498
  [[nodiscard]] bool has_key(const key_type& key) const
1499
  {
70✔
1500
    const node_type* ptr = lookup(key);
70✔
1501
    return ptr && ptr->first == key;
70!
1502
  }
70✔
1503

1504
  //<! Returns "best match" for key_type, which might not be value
1505
  [[nodiscard]] node_type* lookup(const key_type& value) const
1506
  {
332,337✔
1507
    uint8_t max_bits = value.getBits();
332,337✔
1508
    return lookupImpl(value, max_bits);
332,337✔
1509
  }
332,337✔
1510

1511
  //<! Perform best match lookup for value, using at most max_bits
1512
  [[nodiscard]] node_type* lookup(const ComboAddress& value, int max_bits = 128) const
1513
  {
1,596,410✔
1514
    uint8_t addr_bits = value.getBits();
1,596,410✔
1515
    if (max_bits < 0 || max_bits > addr_bits) {
1,596,424!
1516
      max_bits = addr_bits;
939,875✔
1517
    }
939,875✔
1518

1519
    return lookupImpl(key_type(value, max_bits), max_bits);
1,596,410✔
1520
  }
1,596,410✔
1521

1522
  //<! Removes key from TreeMap.
1523
  void erase(const key_type& key)
1524
  {
22,631✔
1525
    TreeNode* node = nullptr;
22,631✔
1526

1527
    if (key.isIPv4()) {
22,631✔
1528
      node = d_root->left.get();
22,596✔
1529
    }
22,596✔
1530
    else if (key.isIPv6()) {
35!
1531
      node = d_root->right.get();
35✔
1532
    }
35✔
1533
    else {
×
1534
      throw NetmaskException("invalid address family");
×
1535
    }
×
1536
    // no tree, no value
1537
    if (node == nullptr) {
22,631!
1538
      return;
×
1539
    }
×
1540
    int bits = 0;
22,631✔
1541
    for (; node && bits < key.getBits(); bits++) {
574,292!
1542
      bool vall = key.getBit(-1 - bits);
551,666✔
1543
      if (bits >= node->d_bits) {
551,666✔
1544
        // the end of the current node is reached; continue with the next
1545
        if (vall) {
356,718!
1546
          node = node->right.get();
244,732✔
1547
        }
244,732✔
1548
        else {
111,986✔
1549
          node = node->left.get();
111,986✔
1550
        }
111,986✔
1551
        continue;
356,718✔
1552
      }
356,718✔
1553
      if (bits >= node->node.first.getBits()) {
194,948!
1554
        // the matching branch ends here
1555
        if (key.getBits() != node->node.first.getBits()) {
×
1556
          node = nullptr;
×
1557
        }
×
1558
        break;
×
1559
      }
×
1560
      bool valr = node->node.first.getBit(-1 - bits);
194,948✔
1561
      if (vall != valr) {
194,948✔
1562
        // the branch matches just upto this point, yet continues in a different
1563
        // direction
1564
        node = nullptr;
5✔
1565
        break;
5✔
1566
      }
5✔
1567
    }
194,948✔
1568
    if (node) {
22,631✔
1569
      if (d_size == 0) {
22,624!
1570
        throw std::logic_error(
×
1571
          "NetmaskTree::erase(): size of tree is zero before erase");
×
1572
      }
×
1573
      d_size--;
22,624✔
1574
      node->assigned = false;
22,624✔
1575
      node->node.second = value_type();
22,624✔
1576

1577
      if (node == d_left) {
22,624!
1578
        d_left = d_left->traverse_lnr_assigned();
3,349✔
1579
      }
3,349✔
1580
      cleanup_tree(node);
22,624✔
1581
    }
22,624✔
1582
  }
22,631✔
1583

1584
  void erase(const string& key)
1585
  {
15✔
1586
    erase(key_type(key));
15✔
1587
  }
15✔
1588

1589
  //<! checks whether the container is empty.
1590
  [[nodiscard]] bool empty() const
1591
  {
112,240✔
1592
    return (d_size == 0);
112,240✔
1593
  }
112,240✔
1594

1595
  //<! returns the number of elements
1596
  [[nodiscard]] size_type size() const
1597
  {
700,737✔
1598
    return d_size;
700,737✔
1599
  }
700,737✔
1600

1601
  //<! See if given ComboAddress matches any prefix
1602
  [[nodiscard]] bool match(const ComboAddress& value) const
1603
  {
1,709✔
1604
    return (lookup(value) != nullptr);
1,709✔
1605
  }
1,709✔
1606

1607
  [[nodiscard]] bool match(const std::string& value) const
1608
  {
×
1609
    return match(ComboAddress(value));
×
1610
  }
×
1611

1612
  //<! Clean out the tree
1613
  void clear()
1614
  {
2,166✔
1615
    d_root = make_unique<TreeNode>();
2,166✔
1616
    d_left = nullptr;
2,166✔
1617
    d_size = 0;
2,166✔
1618
  }
2,166✔
1619

1620
  //<! swaps the contents with another NetmaskTree
1621
  void swap(NetmaskTree& rhs) noexcept
1622
  {
203✔
1623
    std::swap(d_root, rhs.d_root);
203✔
1624
    std::swap(d_left, rhs.d_left);
203✔
1625
    std::swap(d_size, rhs.d_size);
203✔
1626
  }
203✔
1627

1628
private:
1629
  [[nodiscard]] node_type* lookupImpl(const key_type& value, uint8_t max_bits) const
1630
  {
1,928,746✔
1631
    TreeNode* node = nullptr;
1,928,746✔
1632

1633
    if (value.isIPv4()) {
1,928,752!
1634
      node = d_root->left.get();
1,169,369✔
1635
    }
1,169,369✔
1636
    else if (value.isIPv6()) {
2,148,243,028!
1637
      node = d_root->right.get();
759,372✔
1638
    }
759,372✔
1639
    else {
2,147,483,656✔
1640
      throw NetmaskException("invalid address family");
2,147,483,656✔
1641
    }
2,147,483,656✔
1642
    if (node == nullptr) {
1,928,741!
1643
      return nullptr;
222,308✔
1644
    }
222,308✔
1645

1646
    node_type* ret = nullptr;
1,706,433✔
1647

1648
    int bits = 0;
1,706,433✔
1649
    for (; bits < max_bits; bits++) {
57,518,253!
1650
      bool vall = value.getBit(-1 - bits);
57,052,272✔
1651
      if (bits >= node->d_bits) {
57,052,272!
1652
        // the end of the current node is reached; continue with the next
1653
        // (we keep track of last assigned node)
1654
        if (node->assigned && bits == node->node.first.getBits()) {
12,740,001!
1655
          ret = &node->node;
1,124,810✔
1656
        }
1,124,810✔
1657
        if (vall) {
12,740,001!
1658
          if (!node->right) {
5,712,722!
1659
            break;
19,267✔
1660
          }
19,267✔
1661
          node = node->right.get();
5,693,455✔
1662
        }
5,693,455✔
1663
        else {
7,027,279✔
1664
          if (!node->left) {
7,027,279!
1665
            break;
11,069✔
1666
          }
11,069✔
1667
          node = node->left.get();
7,016,210✔
1668
        }
7,016,210✔
1669
        continue;
12,709,665✔
1670
      }
12,740,001✔
1671
      if (bits >= node->node.first.getBits()) {
44,312,271!
1672
        // the matching branch ends here
1673
        break;
371,256✔
1674
      }
371,256✔
1675
      bool valr = node->node.first.getBit(-1 - bits);
43,941,015✔
1676
      if (vall != valr) {
43,941,015!
1677
        // the branch matches just upto this point, yet continues in a different
1678
        // direction
1679
        break;
838,875✔
1680
      }
838,875✔
1681
    }
43,941,015✔
1682
    // needed if we did not find one in loop
1683
    if (node->assigned && bits == node->node.first.getBits()) {
1,706,436!
1684
      ret = &node->node;
866,040✔
1685
    }
866,040✔
1686
    // this can be nullptr.
1687
    return ret;
1,706,433✔
1688
  }
1,928,741✔
1689

1690
  unique_ptr<TreeNode> d_root; //<! Root of our tree
1691
  TreeNode* d_left;
1692
  size_type d_size{0};
1693
};
1694

1695
/** This class represents a group of supplemental Netmask classes. An IP address matches
1696
    if it is matched by one or more of the Netmask objects within.
1697
*/
1698
class NetmaskGroup
1699
{
1700
public:
1701
  NetmaskGroup() noexcept = default;
9,278✔
1702

1703
  //! If this IP address is matched by any of the classes within
1704

1705
  bool match(const ComboAddress* address) const
1706
  {
182,689✔
1707
    const auto& ret = tree.lookup(*address);
182,689✔
1708
    if (ret != nullptr) {
182,689✔
1709
      return ret->second;
17,158✔
1710
    }
17,158✔
1711
    return false;
165,531✔
1712
  }
182,689✔
1713

1714
  [[nodiscard]] bool match(const ComboAddress& address) const
1715
  {
169,954✔
1716
    return match(&address);
169,954✔
1717
  }
169,954✔
1718

1719
  bool lookup(const ComboAddress* address, Netmask* nmp) const
1720
  {
×
1721
    const auto& ret = tree.lookup(*address);
×
1722
    if (ret != nullptr) {
×
1723
      if (nmp != nullptr) {
×
1724
        *nmp = ret->first;
×
1725
      }
×
1726
      return ret->second;
×
1727
    }
×
1728
    return false;
×
1729
  }
×
1730

1731
  bool lookup(const ComboAddress& address, Netmask* nmp) const
1732
  {
×
1733
    return lookup(&address, nmp);
×
1734
  }
×
1735

1736
  //! Add this string to the list of possible matches
1737
  void addMask(const string& address, bool positive = true)
1738
  {
9,444✔
1739
    if (!address.empty() && address[0] == '!') {
9,444!
1740
      addMask(Netmask(address.substr(1)), false);
145✔
1741
    }
145✔
1742
    else {
9,299✔
1743
      addMask(Netmask(address), positive);
9,299✔
1744
    }
9,299✔
1745
  }
9,444✔
1746

1747
  //! Add this Netmask to the list of possible matches
1748
  void addMask(const Netmask& netmask, bool positive = true)
1749
  {
9,202✔
1750
    tree.insert(netmask).second = positive;
9,202✔
1751
  }
9,202✔
1752

1753
  void addMasks(const NetmaskGroup& group, boost::optional<bool> positive)
1754
  {
2✔
1755
    for (const auto& entry : group.tree) {
2✔
1756
      addMask(entry.first, positive ? *positive : entry.second);
2!
1757
    }
2✔
1758
  }
2✔
1759

1760
  //! Delete this Netmask from the list of possible matches
1761
  void deleteMask(const Netmask& netmask)
1762
  {
×
1763
    tree.erase(netmask);
×
1764
  }
×
1765

1766
  void deleteMasks(const NetmaskGroup& group)
1767
  {
×
1768
    for (const auto& entry : group.tree) {
×
1769
      deleteMask(entry.first);
×
1770
    }
×
1771
  }
×
1772

1773
  void deleteMask(const std::string& address)
1774
  {
×
1775
    if (!address.empty()) {
×
1776
      deleteMask(Netmask(address));
×
1777
    }
×
1778
  }
×
1779

1780
  void clear()
1781
  {
1,570✔
1782
    tree.clear();
1,570✔
1783
  }
1,570✔
1784

1785
  [[nodiscard]] bool empty() const
1786
  {
111,056✔
1787
    return tree.empty();
111,056✔
1788
  }
111,056✔
1789

1790
  [[nodiscard]] size_t size() const
1791
  {
326✔
1792
    return tree.size();
326✔
1793
  }
326✔
1794

1795
  [[nodiscard]] string toString() const
1796
  {
31✔
1797
    ostringstream str;
31✔
1798
    for (auto iter = tree.begin(); iter != tree.end(); ++iter) {
195✔
1799
      if (iter != tree.begin()) {
164✔
1800
        str << ", ";
133✔
1801
      }
133✔
1802
      if (!(iter->second)) {
164✔
1803
        str << "!";
30✔
1804
      }
30✔
1805
      str << iter->first.toString();
164✔
1806
    }
164✔
1807
    return str.str();
31✔
1808
  }
31✔
1809

1810
  [[nodiscard]] std::vector<std::string> toStringVector() const
1811
  {
959✔
1812
    std::vector<std::string> out;
959✔
1813
    out.reserve(tree.size());
959✔
1814
    for (const auto& entry : tree) {
1,566✔
1815
      out.push_back((entry.second ? "" : "!") + entry.first.toString());
1,566!
1816
    }
1,566✔
1817
    return out;
959✔
1818
  }
959✔
1819

1820
  void toMasks(const string& ips)
1821
  {
1,347✔
1822
    vector<string> parts;
1,347✔
1823
    stringtok(parts, ips, ", \t");
1,347✔
1824

1825
    for (const auto& part : parts) {
2,188✔
1826
      addMask(part);
2,158✔
1827
    }
2,158✔
1828
  }
1,347✔
1829

1830
private:
1831
  NetmaskTree<bool> tree;
1832
};
1833

1834
struct SComboAddress
1835
{
1836
  SComboAddress(const ComboAddress& orig) :
1837
    ca(orig) {}
4,857✔
1838
  ComboAddress ca;
1839
  bool operator<(const SComboAddress& rhs) const
1840
  {
×
1841
    return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
×
1842
  }
×
1843
  operator const ComboAddress&() const
1844
  {
×
1845
    return ca;
×
1846
  }
×
1847
};
1848

1849
class NetworkError : public runtime_error
1850
{
1851
public:
1852
  NetworkError(const string& why = "Network Error") :
1853
    runtime_error(why.c_str())
8✔
1854
  {}
183✔
1855
  NetworkError(const char* why = "Network Error") :
1856
    runtime_error(why)
28✔
1857
  {}
28✔
1858
};
1859

1860
class AddressAndPortRange
1861
{
1862
public:
1863
  AddressAndPortRange() :
1864
    d_addrMask(0), d_portMask(0)
1,238✔
1865
  {
1,238✔
1866
    d_addr.sin4.sin_family = 0; // disable this doing anything useful
1,238✔
1867
    d_addr.sin4.sin_port = 0; // this guarantees d_network compares identical
1,238✔
1868
  }
1,238✔
1869

1870
  AddressAndPortRange(ComboAddress address, uint8_t addrMask, uint8_t portMask = 0) :
1871
    d_addr(address), d_addrMask(addrMask), d_portMask(portMask)
291,055✔
1872
  {
291,055✔
1873
    if (!d_addr.isIPv4()) {
291,055✔
1874
      d_portMask = 0;
66,523✔
1875
    }
66,523✔
1876

1877
    uint16_t port = d_addr.getPort();
291,055✔
1878
    if (d_portMask < 16) {
291,055✔
1879
      auto mask = static_cast<uint16_t>(~(0xFFFF >> d_portMask));
88,488✔
1880
      port = port & mask;
88,488✔
1881
    }
88,488✔
1882

1883
    if (d_addrMask < d_addr.getBits()) {
291,055✔
1884
      if (d_portMask > 0) {
1,991!
1885
        throw std::runtime_error("Trying to create a AddressAndPortRange with a reduced address mask (" + std::to_string(d_addrMask) + ") and a port range (" + std::to_string(d_portMask) + ")");
×
1886
      }
×
1887
      d_addr = Netmask(d_addr, d_addrMask).getMaskedNetwork();
1,991✔
1888
    }
1,991✔
1889
    d_addr.setPort(port);
291,055✔
1890
  }
291,055✔
1891

1892
  [[nodiscard]] uint8_t getFullBits() const
1893
  {
60,331,308✔
1894
    return d_addr.getBits() + 16;
60,331,308✔
1895
  }
60,331,308✔
1896

1897
  [[nodiscard]] uint8_t getBits() const
1898
  {
15,654,704✔
1899
    if (d_addrMask < d_addr.getBits()) {
15,654,704✔
1900
      return d_addrMask;
32,846✔
1901
    }
32,846✔
1902

1903
    return d_addr.getBits() + d_portMask;
15,621,858✔
1904
  }
15,654,704✔
1905

1906
  /** Get the value of the bit at the provided bit index. When the index >= 0,
1907
      the index is relative to the LSB starting at index zero. When the index < 0,
1908
      the index is relative to the MSB starting at index -1 and counting down.
1909
  */
1910
  [[nodiscard]] bool getBit(int index) const
1911
  {
30,165,087✔
1912
    if (index >= getFullBits()) {
30,165,087!
1913
      return false;
×
1914
    }
×
1915
    if (index < 0) {
30,165,087!
1916
      index = getFullBits() + index;
30,165,087✔
1917
    }
30,165,087✔
1918

1919
    if (index < 16) {
30,165,087✔
1920
      /* we are into the port bits */
1921
      uint16_t port = d_addr.getPort();
688,809✔
1922
      return ((port & (1U << index)) != 0x0000);
688,809✔
1923
    }
688,809✔
1924

1925
    index -= 16;
29,476,278✔
1926

1927
    return d_addr.getBit(index);
29,476,278✔
1928
  }
30,165,087✔
1929

1930
  [[nodiscard]] bool isIPv4() const
1931
  {
269,668✔
1932
    return d_addr.isIPv4();
269,668✔
1933
  }
269,668✔
1934

1935
  [[nodiscard]] bool isIPv6() const
1936
  {
65,569✔
1937
    return d_addr.isIPv6();
65,569✔
1938
  }
65,569✔
1939

1940
  [[nodiscard]] AddressAndPortRange getNormalized() const
1941
  {
1,134✔
1942
    return {d_addr, d_addrMask, d_portMask};
1,134✔
1943
  }
1,134✔
1944

1945
  [[nodiscard]] AddressAndPortRange getSuper(uint8_t bits) const
1946
  {
510✔
1947
    if (bits <= d_addrMask) {
510!
1948
      return {d_addr, bits, 0};
510✔
1949
    }
510✔
1950
    if (bits <= d_addrMask + d_portMask) {
×
1951
      return {d_addr, d_addrMask, static_cast<uint8_t>(d_portMask - (bits - d_addrMask))};
×
1952
    }
×
1953

1954
    return {d_addr, d_addrMask, d_portMask};
×
1955
  }
×
1956

1957
  [[nodiscard]] const ComboAddress& getNetwork() const
1958
  {
340✔
1959
    return d_addr;
340✔
1960
  }
340✔
1961

1962
  [[nodiscard]] string toString() const
1963
  {
51✔
1964
    if (d_addrMask < d_addr.getBits() || d_portMask == 0) {
51!
1965
      return d_addr.toStringNoInterface() + "/" + std::to_string(d_addrMask);
50✔
1966
    }
50✔
1967
    return d_addr.toStringNoInterface() + ":" + std::to_string(d_addr.getPort()) + "/" + std::to_string(d_portMask);
1✔
1968
  }
51✔
1969

1970
  [[nodiscard]] bool empty() const
1971
  {
×
1972
    return d_addr.sin4.sin_family == 0;
×
1973
  }
×
1974

1975
  bool operator==(const AddressAndPortRange& rhs) const
1976
  {
20,275✔
1977
    return std::tie(d_addr, d_addrMask, d_portMask) == std::tie(rhs.d_addr, rhs.d_addrMask, rhs.d_portMask);
20,275✔
1978
  }
20,275✔
1979

1980
  bool operator<(const AddressAndPortRange& rhs) const
1981
  {
×
1982
    if (empty() && !rhs.empty()) {
×
1983
      return false;
×
1984
    }
×
1985

1986
    if (!empty() && rhs.empty()) {
×
1987
      return true;
×
1988
    }
×
1989

1990
    if (d_addrMask > rhs.d_addrMask) {
×
1991
      return true;
×
1992
    }
×
1993

1994
    if (d_addrMask < rhs.d_addrMask) {
×
1995
      return false;
×
1996
    }
×
1997

1998
    if (d_addr < rhs.d_addr) {
×
1999
      return true;
×
2000
    }
×
2001

2002
    if (d_addr > rhs.d_addr) {
×
2003
      return false;
×
2004
    }
×
2005

2006
    if (d_portMask > rhs.d_portMask) {
×
2007
      return true;
×
2008
    }
×
2009

2010
    if (d_portMask < rhs.d_portMask) {
×
2011
      return false;
×
2012
    }
×
2013

2014
    return d_addr.getPort() < rhs.d_addr.getPort();
×
2015
  }
×
2016

2017
  bool operator>(const AddressAndPortRange& rhs) const
2018
  {
×
2019
    return rhs.operator<(*this);
×
2020
  }
×
2021

2022
  struct hash
2023
  {
2024
    uint32_t operator()(const AddressAndPortRange& apr) const
2025
    {
28,331✔
2026
      ComboAddress::addressOnlyHash hashOp;
28,331✔
2027
      uint16_t port = apr.d_addr.getPort();
28,331✔
2028
      /* it's fine to hash the whole address and port because the non-relevant parts have
2029
         been masked to 0 */
2030
      return burtle(reinterpret_cast<const unsigned char*>(&port), sizeof(port), hashOp(apr.d_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
28,331✔
2031
    }
28,331✔
2032
  };
2033

2034
private:
2035
  ComboAddress d_addr;
2036
  uint8_t d_addrMask;
2037
  /* only used for v4 addresses */
2038
  uint8_t d_portMask;
2039
};
2040

2041
int SSocket(int family, int type, int flags);
2042
int SConnect(int sockfd, const ComboAddress& remote);
2043
/* tries to connect to remote for a maximum of timeout seconds.
2044
   sockfd should be set to non-blocking beforehand.
2045
   returns 0 on success (the socket is writable), throw a
2046
   runtime_error otherwise */
2047
int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout);
2048
int SBind(int sockfd, const ComboAddress& local);
2049
int SAccept(int sockfd, ComboAddress& remote);
2050
int SListen(int sockfd, int limit);
2051
int SSetsockopt(int sockfd, int level, int opname, int value);
2052
void setSocketIgnorePMTU(int sockfd, int family);
2053
void setSocketForcePMTU(int sockfd, int family);
2054
bool setReusePort(int sockfd);
2055

2056
#if defined(IP_PKTINFO)
2057
#define GEN_IP_PKTINFO IP_PKTINFO
111✔
2058
#elif defined(IP_RECVDSTADDR)
2059
#define GEN_IP_PKTINFO IP_RECVDSTADDR
2060
#endif
2061

2062
bool IsAnyAddress(const ComboAddress& addr);
2063
bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination);
2064
bool HarvestTimestamp(struct msghdr* msgh, struct timeval* timeval);
2065
void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
2066
int sendOnNBSocket(int fileDesc, const struct msghdr* msgh);
2067
size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
2068

2069
/* requires a non-blocking, connected TCP socket */
2070
bool isTCPSocketUsable(int sock);
2071

2072
extern template class NetmaskTree<bool>;
2073
ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
2074

2075
std::set<std::string> getListOfNetworkInterfaces();
2076
std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& itf);
2077
std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf);
2078

2079
/* These functions throw if the value was already set to a higher value,
2080
   or on error */
2081
void setSocketBuffer(int fileDesc, int optname, uint32_t size);
2082
void setSocketReceiveBuffer(int fileDesc, uint32_t size);
2083
void setSocketSendBuffer(int fileDesc, uint32_t size);
2084
uint32_t raiseSocketReceiveBufferToMax(int socket);
2085
uint32_t raiseSocketSendBufferToMax(int socket);
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