Coverage Report

Created: 2026-07-24 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnsdistdist/iputils.hh
Line
Count
Source
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
#include "expected.hh"
36
37
#include "namespaces.hh"
38
39
#ifdef __APPLE__
40
#include <libkern/OSByteOrder.h>
41
42
#define htobe16(x) OSSwapHostToBigInt16(x)
43
#define htole16(x) OSSwapHostToLittleInt16(x)
44
#define be16toh(x) OSSwapBigToHostInt16(x)
45
#define le16toh(x) OSSwapLittleToHostInt16(x)
46
47
#define htobe32(x) OSSwapHostToBigInt32(x)
48
#define htole32(x) OSSwapHostToLittleInt32(x)
49
#define be32toh(x) OSSwapBigToHostInt32(x)
50
#define le32toh(x) OSSwapLittleToHostInt32(x)
51
52
#define htobe64(x) OSSwapHostToBigInt64(x)
53
#define htole64(x) OSSwapHostToLittleInt64(x)
54
#define be64toh(x) OSSwapBigToHostInt64(x)
55
#define le64toh(x) OSSwapLittleToHostInt64(x)
56
57
#if defined(CONNECT_DATA_IDEMPOTENT) && defined(CONNECT_RESUME_ON_READ_WRITE)
58
#define CONNECTX_FASTOPEN 1
59
#endif
60
61
#endif
62
63
#ifdef __sun
64
65
#define htobe16(x) BE_16(x)
66
#define htole16(x) LE_16(x)
67
#define be16toh(x) BE_IN16(&(x))
68
#define le16toh(x) LE_IN16(&(x))
69
70
#define htobe32(x) BE_32(x)
71
#define htole32(x) LE_32(x)
72
#define be32toh(x) BE_IN32(&(x))
73
#define le32toh(x) LE_IN32(&(x))
74
75
#define htobe64(x) BE_64(x)
76
#define htole64(x) LE_64(x)
77
#define be64toh(x) BE_IN64(&(x))
78
#define le64toh(x) LE_IN64(&(x))
79
80
#endif
81
82
#ifdef __FreeBSD__
83
#include <sys/endian.h>
84
#endif
85
86
#if defined(__NetBSD__) && defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
87
// The IP_PKTINFO option in NetBSD was incompatible with Linux until a
88
// change that also introduced IP_SENDSRCADDR for FreeBSD compatibility.
89
#undef IP_PKTINFO
90
#endif
91
92
union ComboAddress
93
{
94
  sockaddr_in sin4{};
95
  sockaddr_in6 sin6;
96
97
  bool operator==(const ComboAddress& rhs) const
98
0
  {
99
0
    if (std::tie(sin4.sin_family, sin4.sin_port) != std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
100
0
      return false;
101
0
    }
102
0
    if (sin4.sin_family == AF_INET) {
103
0
      return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
104
0
    }
105
0
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) == 0;
106
0
  }
107
108
  bool operator!=(const ComboAddress& rhs) const
109
0
  {
110
0
    return (!operator==(rhs));
111
0
  }
112
113
  bool operator<(const ComboAddress& rhs) const
114
0
  {
115
0
    if (sin4.sin_family == 0) {
116
0
      return false;
117
0
    }
118
0
    if (std::tie(sin4.sin_family, sin4.sin_port) < std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
119
0
      return true;
120
0
    }
121
0
    if (std::tie(sin4.sin_family, sin4.sin_port) > std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
122
0
      return false;
123
0
    }
124
0
    if (sin4.sin_family == AF_INET) {
125
0
      return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
126
0
    }
127
0
    return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0;
128
0
  }
129
130
  bool operator>(const ComboAddress& rhs) const
131
0
  {
132
0
    return rhs.operator<(*this);
133
0
  }
134
135
  struct addressPortOnlyHash
136
  {
137
    uint32_t operator()(const ComboAddress& address) const
138
0
    {
139
0
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
140
0
      if (address.sin4.sin_family == AF_INET) {
141
0
        const auto* start = reinterpret_cast<const unsigned char*>(&address.sin4.sin_addr.s_addr);
142
0
        auto tmp = burtle(start, 4, 0);
143
0
        return burtle(reinterpret_cast<const uint8_t*>(&address.sin4.sin_port), 2, tmp);
144
0
      }
145
0
      const auto* start = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
146
0
      auto tmp = burtle(start, 16, 0);
147
0
      return burtle(reinterpret_cast<const unsigned char*>(&address.sin6.sin6_port), 2, tmp);
148
0
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
149
0
    }
150
  };
151
152
  struct addressOnlyHash
153
  {
154
    uint32_t operator()(const ComboAddress& address) const
155
0
    {
156
0
      const unsigned char* start = nullptr;
157
0
      uint32_t len = 0;
158
0
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
159
0
      if (address.sin4.sin_family == AF_INET) {
160
0
        start = reinterpret_cast<const unsigned char*>(&address.sin4.sin_addr.s_addr);
161
0
        len = 4;
162
0
      }
163
0
      else {
164
0
        start = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
165
0
        len = 16;
166
0
      }
167
0
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
168
0
      return burtle(start, len, 0);
169
0
    }
170
  };
171
172
  struct addressOnlyLessThan
173
  {
174
    bool operator()(const ComboAddress& lhs, const ComboAddress& rhs) const
175
0
    {
176
0
      if (lhs.sin4.sin_family < rhs.sin4.sin_family) {
177
0
        return true;
178
0
      }
179
0
      if (lhs.sin4.sin_family > rhs.sin4.sin_family) {
180
0
        return false;
181
0
      }
182
0
      if (lhs.sin4.sin_family == AF_INET) {
183
0
        return lhs.sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
184
0
      }
185
0
      return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) < 0;
186
0
    }
187
  };
188
189
  struct addressOnlyEqual
190
  {
191
    bool operator()(const ComboAddress& lhs, const ComboAddress& rhs) const
192
0
    {
193
0
      if (lhs.sin4.sin_family != rhs.sin4.sin_family) {
194
0
        return false;
195
0
      }
196
0
      if (lhs.sin4.sin_family == AF_INET) {
197
0
        return lhs.sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
198
0
      }
199
0
      return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) == 0;
200
0
    }
201
  };
202
203
  [[nodiscard]] socklen_t getSocklen() const
204
809k
  {
205
809k
    if (sin4.sin_family == AF_INET) {
206
770k
      return sizeof(sin4);
207
770k
    }
208
38.9k
    return sizeof(sin6);
209
809k
  }
210
211
  ComboAddress()
212
1.29M
  {
213
1.29M
    sin4.sin_family = AF_INET;
214
1.29M
    sin4.sin_addr.s_addr = 0;
215
1.29M
    sin4.sin_port = 0;
216
1.29M
    sin6.sin6_scope_id = 0;
217
1.29M
    sin6.sin6_flowinfo = 0;
218
1.29M
  }
219
220
  ComboAddress(const struct sockaddr* socketAddress, socklen_t salen)
221
0
  {
222
0
    setSockaddr(socketAddress, salen);
223
0
  };
224
225
  ComboAddress(const struct sockaddr_in6* socketAddress)
226
0
  {
227
0
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
228
0
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in6));
229
0
  };
230
231
  ComboAddress(const struct sockaddr_in* socketAddress)
232
0
  {
233
0
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
234
0
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in));
235
0
  };
236
237
  void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen)
238
0
  {
239
0
    if (salen > sizeof(struct sockaddr_in6)) {
240
0
      throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
241
0
    }
242
0
    memcpy(this, socketAddress, salen);
243
0
  }
244
245
  // 'port' sets a default value in case 'str' does not set a port
246
  explicit ComboAddress(const string& str, uint16_t port = 0)
247
97.4k
  {
248
97.4k
    memset(&sin6, 0, sizeof(sin6));
249
97.4k
    sin4.sin_family = AF_INET;
250
97.4k
    sin4.sin_port = 0;
251
97.4k
    if (makeIPv4sockaddr(str, &sin4) != 0) {
252
3.33k
      sin6.sin6_family = AF_INET6;
253
3.33k
      if (makeIPv6sockaddr(str, &sin6) < 0) {
254
158
        throw PDNSException("Unable to convert presentation address '" + str + "'");
255
158
      }
256
3.33k
    }
257
97.2k
    if (sin4.sin_port == 0) { // 'str' overrides port!
258
92.4k
      sin4.sin_port = htons(port);
259
92.4k
    }
260
97.2k
  }
261
262
  [[nodiscard]] bool isIPv6() const
263
48.7k
  {
264
48.7k
    return sin4.sin_family == AF_INET6;
265
48.7k
  }
266
  [[nodiscard]] bool isIPv4() const
267
866k
  {
268
866k
    return sin4.sin_family == AF_INET;
269
866k
  }
270
271
  [[nodiscard]] bool isMappedIPv4() const
272
0
  {
273
0
    if (sin4.sin_family != AF_INET6) {
274
0
      return false;
275
0
    }
276
0
277
0
    int iter = 0;
278
0
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
279
0
    const auto* ptr = reinterpret_cast<const unsigned char*>(&sin6.sin6_addr.s6_addr);
280
0
    for (iter = 0; iter < 10; ++iter) {
281
0
      if (ptr[iter] != 0) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
282
0
        return false;
283
0
      }
284
0
    }
285
0
    for (; iter < 12; ++iter) {
286
0
      if (ptr[iter] != 0xff) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
287
0
        return false;
288
0
      }
289
0
    }
290
0
    return true;
291
0
  }
292
293
  [[nodiscard]] bool isUnspecified() const
294
0
  {
295
0
    static const ComboAddress unspecifiedV4("0.0.0.0:0");
296
0
    static const ComboAddress unspecifiedV6("[::]:0");
297
0
    const auto compare = ComboAddress::addressOnlyEqual();
298
0
    return compare(*this, unspecifiedV4) || compare(*this, unspecifiedV6);
299
0
  }
300
301
  [[nodiscard]] ComboAddress mapToIPv4() const
302
0
  {
303
0
    if (!isMappedIPv4()) {
304
0
      throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
305
0
    }
306
0
    ComboAddress ret;
307
0
    ret.sin4.sin_family = AF_INET;
308
0
    ret.sin4.sin_port = sin4.sin_port;
309
0
310
0
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
311
0
    const auto* ptr = reinterpret_cast<const unsigned char*>(&sin6.sin6_addr.s6_addr);
312
0
    ptr += (sizeof(sin6.sin6_addr.s6_addr) - sizeof(ret.sin4.sin_addr.s_addr)); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
313
0
    memcpy(&ret.sin4.sin_addr.s_addr, ptr, sizeof(ret.sin4.sin_addr.s_addr));
314
0
    return ret;
315
0
  }
316
317
  [[nodiscard]] string toString() const
318
809k
  {
319
809k
    std::array<char, 1024> host{};
320
809k
    if (sin4.sin_family != 0) {
321
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
322
809k
      int retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host.data(), host.size(), nullptr, 0, NI_NUMERICHOST);
323
809k
      if (retval == 0) {
324
809k
        return host.data();
325
809k
      }
326
0
      return "invalid " + string(gai_strerror(retval));
327
809k
    }
328
0
    return "invalid";
329
809k
  }
330
331
  //! Ignores any interface specifiers possibly available in the sockaddr data.
332
  [[nodiscard]] string toStringNoInterface() const
333
15.2k
  {
334
15.2k
    std::array<char, 1024> host{};
335
15.2k
    if (sin4.sin_family == AF_INET) {
336
3.46k
      const auto* ret = inet_ntop(sin4.sin_family, &sin4.sin_addr, host.data(), host.size());
337
3.46k
      if (ret != nullptr) {
338
3.46k
        return host.data();
339
3.46k
      }
340
3.46k
    }
341
11.8k
    else if (sin4.sin_family == AF_INET6) {
342
11.8k
      const auto* ret = inet_ntop(sin4.sin_family, &sin6.sin6_addr, host.data(), host.size());
343
11.8k
      if (ret != nullptr) {
344
11.8k
        return host.data();
345
11.8k
      }
346
11.8k
    }
347
0
    else {
348
0
      return "invalid";
349
0
    }
350
0
    return "invalid " + stringerror();
351
15.2k
  }
352
353
  [[nodiscard]] string toStringReversed() const
354
0
  {
355
0
    if (isIPv4()) {
356
0
      const auto address = ntohl(sin4.sin_addr.s_addr);
357
0
      auto aaa = (address >> 0) & 0xFF;
358
0
      auto bbb = (address >> 8) & 0xFF;
359
0
      auto ccc = (address >> 16) & 0xFF;
360
0
      auto ddd = (address >> 24) & 0xFF;
361
0
      return std::to_string(aaa) + "." + std::to_string(bbb) + "." + std::to_string(ccc) + "." + std::to_string(ddd);
362
0
    }
363
0
    const auto* addr = &sin6.sin6_addr;
364
0
    std::stringstream res{};
365
0
    res << std::hex;
366
0
    for (int i = 15; i >= 0; i--) {
367
0
      auto byte = addr->s6_addr[i]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
368
0
      res << ((byte >> 0) & 0xF) << ".";
369
0
      res << ((byte >> 4) & 0xF);
370
0
      if (i != 0) {
371
0
        res << ".";
372
0
      }
373
0
    }
374
0
    return res.str();
375
0
  }
376
377
  [[nodiscard]] string toStringWithPort() const
378
0
  {
379
0
    if (sin4.sin_family == AF_INET) {
380
0
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
381
0
    }
382
0
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
383
0
  }
384
385
  [[nodiscard]] string toStringWithPortExcept(int port) const
386
0
  {
387
0
    if (ntohs(sin4.sin_port) == port) {
388
0
      return toString();
389
0
    }
390
0
    if (sin4.sin_family == AF_INET) {
391
0
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
392
0
    }
393
0
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
394
0
  }
395
396
  [[nodiscard]] string toLogString() const
397
0
  {
398
0
    return toStringWithPortExcept(53);
399
0
  }
400
401
  [[nodiscard]] string toStructuredLogString() const
402
0
  {
403
0
    return toStringWithPort();
404
0
  }
405
406
  [[nodiscard]] string toByteString() const
407
0
  {
408
0
    // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
409
0
    if (isIPv4()) {
410
0
      return {reinterpret_cast<const char*>(&sin4.sin_addr.s_addr), sizeof(sin4.sin_addr.s_addr)};
411
0
    }
412
0
    return {reinterpret_cast<const char*>(&sin6.sin6_addr.s6_addr), sizeof(sin6.sin6_addr.s6_addr)};
413
0
    // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
414
0
  }
415
416
  void truncate(unsigned int bits) noexcept;
417
418
  [[nodiscard]] uint16_t getNetworkOrderPort() const noexcept
419
0
  {
420
0
    return sin4.sin_port;
421
0
  }
422
  [[nodiscard]] uint16_t getPort() const noexcept
423
0
  {
424
0
    return ntohs(getNetworkOrderPort());
425
0
  }
426
  void setPort(uint16_t port)
427
  {
428
    sin4.sin_port = htons(port);
429
  }
430
431
  void reset()
432
0
  {
433
0
    memset(&sin6, 0, sizeof(sin6));
434
0
  }
435
436
  //! Get the total number of address bits (either 32 or 128 depending on IP version)
437
  [[nodiscard]] uint8_t getBits() const
438
0
  {
439
0
    if (isIPv4()) {
440
0
      return 32;
441
0
    }
442
0
    if (isIPv6()) {
443
0
      return 128;
444
0
    }
445
0
    return 0;
446
0
  }
447
  /** Get the value of the bit at the provided bit index. When the index >= 0,
448
      the index is relative to the LSB starting at index zero. When the index < 0,
449
      the index is relative to the MSB starting at index -1 and counting down.
450
   */
451
  [[nodiscard]] bool getBit(int index) const
452
0
  {
453
0
    if (isIPv4()) {
454
0
      if (index >= 32) {
455
0
        return false;
456
0
      }
457
0
      if (index < 0) {
458
0
        if (index < -32) {
459
0
          return false;
460
0
        }
461
0
        index = 32 + index;
462
0
      }
463
464
0
      uint32_t ls_addr = ntohl(sin4.sin_addr.s_addr);
465
466
0
      return ((ls_addr & (1U << index)) != 0x00000000);
467
0
    }
468
0
    if (isIPv6()) {
469
0
      if (index >= 128) {
470
0
        return false;
471
0
      }
472
0
      if (index < 0) {
473
0
        if (index < -128) {
474
0
          return false;
475
0
        }
476
0
        index = 128 + index;
477
0
      }
478
479
0
      const auto* ls_addr = reinterpret_cast<const uint8_t*>(sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
480
0
      uint8_t byte_idx = index / 8;
481
0
      uint8_t bit_idx = index % 8;
482
483
0
      return ((ls_addr[15 - byte_idx] & (1U << bit_idx)) != 0x00); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
484
0
    }
485
0
    return false;
486
0
  }
487
488
  /*! Returns a comma-separated string of IP addresses
489
   *
490
   * \param c  An stl container with ComboAddresses
491
   * \param withPort  Also print the port (default true)
492
   * \param portExcept  Print the port, except when this is the port (default 53)
493
   */
494
  template <template <class...> class Container, class... Args>
495
  static string caContainerToString(const Container<ComboAddress, Args...>& container, const bool withPort = true, const uint16_t portExcept = 53)
496
  {
497
    vector<string> strs;
498
    for (const auto& address : container) {
499
      if (withPort) {
500
        strs.push_back(address.toStringWithPortExcept(portExcept));
501
        continue;
502
      }
503
      strs.push_back(address.toString());
504
    }
505
    return boost::join(strs, ",");
506
  };
507
};
508
509
union SockaddrWrapper
510
{
511
  sockaddr_in sin4{};
512
  sockaddr_in6 sin6;
513
  sockaddr_un sinun;
514
515
  [[nodiscard]] socklen_t getSocklen() const
516
0
  {
517
0
    if (sin4.sin_family == AF_INET) {
518
0
      return sizeof(sin4);
519
0
    }
520
0
    if (sin6.sin6_family == AF_INET6) {
521
0
      return sizeof(sin6);
522
0
    }
523
0
    if (sinun.sun_family == AF_UNIX) {
524
0
      return sizeof(sinun);
525
0
    }
526
0
    return 0;
527
0
  }
528
529
  SockaddrWrapper()
530
0
  {
531
0
    sin4.sin_family = AF_INET;
532
0
    sin4.sin_addr.s_addr = 0;
533
0
    sin4.sin_port = 0;
534
0
  }
535
536
  SockaddrWrapper(const struct sockaddr* socketAddress, socklen_t salen)
537
0
  {
538
0
    setSockaddr(socketAddress, salen);
539
0
  };
540
541
  SockaddrWrapper(const struct sockaddr_in6* socketAddress)
542
0
  {
543
0
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
544
0
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in6));
545
0
  };
546
547
  SockaddrWrapper(const struct sockaddr_in* socketAddress)
548
0
  {
549
0
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
550
0
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in));
551
0
  };
552
553
  SockaddrWrapper(const struct sockaddr_un* socketAddress)
554
0
  {
555
0
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
556
0
    setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_un));
557
0
  };
558
559
  void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen)
560
0
  {
561
0
    if (salen > sizeof(struct sockaddr_un)) {
562
0
      throw PDNSException("ComboAddress can't handle other than sockaddr_in, sockaddr_in6 or sockaddr_un");
563
0
    }
564
0
    memcpy(this, socketAddress, salen);
565
0
  }
566
567
  explicit SockaddrWrapper(const string& str, uint16_t port = 0)
568
0
  {
569
0
    memset(&sinun, 0, sizeof(sinun));
570
0
    sin4.sin_family = AF_INET;
571
0
    sin4.sin_port = 0;
572
0
    if (str == "\"\"" || str == "''") {
573
0
      throw PDNSException("Stray quotation marks in address.");
574
0
    }
575
0
    if (makeIPv4sockaddr(str, &sin4) != 0) {
576
0
      sin6.sin6_family = AF_INET6;
577
0
      if (makeIPv6sockaddr(str, &sin6) < 0) {
578
0
        sinun.sun_family = AF_UNIX;
579
0
        // only attempt Unix socket address if address candidate does not contain a port
580
0
        if (str.find(':') != string::npos || makeUNsockaddr(str, &sinun) < 0) {
581
0
          throw PDNSException("Unable to convert presentation address '" + str + "'");
582
0
        }
583
0
      }
584
0
    }
585
0
    if (sinun.sun_family != AF_UNIX && sin4.sin_port == 0) { // 'str' overrides port!
586
0
      sin4.sin_port = htons(port);
587
0
    }
588
0
  }
589
590
  [[nodiscard]] bool isIPv6() const
591
0
  {
592
0
    return sin4.sin_family == AF_INET6;
593
0
  }
594
  [[nodiscard]] bool isIPv4() const
595
0
  {
596
0
    return sin4.sin_family == AF_INET;
597
0
  }
598
  [[nodiscard]] bool isUnixSocket() const
599
0
  {
600
0
    return sin4.sin_family == AF_UNIX;
601
0
  }
602
603
  [[nodiscard]] string toString() const
604
0
  {
605
0
    if (sinun.sun_family == AF_UNIX) {
606
0
      return sinun.sun_path;
607
0
    }
608
0
    std::array<char, 1024> host{};
609
0
    if (sin4.sin_family != 0) {
610
0
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
611
0
      int retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host.data(), host.size(), nullptr, 0, NI_NUMERICHOST);
612
0
      if (retval == 0) {
613
0
        return host.data();
614
0
      }
615
0
      return "invalid " + string(gai_strerror(retval));
616
0
    }
617
0
    return "invalid";
618
0
  }
619
620
  [[nodiscard]] string toStringWithPort() const
621
0
  {
622
0
    if (sinun.sun_family == AF_UNIX) {
623
0
      return toString();
624
0
    }
625
0
    if (sin4.sin_family == AF_INET) {
626
0
      return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
627
0
    }
628
0
    return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
629
0
  }
630
631
  void reset()
632
0
  {
633
0
    memset(&sinun, 0, sizeof(sinun));
634
0
  }
635
};
636
637
/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
638
class NetmaskException : public PDNSException
639
{
640
public:
641
  NetmaskException(const string& arg) :
642
231
    PDNSException(arg) {}
643
};
644
645
inline ComboAddress makeComboAddress(const string& str)
646
11.0k
{
647
11.0k
  ComboAddress address;
648
11.0k
  address.sin4.sin_family = AF_INET;
649
11.0k
  if (inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
650
8.87k
    address.sin4.sin_family = AF_INET6;
651
8.87k
    if (makeIPv6sockaddr(str, &address.sin6) < 0) {
652
231
      throw NetmaskException("Unable to convert '" + str + "' to a netmask");
653
231
    }
654
8.87k
  }
655
10.7k
  return address;
656
11.0k
}
657
658
inline ComboAddress makeComboAddressFromRaw(uint8_t version, const char* raw, size_t len)
659
784k
{
660
784k
  ComboAddress address;
661
662
784k
  if (version == 4) {
663
746k
    address.sin4.sin_family = AF_INET;
664
746k
    if (len != sizeof(address.sin4.sin_addr)) {
665
0
      throw NetmaskException("invalid raw address length");
666
0
    }
667
746k
    memcpy(&address.sin4.sin_addr, raw, sizeof(address.sin4.sin_addr));
668
746k
  }
669
38.0k
  else if (version == 6) {
670
38.0k
    address.sin6.sin6_family = AF_INET6;
671
38.0k
    if (len != sizeof(address.sin6.sin6_addr)) {
672
0
      throw NetmaskException("invalid raw address length");
673
0
    }
674
38.0k
    memcpy(&address.sin6.sin6_addr, raw, sizeof(address.sin6.sin6_addr));
675
38.0k
  }
676
0
  else {
677
0
    throw NetmaskException("invalid address family");
678
0
  }
679
680
784k
  return address;
681
784k
}
682
683
inline ComboAddress makeComboAddressFromRaw(uint8_t version, const string& str)
684
455k
{
685
455k
  return makeComboAddressFromRaw(version, str.c_str(), str.size());
686
455k
}
687
688
/** This class represents a netmask and can be queried to see if a certain
689
    IP address is matched by this mask */
690
class Netmask
691
{
692
public:
693
  Netmask()
694
11.9k
  {
695
11.9k
    d_network.sin4.sin_family = 0; // disable this doing anything useful
696
11.9k
    d_network.sin4.sin_port = 0; // this guarantees d_network compares identical
697
11.9k
  }
698
699
  Netmask(const ComboAddress& network, uint8_t bits = 0xff) :
700
15.2k
    d_network(network)
701
15.2k
  {
702
15.2k
    d_network.sin4.sin_port = 0;
703
15.2k
    setBits(bits);
704
15.2k
  }
705
706
  Netmask(const sockaddr_in* network, uint8_t bits = 0xff) :
707
    d_network(network)
708
0
  {
709
0
    d_network.sin4.sin_port = 0;
710
0
    setBits(bits);
711
0
  }
712
  Netmask(const sockaddr_in6* network, uint8_t bits = 0xff) :
713
    d_network(network)
714
0
  {
715
0
    d_network.sin4.sin_port = 0;
716
0
    setBits(bits);
717
0
  }
718
  void setBits(uint8_t value)
719
25.9k
  {
720
25.9k
    d_bits = d_network.isIPv4() ? std::min(value, static_cast<uint8_t>(32U)) : std::min(value, static_cast<uint8_t>(128U));
721
722
25.9k
    if (d_bits < 32) {
723
9.70k
      d_mask = ~(0xFFFFFFFF >> d_bits);
724
9.70k
    }
725
16.2k
    else {
726
      // note that d_mask is unused for IPv6
727
16.2k
      d_mask = 0xFFFFFFFF;
728
16.2k
    }
729
730
25.9k
    if (isIPv4()) {
731
5.59k
      d_network.sin4.sin_addr.s_addr = htonl(ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
732
5.59k
    }
733
20.3k
    else if (isIPv6()) {
734
20.3k
      uint8_t bytes = d_bits / 8;
735
20.3k
      auto* address = reinterpret_cast<uint8_t*>(&d_network.sin6.sin6_addr.s6_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
736
20.3k
      uint8_t bits = d_bits % 8;
737
20.3k
      auto mask = static_cast<uint8_t>(~(0xFF >> bits));
738
739
20.3k
      if (bytes < sizeof(d_network.sin6.sin6_addr.s6_addr)) {
740
7.67k
        address[bytes] &= mask; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
741
7.67k
      }
742
743
123k
      for (size_t idx = bytes + 1; idx < sizeof(d_network.sin6.sin6_addr.s6_addr); ++idx) {
744
103k
        address[idx] = 0; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
745
103k
      }
746
20.3k
    }
747
25.9k
  }
748
749
  enum stringType
750
  {
751
    humanString,
752
    byteString,
753
  };
754
  //! Constructor supplies the mask, which cannot be changed
755
  Netmask(const string& mask, stringType type = humanString)
756
11.0k
  {
757
11.0k
    if (type == byteString) {
758
0
      uint8_t afi = mask.at(0);
759
0
      size_t len = afi == 4 ? 4 : 16;
760
0
      uint8_t bits = mask.at(len + 1);
761
762
0
      d_network = makeComboAddressFromRaw(afi, mask.substr(1, len));
763
764
0
      setBits(bits);
765
0
    }
766
11.0k
    else {
767
11.0k
      pair<string, string> split = splitField(mask, '/');
768
11.0k
      d_network = makeComboAddress(split.first);
769
770
11.0k
      if (!split.second.empty()) {
771
5.56k
        setBits(pdns::checked_stoi<uint8_t>(split.second));
772
5.56k
      }
773
5.43k
      else if (d_network.sin4.sin_family == AF_INET) {
774
737
        setBits(32);
775
737
      }
776
4.69k
      else {
777
4.69k
        setBits(128);
778
4.69k
      }
779
11.0k
    }
780
11.0k
  }
781
782
  [[nodiscard]] bool match(const ComboAddress& address) const
783
0
  {
784
0
    return match(&address);
785
0
  }
786
787
  //! If this IP address in socket address matches
788
  bool match(const ComboAddress* address) const
789
0
  {
790
0
    if (d_network.sin4.sin_family != address->sin4.sin_family) {
791
0
      return false;
792
0
    }
793
0
    if (d_network.sin4.sin_family == AF_INET) {
794
0
      return match4(htonl((unsigned int)address->sin4.sin_addr.s_addr));
795
0
    }
796
0
    if (d_network.sin6.sin6_family == AF_INET6) {
797
0
      uint8_t bytes = d_bits / 8;
798
0
      uint8_t index = 0;
799
0
      // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
800
0
      const auto* lhs = reinterpret_cast<const uint8_t*>(&d_network.sin6.sin6_addr.s6_addr);
801
0
      const auto* rhs = reinterpret_cast<const uint8_t*>(&address->sin6.sin6_addr.s6_addr);
802
0
      // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
803
0
804
0
      // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
805
0
      for (index = 0; index < bytes; ++index) {
806
0
        if (lhs[index] != rhs[index]) {
807
0
          return false;
808
0
        }
809
0
      }
810
0
      // still here, now match remaining bits
811
0
      uint8_t bits = d_bits % 8;
812
0
      auto mask = static_cast<uint8_t>(~(0xFF >> bits));
813
0
814
0
      return ((lhs[index]) == (rhs[index] & mask));
815
0
      // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
816
0
    }
817
0
    return false;
818
0
  }
819
820
  //! If this ASCII IP address matches
821
  [[nodiscard]] bool match(const string& arg) const
822
0
  {
823
0
    ComboAddress address = makeComboAddress(arg);
824
0
    return match(&address);
825
0
  }
826
827
  //! If this IP address in native format matches
828
  [[nodiscard]] bool match4(uint32_t arg) const
829
0
  {
830
0
    return (arg & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr));
831
0
  }
832
833
  [[nodiscard]] string toString() const
834
15.2k
  {
835
15.2k
    return d_network.toStringNoInterface() + "/" + std::to_string((unsigned int)d_bits);
836
15.2k
  }
837
838
  [[nodiscard]] string toStringNoMask() const
839
0
  {
840
0
    return d_network.toStringNoInterface();
841
0
  }
842
843
  [[nodiscard]] string toByteString() const
844
0
  {
845
0
    ostringstream tmp;
846
0
847
0
    tmp << (d_network.isIPv4() ? "\x04" : "\x06")
848
0
        << d_network.toByteString()
849
0
        << getBits();
850
0
851
0
    return tmp.str();
852
0
  }
853
854
  [[nodiscard]] const ComboAddress& getNetwork() const
855
284k
  {
856
284k
    return d_network;
857
284k
  }
858
859
  [[nodiscard]] const ComboAddress& getMaskedNetwork() const
860
0
  {
861
0
    return getNetwork();
862
0
  }
863
864
  [[nodiscard]] uint8_t getBits() const
865
10.6k
  {
866
10.6k
    return d_bits;
867
10.6k
  }
868
869
  [[nodiscard]] bool isIPv6() const
870
20.3k
  {
871
20.3k
    return d_network.sin6.sin6_family == AF_INET6;
872
20.3k
  }
873
874
  [[nodiscard]] bool isIPv4() const
875
25.9k
  {
876
25.9k
    return d_network.sin4.sin_family == AF_INET;
877
25.9k
  }
878
879
  bool operator<(const Netmask& rhs) const
880
0
  {
881
0
    if (empty() && !rhs.empty()) {
882
0
      return false;
883
0
    }
884
0
    if (!empty() && rhs.empty()) {
885
0
      return true;
886
0
    }
887
0
    if (d_bits > rhs.d_bits) {
888
0
      return true;
889
0
    }
890
0
    if (d_bits < rhs.d_bits) {
891
0
      return false;
892
0
    }
893
0
894
0
    return d_network < rhs.d_network;
895
0
  }
896
897
  bool operator>(const Netmask& rhs) const
898
0
  {
899
0
    return rhs.operator<(*this);
900
0
  }
901
902
  bool operator==(const Netmask& rhs) const
903
0
  {
904
0
    return std::tie(d_network, d_bits) == std::tie(rhs.d_network, rhs.d_bits);
905
0
  }
906
907
  bool operator!=(const Netmask& rhs) const
908
0
  {
909
0
    return !operator==(rhs);
910
0
  }
911
912
  [[nodiscard]] bool empty() const
913
0
  {
914
0
    return d_network.sin4.sin_family == 0;
915
0
  }
916
917
  //! Get normalized version of the netmask. This means that all address bits below the network bits are zero.
918
  [[nodiscard]] Netmask getNormalized() const
919
0
  {
920
0
    return {getMaskedNetwork(), d_bits};
921
0
  }
922
  //! Get Netmask for super network of this one (i.e. with fewer network bits)
923
  [[nodiscard]] Netmask getSuper(uint8_t bits) const
924
0
  {
925
0
    return {d_network, std::min(d_bits, bits)};
926
0
  }
927
928
  //! Get the total number of address bits for this netmask (either 32 or 128 depending on IP version)
929
  [[nodiscard]] uint8_t getFullBits() const
930
0
  {
931
0
    return d_network.getBits();
932
0
  }
933
934
  /** Get the value of the bit at the provided bit index. When the index >= 0,
935
      the index is relative to the LSB starting at index zero. When the index < 0,
936
      the index is relative to the MSB starting at index -1 and counting down.
937
      When the index points outside the network bits, it always yields zero.
938
   */
939
  [[nodiscard]] bool getBit(int bit) const
940
0
  {
941
0
    if (bit < -d_bits) {
942
0
      return false;
943
0
    }
944
0
    if (bit >= 0) {
945
0
      if (isIPv4()) {
946
0
        if (bit >= 32 || bit < (32 - d_bits)) {
947
0
          return false;
948
0
        }
949
0
      }
950
0
      if (isIPv6()) {
951
0
        if (bit >= 128 || bit < (128 - d_bits)) {
952
0
          return false;
953
0
        }
954
0
      }
955
0
    }
956
0
    return d_network.getBit(bit);
957
0
  }
958
959
  struct Hash
960
  {
961
    size_t operator()(const Netmask& netmask) const
962
0
    {
963
0
      return burtle(&netmask.d_bits, 1, ComboAddress::addressOnlyHash()(netmask.d_network));
964
0
    }
965
  };
966
967
private:
968
  ComboAddress d_network;
969
  uint32_t d_mask{0};
970
  uint8_t d_bits{0};
971
};
972
973
namespace std
974
{
975
template <>
976
struct hash<Netmask>
977
{
978
  auto operator()(const Netmask& netmask) const
979
0
  {
980
0
    return Netmask::Hash{}(netmask);
981
0
  }
982
};
983
}
984
985
/** Binary tree map implementation with <Netmask,T> pair.
986
 *
987
 * This is a binary tree implementation for storing attributes for IPv4 and IPv6 prefixes.
988
 * The most simple use case is simple NetmaskTree<bool> used by NetmaskGroup, which only
989
 * wants to know if given IP address is matched in the prefixes stored.
990
 *
991
 * This element is useful for anything that needs to *STORE* prefixes, and *MATCH* IP addresses
992
 * to a *LIST* of *PREFIXES*. Not the other way round.
993
 *
994
 * You can store IPv4 and IPv6 addresses to same tree, separate payload storage is kept per AFI.
995
 * Network prefixes (Netmasks) are always recorded in normalized fashion, meaning that only
996
 * the network bits are set. This is what is returned in the insert() and lookup() return
997
 * values.
998
 *
999
 * Use swap if you need to move the tree to another NetmaskTree instance, it is WAY faster
1000
 * than using copy ctor or assignment operator, since it moves the nodes and tree root to
1001
 * new home instead of actually recreating the tree.
1002
 *
1003
 * Please see NetmaskGroup for example of simple use case. Other usecases can be found
1004
 * from GeoIPBackend and Sortlist, and from dnsdist.
1005
 */
1006
template <typename T, class K = Netmask>
1007
class NetmaskTree
1008
{
1009
public:
1010
  class Iterator;
1011
1012
  using key_type = K;
1013
  using value_type = T;
1014
  using node_type = std::pair<const key_type, value_type>;
1015
  using size_type = size_t;
1016
  using iterator = class Iterator;
1017
1018
private:
1019
  /** Single node in tree, internal use only.
1020
   */
1021
  class TreeNode : boost::noncopyable
1022
  {
1023
  public:
1024
    explicit TreeNode() noexcept :
1025
0
      parent(nullptr), node(), assigned(false), d_bits(0)
1026
0
    {
1027
0
    }
1028
    explicit TreeNode(const key_type& key) :
1029
0
      parent(nullptr), node({key.getNormalized(), value_type()}), assigned(false), d_bits(key.getFullBits())
1030
0
    {
1031
0
    }
1032
1033
    //<! Makes a left leaf node with specified key.
1034
    TreeNode* make_left(const key_type& key)
1035
0
    {
1036
0
      d_bits = node.first.getBits();
1037
0
      left = make_unique<TreeNode>(key);
1038
0
      left->parent = this;
1039
0
      return left.get();
1040
0
    }
1041
1042
    //<! Makes a right leaf node with specified key.
1043
    TreeNode* make_right(const key_type& key)
1044
0
    {
1045
0
      d_bits = node.first.getBits();
1046
0
      right = make_unique<TreeNode>(key);
1047
0
      right->parent = this;
1048
0
      return right.get();
1049
0
    }
1050
1051
    //<! Splits branch at indicated bit position by inserting key
1052
    TreeNode* split(const key_type& key, int bits)
1053
0
    {
1054
0
      if (parent == nullptr) {
1055
        // not to be called on the root node
1056
0
        throw std::logic_error(
1057
0
          "NetmaskTree::TreeNode::split(): must not be called on root node");
1058
0
      }
1059
1060
      // determine reference from parent
1061
0
      unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
1062
0
      if (parent_ref.get() != this) {
1063
0
        throw std::logic_error(
1064
0
          "NetmaskTree::TreeNode::split(): parent node reference is invalid");
1065
0
      }
1066
1067
      // create new tree node for the new key and
1068
      // attach the new node under our former parent
1069
0
      auto new_intermediate_node = make_unique<TreeNode>(key);
1070
0
      new_intermediate_node->d_bits = bits;
1071
0
      new_intermediate_node->parent = parent;
1072
0
      auto* new_intermediate_node_raw = new_intermediate_node.get();
1073
1074
      // hereafter new_intermediate points to "this"
1075
      // ie the child of the new intermediate node
1076
0
      std::swap(parent_ref, new_intermediate_node);
1077
      // and we now assign this to current_node so
1078
      // it's clear it no longer refers to the new
1079
      // intermediate node
1080
0
      std::unique_ptr<TreeNode> current_node = std::move(new_intermediate_node);
1081
1082
      // attach "this" node below the new node
1083
      // (left or right depending on bit)
1084
      // technically the raw pointer escapes the duration of the
1085
      // unique pointer, but just below we store the unique pointer
1086
      // in the parent, so it lives as long as necessary
1087
      // coverity[escape]
1088
0
      current_node->parent = new_intermediate_node_raw;
1089
0
      if (current_node->node.first.getBit(-1 - bits)) {
1090
0
        new_intermediate_node_raw->right = std::move(current_node);
1091
0
      }
1092
0
      else {
1093
0
        new_intermediate_node_raw->left = std::move(current_node);
1094
0
      }
1095
1096
0
      return new_intermediate_node_raw;
1097
0
    }
1098
1099
    //<! Forks branch for new key at indicated bit position
1100
    TreeNode* fork(const key_type& key, int bits)
1101
0
    {
1102
0
      if (parent == nullptr) {
1103
        // not to be called on the root node
1104
0
        throw std::logic_error(
1105
0
          "NetmaskTree::TreeNode::fork(): must not be called on root node");
1106
0
      }
1107
1108
      // determine reference from parent
1109
0
      unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
1110
0
      if (parent_ref.get() != this) {
1111
0
        throw std::logic_error(
1112
0
          "NetmaskTree::TreeNode::fork(): parent node reference is invalid");
1113
0
      }
1114
1115
      // create new tree node for the branch point
1116
1117
      // the current node will now be a child of the new branch node
1118
      // (hereafter new_child1 points to "this")
1119
0
      unique_ptr<TreeNode> new_child1 = std::move(parent_ref);
1120
      // attach the branch node under our former parent
1121
0
      parent_ref = make_unique<TreeNode>(node.first.getSuper(bits));
1122
0
      auto* branch_node = parent_ref.get();
1123
0
      branch_node->d_bits = bits;
1124
0
      branch_node->parent = parent;
1125
1126
      // create second new leaf node for the new key
1127
0
      unique_ptr<TreeNode> new_child2 = make_unique<TreeNode>(key);
1128
0
      TreeNode* new_node = new_child2.get();
1129
1130
      // attach the new child nodes below the branch node
1131
      // (left or right depending on bit)
1132
0
      new_child1->parent = branch_node;
1133
0
      new_child2->parent = branch_node;
1134
0
      if (new_child1->node.first.getBit(-1 - bits)) {
1135
0
        branch_node->right = std::move(new_child1);
1136
0
        branch_node->left = std::move(new_child2);
1137
0
      }
1138
0
      else {
1139
0
        branch_node->right = std::move(new_child2);
1140
0
        branch_node->left = std::move(new_child1);
1141
0
      }
1142
      // now we have attached the new unique pointers to the tree:
1143
      // - branch_node is below its parent
1144
      // - new_child1 (ourselves) is below branch_node
1145
      // - new_child2, the new leaf node, is below branch_node as well
1146
1147
0
      return new_node;
1148
0
    }
1149
1150
    //<! Traverse left branch depth-first
1151
    TreeNode* traverse_l()
1152
0
    {
1153
0
      TreeNode* tnode = this;
1154
1155
0
      while (tnode->left) {
1156
0
        tnode = tnode->left.get();
1157
0
      }
1158
0
      return tnode;
1159
0
    }
1160
1161
    //<! Traverse tree depth-first and in-order (L-N-R)
1162
    TreeNode* traverse_lnr()
1163
0
    {
1164
0
      TreeNode* tnode = this;
1165
1166
      // precondition: descended left as deep as possible
1167
0
      if (tnode->right) {
1168
        // descend right
1169
0
        tnode = tnode->right.get();
1170
        // descend left as deep as possible and return next node
1171
0
        return tnode->traverse_l();
1172
0
      }
1173
1174
      // ascend to parent
1175
0
      while (tnode->parent != nullptr) {
1176
0
        TreeNode* prev_child = tnode;
1177
0
        tnode = tnode->parent;
1178
1179
        // return this node, but only when we come from the left child branch
1180
0
        if (tnode->left && tnode->left.get() == prev_child) {
1181
0
          return tnode;
1182
0
        }
1183
0
      }
1184
0
      return nullptr;
1185
0
    }
1186
1187
    //<! Traverse only assigned nodes
1188
    TreeNode* traverse_lnr_assigned()
1189
0
    {
1190
0
      TreeNode* tnode = traverse_lnr();
1191
1192
0
      while (tnode != nullptr && !tnode->assigned) {
1193
0
        tnode = tnode->traverse_lnr();
1194
0
      }
1195
0
      return tnode;
1196
0
    }
1197
1198
    unique_ptr<TreeNode> left;
1199
    unique_ptr<TreeNode> right;
1200
    TreeNode* parent;
1201
1202
    node_type node;
1203
    bool assigned; //<! Whether this node is assigned-to by the application
1204
1205
    int d_bits; //<! How many bits have been used so far
1206
  };
1207
1208
  void cleanup_tree(TreeNode* node)
1209
0
  {
1210
    // only cleanup this node if it has no children and node not assigned
1211
0
    if (!(node->left || node->right || node->assigned)) {
1212
      // get parent node ptr
1213
0
      TreeNode* pparent = node->parent;
1214
      // delete this node
1215
0
      if (pparent) {
1216
0
        if (pparent->left.get() == node) {
1217
0
          pparent->left.reset();
1218
0
        }
1219
0
        else {
1220
0
          pparent->right.reset();
1221
0
        }
1222
        // now recurse up to the parent
1223
0
        cleanup_tree(pparent);
1224
0
      }
1225
0
    }
1226
0
  }
1227
1228
  void copyTree(const NetmaskTree& rhs)
1229
0
  {
1230
0
    try {
1231
0
      TreeNode* node = rhs.d_root.get();
1232
0
      if (node != nullptr) {
1233
0
        node = node->traverse_l();
1234
0
      }
1235
0
      while (node != nullptr) {
1236
0
        if (node->assigned) {
1237
0
          insert(node->node.first).second = node->node.second;
1238
0
        }
1239
0
        node = node->traverse_lnr();
1240
0
      }
1241
0
    }
1242
0
    catch (const NetmaskException&) {
1243
0
      abort();
1244
0
    }
1245
0
    catch (const std::logic_error&) {
1246
0
      abort();
1247
0
    }
1248
0
  }
1249
1250
public:
1251
  class Iterator
1252
  {
1253
  public:
1254
    using value_type = node_type;
1255
    using reference = node_type&;
1256
    using pointer = node_type*;
1257
    using iterator_category = std::forward_iterator_tag;
1258
    using difference_type = size_type;
1259
1260
  private:
1261
    friend class NetmaskTree;
1262
1263
    const NetmaskTree* d_tree;
1264
    TreeNode* d_node;
1265
1266
    Iterator(const NetmaskTree* tree, TreeNode* node) :
1267
0
      d_tree(tree), d_node(node)
1268
0
    {
1269
0
    }
1270
1271
  public:
1272
    Iterator() :
1273
0
      d_tree(nullptr), d_node(nullptr) {}
1274
1275
    Iterator& operator++() // prefix
1276
0
    {
1277
0
      if (d_node == nullptr) {
1278
0
        throw std::logic_error(
1279
0
          "NetmaskTree::Iterator::operator++: iterator is invalid");
1280
0
      }
1281
0
      d_node = d_node->traverse_lnr_assigned();
1282
0
      return *this;
1283
0
    }
1284
    Iterator operator++(int) // postfix
1285
0
    {
1286
0
      Iterator tmp(*this);
1287
0
      operator++();
1288
0
      return tmp;
1289
0
    }
1290
1291
    reference operator*()
1292
0
    {
1293
0
      if (d_node == nullptr) {
1294
0
        throw std::logic_error(
1295
0
          "NetmaskTree::Iterator::operator*: iterator is invalid");
1296
0
      }
1297
0
      return d_node->node;
1298
0
    }
1299
1300
    pointer operator->()
1301
0
    {
1302
0
      if (d_node == nullptr) {
1303
0
        throw std::logic_error(
1304
0
          "NetmaskTree::Iterator::operator->: iterator is invalid");
1305
0
      }
1306
0
      return &d_node->node;
1307
0
    }
1308
1309
    bool operator==(const Iterator& rhs) const
1310
0
    {
1311
0
      return (d_tree == rhs.d_tree && d_node == rhs.d_node);
1312
0
    }
1313
    bool operator!=(const Iterator& rhs) const
1314
0
    {
1315
0
      return !(*this == rhs);
1316
0
    }
1317
  };
1318
1319
  NetmaskTree() noexcept :
1320
0
    d_root(new TreeNode()), d_left(nullptr)
1321
0
  {
1322
0
  }
1323
1324
  NetmaskTree(const NetmaskTree& rhs) :
1325
0
    d_root(new TreeNode()), d_left(nullptr)
1326
0
  {
1327
0
    copyTree(rhs);
1328
0
  }
1329
1330
0
  ~NetmaskTree() = default;
1331
1332
  NetmaskTree& operator=(const NetmaskTree& rhs)
1333
0
  {
1334
0
    if (this != &rhs) {
1335
0
      clear();
1336
0
      copyTree(rhs);
1337
0
    }
1338
0
    return *this;
1339
0
  }
1340
1341
0
  NetmaskTree(NetmaskTree&&) noexcept = default;
1342
  NetmaskTree& operator=(NetmaskTree&&) noexcept = default;
1343
1344
  [[nodiscard]] iterator begin() const
1345
0
  {
1346
0
    return Iterator(this, d_left);
1347
0
  }
1348
  [[nodiscard]] iterator end() const
1349
0
  {
1350
0
    return Iterator(this, nullptr);
1351
0
  }
1352
  iterator begin()
1353
0
  {
1354
0
    return Iterator(this, d_left);
1355
0
  }
1356
  iterator end()
1357
0
  {
1358
0
    return Iterator(this, nullptr);
1359
0
  }
1360
1361
  node_type& insert(const string& mask)
1362
0
  {
1363
0
    return insert(key_type(mask));
1364
0
  }
1365
1366
  //<! Creates new value-pair in tree and returns it.
1367
  node_type& insert(const key_type& key)
1368
0
  {
1369
0
    TreeNode* node{};
1370
0
    bool is_left = true;
1371
1372
    // we turn left on IPv4 and right on IPv6
1373
0
    if (key.isIPv4()) {
1374
0
      node = d_root->left.get();
1375
0
      if (node == nullptr) {
1376
1377
0
        d_root->left = make_unique<TreeNode>(key);
1378
0
        node = d_root->left.get();
1379
0
        node->assigned = true;
1380
0
        node->parent = d_root.get();
1381
0
        d_size++;
1382
0
        d_left = node;
1383
0
        return node->node;
1384
0
      }
1385
0
    }
1386
0
    else if (key.isIPv6()) {
1387
0
      node = d_root->right.get();
1388
0
      if (node == nullptr) {
1389
1390
0
        d_root->right = make_unique<TreeNode>(key);
1391
0
        node = d_root->right.get();
1392
0
        node->assigned = true;
1393
0
        node->parent = d_root.get();
1394
0
        d_size++;
1395
0
        if (!d_root->left) {
1396
0
          d_left = node;
1397
0
        }
1398
0
        return node->node;
1399
0
      }
1400
0
      if (d_root->left) {
1401
0
        is_left = false;
1402
0
      }
1403
0
    }
1404
0
    else {
1405
0
      throw NetmaskException("invalid address family");
1406
0
    }
1407
1408
    // we turn left on 0 and right on 1
1409
0
    int bits = 0;
1410
0
    for (; bits < key.getBits(); bits++) {
1411
0
      bool vall = key.getBit(-1 - bits);
1412
1413
0
      if (bits >= node->d_bits) {
1414
        // the end of the current node is reached; continue with the next
1415
0
        if (vall) {
1416
0
          if (node->left || node->assigned) {
1417
0
            is_left = false;
1418
0
          }
1419
0
          if (!node->right) {
1420
            // the right branch doesn't exist yet; attach our key here
1421
0
            node = node->make_right(key);
1422
0
            break;
1423
0
          }
1424
0
          node = node->right.get();
1425
0
        }
1426
0
        else {
1427
0
          if (!node->left) {
1428
            // the left branch doesn't exist yet; attach our key here
1429
0
            node = node->make_left(key);
1430
0
            break;
1431
0
          }
1432
0
          node = node->left.get();
1433
0
        }
1434
0
        continue;
1435
0
      }
1436
0
      if (bits >= node->node.first.getBits()) {
1437
        // the matching branch ends here, yet the key netmask has more bits; add a
1438
        // child node below the existing branch leaf.
1439
0
        if (vall) {
1440
0
          if (node->assigned) {
1441
0
            is_left = false;
1442
0
          }
1443
0
          node = node->make_right(key);
1444
0
        }
1445
0
        else {
1446
0
          node = node->make_left(key);
1447
0
        }
1448
0
        break;
1449
0
      }
1450
0
      bool valr = node->node.first.getBit(-1 - bits);
1451
0
      if (vall != valr) {
1452
0
        if (vall) {
1453
0
          is_left = false;
1454
0
        }
1455
        // the branch matches just upto this point, yet continues in a different
1456
        // direction; fork the branch.
1457
0
        node = node->fork(key, bits);
1458
0
        break;
1459
0
      }
1460
0
    }
1461
1462
0
    if (node->node.first.getBits() > key.getBits()) {
1463
      // key is a super-network of the matching node; split the branch and
1464
      // insert a node for the key above the matching node.
1465
0
      node = node->split(key, key.getBits());
1466
0
    }
1467
1468
0
    if (node->left) {
1469
0
      is_left = false;
1470
0
    }
1471
1472
0
    node_type& value = node->node;
1473
1474
0
    if (!node->assigned) {
1475
      // only increment size if not assigned before
1476
0
      d_size++;
1477
      // update the pointer to the left-most tree node
1478
0
      if (is_left) {
1479
0
        d_left = node;
1480
0
      }
1481
0
      node->assigned = true;
1482
0
    }
1483
0
    else {
1484
      // tree node exists for this value
1485
0
      if (is_left && d_left != node) {
1486
0
        throw std::logic_error(
1487
0
          "NetmaskTree::insert(): lost track of left-most node in tree");
1488
0
      }
1489
0
    }
1490
1491
0
    return value;
1492
0
  }
1493
1494
  //<! Creates or updates value
1495
  void insert_or_assign(const key_type& mask, const value_type& value)
1496
0
  {
1497
0
    insert(mask).second = value;
1498
0
  }
1499
1500
  void insert_or_assign(const string& mask, const value_type& value)
1501
0
  {
1502
0
    insert(key_type(mask)).second = value;
1503
0
  }
1504
1505
  //<! check if given key is present in TreeMap
1506
  [[nodiscard]] bool has_key(const key_type& key) const
1507
0
  {
1508
0
    const node_type* ptr = lookup(key);
1509
0
    return ptr && ptr->first == key;
1510
0
  }
1511
1512
  //<! Returns "best match" for key_type, which might not be value
1513
  [[nodiscard]] node_type* lookup(const key_type& value) const
1514
0
  {
1515
0
    if (empty()) {
1516
0
      return nullptr;
1517
0
    }
1518
0
    uint8_t max_bits = value.getBits();
1519
0
    return lookupImpl(value, max_bits);
1520
0
  }
1521
1522
  //<! Perform best match lookup for value, using at most max_bits
1523
  [[nodiscard]] node_type* lookup(const ComboAddress& value, int max_bits = 128) const
1524
0
  {
1525
0
    if (empty()) {
1526
0
      return nullptr;
1527
0
    }
1528
0
    uint8_t addr_bits = value.getBits();
1529
0
    if (max_bits < 0 || max_bits > addr_bits) {
1530
0
      max_bits = addr_bits;
1531
0
    }
1532
1533
0
    return lookupImpl(key_type(value, max_bits), max_bits);
1534
0
  }
1535
1536
  //<! Removes key from TreeMap.
1537
  void erase(const key_type& key)
1538
0
  {
1539
0
    TreeNode* node = nullptr;
1540
1541
0
    if (key.isIPv4()) {
1542
0
      node = d_root->left.get();
1543
0
    }
1544
0
    else if (key.isIPv6()) {
1545
0
      node = d_root->right.get();
1546
0
    }
1547
0
    else {
1548
0
      throw NetmaskException("invalid address family");
1549
0
    }
1550
    // no tree, no value
1551
0
    if (node == nullptr) {
1552
0
      return;
1553
0
    }
1554
0
    int bits = 0;
1555
0
    for (; node && bits < key.getBits(); bits++) {
1556
0
      bool vall = key.getBit(-1 - bits);
1557
0
      if (bits >= node->d_bits) {
1558
        // the end of the current node is reached; continue with the next
1559
0
        if (vall) {
1560
0
          node = node->right.get();
1561
0
        }
1562
0
        else {
1563
0
          node = node->left.get();
1564
0
        }
1565
0
        continue;
1566
0
      }
1567
0
      if (bits >= node->node.first.getBits()) {
1568
        // the matching branch ends here
1569
0
        if (key.getBits() != node->node.first.getBits()) {
1570
0
          node = nullptr;
1571
0
        }
1572
0
        break;
1573
0
      }
1574
0
      bool valr = node->node.first.getBit(-1 - bits);
1575
0
      if (vall != valr) {
1576
        // the branch matches just upto this point, yet continues in a different
1577
        // direction
1578
0
        node = nullptr;
1579
0
        break;
1580
0
      }
1581
0
    }
1582
0
    if (node) {
1583
0
      if (d_size == 0) {
1584
0
        throw std::logic_error(
1585
0
          "NetmaskTree::erase(): size of tree is zero before erase");
1586
0
      }
1587
0
      d_size--;
1588
0
      node->assigned = false;
1589
0
      node->node.second = value_type();
1590
1591
0
      if (node == d_left) {
1592
0
        d_left = d_left->traverse_lnr_assigned();
1593
0
      }
1594
0
      cleanup_tree(node);
1595
0
    }
1596
0
  }
1597
1598
  void erase(const string& key)
1599
0
  {
1600
0
    erase(key_type(key));
1601
0
  }
1602
1603
  //<! checks whether the container is empty.
1604
  [[nodiscard]] bool empty() const
1605
0
  {
1606
0
    return (d_size == 0);
1607
0
  }
1608
1609
  //<! returns the number of elements
1610
  [[nodiscard]] size_type size() const
1611
0
  {
1612
0
    return d_size;
1613
0
  }
1614
1615
  //<! See if given ComboAddress matches any prefix
1616
  [[nodiscard]] bool match(const ComboAddress& value) const
1617
0
  {
1618
0
    return (lookup(value) != nullptr);
1619
0
  }
1620
1621
  [[nodiscard]] bool match(const std::string& value) const
1622
0
  {
1623
0
    return match(ComboAddress(value));
1624
0
  }
1625
1626
  //<! Clean out the tree
1627
  void clear()
1628
0
  {
1629
0
    d_root = make_unique<TreeNode>();
1630
0
    d_left = nullptr;
1631
0
    d_size = 0;
1632
0
  }
1633
1634
  //<! swaps the contents with another NetmaskTree
1635
  void swap(NetmaskTree& rhs) noexcept
1636
0
  {
1637
0
    std::swap(d_root, rhs.d_root);
1638
0
    std::swap(d_left, rhs.d_left);
1639
0
    std::swap(d_size, rhs.d_size);
1640
0
  }
1641
1642
private:
1643
  [[nodiscard]] node_type* lookupImpl(const key_type& value, uint8_t max_bits) const
1644
0
  {
1645
0
    TreeNode* node = nullptr;
1646
1647
0
    if (value.isIPv4()) {
1648
0
      node = d_root->left.get();
1649
0
    }
1650
0
    else if (value.isIPv6()) {
1651
0
      node = d_root->right.get();
1652
0
    }
1653
0
    else {
1654
0
      throw NetmaskException("invalid address family");
1655
0
    }
1656
0
    if (node == nullptr) {
1657
0
      return nullptr;
1658
0
    }
1659
1660
0
    node_type* ret = nullptr;
1661
1662
0
    int bits = 0;
1663
0
    for (; bits < max_bits; bits++) {
1664
0
      bool vall = value.getBit(-1 - bits);
1665
0
      if (bits >= node->d_bits) {
1666
        // the end of the current node is reached; continue with the next
1667
        // (we keep track of last assigned node)
1668
0
        if (node->assigned && bits == node->node.first.getBits()) {
1669
0
          ret = &node->node;
1670
0
        }
1671
0
        if (vall) {
1672
0
          if (!node->right) {
1673
0
            break;
1674
0
          }
1675
0
          node = node->right.get();
1676
0
        }
1677
0
        else {
1678
0
          if (!node->left) {
1679
0
            break;
1680
0
          }
1681
0
          node = node->left.get();
1682
0
        }
1683
0
        continue;
1684
0
      }
1685
0
      if (bits >= node->node.first.getBits()) {
1686
        // the matching branch ends here
1687
0
        break;
1688
0
      }
1689
0
      bool valr = node->node.first.getBit(-1 - bits);
1690
0
      if (vall != valr) {
1691
        // the branch matches just upto this point, yet continues in a different
1692
        // direction
1693
0
        break;
1694
0
      }
1695
0
    }
1696
    // needed if we did not find one in loop
1697
0
    if (node->assigned && bits == node->node.first.getBits()) {
1698
0
      ret = &node->node;
1699
0
    }
1700
    // this can be nullptr.
1701
0
    return ret;
1702
0
  }
1703
1704
  unique_ptr<TreeNode> d_root; //<! Root of our tree
1705
  TreeNode* d_left;
1706
  size_type d_size{0};
1707
};
1708
1709
/** This class represents a group of supplemental Netmask classes. An IP address matches
1710
    if it is matched by one or more of the Netmask objects within.
1711
*/
1712
class NetmaskGroup
1713
{
1714
public:
1715
0
  NetmaskGroup() noexcept = default;
1716
1717
  //! If this IP address is matched by any of the classes within
1718
1719
  bool match(const ComboAddress* address) const
1720
0
  {
1721
0
    const auto& ret = tree.lookup(*address);
1722
0
    if (ret != nullptr) {
1723
0
      return ret->second;
1724
0
    }
1725
0
    return false;
1726
0
  }
1727
1728
  [[nodiscard]] bool match(const ComboAddress& address) const
1729
0
  {
1730
0
    return match(&address);
1731
0
  }
1732
1733
  bool lookup(const ComboAddress* address, Netmask* nmp) const
1734
0
  {
1735
0
    const auto& ret = tree.lookup(*address);
1736
0
    if (ret != nullptr) {
1737
0
      if (nmp != nullptr) {
1738
0
        *nmp = ret->first;
1739
0
      }
1740
0
      return ret->second;
1741
0
    }
1742
0
    return false;
1743
0
  }
1744
1745
  bool lookup(const ComboAddress& address, Netmask* nmp) const
1746
0
  {
1747
0
    return lookup(&address, nmp);
1748
0
  }
1749
1750
  //! Add this string to the list of possible matches
1751
  void addMask(const string& address, bool positive = true)
1752
0
  {
1753
0
    if (!address.empty() && address[0] == '!') {
1754
0
      addMask(Netmask(address.substr(1)), false);
1755
0
    }
1756
0
    else {
1757
0
      addMask(Netmask(address), positive);
1758
0
    }
1759
0
  }
1760
1761
  //! Add this Netmask to the list of possible matches
1762
  void addMask(const Netmask& netmask, bool positive = true)
1763
0
  {
1764
0
    tree.insert(netmask).second = positive;
1765
0
  }
1766
1767
  void addMasks(const NetmaskGroup& group, std::optional<bool> positive)
1768
0
  {
1769
0
    for (const auto& entry : group.tree) {
1770
0
      addMask(entry.first, positive ? *positive : entry.second);
1771
0
    }
1772
0
  }
1773
1774
  //! Delete this Netmask from the list of possible matches
1775
  void deleteMask(const Netmask& netmask)
1776
0
  {
1777
0
    tree.erase(netmask);
1778
0
  }
1779
1780
  void deleteMasks(const NetmaskGroup& group)
1781
0
  {
1782
0
    for (const auto& entry : group.tree) {
1783
0
      deleteMask(entry.first);
1784
0
    }
1785
0
  }
1786
1787
  void deleteMask(const std::string& address)
1788
0
  {
1789
0
    if (!address.empty()) {
1790
0
      deleteMask(Netmask(address));
1791
0
    }
1792
0
  }
1793
1794
  void clear()
1795
0
  {
1796
0
    tree.clear();
1797
0
  }
1798
1799
  [[nodiscard]] bool empty() const
1800
0
  {
1801
0
    return tree.empty();
1802
0
  }
1803
1804
  [[nodiscard]] size_t size() const
1805
0
  {
1806
0
    return tree.size();
1807
0
  }
1808
1809
  [[nodiscard]] string toString() const
1810
0
  {
1811
0
    ostringstream str;
1812
0
    for (auto iter = tree.begin(); iter != tree.end(); ++iter) {
1813
0
      if (iter != tree.begin()) {
1814
0
        str << ", ";
1815
0
      }
1816
0
      if (!(iter->second)) {
1817
0
        str << "!";
1818
0
      }
1819
0
      str << iter->first.toString();
1820
0
    }
1821
0
    return str.str();
1822
0
  }
1823
1824
  [[nodiscard]] std::vector<std::string> toStringVector() const
1825
0
  {
1826
0
    std::vector<std::string> out;
1827
0
    out.reserve(tree.size());
1828
0
    for (const auto& entry : tree) {
1829
0
      out.push_back((entry.second ? "" : "!") + entry.first.toString());
1830
0
    }
1831
0
    return out;
1832
0
  }
1833
1834
  void toMasks(const string& ips)
1835
0
  {
1836
0
    vector<string> parts;
1837
0
    stringtok(parts, ips, ", \t");
1838
0
1839
0
    for (const auto& part : parts) {
1840
0
      addMask(part);
1841
0
    }
1842
0
  }
1843
1844
private:
1845
  NetmaskTree<bool> tree;
1846
};
1847
1848
struct SComboAddress
1849
{
1850
  SComboAddress(const ComboAddress& orig) :
1851
0
    ca(orig) {}
1852
  ComboAddress ca;
1853
  bool operator<(const SComboAddress& rhs) const
1854
0
  {
1855
0
    return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
1856
0
  }
1857
  operator const ComboAddress&() const
1858
0
  {
1859
0
    return ca;
1860
0
  }
1861
};
1862
1863
class NetworkError : public runtime_error
1864
{
1865
public:
1866
  NetworkError(const string& why = "Network Error") :
1867
0
    runtime_error(why.c_str())
1868
0
  {}
1869
  NetworkError(const char* why = "Network Error") :
1870
    runtime_error(why)
1871
0
  {}
1872
};
1873
1874
class AddressAndPortRange
1875
{
1876
public:
1877
  AddressAndPortRange() :
1878
    d_addrMask(0), d_portMask(0)
1879
0
  {
1880
0
    d_addr.sin4.sin_family = 0; // disable this doing anything useful
1881
0
    d_addr.sin4.sin_port = 0; // this guarantees d_network compares identical
1882
0
  }
1883
1884
  AddressAndPortRange(ComboAddress address, uint8_t addrMask, uint8_t portMask = 0) :
1885
    d_addr(address), d_addrMask(addrMask), d_portMask(portMask)
1886
0
  {
1887
0
    if (!d_addr.isIPv4()) {
1888
0
      d_portMask = 0;
1889
0
    }
1890
0
1891
0
    uint16_t port = d_addr.getPort();
1892
0
    if (d_portMask < 16) {
1893
0
      auto mask = static_cast<uint16_t>(~(0xFFFF >> d_portMask));
1894
0
      port = port & mask;
1895
0
    }
1896
0
1897
0
    if (d_addrMask < d_addr.getBits()) {
1898
0
      if (d_portMask > 0) {
1899
0
        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) + ")");
1900
0
      }
1901
0
      d_addr = Netmask(d_addr, d_addrMask).getMaskedNetwork();
1902
0
    }
1903
0
    d_addr.setPort(port);
1904
0
  }
1905
1906
  [[nodiscard]] uint8_t getFullBits() const
1907
0
  {
1908
0
    return d_addr.getBits() + 16;
1909
0
  }
1910
1911
  [[nodiscard]] uint8_t getBits() const
1912
0
  {
1913
0
    if (d_addrMask < d_addr.getBits()) {
1914
0
      return d_addrMask;
1915
0
    }
1916
0
1917
0
    return d_addr.getBits() + d_portMask;
1918
0
  }
1919
1920
  /** Get the value of the bit at the provided bit index. When the index >= 0,
1921
      the index is relative to the LSB starting at index zero. When the index < 0,
1922
      the index is relative to the MSB starting at index -1 and counting down.
1923
  */
1924
  [[nodiscard]] bool getBit(int index) const
1925
0
  {
1926
0
    if (index >= getFullBits()) {
1927
0
      return false;
1928
0
    }
1929
0
    if (index < 0) {
1930
0
      index = getFullBits() + index;
1931
0
    }
1932
0
1933
0
    if (index < 16) {
1934
0
      /* we are into the port bits */
1935
0
      uint16_t port = d_addr.getPort();
1936
0
      return ((port & (1U << index)) != 0x0000);
1937
0
    }
1938
0
1939
0
    index -= 16;
1940
0
1941
0
    return d_addr.getBit(index);
1942
0
  }
1943
1944
  [[nodiscard]] bool isIPv4() const
1945
0
  {
1946
0
    return d_addr.isIPv4();
1947
0
  }
1948
1949
  [[nodiscard]] bool isIPv6() const
1950
0
  {
1951
0
    return d_addr.isIPv6();
1952
0
  }
1953
1954
  [[nodiscard]] AddressAndPortRange getNormalized() const
1955
0
  {
1956
0
    return {d_addr, d_addrMask, d_portMask};
1957
0
  }
1958
1959
  [[nodiscard]] AddressAndPortRange getSuper(uint8_t bits) const
1960
0
  {
1961
0
    if (bits <= d_addrMask) {
1962
0
      return {d_addr, bits, 0};
1963
0
    }
1964
0
    if (bits <= d_addrMask + d_portMask) {
1965
0
      return {d_addr, d_addrMask, static_cast<uint8_t>(d_portMask - (bits - d_addrMask))};
1966
0
    }
1967
0
1968
0
    return {d_addr, d_addrMask, d_portMask};
1969
0
  }
1970
1971
  [[nodiscard]] const ComboAddress& getNetwork() const
1972
0
  {
1973
0
    return d_addr;
1974
0
  }
1975
1976
  [[nodiscard]] string toString() const
1977
0
  {
1978
0
    if (d_addrMask < d_addr.getBits() || d_portMask == 0) {
1979
0
      return d_addr.toStringNoInterface() + "/" + std::to_string(d_addrMask);
1980
0
    }
1981
0
    return d_addr.toStringNoInterface() + ":" + std::to_string(d_addr.getPort()) + "/" + std::to_string(d_portMask);
1982
0
  }
1983
1984
  [[nodiscard]] bool empty() const
1985
0
  {
1986
0
    return d_addr.sin4.sin_family == 0;
1987
0
  }
1988
1989
  bool operator==(const AddressAndPortRange& rhs) const
1990
0
  {
1991
0
    return std::tie(d_addr, d_addrMask, d_portMask) == std::tie(rhs.d_addr, rhs.d_addrMask, rhs.d_portMask);
1992
0
  }
1993
1994
  bool operator<(const AddressAndPortRange& rhs) const
1995
0
  {
1996
0
    if (empty() && !rhs.empty()) {
1997
0
      return false;
1998
0
    }
1999
0
2000
0
    if (!empty() && rhs.empty()) {
2001
0
      return true;
2002
0
    }
2003
0
2004
0
    if (d_addrMask > rhs.d_addrMask) {
2005
0
      return true;
2006
0
    }
2007
0
2008
0
    if (d_addrMask < rhs.d_addrMask) {
2009
0
      return false;
2010
0
    }
2011
0
2012
0
    if (d_addr < rhs.d_addr) {
2013
0
      return true;
2014
0
    }
2015
0
2016
0
    if (d_addr > rhs.d_addr) {
2017
0
      return false;
2018
0
    }
2019
0
2020
0
    if (d_portMask > rhs.d_portMask) {
2021
0
      return true;
2022
0
    }
2023
0
2024
0
    if (d_portMask < rhs.d_portMask) {
2025
0
      return false;
2026
0
    }
2027
0
2028
0
    return d_addr.getPort() < rhs.d_addr.getPort();
2029
0
  }
2030
2031
  bool operator>(const AddressAndPortRange& rhs) const
2032
0
  {
2033
0
    return rhs.operator<(*this);
2034
0
  }
2035
2036
  struct hash
2037
  {
2038
    uint32_t operator()(const AddressAndPortRange& apr) const
2039
0
    {
2040
0
      ComboAddress::addressOnlyHash hashOp;
2041
0
      uint16_t port = apr.d_addr.getPort();
2042
0
      /* it's fine to hash the whole address and port because the non-relevant parts have
2043
0
         been masked to 0 */
2044
0
      return burtle(reinterpret_cast<const unsigned char*>(&port), sizeof(port), hashOp(apr.d_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
2045
0
    }
2046
  };
2047
2048
private:
2049
  ComboAddress d_addr;
2050
  uint8_t d_addrMask;
2051
  /* only used for v4 addresses */
2052
  uint8_t d_portMask;
2053
};
2054
2055
int SSocket(int family, int type, int flags);
2056
int SConnect(int sockfd, bool fastopen, const ComboAddress& remote);
2057
/* tries to connect to remote for a maximum of timeout seconds.
2058
   sockfd should be set to non-blocking beforehand.
2059
   returns 0 on success (the socket is writable), throw a
2060
   runtime_error otherwise */
2061
int SConnectWithTimeout(int sockfd, bool fastopen, const ComboAddress& remote, const struct timeval& timeout);
2062
int SBind(int sockfd, const ComboAddress& local);
2063
int SAccept(int sockfd, ComboAddress& remote);
2064
int SListen(int sockfd, int limit);
2065
int SSetsockopt(int sockfd, int level, int opname, int value);
2066
void setSocketIgnorePMTU(int sockfd, int family);
2067
void setSocketForcePMTU(int sockfd, int family);
2068
bool setReusePort(int sockfd);
2069
2070
#if defined(IP_PKTINFO)
2071
#define GEN_IP_PKTINFO IP_PKTINFO
2072
#elif defined(IP_RECVDSTADDR)
2073
#define GEN_IP_PKTINFO IP_RECVDSTADDR
2074
#endif
2075
2076
bool IsAnyAddress(const ComboAddress& addr);
2077
bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination);
2078
bool HarvestTimestamp(struct msghdr* msgh, struct timeval* timeval);
2079
void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
2080
int sendOnNBSocket(int fileDesc, const struct msghdr* msgh);
2081
[[nodiscard]] pdns::expected<size_t, int> sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
2082
2083
/* requires a non-blocking, connected TCP socket */
2084
bool isTCPSocketUsable(int sock);
2085
2086
extern template class NetmaskTree<bool>;
2087
ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
2088
2089
std::set<std::string> getListOfNetworkInterfaces();
2090
std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& itf);
2091
std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf);
2092
2093
/* These functions throw if the value was already set to a higher value,
2094
   or on error */
2095
void setSocketBuffer(int fileDesc, int optname, uint32_t size);
2096
void setSocketReceiveBuffer(int fileDesc, uint32_t size);
2097
void setSocketSendBuffer(int fileDesc, uint32_t size);
2098
uint32_t raiseSocketReceiveBufferToMax(int socket);
2099
uint32_t raiseSocketSendBufferToMax(int socket);