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