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

PowerDNS / pdns / 13012068652

28 Jan 2025 01:59PM UTC coverage: 64.71% (+0.01%) from 64.699%
13012068652

Pull #14724

github

web-flow
Merge b15562560 into db18c3a17
Pull Request #14724: dnsdist: Add meson support

38328 of 90334 branches covered (42.43%)

Branch coverage included in aggregate %.

361 of 513 new or added lines in 35 files covered. (70.37%)

42 existing lines in 13 files now uncovered.

128150 of 166934 relevant lines covered (76.77%)

4540890.91 hits per line

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

77.94
/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 <bitset>
31
#include "pdnsexception.hh"
32
#include "misc.hh"
33
#include <netdb.h>
34
#include <sstream>
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
  {
143,108,625✔
93
    if (std::tie(sin4.sin_family, sin4.sin_port) != std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
143,108,625✔
94
      return false;
68,339,938✔
95
    }
68,339,938✔
96
    if (sin4.sin_family == AF_INET) {
74,768,687✔
97
      return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
25,784,282✔
98
    }
25,784,282✔
99
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) == 0;
48,984,405✔
100
  }
74,768,687✔
101

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

107
  bool operator<(const ComboAddress& rhs) const
108
  {
3,597,017✔
109
    if (sin4.sin_family == 0) {
3,597,017✔
110
      return false;
58,726✔
111
    }
58,726✔
112
    if (std::tie(sin4.sin_family, sin4.sin_port) < std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
3,538,291✔
113
      return true;
46,243✔
114
    }
46,243✔
115
    if (std::tie(sin4.sin_family, sin4.sin_port) > std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
3,492,048✔
116
      return false;
23,978✔
117
    }
23,978✔
118
    if (sin4.sin_family == AF_INET) {
3,468,249✔
119
      return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
1,954,567✔
120
    }
1,954,567✔
121
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0;
2,148,997,329✔
122
  }
3,468,070✔
123

124
  bool operator>(const ComboAddress& rhs) const
125
  {
6✔
126
    return rhs.operator<(*this);
6✔
127
  }
6✔
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
    {
923,383✔
150
      const unsigned char* start = nullptr;
923,383✔
151
      uint32_t len = 0;
923,383✔
152
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
153
      if (address.sin4.sin_family == AF_INET) {
923,383✔
154
        start = reinterpret_cast<const unsigned char*>(&address.sin4.sin_addr.s_addr);
921,481✔
155
        len = 4;
921,481✔
156
      }
921,481✔
157
      else {
1,902✔
158
        start = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
1,902✔
159
        len = 16;
1,902✔
160
      }
1,902✔
161
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
162
      return burtle(start, len, 0);
923,383✔
163
    }
923,383✔
164
  };
165

166
  struct addressOnlyLessThan
167
  {
168
    bool operator()(const ComboAddress& lhs, const ComboAddress& rhs) const
169
    {
4,514✔
170
      if (lhs.sin4.sin_family < rhs.sin4.sin_family) {
4,514✔
171
        return true;
43✔
172
      }
43✔
173
      if (lhs.sin4.sin_family > rhs.sin4.sin_family) {
4,471✔
174
        return false;
18✔
175
      }
18✔
176
      if (lhs.sin4.sin_family == AF_INET) {
4,453✔
177
        return lhs.sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
4,397✔
178
      }
4,397✔
179
      return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) < 0;
56✔
180
    }
4,453✔
181
  };
182

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

197
  [[nodiscard]] socklen_t getSocklen() const
198
  {
207,272,803✔
199
    if (sin4.sin_family == AF_INET) {
207,272,803✔
200
      return sizeof(sin4);
205,955,959✔
201
    }
205,955,959✔
202
    return sizeof(sin6);
1,316,844✔
203
  }
207,272,803✔
204

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

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

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

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

231
  void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen)
232
  {
716✔
233
    if (salen > sizeof(struct sockaddr_in6)) {
716!
234
      throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
×
235
    }
×
236
    memcpy(this, socketAddress, salen);
716✔
237
  }
716✔
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
  {
31,248,722✔
242
    memset(&sin6, 0, sizeof(sin6));
31,248,722✔
243
    sin4.sin_family = AF_INET;
31,248,722✔
244
    sin4.sin_port = 0;
31,248,722✔
245
    if (makeIPv4sockaddr(str, &sin4) != 0) {
31,248,722✔
246
      sin6.sin6_family = AF_INET6;
14,394,810✔
247
      if (makeIPv6sockaddr(str, &sin6) < 0) {
14,394,810✔
248
        throw PDNSException("Unable to convert presentation address '" + str + "'");
1,110✔
249
      }
1,110✔
250
    }
14,394,810✔
251
    if (sin4.sin_port == 0) { // 'str' overrides port!
31,247,612✔
252
      sin4.sin_port = htons(port);
23,440,672✔
253
    }
23,440,672✔
254
  }
31,247,612✔
255

256
  [[nodiscard]] bool isIPv6() const
257
  {
2,044,876,391✔
258
    return sin4.sin_family == AF_INET6;
2,044,876,391✔
259
  }
2,044,876,391✔
260
  [[nodiscard]] bool isIPv4() const
261
  {
3,059,032,996✔
262
    return sin4.sin_family == AF_INET;
3,059,032,996✔
263
  }
3,059,032,996✔
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]] ComboAddress mapToIPv4() const
288
  {
×
289
    if (!isMappedIPv4()) {
×
290
      throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
×
291
    }
×
292
    ComboAddress ret;
×
293
    ret.sin4.sin_family = AF_INET;
×
294
    ret.sin4.sin_port = sin4.sin_port;
×
295

296
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
297
    const auto* ptr = reinterpret_cast<const unsigned char*>(&sin6.sin6_addr.s6_addr);
×
298
    ptr += (sizeof(sin6.sin6_addr.s6_addr) - sizeof(ret.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
×
299
    memcpy(&ret.sin4.sin_addr.s_addr, ptr, sizeof(ret.sin4.sin_addr.s_addr));
×
300
    return ret;
×
301
  }
×
302

303
  [[nodiscard]] string toString() const
304
  {
194,347,786✔
305
    std::array<char, 1024> host{};
194,347,786✔
306
    if (sin4.sin_family != 0) {
194,347,787✔
307
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
308
      int retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host.data(), host.size(), nullptr, 0, NI_NUMERICHOST);
194,347,749✔
309
      if (retval == 0) {
194,347,788✔
310
        return host.data();
194,347,787✔
311
      }
194,347,787✔
312
      return "invalid " + string(gai_strerror(retval));
8,589,934,588✔
313
    }
194,347,749✔
314
    return "invalid";
2,147,483,685✔
315
  }
194,347,786✔
316

317
  //! Ignores any interface specifiers possibly available in the sockaddr data.
318
  [[nodiscard]] string toStringNoInterface() const
319
  {
20,995✔
320
    std::array<char, 1024> host{};
20,995✔
321
    if (sin4.sin_family == AF_INET) {
20,995✔
322
      const auto* ret = inet_ntop(sin4.sin_family, &sin4.sin_addr, host.data(), host.size());
15,153✔
323
      if (ret != nullptr) {
15,153!
324
        return host.data();
15,153✔
325
      }
15,153✔
326
    }
15,153✔
327
    else if (sin4.sin_family == AF_INET6) {
5,842✔
328
      const auto* ret = inet_ntop(sin4.sin_family, &sin6.sin6_addr, host.data(), host.size());
5,468✔
329
      if (ret != nullptr) {
5,468!
330
        return host.data();
5,468✔
331
      }
5,468✔
332
    }
5,468✔
333
    return "invalid " + stringerror();
374✔
334
  }
20,995✔
335

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

360
  [[nodiscard]] string toStringWithPort() const
361
  {
150,493,771✔
362
    if (sin4.sin_family == AF_INET) {
150,493,771✔
363
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
150,491,775✔
364
    }
150,491,775✔
365
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
1,996✔
366
  }
150,493,771✔
367

368
  [[nodiscard]] string toStringWithPortExcept(int port) const
369
  {
99,531✔
370
    if (ntohs(sin4.sin_port) == port) {
99,531✔
371
      return toString();
288✔
372
    }
288✔
373
    if (sin4.sin_family == AF_INET) {
99,243✔
374
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
99,211✔
375
    }
99,211✔
376
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
32✔
377
  }
99,243✔
378

379
  [[nodiscard]] string toLogString() const
380
  {
98,494✔
381
    return toStringWithPortExcept(53);
98,494✔
382
  }
98,494✔
383

384
  [[nodiscard]] string toStructuredLogString() const
385
  {
613✔
386
    return toStringWithPort();
613✔
387
  }
613✔
388

389
  [[nodiscard]] string toByteString() const
390
  {
421✔
391
    // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
392
    if (isIPv4()) {
421!
393
      return {reinterpret_cast<const char*>(&sin4.sin_addr.s_addr), sizeof(sin4.sin_addr.s_addr)};
421✔
394
    }
421✔
395
    return {reinterpret_cast<const char*>(&sin6.sin6_addr.s6_addr), sizeof(sin6.sin6_addr.s6_addr)};
×
396
    // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
397
  }
421✔
398

399
  void truncate(unsigned int bits) noexcept;
400

401
  [[nodiscard]] uint16_t getNetworkOrderPort() const noexcept
402
  {
5,015,694✔
403
    return sin4.sin_port;
5,015,694✔
404
  }
5,015,694✔
405
  [[nodiscard]] uint16_t getPort() const noexcept
406
  {
5,015,695✔
407
    return ntohs(getNetworkOrderPort());
5,015,695✔
408
  }
5,015,695✔
409
  void setPort(uint16_t port)
410
  {
1,740,667✔
411
    sin4.sin_port = htons(port);
1,740,667✔
412
  }
1,740,667✔
413

414
  void reset()
415
  {
748,940✔
416
    memset(&sin4, 0, sizeof(sin4));
748,940✔
417
    memset(&sin6, 0, sizeof(sin6));
748,940✔
418
  }
748,940✔
419

420
  //! Get the total number of address bits (either 32 or 128 depending on IP version)
421
  [[nodiscard]] uint8_t getBits() const
422
  {
1,395,055,765✔
423
    if (isIPv4()) {
1,395,055,765✔
424
      return 32;
627,508,082✔
425
    }
627,508,082✔
426
    if (isIPv6()) {
767,547,685✔
427
      return 128;
767,547,679✔
428
    }
767,547,679✔
429
    return 0;
2,147,483,647✔
430
  }
767,547,683✔
431
  /** Get the value of the bit at the provided bit index. When the index >= 0,
432
      the index is relative to the LSB starting at index zero. When the index < 0,
433
      the index is relative to the MSB starting at index -1 and counting down.
434
   */
435
  [[nodiscard]] bool getBit(int index) const
436
  {
1,104,747,210✔
437
    if (isIPv4()) {
1,104,747,210✔
438
      if (index >= 32) {
388,953,422!
439
        return false;
×
440
      }
×
441
      if (index < 0) {
388,953,427✔
442
        if (index < -32) {
210,963,555!
443
          return false;
×
444
        }
×
445
        index = 32 + index;
210,963,555✔
446
      }
210,963,555✔
447

448
      uint32_t ls_addr = ntohl(sin4.sin_addr.s_addr);
388,953,422✔
449

450
      return ((ls_addr & (1U << index)) != 0x00000000);
388,953,422✔
451
    }
388,953,422✔
452
    if (isIPv6()) {
715,793,790✔
453
      if (index >= 128) {
715,793,779!
454
        return false;
×
455
      }
×
456
      if (index < 0) {
715,793,779✔
457
        if (index < -128) {
480,896,641!
458
          return false;
×
459
        }
×
460
        index = 128 + index;
480,896,641✔
461
      }
480,896,641✔
462

463
      const auto* ls_addr = reinterpret_cast<const uint8_t*>(sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
715,793,779✔
464
      uint8_t byte_idx = index / 8;
715,793,779✔
465
      uint8_t bit_idx = index % 8;
715,793,779✔
466

467
      return ((ls_addr[15 - byte_idx] & (1U << bit_idx)) != 0x00); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
715,793,779✔
468
    }
715,793,779✔
469
    return false;
2,147,483,647✔
470
  }
715,793,788✔
471

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

493
/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
494
class NetmaskException : public PDNSException
495
{
496
public:
497
  NetmaskException(const string& arg) :
498
    PDNSException(arg) {}
7,918✔
499
};
500

501
inline ComboAddress makeComboAddress(const string& str)
502
{
1,841,215✔
503
  ComboAddress address;
1,841,215✔
504
  address.sin4.sin_family = AF_INET;
1,841,215✔
505
  if (inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
1,841,215✔
506
    address.sin4.sin_family = AF_INET6;
891,536✔
507
    if (makeIPv6sockaddr(str, &address.sin6) < 0) {
891,536✔
508
      throw NetmaskException("Unable to convert '" + str + "' to a netmask");
2,750✔
509
    }
2,750✔
510
  }
891,536✔
511
  return address;
1,838,465✔
512
}
1,841,215✔
513

514
inline ComboAddress makeComboAddressFromRaw(uint8_t version, const char* raw, size_t len)
515
{
497✔
516
  ComboAddress address;
497✔
517

518
  if (version == 4) {
497✔
519
    address.sin4.sin_family = AF_INET;
238✔
520
    if (len != sizeof(address.sin4.sin_addr)) {
238!
521
      throw NetmaskException("invalid raw address length");
×
522
    }
×
523
    memcpy(&address.sin4.sin_addr, raw, sizeof(address.sin4.sin_addr));
238✔
524
  }
238✔
525
  else if (version == 6) {
259!
526
    address.sin6.sin6_family = AF_INET6;
259✔
527
    if (len != sizeof(address.sin6.sin6_addr)) {
259!
528
      throw NetmaskException("invalid raw address length");
×
529
    }
×
530
    memcpy(&address.sin6.sin6_addr, raw, sizeof(address.sin6.sin6_addr));
259✔
531
  }
259✔
532
  else {
×
533
    throw NetmaskException("invalid address family");
×
534
  }
×
535

536
  return address;
497✔
537
}
497✔
538

539
inline ComboAddress makeComboAddressFromRaw(uint8_t version, const string& str)
540
{
63✔
541
  return makeComboAddressFromRaw(version, str.c_str(), str.size());
63✔
542
}
63✔
543

544
/** This class represents a netmask and can be queried to see if a certain
545
    IP address is matched by this mask */
546
class Netmask
547
{
548
public:
549
  Netmask()
550
  {
3,461,258✔
551
    d_network.sin4.sin_family = 0; // disable this doing anything useful
3,461,258✔
552
    d_network.sin4.sin_port = 0; // this guarantees d_network compares identical
3,461,258✔
553
  }
3,461,258✔
554

555
  Netmask(const ComboAddress& network, uint8_t bits = 0xff) :
556
    d_network(network)
557
  {
273,535,782✔
558
    d_network.sin4.sin_port = 0;
273,535,782✔
559
    setBits(bits);
273,535,782✔
560
  }
273,535,782✔
561

562
  Netmask(const sockaddr_in* network, uint8_t bits = 0xff) :
563
    d_network(network)
564
  {
×
565
    d_network.sin4.sin_port = 0;
×
566
    setBits(bits);
×
567
  }
×
568
  Netmask(const sockaddr_in6* network, uint8_t bits = 0xff) :
569
    d_network(network)
570
  {
×
571
    d_network.sin4.sin_port = 0;
×
572
    setBits(bits);
×
573
  }
×
574
  void setBits(uint8_t value)
575
  {
300,791,162✔
576
    d_bits = d_network.isIPv4() ? std::min(value, static_cast<uint8_t>(32U)) : std::min(value, static_cast<uint8_t>(128U));
300,791,162✔
577

578
    if (d_bits < 32) {
300,791,162✔
579
      d_mask = ~(0xFFFFFFFF >> d_bits);
56,918,166✔
580
    }
56,918,166✔
581
    else {
243,872,996✔
582
      // note that d_mask is unused for IPv6
583
      d_mask = 0xFFFFFFFF;
243,872,996✔
584
    }
243,872,996✔
585

586
    if (isIPv4()) {
300,791,162✔
587
      d_network.sin4.sin_addr.s_addr = htonl(ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
126,954,401✔
588
    }
126,954,401✔
589
    else if (isIPv6()) {
173,836,761✔
590
      uint8_t bytes = d_bits / 8;
172,590,811✔
591
      auto* address = reinterpret_cast<uint8_t*>(&d_network.sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
172,590,811✔
592
      uint8_t bits = d_bits % 8;
172,590,811✔
593
      auto mask = static_cast<uint8_t>(~(0xFF >> bits));
172,590,811✔
594

595
      if (bytes < sizeof(d_network.sin6.sin6_addr.s6_addr)) {
172,590,811✔
596
        address[bytes] &= mask; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
139,994,836✔
597
      }
139,994,836✔
598

599
      for (size_t idx = bytes + 1; idx < sizeof(d_network.sin6.sin6_addr.s6_addr); ++idx) {
1,286,176,586✔
600
        address[idx] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1,113,585,775✔
601
      }
1,113,585,775✔
602
    }
172,590,811✔
603
  }
300,791,162✔
604

605
  //! Constructor supplies the mask, which cannot be changed
606
  Netmask(const string& mask)
607
  {
1,841,124✔
608
    pair<string, string> split = splitField(mask, '/');
1,841,124✔
609
    d_network = makeComboAddress(split.first);
1,841,124✔
610

611
    if (!split.second.empty()) {
1,841,124✔
612
      setBits(pdns::checked_stoi<uint8_t>(split.second));
959,057✔
613
    }
959,057✔
614
    else if (d_network.sin4.sin_family == AF_INET) {
882,067✔
615
      setBits(32);
868,418✔
616
    }
868,418✔
617
    else {
13,649✔
618
      setBits(128);
13,649✔
619
    }
13,649✔
620
  }
1,841,124✔
621

622
  [[nodiscard]] bool match(const ComboAddress& address) const
623
  {
49✔
624
    return match(&address);
49✔
625
  }
49✔
626

627
  //! If this IP address in socket address matches
628
  bool match(const ComboAddress* address) const
629
  {
97✔
630
    if (d_network.sin4.sin_family != address->sin4.sin_family) {
97!
631
      return false;
×
632
    }
×
633
    if (d_network.sin4.sin_family == AF_INET) {
97✔
634
      return match4(htonl((unsigned int)address->sin4.sin_addr.s_addr));
61✔
635
    }
61✔
636
    if (d_network.sin6.sin6_family == AF_INET6) {
36!
637
      uint8_t bytes = d_bits / 8;
36✔
638
      uint8_t index = 0;
36✔
639
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
640
      const auto* lhs = reinterpret_cast<const uint8_t*>(&d_network.sin6.sin6_addr.s6_addr);
36✔
641
      const auto* rhs = reinterpret_cast<const uint8_t*>(&address->sin6.sin6_addr.s6_addr);
36✔
642
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
643

644
      // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
645
      for (index = 0; index < bytes; ++index) {
192✔
646
        if (lhs[index] != rhs[index]) {
168✔
647
          return false;
12✔
648
        }
12✔
649
      }
168✔
650
      // still here, now match remaining bits
651
      uint8_t bits = d_bits % 8;
24✔
652
      auto mask = static_cast<uint8_t>(~(0xFF >> bits));
24✔
653

654
      return ((lhs[index]) == (rhs[index] & mask));
24✔
655
      // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
656
    }
36✔
657
    return false;
×
658
  }
36✔
659

660
  //! If this ASCII IP address matches
661
  [[nodiscard]] bool match(const string& arg) const
662
  {
42✔
663
    ComboAddress address = makeComboAddress(arg);
42✔
664
    return match(&address);
42✔
665
  }
42✔
666

667
  //! If this IP address in native format matches
668
  [[nodiscard]] bool match4(uint32_t arg) const
669
  {
61✔
670
    return (arg & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr));
61✔
671
  }
61✔
672

673
  [[nodiscard]] string toString() const
674
  {
15,892✔
675
    return d_network.toStringNoInterface() + "/" + std::to_string((unsigned int)d_bits);
15,892✔
676
  }
15,892✔
677

678
  [[nodiscard]] string toStringNoMask() const
679
  {
1,501✔
680
    return d_network.toStringNoInterface();
1,501✔
681
  }
1,501✔
682

683
  [[nodiscard]] const ComboAddress& getNetwork() const
684
  {
170,018,632✔
685
    return d_network;
170,018,632✔
686
  }
170,018,632✔
687

688
  [[nodiscard]] const ComboAddress& getMaskedNetwork() const
689
  {
136,211,466✔
690
    return getNetwork();
136,211,466✔
691
  }
136,211,466✔
692

693
  [[nodiscard]] uint8_t getBits() const
694
  {
582,537,713✔
695
    return d_bits;
582,537,713✔
696
  }
582,537,713✔
697

698
  [[nodiscard]] bool isIPv6() const
699
  {
182,717,234✔
700
    return d_network.sin6.sin6_family == AF_INET6;
182,717,234✔
701
  }
182,717,234✔
702

703
  [[nodiscard]] bool isIPv4() const
704
  {
319,512,821✔
705
    return d_network.sin4.sin_family == AF_INET;
319,512,821✔
706
  }
319,512,821✔
707

708
  bool operator<(const Netmask& rhs) const
709
  {
1,594,421✔
710
    if (empty() && !rhs.empty()) {
1,594,421✔
711
      return false;
6✔
712
    }
6✔
713
    if (!empty() && rhs.empty()) {
1,594,415✔
714
      return true;
3,154✔
715
    }
3,154✔
716
    if (d_bits > rhs.d_bits) {
1,591,261✔
717
      return true;
297,724✔
718
    }
297,724✔
719
    if (d_bits < rhs.d_bits) {
1,293,537✔
720
      return false;
154,883✔
721
    }
154,883✔
722

723
    return d_network < rhs.d_network;
1,138,654✔
724
  }
1,293,537✔
725

726
  bool operator>(const Netmask& rhs) const
727
  {
30✔
728
    return rhs.operator<(*this);
30✔
729
  }
30✔
730

731
  bool operator==(const Netmask& rhs) const
732
  {
64,161,084✔
733
    return std::tie(d_network, d_bits) == std::tie(rhs.d_network, rhs.d_bits);
64,161,084✔
734
  }
64,161,084✔
735

736
  [[nodiscard]] bool empty() const
737
  {
7,051,877✔
738
    return d_network.sin4.sin_family == 0;
7,051,877✔
739
  }
7,051,877✔
740

741
  //! Get normalized version of the netmask. This means that all address bits below the network bits are zero.
742
  [[nodiscard]] Netmask getNormalized() const
743
  {
102,358,011✔
744
    return {getMaskedNetwork(), d_bits};
102,358,011✔
745
  }
102,358,011✔
746
  //! Get Netmask for super network of this one (i.e. with fewer network bits)
747
  [[nodiscard]] Netmask getSuper(uint8_t bits) const
748
  {
2,100,281✔
749
    return {d_network, std::min(d_bits, bits)};
2,100,281✔
750
  }
2,100,281✔
751

752
  //! Get the total number of address bits for this netmask (either 32 or 128 depending on IP version)
753
  [[nodiscard]] uint8_t getFullBits() const
754
  {
4,564,194✔
755
    return d_network.getBits();
4,564,194✔
756
  }
4,564,194✔
757

758
  /** Get the value of the bit at the provided bit index. When the index >= 0,
759
      the index is relative to the LSB starting at index zero. When the index < 0,
760
      the index is relative to the MSB starting at index -1 and counting down.
761
      When the index points outside the network bits, it always yields zero.
762
   */
763
  [[nodiscard]] bool getBit(int bit) const
764
  {
691,860,191✔
765
    if (bit < -d_bits) {
691,860,191!
766
      return false;
×
767
    }
×
768
    if (bit >= 0) {
691,860,191!
769
      if (isIPv4()) {
×
770
        if (bit >= 32 || bit < (32 - d_bits)) {
×
771
          return false;
×
772
        }
×
773
      }
×
774
      if (isIPv6()) {
×
775
        if (bit >= 128 || bit < (128 - d_bits)) {
×
776
          return false;
×
777
        }
×
778
      }
×
779
    }
×
780
    return d_network.getBit(bit);
691,860,191✔
781
  }
691,860,191✔
782

783
  struct Hash
784
  {
785
    size_t operator()(const Netmask& netmask) const
786
    {
×
787
      return burtle(&netmask.d_bits, 1, ComboAddress::addressOnlyHash()(netmask.d_network));
×
788
    }
×
789
  };
790

791
private:
792
  ComboAddress d_network;
793
  uint32_t d_mask{0};
794
  uint8_t d_bits{0};
795
};
796

797
namespace std
798
{
799
template <>
800
struct hash<Netmask>
801
{
802
  auto operator()(const Netmask& netmask) const
803
  {
×
804
    return Netmask::Hash{}(netmask);
×
805
  }
×
806
};
807
}
808

809
/** Binary tree map implementation with <Netmask,T> pair.
810
 *
811
 * This is an binary tree implementation for storing attributes for IPv4 and IPv6 prefixes.
812
 * The most simple use case is simple NetmaskTree<bool> used by NetmaskGroup, which only
813
 * wants to know if given IP address is matched in the prefixes stored.
814
 *
815
 * This element is useful for anything that needs to *STORE* prefixes, and *MATCH* IP addresses
816
 * to a *LIST* of *PREFIXES*. Not the other way round.
817
 *
818
 * You can store IPv4 and IPv6 addresses to same tree, separate payload storage is kept per AFI.
819
 * Network prefixes (Netmasks) are always recorded in normalized fashion, meaning that only
820
 * the network bits are set. This is what is returned in the insert() and lookup() return
821
 * values.
822
 *
823
 * Use swap if you need to move the tree to another NetmaskTree instance, it is WAY faster
824
 * than using copy ctor or assignment operator, since it moves the nodes and tree root to
825
 * new home instead of actually recreating the tree.
826
 *
827
 * Please see NetmaskGroup for example of simple use case. Other usecases can be found
828
 * from GeoIPBackend and Sortlist, and from dnsdist.
829
 */
830
template <typename T, class K = Netmask>
831
class NetmaskTree
832
{
833
public:
834
  class Iterator;
835

836
  using key_type = K;
837
  using value_type = T;
838
  using node_type = std::pair<const key_type, value_type>;
839
  using size_type = size_t;
840
  using iterator = class Iterator;
841

842
private:
843
  /** Single node in tree, internal use only.
844
   */
845
  class TreeNode : boost::noncopyable
846
  {
847
  public:
848
    explicit TreeNode() noexcept :
849
      parent(nullptr), node(), assigned(false), d_bits(0)
850
    {
324,662✔
851
    }
324,662✔
852
    explicit TreeNode(const key_type& key) :
853
      parent(nullptr), node({key.getNormalized(), value_type()}), assigned(false), d_bits(key.getFullBits())
854
    {
1,719,656✔
855
    }
1,719,656✔
856

857
    //<! Makes a left leaf node with specified key.
858
    TreeNode* make_left(const key_type& key)
859
    {
2,584✔
860
      d_bits = node.first.getBits();
2,584✔
861
      left = make_unique<TreeNode>(key);
2,584✔
862
      left->parent = this;
2,584✔
863
      return left.get();
2,584✔
864
    }
2,584✔
865

866
    //<! Makes a right leaf node with specified key.
867
    TreeNode* make_right(const key_type& key)
868
    {
24,960✔
869
      d_bits = node.first.getBits();
24,960✔
870
      right = make_unique<TreeNode>(key);
24,960✔
871
      right->parent = this;
24,960✔
872
      return right.get();
24,960✔
873
    }
24,960✔
874

875
    //<! Splits branch at indicated bit position by inserting key
876
    TreeNode* split(const key_type& key, int bits)
877
    {
5,298✔
878
      if (parent == nullptr) {
5,298!
879
        // not to be called on the root node
880
        throw std::logic_error(
×
881
          "NetmaskTree::TreeNode::split(): must not be called on root node");
×
882
      }
×
883

884
      // determine reference from parent
885
      unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
5,298!
886
      if (parent_ref.get() != this) {
5,298!
887
        throw std::logic_error(
×
888
          "NetmaskTree::TreeNode::split(): parent node reference is invalid");
×
889
      }
×
890

891
      // create new tree node for the new key and
892
      // attach the new node under our former parent
893
      auto new_intermediate_node = make_unique<TreeNode>(key);
5,298✔
894
      new_intermediate_node->d_bits = bits;
5,298✔
895
      new_intermediate_node->parent = parent;
5,298✔
896
      auto* new_intermediate_node_raw = new_intermediate_node.get();
5,298✔
897

898
      // hereafter new_intermediate points to "this"
899
      // ie the child of the new intermediate node
900
      std::swap(parent_ref, new_intermediate_node);
5,298✔
901
      // and we now assign this to current_node so
902
      // it's clear it no longer refers to the new
903
      // intermediate node
904
      std::unique_ptr<TreeNode> current_node = std::move(new_intermediate_node);
5,298✔
905

906
      // attach "this" node below the new node
907
      // (left or right depending on bit)
908
      // technically the raw pointer escapes the duration of the
909
      // unique pointer, but just below we store the unique pointer
910
      // in the parent, so it lives as long as necessary
911
      // coverity[escape]
912
      current_node->parent = new_intermediate_node_raw;
5,298✔
913
      if (current_node->node.first.getBit(-1 - bits)) {
5,298!
914
        new_intermediate_node_raw->right = std::move(current_node);
188✔
915
      }
188✔
916
      else {
5,110✔
917
        new_intermediate_node_raw->left = std::move(current_node);
5,110✔
918
      }
5,110✔
919

920
      return new_intermediate_node_raw;
5,298✔
921
    }
5,298✔
922

923
    //<! Forks branch for new key at indicated bit position
924
    TreeNode* fork(const key_type& key, int bits)
925
    {
710,151✔
926
      if (parent == nullptr) {
710,151!
927
        // not to be called on the root node
928
        throw std::logic_error(
×
929
          "NetmaskTree::TreeNode::fork(): must not be called on root node");
×
930
      }
×
931

932
      // determine reference from parent
933
      unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
710,151!
934
      if (parent_ref.get() != this) {
710,151!
935
        throw std::logic_error(
×
936
          "NetmaskTree::TreeNode::fork(): parent node reference is invalid");
×
937
      }
×
938

939
      // create new tree node for the branch point
940

941
      // the current node will now be a child of the new branch node
942
      // (hereafter new_child1 points to "this")
943
      unique_ptr<TreeNode> new_child1 = std::move(parent_ref);
710,151✔
944
      // attach the branch node under our former parent
945
      parent_ref = make_unique<TreeNode>(node.first.getSuper(bits));
710,151✔
946
      auto* branch_node = parent_ref.get();
710,151✔
947
      branch_node->d_bits = bits;
710,151✔
948
      branch_node->parent = parent;
710,151✔
949

950
      // create second new leaf node for the new key
951
      unique_ptr<TreeNode> new_child2 = make_unique<TreeNode>(key);
710,151✔
952
      TreeNode* new_node = new_child2.get();
710,151✔
953

954
      // attach the new child nodes below the branch node
955
      // (left or right depending on bit)
956
      new_child1->parent = branch_node;
710,151✔
957
      new_child2->parent = branch_node;
710,151✔
958
      if (new_child1->node.first.getBit(-1 - bits)) {
710,151!
959
        branch_node->right = std::move(new_child1);
4,587✔
960
        branch_node->left = std::move(new_child2);
4,587✔
961
      }
4,587✔
962
      else {
705,564✔
963
        branch_node->right = std::move(new_child2);
705,564✔
964
        branch_node->left = std::move(new_child1);
705,564✔
965
      }
705,564✔
966
      // now we have attached the new unique pointers to the tree:
967
      // - branch_node is below its parent
968
      // - new_child1 (ourselves) is below branch_node
969
      // - new_child2, the new leaf node, is below branch_node as well
970

971
      return new_node;
710,151✔
972
    }
710,151✔
973

974
    //<! Traverse left branch depth-first
975
    TreeNode* traverse_l()
976
    {
479,428✔
977
      TreeNode* tnode = this;
479,428✔
978

979
      while (tnode->left) {
776,489✔
980
        tnode = tnode->left.get();
297,061✔
981
      }
297,061✔
982
      return tnode;
479,428✔
983
    }
479,428✔
984

985
    //<! Traverse tree depth-first and in-order (L-N-R)
986
    TreeNode* traverse_lnr()
987
    {
794,530✔
988
      TreeNode* tnode = this;
794,530✔
989

990
      // precondition: descended left as deep as possible
991
      if (tnode->right) {
794,530!
992
        // descend right
993
        tnode = tnode->right.get();
250,373✔
994
        // descend left as deep as possible and return next node
995
        return tnode->traverse_l();
250,373✔
996
      }
250,373✔
997

998
      // ascend to parent
999
      while (tnode->parent != nullptr) {
794,530✔
1000
        TreeNode* prev_child = tnode;
557,153✔
1001
        tnode = tnode->parent;
557,153✔
1002

1003
        // return this node, but only when we come from the left child branch
1004
        if (tnode->left && tnode->left.get() == prev_child) {
557,153!
1005
          return tnode;
306,780✔
1006
        }
306,780✔
1007
      }
557,153✔
1008
      return nullptr;
237,377✔
1009
    }
544,157✔
1010

1011
    //<! Traverse only assigned nodes
1012
    TreeNode* traverse_lnr_assigned()
1013
    {
155,839✔
1014
      TreeNode* tnode = traverse_lnr();
155,839✔
1015

1016
      while (tnode != nullptr && !tnode->assigned) {
273,770!
1017
        tnode = tnode->traverse_lnr();
117,931✔
1018
      }
117,931✔
1019
      return tnode;
155,839✔
1020
    }
155,839✔
1021

1022
    unique_ptr<TreeNode> left;
1023
    unique_ptr<TreeNode> right;
1024
    TreeNode* parent;
1025

1026
    node_type node;
1027
    bool assigned; //<! Whether this node is assigned-to by the application
1028

1029
    int d_bits; //<! How many bits have been used so far
1030
  };
1031

1032
  void cleanup_tree(TreeNode* node)
1033
  {
47,276✔
1034
    // only cleanup this node if it has no children and node not assigned
1035
    if (!(node->left || node->right || node->assigned)) {
47,276!
1036
      // get parent node ptr
1037
      TreeNode* pparent = node->parent;
24,679✔
1038
      // delete this node
1039
      if (pparent) {
24,679✔
1040
        if (pparent->left.get() == node) {
24,653✔
1041
          pparent->left.reset();
3,388✔
1042
        }
3,388✔
1043
        else {
21,265✔
1044
          pparent->right.reset();
21,265✔
1045
        }
21,265✔
1046
        // now recurse up to the parent
1047
        cleanup_tree(pparent);
24,653✔
1048
      }
24,653✔
1049
    }
24,679✔
1050
  }
47,276✔
1051

1052
  void copyTree(const NetmaskTree& rhs)
1053
  {
153,350✔
1054
    try {
153,350✔
1055
      TreeNode* node = rhs.d_root.get();
153,350✔
1056
      if (node != nullptr) {
153,350!
1057
        node = node->traverse_l();
153,350✔
1058
      }
153,350✔
1059
      while (node != nullptr) {
521,523✔
1060
        if (node->assigned) {
368,173!
1061
          insert(node->node.first).second = node->node.second;
179,767✔
1062
        }
179,767✔
1063
        node = node->traverse_lnr();
368,173✔
1064
      }
368,173✔
1065
    }
153,350✔
1066
    catch (const NetmaskException&) {
153,350✔
1067
      abort();
×
1068
    }
×
1069
    catch (const std::logic_error&) {
153,350✔
1070
      abort();
×
1071
    }
×
1072
  }
153,350✔
1073

1074
public:
1075
  class Iterator
1076
  {
1077
  public:
1078
    using value_type = node_type;
1079
    using reference = node_type&;
1080
    using pointer = node_type*;
1081
    using iterator_category = std::forward_iterator_tag;
1082
    using difference_type = size_type;
1083

1084
  private:
1085
    friend class NetmaskTree;
1086

1087
    const NetmaskTree* d_tree;
1088
    TreeNode* d_node;
1089

1090
    Iterator(const NetmaskTree* tree, TreeNode* node) :
1091
      d_tree(tree), d_node(node)
1092
    {
15,844✔
1093
    }
15,844✔
1094

1095
  public:
1096
    Iterator() :
1097
      d_tree(nullptr), d_node(nullptr) {}
×
1098

1099
    Iterator& operator++() // prefix
1100
    {
152,229✔
1101
      if (d_node == nullptr) {
152,229!
1102
        throw std::logic_error(
×
1103
          "NetmaskTree::Iterator::operator++: iterator is invalid");
×
1104
      }
×
1105
      d_node = d_node->traverse_lnr_assigned();
152,229✔
1106
      return *this;
152,229✔
1107
    }
152,229✔
1108
    Iterator operator++(int) // postfix
1109
    {
×
1110
      Iterator tmp(*this);
×
1111
      operator++();
×
1112
      return tmp;
×
1113
    }
×
1114

1115
    reference operator*()
1116
    {
85,701✔
1117
      if (d_node == nullptr) {
85,701!
1118
        throw std::logic_error(
×
1119
          "NetmaskTree::Iterator::operator*: iterator is invalid");
×
1120
      }
×
1121
      return d_node->node;
85,701✔
1122
    }
85,701✔
1123

1124
    pointer operator->()
1125
    {
768✔
1126
      if (d_node == nullptr) {
768!
1127
        throw std::logic_error(
×
1128
          "NetmaskTree::Iterator::operator->: iterator is invalid");
×
1129
      }
×
1130
      return &d_node->node;
768✔
1131
    }
768✔
1132

1133
    bool operator==(const Iterator& rhs)
1134
    {
160,151✔
1135
      return (d_tree == rhs.d_tree && d_node == rhs.d_node);
160,151!
1136
    }
160,151✔
1137
    bool operator!=(const Iterator& rhs)
1138
    {
160,151✔
1139
      return !(*this == rhs);
160,151✔
1140
    }
160,151✔
1141
  };
1142

1143
  NetmaskTree() noexcept :
1144
    d_root(new TreeNode()), d_left(nullptr)
1145
  {
61,464✔
1146
  }
61,464✔
1147

1148
  NetmaskTree(const NetmaskTree& rhs) :
1149
    d_root(new TreeNode()), d_left(nullptr)
1150
  {
128,443✔
1151
    copyTree(rhs);
128,443✔
1152
  }
128,443✔
1153

1154
  ~NetmaskTree() = default;
489,258✔
1155

1156
  NetmaskTree& operator=(const NetmaskTree& rhs)
1157
  {
35✔
1158
    if (this != &rhs) {
35!
1159
      clear();
35✔
1160
      copyTree(rhs);
35✔
1161
    }
35✔
1162
    return *this;
35✔
1163
  }
35✔
1164

1165
  NetmaskTree(NetmaskTree&&) noexcept = default;
75,903✔
1166
  NetmaskTree& operator=(NetmaskTree&&) noexcept = default;
5,753✔
1167

1168
  [[nodiscard]] iterator begin() const
1169
  {
7,867✔
1170
    return Iterator(this, d_left);
7,867✔
1171
  }
7,867✔
1172
  [[nodiscard]] iterator end() const
1173
  {
7,867✔
1174
    return Iterator(this, nullptr);
7,867✔
1175
  }
7,867✔
1176
  iterator begin()
1177
  {
55✔
1178
    return Iterator(this, d_left);
55✔
1179
  }
55✔
1180
  iterator end()
1181
  {
55✔
1182
    return Iterator(this, nullptr);
55✔
1183
  }
55✔
1184

1185
  node_type& insert(const string& mask)
1186
  {
15✔
1187
    return insert(key_type(mask));
15✔
1188
  }
15✔
1189

1190
  //<! Creates new value-pair in tree and returns it.
1191
  node_type& insert(const key_type& key)
1192
  {
1,010,393✔
1193
    TreeNode* node{};
1,010,393✔
1194
    bool is_left = true;
1,010,393✔
1195

1196
    // we turn left on IPv4 and right on IPv6
1197
    if (key.isIPv4()) {
1,010,393✔
1198
      node = d_root->left.get();
546,058✔
1199
      if (node == nullptr) {
546,058✔
1200

1201
        d_root->left = make_unique<TreeNode>(key);
164,094✔
1202
        node = d_root->left.get();
164,094✔
1203
        node->assigned = true;
164,094✔
1204
        node->parent = d_root.get();
164,094✔
1205
        d_size++;
164,094✔
1206
        d_left = node;
164,094✔
1207
        return node->node;
164,094✔
1208
      }
164,094✔
1209
    }
546,058✔
1210
    else if (key.isIPv6()) {
464,335!
1211
      node = d_root->right.get();
464,335✔
1212
      if (node == nullptr) {
464,335✔
1213

1214
        d_root->right = make_unique<TreeNode>(key);
102,418✔
1215
        node = d_root->right.get();
102,418✔
1216
        node->assigned = true;
102,418✔
1217
        node->parent = d_root.get();
102,418✔
1218
        d_size++;
102,418✔
1219
        if (!d_root->left) {
102,418!
1220
          d_left = node;
40✔
1221
        }
40✔
1222
        return node->node;
102,418✔
1223
      }
102,418✔
1224
      if (d_root->left) {
361,917!
1225
        is_left = false;
361,905✔
1226
      }
361,905✔
1227
    }
361,917✔
UNCOV
1228
    else {
×
UNCOV
1229
      throw NetmaskException("invalid address family");
×
UNCOV
1230
    }
×
1231

1232
    // we turn left on 0 and right on 1
1233
    int bits = 0;
743,881✔
1234
    for (; bits < key.getBits(); bits++) {
32,682,066!
1235
      bool vall = key.getBit(-1 - bits);
32,675,880✔
1236

1237
      if (bits >= node->d_bits) {
32,675,880!
1238
        // the end of the current node is reached; continue with the next
1239
        if (vall) {
5,006,372!
1240
          if (node->left || node->assigned) {
4,851,561!
1241
            is_left = false;
4,851,561✔
1242
          }
4,851,561✔
1243
          if (!node->right) {
4,851,561!
1244
            // the right branch doesn't exist yet; attach our key here
1245
            node = node->make_right(key);
1,847✔
1246
            break;
1,847✔
1247
          }
1,847✔
1248
          node = node->right.get();
4,849,714✔
1249
        }
4,849,714✔
1250
        else {
154,811✔
1251
          if (!node->left) {
154,811!
1252
            // the left branch doesn't exist yet; attach our key here
1253
            node = node->make_left(key);
56✔
1254
            break;
56✔
1255
          }
56✔
1256
          node = node->left.get();
154,755✔
1257
        }
154,755✔
1258
        continue;
5,004,469✔
1259
      }
5,006,372✔
1260
      if (bits >= node->node.first.getBits()) {
27,669,508✔
1261
        // the matching branch ends here, yet the key netmask has more bits; add a
1262
        // child node below the existing branch leaf.
1263
        if (vall) {
25,641!
1264
          if (node->assigned) {
23,113!
1265
            is_left = false;
23,113✔
1266
          }
23,113✔
1267
          node = node->make_right(key);
23,113✔
1268
        }
23,113✔
1269
        else {
2,528✔
1270
          node = node->make_left(key);
2,528✔
1271
        }
2,528✔
1272
        break;
25,641✔
1273
      }
25,641✔
1274
      bool valr = node->node.first.getBit(-1 - bits);
27,643,867✔
1275
      if (vall != valr) {
27,643,867✔
1276
        if (vall) {
710,151✔
1277
          is_left = false;
705,564✔
1278
        }
705,564✔
1279
        // the branch matches just upto this point, yet continues in a different
1280
        // direction; fork the branch.
1281
        node = node->fork(key, bits);
710,151✔
1282
        break;
710,151✔
1283
      }
710,151✔
1284
    }
27,643,867✔
1285

1286
    if (node->node.first.getBits() > key.getBits()) {
743,881!
1287
      // key is a super-network of the matching node; split the branch and
1288
      // insert a node for the key above the matching node.
1289
      node = node->split(key, key.getBits());
5,298✔
1290
    }
5,298✔
1291

1292
    if (node->left) {
743,881!
1293
      is_left = false;
5,860✔
1294
    }
5,860✔
1295

1296
    node_type& value = node->node;
743,881✔
1297

1298
    if (!node->assigned) {
743,881!
1299
      // only increment size if not assigned before
1300
      d_size++;
743,278✔
1301
      // update the pointer to the left-most tree node
1302
      if (is_left) {
743,278!
1303
        d_left = node;
945✔
1304
      }
945✔
1305
      node->assigned = true;
743,278✔
1306
    }
743,278✔
1307
    else {
603✔
1308
      // tree node exists for this value
1309
      if (is_left && d_left != node) {
603!
1310
        throw std::logic_error(
×
1311
          "NetmaskTree::insert(): lost track of left-most node in tree");
×
1312
      }
×
1313
    }
603✔
1314

1315
    return value;
743,881✔
1316
  }
743,881✔
1317

1318
  //<! Creates or updates value
1319
  void insert_or_assign(const key_type& mask, const value_type& value)
1320
  {
10✔
1321
    insert(mask).second = value;
10✔
1322
  }
10✔
1323

1324
  void insert_or_assign(const string& mask, const value_type& value)
1325
  {
×
1326
    insert(key_type(mask)).second = value;
×
1327
  }
×
1328

1329
  //<! check if given key is present in TreeMap
1330
  [[nodiscard]] bool has_key(const key_type& key) const
1331
  {
80✔
1332
    const node_type* ptr = lookup(key);
80✔
1333
    return ptr && ptr->first == key;
80!
1334
  }
80✔
1335

1336
  //<! Returns "best match" for key_type, which might not be value
1337
  [[nodiscard]] node_type* lookup(const key_type& value) const
1338
  {
341,990✔
1339
    uint8_t max_bits = value.getBits();
341,990✔
1340
    return lookupImpl(value, max_bits);
341,990✔
1341
  }
341,990✔
1342

1343
  //<! Perform best match lookup for value, using at most max_bits
1344
  [[nodiscard]] node_type* lookup(const ComboAddress& value, int max_bits = 128) const
1345
  {
1,662,891✔
1346
    uint8_t addr_bits = value.getBits();
1,662,891✔
1347
    if (max_bits < 0 || max_bits > addr_bits) {
1,662,892!
1348
      max_bits = addr_bits;
1,005,969✔
1349
    }
1,005,969✔
1350

1351
    return lookupImpl(key_type(value, max_bits), max_bits);
1,662,891✔
1352
  }
1,662,891✔
1353

1354
  //<! Removes key from TreeMap.
1355
  void erase(const key_type& key)
1356
  {
22,630✔
1357
    TreeNode* node = nullptr;
22,630✔
1358

1359
    if (key.isIPv4()) {
22,630✔
1360
      node = d_root->left.get();
22,595✔
1361
    }
22,595✔
1362
    else if (key.isIPv6()) {
35!
1363
      node = d_root->right.get();
35✔
1364
    }
35✔
1365
    else {
×
1366
      throw NetmaskException("invalid address family");
×
1367
    }
×
1368
    // no tree, no value
1369
    if (node == nullptr) {
22,630!
1370
      return;
×
1371
    }
×
1372
    int bits = 0;
22,630✔
1373
    for (; node && bits < key.getBits(); bits++) {
574,267!
1374
      bool vall = key.getBit(-1 - bits);
551,642✔
1375
      if (bits >= node->d_bits) {
551,642✔
1376
        // the end of the current node is reached; continue with the next
1377
        if (vall) {
356,718✔
1378
          node = node->right.get();
244,732✔
1379
        }
244,732✔
1380
        else {
111,986✔
1381
          node = node->left.get();
111,986✔
1382
        }
111,986✔
1383
        continue;
356,718✔
1384
      }
356,718✔
1385
      if (bits >= node->node.first.getBits()) {
194,924!
1386
        // the matching branch ends here
1387
        if (key.getBits() != node->node.first.getBits()) {
×
1388
          node = nullptr;
×
1389
        }
×
1390
        break;
×
1391
      }
×
1392
      bool valr = node->node.first.getBit(-1 - bits);
194,924✔
1393
      if (vall != valr) {
194,924!
1394
        // the branch matches just upto this point, yet continues in a different
1395
        // direction
1396
        node = nullptr;
5✔
1397
        break;
5✔
1398
      }
5✔
1399
    }
194,924✔
1400
    if (node) {
22,630✔
1401
      if (d_size == 0) {
22,623!
1402
        throw std::logic_error(
×
1403
          "NetmaskTree::erase(): size of tree is zero before erase");
×
1404
      }
×
1405
      d_size--;
22,623✔
1406
      node->assigned = false;
22,623✔
1407
      node->node.second = value_type();
22,623✔
1408

1409
      if (node == d_left) {
22,623!
1410
        d_left = d_left->traverse_lnr_assigned();
3,348✔
1411
      }
3,348✔
1412
      cleanup_tree(node);
22,623✔
1413
    }
22,623✔
1414
  }
22,630✔
1415

1416
  void erase(const string& key)
1417
  {
15✔
1418
    erase(key_type(key));
15✔
1419
  }
15✔
1420

1421
  //<! checks whether the container is empty.
1422
  [[nodiscard]] bool empty() const
1423
  {
103,797✔
1424
    return (d_size == 0);
103,797✔
1425
  }
103,797✔
1426

1427
  //<! returns the number of elements
1428
  [[nodiscard]] size_type size() const
1429
  {
704,568✔
1430
    return d_size;
704,568✔
1431
  }
704,568✔
1432

1433
  //<! See if given ComboAddress matches any prefix
1434
  [[nodiscard]] bool match(const ComboAddress& value) const
1435
  {
2,280✔
1436
    return (lookup(value) != nullptr);
2,280✔
1437
  }
2,280✔
1438

1439
  [[nodiscard]] bool match(const std::string& value) const
1440
  {
×
1441
    return match(ComboAddress(value));
×
1442
  }
×
1443

1444
  //<! Clean out the tree
1445
  void clear()
1446
  {
2,277✔
1447
    d_root = make_unique<TreeNode>();
2,277✔
1448
    d_left = nullptr;
2,277✔
1449
    d_size = 0;
2,277✔
1450
  }
2,277✔
1451

1452
  //<! swaps the contents with another NetmaskTree
1453
  void swap(NetmaskTree& rhs) noexcept
1454
  {
47✔
1455
    std::swap(d_root, rhs.d_root);
47✔
1456
    std::swap(d_left, rhs.d_left);
47✔
1457
    std::swap(d_size, rhs.d_size);
47✔
1458
  }
47✔
1459

1460
private:
1461
  [[nodiscard]] node_type* lookupImpl(const key_type& value, uint8_t max_bits) const
1462
  {
2,010,570✔
1463
    TreeNode* node = nullptr;
2,010,570✔
1464

1465
    if (value.isIPv4()) {
2,010,576!
1466
      node = d_root->left.get();
1,250,764✔
1467
    }
1,250,764✔
1468
    else if (value.isIPv6()) {
2,148,243,458!
1469
      node = d_root->right.get();
759,811✔
1470
    }
759,811✔
1471
    else {
2,147,483,647✔
1472
      throw NetmaskException("invalid address family");
2,147,483,647✔
1473
    }
2,147,483,647✔
1474
    if (node == nullptr) {
2,010,575✔
1475
      return nullptr;
239,927✔
1476
    }
239,927✔
1477

1478
    node_type* ret = nullptr;
1,770,648✔
1479

1480
    int bits = 0;
1,770,648✔
1481
    for (; bits < max_bits; bits++) {
60,126,946!
1482
      bool vall = value.getBit(-1 - bits);
59,585,551✔
1483
      if (bits >= node->d_bits) {
59,585,551!
1484
        // the end of the current node is reached; continue with the next
1485
        // (we keep track of last assigned node)
1486
        if (node->assigned && bits == node->node.first.getBits()) {
12,738,685!
1487
          ret = &node->node;
1,117,161✔
1488
        }
1,117,161✔
1489
        if (vall) {
12,738,685✔
1490
          if (!node->right) {
5,717,760!
1491
            break;
19,202✔
1492
          }
19,202✔
1493
          node = node->right.get();
5,698,558✔
1494
        }
5,698,558✔
1495
        else {
7,020,925✔
1496
          if (!node->left) {
7,020,925!
1497
            break;
2,822✔
1498
          }
2,822✔
1499
          node = node->left.get();
7,018,103✔
1500
        }
7,018,103✔
1501
        continue;
12,716,661✔
1502
      }
12,738,685✔
1503
      if (bits >= node->node.first.getBits()) {
46,846,866✔
1504
        // the matching branch ends here
1505
        break;
380,342✔
1506
      }
380,342✔
1507
      bool valr = node->node.first.getBit(-1 - bits);
46,466,524✔
1508
      if (vall != valr) {
46,466,524✔
1509
        // the branch matches just upto this point, yet continues in a different
1510
        // direction
1511
        break;
826,890✔
1512
      }
826,890✔
1513
    }
46,466,524✔
1514
    // needed if we did not find one in loop
1515
    if (node->assigned && bits == node->node.first.getBits()) {
1,770,648✔
1516
      ret = &node->node;
942,219✔
1517
    }
942,219✔
1518
    // this can be nullptr.
1519
    return ret;
1,770,648✔
1520
  }
2,010,575✔
1521

1522
  unique_ptr<TreeNode> d_root; //<! Root of our tree
1523
  TreeNode* d_left;
1524
  size_type d_size{0};
1525
};
1526

1527
/** This class represents a group of supplemental Netmask classes. An IP address matches
1528
    if it is matched by one or more of the Netmask objects within.
1529
*/
1530
class NetmaskGroup
1531
{
1532
public:
1533
  NetmaskGroup() noexcept = default;
50,301✔
1534

1535
  //! If this IP address is matched by any of the classes within
1536

1537
  bool match(const ComboAddress* address) const
1538
  {
314,067✔
1539
    const auto& ret = tree.lookup(*address);
314,067✔
1540
    if (ret != nullptr) {
314,067✔
1541
      return ret->second;
94,093✔
1542
    }
94,093✔
1543
    return false;
219,974✔
1544
  }
314,067✔
1545

1546
  [[nodiscard]] bool match(const ComboAddress& address) const
1547
  {
303,231✔
1548
    return match(&address);
303,231✔
1549
  }
303,231✔
1550

1551
  bool lookup(const ComboAddress* address, Netmask* nmp) const
1552
  {
×
1553
    const auto& ret = tree.lookup(*address);
×
1554
    if (ret != nullptr) {
×
1555
      if (nmp != nullptr) {
×
1556
        *nmp = ret->first;
×
1557
      }
×
1558
      return ret->second;
×
1559
    }
×
1560
    return false;
×
1561
  }
×
1562

1563
  bool lookup(const ComboAddress& address, Netmask* nmp) const
1564
  {
×
1565
    return lookup(&address, nmp);
×
1566
  }
×
1567

1568
  //! Add this string to the list of possible matches
1569
  void addMask(const string& address, bool positive = true)
1570
  {
31,532✔
1571
    if (!address.empty() && address[0] == '!') {
31,532!
1572
      addMask(Netmask(address.substr(1)), false);
1,249✔
1573
    }
1,249✔
1574
    else {
30,283✔
1575
      addMask(Netmask(address), positive);
30,283✔
1576
    }
30,283✔
1577
  }
31,532✔
1578

1579
  //! Add this Netmask to the list of possible matches
1580
  void addMask(const Netmask& netmask, bool positive = true)
1581
  {
33,599✔
1582
    tree.insert(netmask).second = positive;
33,599✔
1583
  }
33,599✔
1584

1585
  void addMasks(const NetmaskGroup& group, boost::optional<bool> positive)
1586
  {
2✔
1587
    for (const auto& entry : group.tree) {
2✔
1588
      addMask(entry.first, positive ? *positive : entry.second);
2!
1589
    }
2✔
1590
  }
2✔
1591

1592
  //! Delete this Netmask from the list of possible matches
1593
  void deleteMask(const Netmask& netmask)
1594
  {
×
1595
    tree.erase(netmask);
×
1596
  }
×
1597

1598
  void deleteMasks(const NetmaskGroup& group)
1599
  {
×
1600
    for (const auto& entry : group.tree) {
×
1601
      deleteMask(entry.first);
×
1602
    }
×
1603
  }
×
1604

1605
  void deleteMask(const std::string& address)
1606
  {
×
1607
    if (!address.empty()) {
×
1608
      deleteMask(Netmask(address));
×
1609
    }
×
1610
  }
×
1611

1612
  void clear()
1613
  {
1,611✔
1614
    tree.clear();
1,611✔
1615
  }
1,611✔
1616

1617
  [[nodiscard]] bool empty() const
1618
  {
100,762✔
1619
    return tree.empty();
100,762✔
1620
  }
100,762✔
1621

1622
  [[nodiscard]] size_t size() const
1623
  {
350✔
1624
    return tree.size();
350✔
1625
  }
350✔
1626

1627
  [[nodiscard]] string toString() const
1628
  {
71✔
1629
    ostringstream str;
71✔
1630
    for (auto iter = tree.begin(); iter != tree.end(); ++iter) {
382✔
1631
      if (iter != tree.begin()) {
311✔
1632
        str << ", ";
240✔
1633
      }
240✔
1634
      if (!(iter->second)) {
311✔
1635
        str << "!";
48✔
1636
      }
48✔
1637
      str << iter->first.toString();
311✔
1638
    }
311✔
1639
    return str.str();
71✔
1640
  }
71✔
1641

1642
  [[nodiscard]] std::vector<std::string> toStringVector() const
1643
  {
3,521✔
1644
    std::vector<std::string> out;
3,521✔
1645
    out.reserve(tree.size());
3,521✔
1646
    for (const auto& entry : tree) {
5,706✔
1647
      out.push_back((entry.second ? "" : "!") + entry.first.toString());
5,706!
1648
    }
5,706✔
1649
    return out;
3,521✔
1650
  }
3,521✔
1651

1652
  void toMasks(const string& ips)
1653
  {
3,066✔
1654
    vector<string> parts;
3,066✔
1655
    stringtok(parts, ips, ", \t");
3,066✔
1656

1657
    for (const auto& part : parts) {
5,191✔
1658
      addMask(part);
4,759✔
1659
    }
4,759✔
1660
  }
3,066✔
1661

1662
private:
1663
  NetmaskTree<bool> tree;
1664
};
1665

1666
struct SComboAddress
1667
{
1668
  SComboAddress(const ComboAddress& orig) :
1669
    ca(orig) {}
4,764✔
1670
  ComboAddress ca;
1671
  bool operator<(const SComboAddress& rhs) const
1672
  {
×
1673
    return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
×
1674
  }
×
1675
  operator const ComboAddress&() const
1676
  {
×
1677
    return ca;
×
1678
  }
×
1679
};
1680

1681
class NetworkError : public runtime_error
1682
{
1683
public:
1684
  NetworkError(const string& why = "Network Error") :
1685
    runtime_error(why.c_str())
1686
  {}
632✔
1687
  NetworkError(const char* why = "Network Error") :
1688
    runtime_error(why)
1689
  {}
28✔
1690
};
1691

1692
class AddressAndPortRange
1693
{
1694
public:
1695
  AddressAndPortRange() :
1696
    d_addrMask(0), d_portMask(0)
1697
  {
897✔
1698
    d_addr.sin4.sin_family = 0; // disable this doing anything useful
897✔
1699
    d_addr.sin4.sin_port = 0; // this guarantees d_network compares identical
897✔
1700
  }
897✔
1701

1702
  AddressAndPortRange(ComboAddress address, uint8_t addrMask, uint8_t portMask = 0) :
1703
    d_addr(address), d_addrMask(addrMask), d_portMask(portMask)
1704
  {
1,155,520✔
1705
    if (!d_addr.isIPv4()) {
1,155,520✔
1706
      d_portMask = 0;
266,130✔
1707
    }
266,130✔
1708

1709
    uint16_t port = d_addr.getPort();
1,155,520✔
1710
    if (d_portMask < 16) {
1,155,520✔
1711
      auto mask = static_cast<uint16_t>(~(0xFFFF >> d_portMask));
338,472✔
1712
      port = port & mask;
338,472✔
1713
    }
338,472✔
1714

1715
    if (d_addrMask < d_addr.getBits()) {
1,155,520✔
1716
      if (d_portMask > 0) {
7,964!
1717
        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) + ")");
×
1718
      }
×
1719
      d_addr = Netmask(d_addr, d_addrMask).getMaskedNetwork();
7,964✔
1720
    }
7,964✔
1721
    d_addr.setPort(port);
1,155,520✔
1722
  }
1,155,520✔
1723

1724
  [[nodiscard]] uint8_t getFullBits() const
1725
  {
181,067,780✔
1726
    return d_addr.getBits() + 16;
181,067,780✔
1727
  }
181,067,780✔
1728

1729
  [[nodiscard]] uint8_t getBits() const
1730
  {
46,987,747✔
1731
    if (d_addrMask < d_addr.getBits()) {
46,987,747✔
1732
      return d_addrMask;
98,538✔
1733
    }
98,538✔
1734

1735
    return d_addr.getBits() + d_portMask;
46,889,209✔
1736
  }
46,987,747✔
1737

1738
  /** Get the value of the bit at the provided bit index. When the index >= 0,
1739
      the index is relative to the LSB starting at index zero. When the index < 0,
1740
      the index is relative to the MSB starting at index -1 and counting down.
1741
  */
1742
  [[nodiscard]] bool getBit(int index) const
1743
  {
90,532,152✔
1744
    if (index >= getFullBits()) {
90,532,152!
1745
      return false;
×
1746
    }
×
1747
    if (index < 0) {
90,532,152!
1748
      index = getFullBits() + index;
90,532,152✔
1749
    }
90,532,152✔
1750

1751
    if (index < 16) {
90,532,152✔
1752
      /* we are into the port bits */
1753
      uint16_t port = d_addr.getPort();
2,066,966✔
1754
      return ((port & (1U << index)) != 0x0000);
2,066,966✔
1755
    }
2,066,966✔
1756

1757
    index -= 16;
88,465,186✔
1758

1759
    return d_addr.getBit(index);
88,465,186✔
1760
  }
90,532,152✔
1761

1762
  [[nodiscard]] bool isIPv4() const
1763
  {
811,677✔
1764
    return d_addr.isIPv4();
811,677✔
1765
  }
811,677✔
1766

1767
  [[nodiscard]] bool isIPv6() const
1768
  {
196,726✔
1769
    return d_addr.isIPv6();
196,726✔
1770
  }
196,726✔
1771

1772
  [[nodiscard]] AddressAndPortRange getNormalized() const
1773
  {
2,264✔
1774
    return {d_addr, d_addrMask, d_portMask};
2,264✔
1775
  }
2,264✔
1776

1777
  [[nodiscard]] AddressAndPortRange getSuper(uint8_t bits) const
1778
  {
1,020✔
1779
    if (bits <= d_addrMask) {
1,020!
1780
      return {d_addr, bits, 0};
1,020✔
1781
    }
1,020✔
1782
    if (bits <= d_addrMask + d_portMask) {
×
1783
      return {d_addr, d_addrMask, static_cast<uint8_t>(d_portMask - (bits - d_addrMask))};
×
1784
    }
×
1785

1786
    return {d_addr, d_addrMask, d_portMask};
×
1787
  }
×
1788

1789
  [[nodiscard]] const ComboAddress& getNetwork() const
1790
  {
804✔
1791
    return d_addr;
804✔
1792
  }
804✔
1793

1794
  [[nodiscard]] string toString() const
1795
  {
184✔
1796
    if (d_addrMask < d_addr.getBits() || d_portMask == 0) {
184!
1797
      return d_addr.toStringNoInterface() + "/" + std::to_string(d_addrMask);
180✔
1798
    }
180✔
1799
    return d_addr.toStringNoInterface() + ":" + std::to_string(d_addr.getPort()) + "/" + std::to_string(d_portMask);
4✔
1800
  }
184✔
1801

1802
  [[nodiscard]] bool empty() const
1803
  {
×
1804
    return d_addr.sin4.sin_family == 0;
×
1805
  }
×
1806

1807
  bool operator==(const AddressAndPortRange& rhs) const
1808
  {
16,012✔
1809
    return std::tie(d_addr, d_addrMask, d_portMask) == std::tie(rhs.d_addr, rhs.d_addrMask, rhs.d_portMask);
16,012✔
1810
  }
16,012✔
1811

1812
  bool operator<(const AddressAndPortRange& rhs) const
1813
  {
×
1814
    if (empty() && !rhs.empty()) {
×
1815
      return false;
×
1816
    }
×
1817

1818
    if (!empty() && rhs.empty()) {
×
1819
      return true;
×
1820
    }
×
1821

1822
    if (d_addrMask > rhs.d_addrMask) {
×
1823
      return true;
×
1824
    }
×
1825

1826
    if (d_addrMask < rhs.d_addrMask) {
×
1827
      return false;
×
1828
    }
×
1829

1830
    if (d_addr < rhs.d_addr) {
×
1831
      return true;
×
1832
    }
×
1833

1834
    if (d_addr > rhs.d_addr) {
×
1835
      return false;
×
1836
    }
×
1837

1838
    if (d_portMask > rhs.d_portMask) {
×
1839
      return true;
×
1840
    }
×
1841

1842
    if (d_portMask < rhs.d_portMask) {
×
1843
      return false;
×
1844
    }
×
1845

1846
    return d_addr.getPort() < rhs.d_addr.getPort();
×
1847
  }
×
1848

1849
  bool operator>(const AddressAndPortRange& rhs) const
1850
  {
×
1851
    return rhs.operator<(*this);
×
1852
  }
×
1853

1854
  struct hash
1855
  {
1856
    uint32_t operator()(const AddressAndPortRange& apr) const
1857
    {
16,393✔
1858
      ComboAddress::addressOnlyHash hashOp;
16,393✔
1859
      uint16_t port = apr.d_addr.getPort();
16,393✔
1860
      /* it's fine to hash the whole address and port because the non-relevant parts have
1861
         been masked to 0 */
1862
      return burtle(reinterpret_cast<const unsigned char*>(&port), sizeof(port), hashOp(apr.d_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
16,393✔
1863
    }
16,393✔
1864
  };
1865

1866
private:
1867
  ComboAddress d_addr;
1868
  uint8_t d_addrMask;
1869
  /* only used for v4 addresses */
1870
  uint8_t d_portMask;
1871
};
1872

1873
int SSocket(int family, int type, int flags);
1874
int SConnect(int sockfd, const ComboAddress& remote);
1875
/* tries to connect to remote for a maximum of timeout seconds.
1876
   sockfd should be set to non-blocking beforehand.
1877
   returns 0 on success (the socket is writable), throw a
1878
   runtime_error otherwise */
1879
int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout);
1880
int SBind(int sockfd, const ComboAddress& local);
1881
int SAccept(int sockfd, ComboAddress& remote);
1882
int SListen(int sockfd, int limit);
1883
int SSetsockopt(int sockfd, int level, int opname, int value);
1884
void setSocketIgnorePMTU(int sockfd, int family);
1885
void setSocketForcePMTU(int sockfd, int family);
1886
bool setReusePort(int sockfd);
1887

1888
#if defined(IP_PKTINFO)
1889
#define GEN_IP_PKTINFO IP_PKTINFO
113✔
1890
#elif defined(IP_RECVDSTADDR)
1891
#define GEN_IP_PKTINFO IP_RECVDSTADDR
1892
#endif
1893

1894
bool IsAnyAddress(const ComboAddress& addr);
1895
bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination);
1896
bool HarvestTimestamp(struct msghdr* msgh, struct timeval* timeval);
1897
void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
1898
int sendOnNBSocket(int fileDesc, const struct msghdr* msgh);
1899
size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
1900

1901
/* requires a non-blocking, connected TCP socket */
1902
bool isTCPSocketUsable(int sock);
1903

1904
extern template class NetmaskTree<bool>;
1905
ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
1906

1907
std::set<std::string> getListOfNetworkInterfaces();
1908
std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& itf);
1909
std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf);
1910

1911
/* These functions throw if the value was already set to a higher value,
1912
   or on error */
1913
void setSocketBuffer(int fileDesc, int optname, uint32_t size);
1914
void setSocketReceiveBuffer(int fileDesc, uint32_t size);
1915
void setSocketSendBuffer(int fileDesc, uint32_t size);
1916
uint32_t raiseSocketReceiveBufferToMax(int socket);
1917
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