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