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

PowerDNS / pdns / 19362469839

14 Nov 2025 10:58AM UTC coverage: 55.508% (+0.01%) from 55.495%
19362469839

Pull #16508

github

web-flow
Merge ea63bc2a2 into edecbcf35
Pull Request #16508: dnsdist-2.0.x: Backport 16503 - `dnsheader_aligned`: Prevent copies

18577 of 57380 branches covered (32.38%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

3 existing lines in 2 files now uncovered.

52275 of 70262 relevant lines covered (74.4%)

1647404.54 hits per line

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

72.68
/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
  {
19,051,807✔
93
    if (std::tie(sin4.sin_family, sin4.sin_port) != std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
19,051,807✔
94
      return false;
6,212,694✔
95
    }
6,212,694✔
96
    if (sin4.sin_family == AF_INET) {
12,839,113✔
97
      return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
8,385,997✔
98
    }
8,385,997✔
99
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) == 0;
4,453,116✔
100
  }
12,839,113✔
101

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

107
  bool operator<(const ComboAddress& rhs) const
108
  {
424,131✔
109
    if (sin4.sin_family == 0) {
424,131✔
110
      return false;
4✔
111
    }
4✔
112
    if (std::tie(sin4.sin_family, sin4.sin_port) < std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
424,127✔
113
      return true;
5,702✔
114
    }
5,702✔
115
    if (std::tie(sin4.sin_family, sin4.sin_port) > std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
418,425✔
116
      return false;
3,182✔
117
    }
3,182✔
118
    if (sin4.sin_family == AF_INET) {
415,243✔
119
      return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
183,829✔
120
    }
183,829✔
121
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0;
231,414✔
122
  }
415,243✔
123

124
  bool operator>(const ComboAddress& rhs) const
125
  {
2✔
126
    return rhs.operator<(*this);
2✔
127
  }
2✔
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
    {
619,388✔
150
      const unsigned char* start = nullptr;
619,388✔
151
      uint32_t len = 0;
619,388✔
152
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
153
      if (address.sin4.sin_family == AF_INET) {
619,388✔
154
        start = reinterpret_cast<const unsigned char*>(&address.sin4.sin_addr.s_addr);
618,437✔
155
        len = 4;
618,437✔
156
      }
618,437✔
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);
619,388✔
163
    }
619,388✔
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✔
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
    {
4,003✔
187
      if (lhs.sin4.sin_family != rhs.sin4.sin_family) {
4,003✔
188
        return false;
1,682✔
189
      }
1,682✔
190
      if (lhs.sin4.sin_family == AF_INET) {
2,321✔
191
        return lhs.sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
2,313✔
192
      }
2,313✔
193
      return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) == 0;
8✔
194
    }
2,321✔
195
  };
196

197
  [[nodiscard]] socklen_t getSocklen() const
198
  {
47,399✔
199
    if (sin4.sin_family == AF_INET) {
47,399✔
200
      return sizeof(sin4);
47,288✔
201
    }
47,288✔
202
    return sizeof(sin6);
111✔
203
  }
47,399✔
204

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

214
  ComboAddress(const struct sockaddr* socketAddress, socklen_t salen)
215
  {
2✔
216
    setSockaddr(socketAddress, salen);
2✔
217
  };
2✔
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
  {
8✔
233
    if (salen > sizeof(struct sockaddr_in6)) {
8!
234
      throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
×
235
    }
×
236
    memcpy(this, socketAddress, salen);
8✔
237
  }
8✔
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,139,961✔
242
    memset(&sin6, 0, sizeof(sin6));
1,139,961✔
243
    sin4.sin_family = AF_INET;
1,139,961✔
244
    sin4.sin_port = 0;
1,139,961✔
245
    if (makeIPv4sockaddr(str, &sin4) != 0) {
1,139,961✔
246
      sin6.sin6_family = AF_INET6;
530,590✔
247
      if (makeIPv6sockaddr(str, &sin6) < 0) {
530,590✔
248
        throw PDNSException("Unable to convert presentation address '" + str + "'");
47✔
249
      }
47✔
250
    }
530,590✔
251
    if (sin4.sin_port == 0) { // 'str' overrides port!
1,139,914✔
252
      sin4.sin_port = htons(port);
868,849✔
253
    }
868,849✔
254
  }
1,139,914✔
255

256
  [[nodiscard]] bool isIPv6() const
257
  {
105,057,206✔
258
    return sin4.sin_family == AF_INET6;
105,057,206✔
259
  }
105,057,206✔
260
  [[nodiscard]] bool isIPv4() const
261
  {
190,802,713✔
262
    return sin4.sin_family == AF_INET;
190,802,713✔
263
  }
190,802,713✔
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,708✔
289
    static const ComboAddress unspecifiedV4("0.0.0.0:0");
1,708✔
290
    static const ComboAddress unspecifiedV6("[::]:0");
1,708✔
291
    const auto compare = ComboAddress::addressOnlyEqual();
1,708✔
292
    return compare(*this, unspecifiedV4) || compare(*this, unspecifiedV6);
1,708✔
293
  }
1,708✔
294

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

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

311
  [[nodiscard]] string toString() const
312
  {
25,912✔
313
    std::array<char, 1024> host{};
25,912✔
314
    if (sin4.sin_family != 0) {
25,912!
315
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
316
      int retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host.data(), host.size(), nullptr, 0, NI_NUMERICHOST);
25,912✔
317
      if (retval == 0) {
25,914✔
318
        return host.data();
25,914✔
319
      }
25,914✔
320
      return "invalid " + string(gai_strerror(retval));
2,147,483,647✔
321
    }
25,912✔
UNCOV
322
    return "invalid";
×
323
  }
25,912✔
324

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

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

371
  [[nodiscard]] string toStringWithPort() const
372
  {
8,303✔
373
    if (sin4.sin_family == AF_INET) {
8,303✔
374
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
8,253✔
375
    }
8,253✔
376
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
50✔
377
  }
8,303✔
378

379
  [[nodiscard]] string toStringWithPortExcept(int port) const
380
  {
32✔
381
    if (ntohs(sin4.sin_port) == port) {
32✔
382
      return toString();
8✔
383
    }
8✔
384
    if (sin4.sin_family == AF_INET) {
24✔
385
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
12✔
386
    }
12✔
387
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
12✔
388
  }
24✔
389

390
  [[nodiscard]] string toLogString() const
391
  {
×
392
    return toStringWithPortExcept(53);
×
393
  }
×
394

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

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

410
  void truncate(unsigned int bits) noexcept;
411

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

425
  void reset()
426
  {
6,544✔
427
    memset(&sin6, 0, sizeof(sin6));
6,544✔
428
  }
6,544✔
429

430
  //! Get the total number of address bits (either 32 or 128 depending on IP version)
431
  [[nodiscard]] uint8_t getBits() const
432
  {
93,059,106✔
433
    if (isIPv4()) {
93,059,106✔
434
      return 32;
41,836,951✔
435
    }
41,836,951✔
436
    if (isIPv6()) {
51,222,155!
437
      return 128;
51,222,155✔
438
    }
51,222,155✔
439
    return 0;
×
440
  }
51,222,155✔
441
  /** Get the value of the bit at the provided bit index. When the index >= 0,
442
      the index is relative to the LSB starting at index zero. When the index < 0,
443
      the index is relative to the MSB starting at index -1 and counting down.
444
   */
445
  [[nodiscard]] bool getBit(int index) const
446
  {
82,544,108✔
447
    if (isIPv4()) {
82,544,108✔
448
      if (index >= 32) {
28,774,741!
449
        return false;
×
450
      }
×
451
      if (index < 0) {
28,774,741✔
452
        if (index < -32) {
16,073,663!
453
          return false;
×
454
        }
×
455
        index = 32 + index;
16,073,663✔
456
      }
16,073,663✔
457

458
      uint32_t ls_addr = ntohl(sin4.sin_addr.s_addr);
28,774,741✔
459

460
      return ((ls_addr & (1U << index)) != 0x00000000);
28,774,741✔
461
    }
28,774,741✔
462
    if (isIPv6()) {
53,769,367!
463
      if (index >= 128) {
53,769,367!
464
        return false;
×
465
      }
×
466
      if (index < 0) {
53,769,367✔
467
        if (index < -128) {
36,991,000!
468
          return false;
×
469
        }
×
470
        index = 128 + index;
36,991,000✔
471
      }
36,991,000✔
472

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

477
      return ((ls_addr[15 - byte_idx] & (1U << bit_idx)) != 0x00); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
53,769,367✔
478
    }
53,769,367✔
479
    return false;
×
480
  }
53,769,367✔
481

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

639
inline ComboAddress makeComboAddress(const string& str)
640
{
280,985✔
641
  ComboAddress address;
280,985✔
642
  address.sin4.sin_family = AF_INET;
280,985✔
643
  if (inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
280,985✔
644
    address.sin4.sin_family = AF_INET6;
136,235✔
645
    if (makeIPv6sockaddr(str, &address.sin6) < 0) {
136,235✔
646
      throw NetmaskException("Unable to convert '" + str + "' to a netmask");
328✔
647
    }
328✔
648
  }
136,235✔
649
  return address;
280,657✔
650
}
280,985✔
651

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

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

674
  return address;
80✔
675
}
80✔
676

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

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

693
  Netmask(const ComboAddress& network, uint8_t bits = 0xff) :
694
    d_network(network)
14,323,155✔
695
  {
14,323,155✔
696
    d_network.sin4.sin_port = 0;
14,323,155✔
697
    setBits(bits);
14,323,155✔
698
  }
14,323,155✔
699

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

716
    if (d_bits < 32) {
14,603,798✔
717
      d_mask = ~(0xFFFFFFFF >> d_bits);
2,717,652✔
718
    }
2,717,652✔
719
    else {
11,886,146✔
720
      // note that d_mask is unused for IPv6
721
      d_mask = 0xFFFFFFFF;
11,886,146✔
722
    }
11,886,146✔
723

724
    if (isIPv4()) {
14,603,798✔
725
      d_network.sin4.sin_addr.s_addr = htonl(ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
6,185,020✔
726
    }
6,185,020✔
727
    else if (isIPv6()) {
8,418,778!
728
      uint8_t bytes = d_bits / 8;
8,418,778✔
729
      auto* address = reinterpret_cast<uint8_t*>(&d_network.sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
8,418,778✔
730
      uint8_t bits = d_bits % 8;
8,418,778✔
731
      auto mask = static_cast<uint8_t>(~(0xFF >> bits));
8,418,778✔
732

733
      if (bytes < sizeof(d_network.sin6.sin6_addr.s6_addr)) {
8,418,778✔
734
        address[bytes] &= mask; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
6,829,564✔
735
      }
6,829,564✔
736

737
      for (size_t idx = bytes + 1; idx < sizeof(d_network.sin6.sin6_addr.s6_addr); ++idx) {
62,748,809✔
738
        address[idx] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
54,330,031✔
739
      }
54,330,031✔
740
    }
8,418,778✔
741
  }
14,603,798✔
742

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

756
      d_network = makeComboAddressFromRaw(afi, mask.substr(1, len));
×
757

758
      setBits(bits);
×
759
    }
×
760
    else {
280,971✔
761
      pair<string, string> split = splitField(mask, '/');
280,971✔
762
      d_network = makeComboAddress(split.first);
280,971✔
763

764
      if (!split.second.empty()) {
280,971✔
765
        setBits(pdns::checked_stoi<uint8_t>(split.second));
145,962✔
766
      }
145,962✔
767
      else if (d_network.sin4.sin_family == AF_INET) {
135,009✔
768
        setBits(32);
133,400✔
769
      }
133,400✔
770
      else {
1,609✔
771
        setBits(128);
1,609✔
772
      }
1,609✔
773
    }
280,971✔
774
  }
280,971✔
775

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

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

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

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

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

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

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

832
  [[nodiscard]] string toStringNoMask() const
833
  {
×
834
    return d_network.toStringNoInterface();
×
835
  }
×
836

837
  [[nodiscard]] string toByteString() const
838
  {
×
839
    ostringstream tmp;
×
840

×
841
    tmp << (d_network.isIPv4() ? "\x04" : "\x06")
×
842
        << d_network.toByteString()
×
843
        << getBits();
×
844

×
845
    return tmp.str();
×
846
  }
×
847

848
  [[nodiscard]] const ComboAddress& getNetwork() const
849
  {
13,496,774✔
850
    return d_network;
13,496,774✔
851
  }
13,496,774✔
852

853
  [[nodiscard]] const ComboAddress& getMaskedNetwork() const
854
  {
13,496,218✔
855
    return getNetwork();
13,496,218✔
856
  }
13,496,218✔
857

858
  [[nodiscard]] uint8_t getBits() const
859
  {
37,503,263✔
860
    return d_bits;
37,503,263✔
861
  }
37,503,263✔
862

863
  [[nodiscard]] bool isIPv6() const
864
  {
8,851,359✔
865
    return d_network.sin6.sin6_family == AF_INET6;
8,851,359✔
866
  }
8,851,359✔
867

868
  [[nodiscard]] bool isIPv4() const
869
  {
15,508,045✔
870
    return d_network.sin4.sin_family == AF_INET;
15,508,045✔
871
  }
15,508,045✔
872

873
  bool operator<(const Netmask& rhs) const
874
  {
605,004✔
875
    if (empty() && !rhs.empty()) {
605,004!
876
      return false;
×
877
    }
×
878
    if (!empty() && rhs.empty()) {
605,004!
879
      return true;
8✔
880
    }
8✔
881
    if (d_bits > rhs.d_bits) {
604,996✔
882
      return true;
119,048✔
883
    }
119,048✔
884
    if (d_bits < rhs.d_bits) {
485,948✔
885
      return false;
61,940✔
886
    }
61,940✔
887

888
    return d_network < rhs.d_network;
424,008✔
889
  }
485,948✔
890

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

896
  bool operator==(const Netmask& rhs) const
897
  {
12,832,194✔
898
    return std::tie(d_network, d_bits) == std::tie(rhs.d_network, rhs.d_bits);
12,832,194✔
899
  }
12,832,194✔
900
  bool operator!=(const Netmask& rhs) const
901
  {
×
902
    return !operator==(rhs);
×
903
  }
×
904

905
  [[nodiscard]] bool empty() const
906
  {
1,815,012✔
907
    return d_network.sin4.sin_family == 0;
1,815,012✔
908
  }
1,815,012✔
909

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

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

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

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

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

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

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

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

1011
private:
1012
  /** Single node in tree, internal use only.
1013
   */
1014
  class TreeNode : boost::noncopyable
1015
  {
1016
  public:
1017
    explicit TreeNode() noexcept :
1018
      parent(nullptr), node(), assigned(false), d_bits(0)
37,086✔
1019
    {
37,086✔
1020
    }
37,086✔
1021
    explicit TreeNode(const key_type& key) :
1022
      parent(nullptr), node({key.getNormalized(), value_type()}), assigned(false), d_bits(key.getFullBits())
605,390✔
1023
    {
605,390✔
1024
    }
605,390✔
1025

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

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

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

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

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

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

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

1089
      return new_intermediate_node_raw;
2,116✔
1090
    }
2,116✔
1091

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

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

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

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

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

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

1140
      return new_node;
281,000✔
1141
    }
281,000✔
1142

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

1148
      while (tnode->left) {
188,729✔
1149
        tnode = tnode->left.get();
82,811✔
1150
      }
82,811✔
1151
      return tnode;
105,918✔
1152
    }
105,918✔
1153

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

1159
      // precondition: descended left as deep as possible
1160
      if (tnode->right) {
191,301✔
1161
        // descend right
1162
        tnode = tnode->right.get();
76,383✔
1163
        // descend left as deep as possible and return next node
1164
        return tnode->traverse_l();
76,383✔
1165
      }
76,383✔
1166

1167
      // ascend to parent
1168
      while (tnode->parent != nullptr) {
191,301✔
1169
        TreeNode* prev_child = tnode;
160,685✔
1170
        tnode = tnode->parent;
160,685✔
1171

1172
        // return this node, but only when we come from the left child branch
1173
        if (tnode->left && tnode->left.get() == prev_child) {
160,685✔
1174
          return tnode;
84,302✔
1175
        }
84,302✔
1176
      }
160,685✔
1177
      return nullptr;
30,616✔
1178
    }
114,918✔
1179

1180
    //<! Traverse only assigned nodes
1181
    TreeNode* traverse_lnr_assigned()
1182
    {
59,276✔
1183
      TreeNode* tnode = traverse_lnr();
59,276✔
1184

1185
      while (tnode != nullptr && !tnode->assigned) {
104,186✔
1186
        tnode = tnode->traverse_lnr();
44,910✔
1187
      }
44,910✔
1188
      return tnode;
59,276✔
1189
    }
59,276✔
1190

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

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

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

1201
  void cleanup_tree(TreeNode* node)
1202
  {
18,745✔
1203
    // only cleanup this node if it has no children and node not assigned
1204
    if (!(node->left || node->right || node->assigned)) {
18,745!
1205
      // get parent node ptr
1206
      TreeNode* pparent = node->parent;
9,758✔
1207
      // delete this node
1208
      if (pparent) {
9,758✔
1209
        if (pparent->left.get() == node) {
9,753✔
1210
          pparent->left.reset();
1,298✔
1211
        }
1,298✔
1212
        else {
8,455✔
1213
          pparent->right.reset();
8,455✔
1214
        }
8,455✔
1215
        // now recurse up to the parent
1216
        cleanup_tree(pparent);
9,753✔
1217
      }
9,753✔
1218
    }
9,758✔
1219
  }
18,745✔
1220

1221
  void copyTree(const NetmaskTree& rhs)
1222
  {
29,535✔
1223
    try {
29,535✔
1224
      TreeNode* node = rhs.d_root.get();
29,535✔
1225
      if (node != nullptr) {
29,535!
1226
        node = node->traverse_l();
29,535✔
1227
      }
29,535✔
1228
      while (node != nullptr) {
116,650✔
1229
        if (node->assigned) {
87,115✔
1230
          insert(node->node.first).second = node->node.second;
43,830✔
1231
        }
43,830✔
1232
        node = node->traverse_lnr();
87,115✔
1233
      }
87,115✔
1234
    }
29,535✔
1235
    catch (const NetmaskException&) {
29,535✔
1236
      abort();
×
1237
    }
×
1238
    catch (const std::logic_error&) {
29,535✔
1239
      abort();
×
1240
    }
×
1241
  }
29,535✔
1242

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

1253
  private:
1254
    friend class NetmaskTree;
1255

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

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

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

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

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

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

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

1312
  NetmaskTree() noexcept :
1313
    d_root(new TreeNode()), d_left(nullptr)
7,359✔
1314
  {
7,359✔
1315
  }
7,359✔
1316

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

1323
  ~NetmaskTree() = default;
61,107✔
1324

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

1334
  NetmaskTree(NetmaskTree&&) noexcept = default;
29,627✔
1335
  NetmaskTree& operator=(NetmaskTree&&) noexcept = default;
3,093✔
1336

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

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

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

1365
    // we turn left on IPv4 and right on IPv6
1366
    if (key.isIPv4()) {
324,764✔
1367
      node = d_root->left.get();
169,296✔
1368
      if (node == nullptr) {
169,296✔
1369

1370
        d_root->left = make_unique<TreeNode>(key);
18,810✔
1371
        node = d_root->left.get();
18,810✔
1372
        node->assigned = true;
18,810✔
1373
        node->parent = d_root.get();
18,810✔
1374
        d_size++;
18,810✔
1375
        d_left = node;
18,810✔
1376
        return node->node;
18,810✔
1377
      }
18,810✔
1378
    }
169,296✔
1379
    else if (key.isIPv6()) {
155,468!
1380
      node = d_root->right.get();
155,468✔
1381
      if (node == nullptr) {
155,468!
1382

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

1401
    // we turn left on 0 and right on 1
1402
    int bits = 0;
294,258✔
1403
    for (; bits < key.getBits(); bits++) {
13,062,368✔
1404
      bool vall = key.getBit(-1 - bits);
13,059,878✔
1405

1406
      if (bits >= node->d_bits) {
13,059,878✔
1407
        // the end of the current node is reached; continue with the next
1408
        if (vall) {
2,000,625✔
1409
          if (node->left || node->assigned) {
1,938,621!
1410
            is_left = false;
1,938,621✔
1411
          }
1,938,621✔
1412
          if (!node->right) {
1,938,621!
1413
            // the right branch doesn't exist yet; attach our key here
1414
            node = node->make_right(key);
629✔
1415
            break;
629✔
1416
          }
629✔
1417
          node = node->right.get();
1,937,992✔
1418
        }
1,937,992✔
1419
        else {
62,004✔
1420
          if (!node->left) {
62,004!
1421
            // the left branch doesn't exist yet; attach our key here
1422
            node = node->make_left(key);
23✔
1423
            break;
23✔
1424
          }
23✔
1425
          node = node->left.get();
61,981✔
1426
        }
61,981✔
1427
        continue;
1,999,973✔
1428
      }
2,000,625✔
1429
      if (bits >= node->node.first.getBits()) {
11,059,253!
1430
        // the matching branch ends here, yet the key netmask has more bits; add a
1431
        // child node below the existing branch leaf.
1432
        if (vall) {
10,116!
1433
          if (node->assigned) {
9,241!
1434
            is_left = false;
9,241✔
1435
          }
9,241✔
1436
          node = node->make_right(key);
9,241✔
1437
        }
9,241✔
1438
        else {
875✔
1439
          node = node->make_left(key);
875✔
1440
        }
875✔
1441
        break;
10,116✔
1442
      }
10,116✔
1443
      bool valr = node->node.first.getBit(-1 - bits);
11,049,137✔
1444
      if (vall != valr) {
11,049,137!
1445
        if (vall) {
281,000!
1446
          is_left = false;
279,396✔
1447
        }
279,396✔
1448
        // the branch matches just upto this point, yet continues in a different
1449
        // direction; fork the branch.
1450
        node = node->fork(key, bits);
281,000✔
1451
        break;
281,000✔
1452
      }
281,000✔
1453
    }
11,049,137✔
1454

1455
    if (node->node.first.getBits() > key.getBits()) {
294,258!
1456
      // key is a super-network of the matching node; split the branch and
1457
      // insert a node for the key above the matching node.
1458
      node = node->split(key, key.getBits());
2,116✔
1459
    }
2,116✔
1460

1461
    if (node->left) {
294,258!
1462
      is_left = false;
2,339✔
1463
    }
2,339✔
1464

1465
    node_type& value = node->node;
294,258✔
1466

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

1484
    return value;
294,258✔
1485
  }
294,258✔
1486

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

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

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

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

1512
  //<! Perform best match lookup for value, using at most max_bits
1513
  [[nodiscard]] node_type* lookup(const ComboAddress& value, int max_bits = 128) const
1514
  {
546,451✔
1515
    uint8_t addr_bits = value.getBits();
546,451✔
1516
    if (max_bits < 0 || max_bits > addr_bits) {
546,451!
1517
      max_bits = addr_bits;
284,253✔
1518
    }
284,253✔
1519

1520
    return lookupImpl(key_type(value, max_bits), max_bits);
546,451✔
1521
  }
546,451✔
1522

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

1528
    if (key.isIPv4()) {
8,994!
1529
      node = d_root->left.get();
8,980✔
1530
    }
8,980✔
1531
    else if (key.isIPv6()) {
14!
1532
      node = d_root->right.get();
14✔
1533
    }
14✔
1534
    else {
×
1535
      throw NetmaskException("invalid address family");
×
1536
    }
×
1537
    // no tree, no value
1538
    if (node == nullptr) {
8,994!
1539
      return;
×
1540
    }
×
1541
    int bits = 0;
8,994✔
1542
    for (; node && bits < key.getBits(); bits++) {
227,820!
1543
      bool vall = key.getBit(-1 - bits);
218,828✔
1544
      if (bits >= node->d_bits) {
218,828!
1545
        // the end of the current node is reached; continue with the next
1546
        if (vall) {
142,276!
1547
          node = node->right.get();
97,688✔
1548
        }
97,688✔
1549
        else {
44,588✔
1550
          node = node->left.get();
44,588✔
1551
        }
44,588✔
1552
        continue;
142,276✔
1553
      }
142,276✔
1554
      if (bits >= node->node.first.getBits()) {
76,552!
1555
        // the matching branch ends here
1556
        if (key.getBits() != node->node.first.getBits()) {
×
1557
          node = nullptr;
×
1558
        }
×
1559
        break;
×
1560
      }
×
1561
      bool valr = node->node.first.getBit(-1 - bits);
76,552✔
1562
      if (vall != valr) {
76,552!
1563
        // the branch matches just upto this point, yet continues in a different
1564
        // direction
1565
        node = nullptr;
2✔
1566
        break;
2✔
1567
      }
2✔
1568
    }
76,552✔
1569
    if (node) {
8,994!
1570
      if (d_size == 0) {
8,992!
1571
        throw std::logic_error(
×
1572
          "NetmaskTree::erase(): size of tree is zero before erase");
×
1573
      }
×
1574
      d_size--;
8,992✔
1575
      node->assigned = false;
8,992✔
1576
      node->node.second = value_type();
8,992✔
1577

1578
      if (node == d_left) {
8,992!
1579
        d_left = d_left->traverse_lnr_assigned();
1,282✔
1580
      }
1,282✔
1581
      cleanup_tree(node);
8,992✔
1582
    }
8,992✔
1583
  }
8,994✔
1584

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

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

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

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

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

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

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

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

1634
    if (value.isIPv4()) {
840,355✔
1635
      node = d_root->left.get();
497,691✔
1636
    }
497,691✔
1637
    else if (value.isIPv6()) {
342,664!
1638
      node = d_root->right.get();
342,664✔
1639
    }
342,664✔
1640
    else {
×
1641
      throw NetmaskException("invalid address family");
×
1642
    }
×
1643
    if (node == nullptr) {
840,355✔
1644
      return nullptr;
11,508✔
1645
    }
11,508✔
1646

1647
    node_type* ret = nullptr;
828,847✔
1648

1649
    int bits = 0;
828,847✔
1650
    for (; bits < max_bits; bits++) {
32,121,479✔
1651
      bool vall = value.getBit(-1 - bits);
31,892,957✔
1652
      if (bits >= node->d_bits) {
31,892,957✔
1653
        // the end of the current node is reached; continue with the next
1654
        // (we keep track of last assigned node)
1655
        if (node->assigned && bits == node->node.first.getBits()) {
5,075,230!
1656
          ret = &node->node;
445,866✔
1657
        }
445,866✔
1658
        if (vall) {
5,075,230✔
1659
          if (!node->right) {
2,275,712!
1660
            break;
7,680✔
1661
          }
7,680✔
1662
          node = node->right.get();
2,268,032✔
1663
        }
2,268,032✔
1664
        else {
2,799,518✔
1665
          if (!node->left) {
2,799,518!
1666
            break;
1,023✔
1667
          }
1,023✔
1668
          node = node->left.get();
2,798,495✔
1669
        }
2,798,495✔
1670
        continue;
5,066,527✔
1671
      }
5,075,230✔
1672
      if (bits >= node->node.first.getBits()) {
26,817,727✔
1673
        // the matching branch ends here
1674
        break;
165,279✔
1675
      }
165,279✔
1676
      bool valr = node->node.first.getBit(-1 - bits);
26,652,448✔
1677
      if (vall != valr) {
26,652,448✔
1678
        // the branch matches just upto this point, yet continues in a different
1679
        // direction
1680
        break;
426,343✔
1681
      }
426,343✔
1682
    }
26,652,448✔
1683
    // needed if we did not find one in loop
1684
    if (node->assigned && bits == node->node.first.getBits()) {
828,847✔
1685
      ret = &node->node;
401,994✔
1686
    }
401,994✔
1687
    // this can be nullptr.
1688
    return ret;
828,847✔
1689
  }
840,355✔
1690

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

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

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

1706
  bool match(const ComboAddress* address) const
1707
  {
12,603✔
1708
    const auto& ret = tree.lookup(*address);
12,603✔
1709
    if (ret != nullptr) {
12,603✔
1710
      return ret->second;
6,653✔
1711
    }
6,653✔
1712
    return false;
5,950✔
1713
  }
12,603✔
1714

1715
  [[nodiscard]] bool match(const ComboAddress& address) const
1716
  {
12,603✔
1717
    return match(&address);
12,603✔
1718
  }
12,603✔
1719

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

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

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

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

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

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

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

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

1781
  void clear()
1782
  {
188✔
1783
    tree.clear();
188✔
1784
  }
188✔
1785

1786
  [[nodiscard]] bool empty() const
1787
  {
1,836✔
1788
    return tree.empty();
1,836✔
1789
  }
1,836✔
1790

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

1796
  [[nodiscard]] string toString() const
1797
  {
15✔
1798
    ostringstream str;
15✔
1799
    for (auto iter = tree.begin(); iter != tree.end(); ++iter) {
88✔
1800
      if (iter != tree.begin()) {
73✔
1801
        str << ", ";
58✔
1802
      }
58✔
1803
      if (!(iter->second)) {
73✔
1804
        str << "!";
12✔
1805
      }
12✔
1806
      str << iter->first.toString();
73✔
1807
    }
73✔
1808
    return str.str();
15✔
1809
  }
15✔
1810

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

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

1826
    for (const auto& part : parts) {
1,529✔
1827
      addMask(part);
1,529✔
1828
    }
1,529✔
1829
  }
770✔
1830

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

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

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

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

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

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

1884
    if (d_addrMask < d_addr.getBits()) {
291,580✔
1885
      if (d_portMask > 0) {
2,170!
1886
        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) + ")");
×
1887
      }
×
1888
      d_addr = Netmask(d_addr, d_addrMask).getMaskedNetwork();
2,170✔
1889
    }
2,170✔
1890
    d_addr.setPort(port);
291,580✔
1891
  }
291,580✔
1892

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

1898
  [[nodiscard]] uint8_t getBits() const
1899
  {
15,656,712✔
1900
    if (d_addrMask < d_addr.getBits()) {
15,656,712✔
1901
      return d_addrMask;
34,300✔
1902
    }
34,300✔
1903

1904
    return d_addr.getBits() + d_portMask;
15,622,412✔
1905
  }
15,656,712✔
1906

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

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

1926
    index -= 16;
29,479,445✔
1927

1928
    return d_addr.getBit(index);
29,479,445✔
1929
  }
30,168,253✔
1930

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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