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