Coverage Report

Created: 2025-08-05 06:59

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