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