2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
30 #include "pdnsexception.hh"
36 #include "namespaces.hh"
39 #include <libkern/OSByteOrder.h>
41 #define htobe16(x) OSSwapHostToBigInt16(x)
42 #define htole16(x) OSSwapHostToLittleInt16(x)
43 #define be16toh(x) OSSwapBigToHostInt16(x)
44 #define le16toh(x) OSSwapLittleToHostInt16(x)
46 #define htobe32(x) OSSwapHostToBigInt32(x)
47 #define htole32(x) OSSwapHostToLittleInt32(x)
48 #define be32toh(x) OSSwapBigToHostInt32(x)
49 #define le32toh(x) OSSwapLittleToHostInt32(x)
51 #define htobe64(x) OSSwapHostToBigInt64(x)
52 #define htole64(x) OSSwapHostToLittleInt64(x)
53 #define be64toh(x) OSSwapBigToHostInt64(x)
54 #define le64toh(x) OSSwapLittleToHostInt64(x)
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))
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))
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))
77 #include <sys/endian.h>
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.
91 bool operator==(const ComboAddress& rhs) const
93 if (std::tie(sin4.sin_family, sin4.sin_port) != std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
96 if (sin4.sin_family == AF_INET) {
97 return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
99 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) == 0;
102 bool operator!=(const ComboAddress& rhs) const
104 return (!operator==(rhs));
107 bool operator<(const ComboAddress& rhs) const
109 if (sin4.sin_family == 0) {
112 if (std::tie(sin4.sin_family, sin4.sin_port) < std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
115 if (std::tie(sin4.sin_family, sin4.sin_port) > std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) {
118 if (sin4.sin_family == AF_INET) {
119 return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
121 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0;
124 bool operator>(const ComboAddress& rhs) const
126 return rhs.operator<(*this);
129 struct addressPortOnlyHash
131 uint32_t operator()(const ComboAddress& address) const
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);
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)
146 struct addressOnlyHash
148 uint32_t operator()(const ComboAddress& address) const
150 const unsigned char* start = nullptr;
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);
158 start = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
161 // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
162 return burtle(start, len, 0);
166 struct addressOnlyLessThan
168 bool operator()(const ComboAddress& lhs, const ComboAddress& rhs) const
170 if (lhs.sin4.sin_family < rhs.sin4.sin_family) {
173 if (lhs.sin4.sin_family > rhs.sin4.sin_family) {
176 if (lhs.sin4.sin_family == AF_INET) {
177 return lhs.sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
179 return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) < 0;
183 struct addressOnlyEqual
185 bool operator()(const ComboAddress& lhs, const ComboAddress& rhs) const
187 if (lhs.sin4.sin_family != rhs.sin4.sin_family) {
190 if (lhs.sin4.sin_family == AF_INET) {
191 return lhs.sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
193 return memcmp(&lhs.sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(lhs.sin6.sin6_addr.s6_addr)) == 0;
197 [[nodiscard]] socklen_t getSocklen() const
199 if (sin4.sin_family == AF_INET) {
207 sin4.sin_family = AF_INET;
208 sin4.sin_addr.s_addr = 0;
210 sin6.sin6_scope_id = 0;
211 sin6.sin6_flowinfo = 0;
214 ComboAddress(const struct sockaddr* socketAddress, socklen_t salen)
216 setSockaddr(socketAddress, salen);
219 ComboAddress(const struct sockaddr_in6* socketAddress)
221 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
222 setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in6));
225 ComboAddress(const struct sockaddr_in* socketAddress)
227 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
228 setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in));
231 void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen)
233 if (salen > sizeof(struct sockaddr_in6)) {
234 throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
236 memcpy(this, socketAddress, salen);
239 // 'port' sets a default value in case 'str' does not set a port
240 explicit ComboAddress(const string& str, uint16_t port = 0)
242 memset(&sin6, 0, sizeof(sin6));
243 sin4.sin_family = AF_INET;
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 + "'");
251 if (sin4.sin_port == 0) { // 'str' overrides port!
252 sin4.sin_port = htons(port);
256 [[nodiscard]] bool isIPv6() const
258 return sin4.sin_family == AF_INET6;
260 [[nodiscard]] bool isIPv4() const
262 return sin4.sin_family == AF_INET;
265 [[nodiscard]] bool isMappedIPv4() const
267 if (sin4.sin_family != AF_INET6) {
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)
279 for (; iter < 12; ++iter) {
280 if (ptr[iter] != 0xff) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
287 [[nodiscard]] bool isUnspecified() const
289 const ComboAddress unspecifiedV4("0.0.0.0:0");
290 const ComboAddress unspecifiedV6("[::]:0");
291 return *this == unspecifiedV4 || *this == unspecifiedV6;
294 [[nodiscard]] ComboAddress mapToIPv4() const
296 if (!isMappedIPv4()) {
297 throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
300 ret.sin4.sin_family = AF_INET;
301 ret.sin4.sin_port = sin4.sin_port;
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));
310 [[nodiscard]] string toString() const
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);
319 return "invalid " + string(gai_strerror(retval));
324 //! Ignores any interface specifiers possibly available in the sockaddr data.
325 [[nodiscard]] string toStringNoInterface() const
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) {
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) {
343 return "invalid " + stringerror();
346 [[nodiscard]] string toStringReversed() const
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);
356 const auto* addr = &sin6.sin6_addr;
357 std::stringstream res{};
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);
370 [[nodiscard]] string toStringWithPort() const
372 if (sin4.sin_family == AF_INET) {
373 return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
375 return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
378 [[nodiscard]] string toStringWithPortExcept(int port) const
380 if (ntohs(sin4.sin_port) == port) {
383 if (sin4.sin_family == AF_INET) {
384 return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
386 return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
389 [[nodiscard]] string toLogString() const
391 return toStringWithPortExcept(53);
394 [[nodiscard]] string toStructuredLogString() const
396 return toStringWithPort();
399 [[nodiscard]] string toByteString() const
401 // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
403 return {reinterpret_cast<const char*>(&sin4.sin_addr.s_addr), sizeof(sin4.sin_addr.s_addr)};
405 return {reinterpret_cast<const char*>(&sin6.sin6_addr.s6_addr), sizeof(sin6.sin6_addr.s6_addr)};
406 // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
409 void truncate(unsigned int bits) noexcept;
411 [[nodiscard]] uint16_t getNetworkOrderPort() const noexcept
413 return sin4.sin_port;
415 [[nodiscard]] uint16_t getPort() const noexcept
417 return ntohs(getNetworkOrderPort());
419 void setPort(uint16_t port)
421 sin4.sin_port = htons(port);
426 memset(&sin6, 0, sizeof(sin6));
429 //! Get the total number of address bits (either 32 or 128 depending on IP version)
430 [[nodiscard]] uint8_t getBits() const
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.
444 [[nodiscard]] bool getBit(int index) const
457 uint32_t ls_addr = ntohl(sin4.sin_addr.s_addr);
459 return ((ls_addr & (1U << index)) != 0x00000000);
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;
476 return ((ls_addr[15 - byte_idx] & (1U << bit_idx)) != 0x00); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
481 /*! Returns a comma-separated string of IP addresses
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)
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)
491 for (const auto& address : container) {
493 strs.push_back(address.toStringWithPortExcept(portExcept));
496 strs.push_back(address.toString());
498 return boost::join(strs, ",");
502 union SockaddrWrapper
508 [[nodiscard]] socklen_t getSocklen() const
510 if (sin4.sin_family == AF_INET) {
513 if (sin6.sin6_family == AF_INET6) {
516 if (sinun.sun_family == AF_UNIX) {
517 return sizeof(sinun);
524 sin4.sin_family = AF_INET;
525 sin4.sin_addr.s_addr = 0;
529 SockaddrWrapper(const struct sockaddr* socketAddress, socklen_t salen)
531 setSockaddr(socketAddress, salen);
534 SockaddrWrapper(const struct sockaddr_in6* socketAddress)
536 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
537 setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in6));
540 SockaddrWrapper(const struct sockaddr_in* socketAddress)
542 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
543 setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_in));
546 SockaddrWrapper(const struct sockaddr_un* socketAddress)
548 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
549 setSockaddr(reinterpret_cast<const struct sockaddr*>(socketAddress), sizeof(struct sockaddr_un));
552 void setSockaddr(const struct sockaddr* socketAddress, socklen_t salen)
554 if (salen > sizeof(struct sockaddr_un)) {
555 throw PDNSException("ComboAddress can't handle other than sockaddr_in, sockaddr_in6 or sockaddr_un");
557 memcpy(this, socketAddress, salen);
560 explicit SockaddrWrapper(const string& str, uint16_t port = 0)
562 memset(&sinun, 0, sizeof(sinun));
563 sin4.sin_family = AF_INET;
565 if (str == "\"\"" || str == "''") {
566 throw PDNSException("Stray quotation marks in address.");
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 + "'");
578 if (sinun.sun_family != AF_UNIX && sin4.sin_port == 0) { // 'str' overrides port!
579 sin4.sin_port = htons(port);
583 [[nodiscard]] bool isIPv6() const
585 return sin4.sin_family == AF_INET6;
587 [[nodiscard]] bool isIPv4() const
589 return sin4.sin_family == AF_INET;
591 [[nodiscard]] bool isUnixSocket() const
593 return sin4.sin_family == AF_UNIX;
596 [[nodiscard]] string toString() const
598 if (sinun.sun_family == AF_UNIX) {
599 return sinun.sun_path;
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);
608 return "invalid " + string(gai_strerror(retval));
613 [[nodiscard]] string toStringWithPort() const
615 if (sinun.sun_family == AF_UNIX) {
618 if (sin4.sin_family == AF_INET) {
619 return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
621 return "[" + toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
626 memset(&sinun, 0, sizeof(sinun));
630 /** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
631 class NetmaskException : public PDNSException
634 NetmaskException(const string& arg) :
635 PDNSException(arg) {}
638 inline ComboAddress makeComboAddress(const string& str)
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");
651 inline ComboAddress makeComboAddressFromRaw(uint8_t version, const char* raw, size_t len)
653 ComboAddress address;
656 address.sin4.sin_family = AF_INET;
657 if (len != sizeof(address.sin4.sin_addr)) {
658 throw NetmaskException("invalid raw address length");
660 memcpy(&address.sin4.sin_addr, raw, sizeof(address.sin4.sin_addr));
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");
667 memcpy(&address.sin6.sin6_addr, raw, sizeof(address.sin6.sin6_addr));
670 throw NetmaskException("invalid address family");
676 inline ComboAddress makeComboAddressFromRaw(uint8_t version, const string& str)
678 return makeComboAddressFromRaw(version, str.c_str(), str.size());
681 /** This class represents a netmask and can be queried to see if a certain
682 IP address is matched by this mask */
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
692 Netmask(const ComboAddress& network, uint8_t bits = 0xff) :
695 d_network.sin4.sin_port = 0;
699 Netmask(const sockaddr_in* network, uint8_t bits = 0xff) :
702 d_network.sin4.sin_port = 0;
705 Netmask(const sockaddr_in6* network, uint8_t bits = 0xff) :
708 d_network.sin4.sin_port = 0;
711 void setBits(uint8_t value)
713 d_bits = d_network.isIPv4() ? std::min(value, static_cast<uint8_t>(32U)) : std::min(value, static_cast<uint8_t>(128U));
716 d_mask = ~(0xFFFFFFFF >> d_bits);
719 // note that d_mask is unused for IPv6
724 d_network.sin4.sin_addr.s_addr = htonl(ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
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));
732 if (bytes < sizeof(d_network.sin6.sin6_addr.s6_addr)) {
733 address[bytes] &= mask; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
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)
747 //! Constructor supplies the mask, which cannot be changed
748 Netmask(const string& mask, stringType type = humanString)
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);
755 d_network = makeComboAddressFromRaw(afi, mask.substr(1, len));
760 pair<string, string> split = splitField(mask, '/');
761 d_network = makeComboAddress(split.first);
763 if (!split.second.empty()) {
764 setBits(pdns::checked_stoi<uint8_t>(split.second));
766 else if (d_network.sin4.sin_family == AF_INET) {
775 [[nodiscard]] bool match(const ComboAddress& address) const
777 return match(&address);
780 //! If this IP address in socket address matches
781 bool match(const ComboAddress* address) const
783 if (d_network.sin4.sin_family != address->sin4.sin_family) {
786 if (d_network.sin4.sin_family == AF_INET) {
787 return match4(htonl((unsigned int)address->sin4.sin_addr.s_addr));
789 if (d_network.sin6.sin6_family == AF_INET6) {
790 uint8_t bytes = d_bits / 8;
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)
797 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
798 for (index = 0; index < bytes; ++index) {
799 if (lhs[index] != rhs[index]) {
803 // still here, now match remaining bits
804 uint8_t bits = d_bits % 8;
805 auto mask = static_cast<uint8_t>(~(0xFF >> bits));
807 return ((lhs[index]) == (rhs[index] & mask));
808 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
813 //! If this ASCII IP address matches
814 [[nodiscard]] bool match(const string& arg) const
816 ComboAddress address = makeComboAddress(arg);
817 return match(&address);
820 //! If this IP address in native format matches
821 [[nodiscard]] bool match4(uint32_t arg) const
823 return (arg & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr));
826 [[nodiscard]] string toString() const
828 return d_network.toStringNoInterface() + "/" + std::to_string((unsigned int)d_bits);
831 [[nodiscard]] string toStringNoMask() const
833 return d_network.toStringNoInterface();
836 [[nodiscard]] string toByteString() const
840 tmp << (d_network.isIPv4() ? "\x04" : "\x06")
841 << d_network.toByteString()
847 [[nodiscard]] const ComboAddress& getNetwork() const
852 [[nodiscard]] const ComboAddress& getMaskedNetwork() const
857 [[nodiscard]] uint8_t getBits() const
862 [[nodiscard]] bool isIPv6() const
864 return d_network.sin6.sin6_family == AF_INET6;
867 [[nodiscard]] bool isIPv4() const
869 return d_network.sin4.sin_family == AF_INET;
872 bool operator<(const Netmask& rhs) const
874 if (empty() && !rhs.empty()) {
877 if (!empty() && rhs.empty()) {
880 if (d_bits > rhs.d_bits) {
883 if (d_bits < rhs.d_bits) {
887 return d_network < rhs.d_network;
890 bool operator>(const Netmask& rhs) const
892 return rhs.operator<(*this);
895 bool operator==(const Netmask& rhs) const
897 return std::tie(d_network, d_bits) == std::tie(rhs.d_network, rhs.d_bits);
900 bool operator!=(const Netmask& rhs) const
902 return !operator==(rhs);
905 [[nodiscard]] bool empty() const
907 return d_network.sin4.sin_family == 0;
910 //! Get normalized version of the netmask. This means that all address bits below the network bits are zero.
911 [[nodiscard]] Netmask getNormalized() const
913 return {getMaskedNetwork(), d_bits};
915 //! Get Netmask for super network of this one (i.e. with fewer network bits)
916 [[nodiscard]] Netmask getSuper(uint8_t bits) const
918 return {d_network, std::min(d_bits, bits)};
921 //! Get the total number of address bits for this netmask (either 32 or 128 depending on IP version)
922 [[nodiscard]] uint8_t getFullBits() const
924 return d_network.getBits();
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.
932 [[nodiscard]] bool getBit(int bit) const
939 if (bit >= 32 || bit < (32 - d_bits)) {
944 if (bit >= 128 || bit < (128 - d_bits)) {
949 return d_network.getBit(bit);
954 size_t operator()(const Netmask& netmask) const
956 return burtle(&netmask.d_bits, 1, ComboAddress::addressOnlyHash()(netmask.d_network));
961 ComboAddress d_network;
971 auto operator()(const Netmask& netmask) const
973 return Netmask::Hash{}(netmask);
978 /** Binary tree map implementation with <Netmask,T> pair.
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.
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.
987 * You can store IPv4 and IPv6 addresses to same tree, separate payload storage is kept per AFI.
988 * Network prefixes (Netmasks) are always recorded in normalized fashion, meaning that only
989 * the network bits are set. This is what is returned in the insert() and lookup() return
992 * Use swap if you need to move the tree to another NetmaskTree instance, it is WAY faster
993 * than using copy ctor or assignment operator, since it moves the nodes and tree root to
994 * new home instead of actually recreating the tree.
996 * Please see NetmaskGroup for example of simple use case. Other usecases can be found
997 * from GeoIPBackend and Sortlist, and from dnsdist.
999 template <typename T, class K = Netmask>
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;
1012 /** Single node in tree, internal use only.
1014 class TreeNode : boost::noncopyable
1017 explicit TreeNode() noexcept :
1018 parent(nullptr), node(), assigned(false), d_bits(0)
1021 explicit TreeNode(const key_type& key) :
1022 parent(nullptr), node({key.getNormalized(), value_type()}), assigned(false), d_bits(key.getFullBits())
1026 //<! Makes a left leaf node with specified key.
1027 TreeNode* make_left(const key_type& key)
1029 d_bits = node.first.getBits();
1030 left = make_unique<TreeNode>(key);
1031 left->parent = this;
1035 //<! Makes a right leaf node with specified key.
1036 TreeNode* make_right(const key_type& key)
1038 d_bits = node.first.getBits();
1039 right = make_unique<TreeNode>(key);
1040 right->parent = this;
1044 //<! Splits branch at indicated bit position by inserting key
1045 TreeNode* split(const key_type& key, int bits)
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");
1053 // determine reference from parent
1054 unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
1055 if (parent_ref.get() != this) {
1056 throw std::logic_error(
1057 "NetmaskTree::TreeNode::split(): parent node reference is invalid");
1060 // create new tree node for the new key and
1061 // attach the new node under our former parent
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();
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);
1075 // attach "this" node below the new node
1076 // (left or right depending on bit)
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
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);
1086 new_intermediate_node_raw->left = std::move(current_node);
1089 return new_intermediate_node_raw;
1092 //<! Forks branch for new key at indicated bit position
1093 TreeNode* fork(const key_type& key, int bits)
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");
1101 // determine reference from parent
1102 unique_ptr<TreeNode>& parent_ref = (parent->left.get() == this ? parent->left : parent->right);
1103 if (parent_ref.get() != this) {
1104 throw std::logic_error(
1105 "NetmaskTree::TreeNode::fork(): parent node reference is invalid");
1108 // create new tree node for the branch point
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);
1113 // attach the branch node under our former parent
1114 parent_ref = make_unique<TreeNode>(node.first.getSuper(bits));
1115 auto* branch_node = parent_ref.get();
1116 branch_node->d_bits = bits;
1117 branch_node->parent = parent;
1119 // create second new leaf node for the new key
1120 unique_ptr<TreeNode> new_child2 = make_unique<TreeNode>(key);
1121 TreeNode* new_node = new_child2.get();
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;
1127 if (new_child1->node.first.getBit(-1 - bits)) {
1128 branch_node->right = std::move(new_child1);
1129 branch_node->left = std::move(new_child2);
1132 branch_node->right = std::move(new_child2);
1133 branch_node->left = std::move(new_child1);
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
1143 //<! Traverse left branch depth-first
1144 TreeNode* traverse_l()
1146 TreeNode* tnode = this;
1148 while (tnode->left) {
1149 tnode = tnode->left.get();
1154 //<! Traverse tree depth-first and in-order (L-N-R)
1155 TreeNode* traverse_lnr()
1157 TreeNode* tnode = this;
1159 // precondition: descended left as deep as possible
1162 tnode = tnode->right.get();
1163 // descend left as deep as possible and return next node
1164 return tnode->traverse_l();
1168 while (tnode->parent != nullptr) {
1169 TreeNode* prev_child = tnode;
1170 tnode = tnode->parent;
1172 // return this node, but only when we come from the left child branch
1173 if (tnode->left && tnode->left.get() == prev_child) {
1180 //<! Traverse only assigned nodes
1181 TreeNode* traverse_lnr_assigned()
1183 TreeNode* tnode = traverse_lnr();
1185 while (tnode != nullptr && !tnode->assigned) {
1186 tnode = tnode->traverse_lnr();
1191 unique_ptr<TreeNode> left;
1192 unique_ptr<TreeNode> right;
1196 bool assigned; //<! Whether this node is assigned-to by the application
1198 int d_bits; //<! How many bits have been used so far
1201 void cleanup_tree(TreeNode* node)
1203 // only cleanup this node if it has no children and node not assigned
1204 if (!(node->left || node->right || node->assigned)) {
1205 // get parent node ptr
1206 TreeNode* pparent = node->parent;
1209 if (pparent->left.get() == node) {
1210 pparent->left.reset();
1213 pparent->right.reset();
1215 // now recurse up to the parent
1216 cleanup_tree(pparent);
1221 void copyTree(const NetmaskTree& rhs)
1224 TreeNode* node = rhs.d_root.get();
1225 if (node != nullptr) {
1226 node = node->traverse_l();
1228 while (node != nullptr) {
1229 if (node->assigned) {
1230 insert(node->node.first).second = node->node.second;
1232 node = node->traverse_lnr();
1235 catch (const NetmaskException&) {
1238 catch (const std::logic_error&) {
1247 using value_type = node_type;
1248 using reference = node_type&;
1249 using pointer = node_type*;
1250 using iterator_category = std::forward_iterator_tag;
1251 using difference_type = size_type;
1254 friend class NetmaskTree;
1256 const NetmaskTree* d_tree;
1259 Iterator(const NetmaskTree* tree, TreeNode* node) :
1260 d_tree(tree), d_node(node)
1266 d_tree(nullptr), d_node(nullptr) {}
1268 Iterator& operator++() // prefix
1270 if (d_node == nullptr) {
1271 throw std::logic_error(
1272 "NetmaskTree::Iterator::operator++: iterator is invalid");
1274 d_node = d_node->traverse_lnr_assigned();
1277 Iterator operator++(int) // postfix
1279 Iterator tmp(*this);
1284 reference operator*()
1286 if (d_node == nullptr) {
1287 throw std::logic_error(
1288 "NetmaskTree::Iterator::operator*: iterator is invalid");
1290 return d_node->node;
1293 pointer operator->()
1295 if (d_node == nullptr) {
1296 throw std::logic_error(
1297 "NetmaskTree::Iterator::operator->: iterator is invalid");
1299 return &d_node->node;
1302 bool operator==(const Iterator& rhs)
1304 return (d_tree == rhs.d_tree && d_node == rhs.d_node);
1306 bool operator!=(const Iterator& rhs)
1308 return !(*this == rhs);
1312 NetmaskTree() noexcept :
1313 d_root(new TreeNode()), d_left(nullptr)
1317 NetmaskTree(const NetmaskTree& rhs) :
1318 d_root(new TreeNode()), d_left(nullptr)
1323 ~NetmaskTree() = default;
1325 NetmaskTree& operator=(const NetmaskTree& rhs)
1334 NetmaskTree(NetmaskTree&&) noexcept = default;
1335 NetmaskTree& operator=(NetmaskTree&&) noexcept = default;
1337 [[nodiscard]] iterator begin() const
1339 return Iterator(this, d_left);
1341 [[nodiscard]] iterator end() const
1343 return Iterator(this, nullptr);
1347 return Iterator(this, d_left);
1351 return Iterator(this, nullptr);
1354 node_type& insert(const string& mask)
1356 return insert(key_type(mask));
1359 //<! Creates new value-pair in tree and returns it.
1360 node_type& insert(const key_type& key)
1363 bool is_left = true;
1365 // we turn left on IPv4 and right on IPv6
1367 node = d_root->left.get();
1368 if (node == nullptr) {
1370 d_root->left = make_unique<TreeNode>(key);
1371 node = d_root->left.get();
1372 node->assigned = true;
1373 node->parent = d_root.get();
1379 else if (key.isIPv6()) {
1380 node = d_root->right.get();
1381 if (node == nullptr) {
1383 d_root->right = make_unique<TreeNode>(key);
1384 node = d_root->right.get();
1385 node->assigned = true;
1386 node->parent = d_root.get();
1388 if (!d_root->left) {
1398 throw NetmaskException("invalid address family");
1401 // we turn left on 0 and right on 1
1403 for (; bits < key.getBits(); bits++) {
1404 bool vall = key.getBit(-1 - bits);
1406 if (bits >= node->d_bits) {
1407 // the end of the current node is reached; continue with the next
1409 if (node->left || node->assigned) {
1413 // the right branch doesn't exist yet; attach our key here
1414 node = node->make_right(key);
1417 node = node->right.get();
1421 // the left branch doesn't exist yet; attach our key here
1422 node = node->make_left(key);
1425 node = node->left.get();
1429 if (bits >= node->node.first.getBits()) {
1430 // the matching branch ends here, yet the key netmask has more bits; add a
1431 // child node below the existing branch leaf.
1433 if (node->assigned) {
1436 node = node->make_right(key);
1439 node = node->make_left(key);
1443 bool valr = node->node.first.getBit(-1 - bits);
1448 // the branch matches just upto this point, yet continues in a different
1449 // direction; fork the branch.
1450 node = node->fork(key, bits);
1455 if (node->node.first.getBits() > key.getBits()) {
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());
1465 node_type& value = node->node;
1467 if (!node->assigned) {
1468 // only increment size if not assigned before
1470 // update the pointer to the left-most tree node
1474 node->assigned = true;
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");
1487 //<! Creates or updates value
1488 void insert_or_assign(const key_type& mask, const value_type& value)
1490 insert(mask).second = value;
1493 void insert_or_assign(const string& mask, const value_type& value)
1495 insert(key_type(mask)).second = value;
1498 //<! check if given key is present in TreeMap
1499 [[nodiscard]] bool has_key(const key_type& key) const
1501 const node_type* ptr = lookup(key);
1502 return ptr && ptr->first == key;
1505 //<! Returns "best match" for key_type, which might not be value
1506 [[nodiscard]] node_type* lookup(const key_type& value) const
1508 uint8_t max_bits = value.getBits();
1509 return lookupImpl(value, max_bits);
1512 //<! Perform best match lookup for value, using at most max_bits
1513 [[nodiscard]] node_type* lookup(const ComboAddress& value, int max_bits = 128) const
1515 uint8_t addr_bits = value.getBits();
1516 if (max_bits < 0 || max_bits > addr_bits) {
1517 max_bits = addr_bits;
1520 return lookupImpl(key_type(value, max_bits), max_bits);
1523 //<! Removes key from TreeMap.
1524 void erase(const key_type& key)
1526 TreeNode* node = nullptr;
1529 node = d_root->left.get();
1531 else if (key.isIPv6()) {
1532 node = d_root->right.get();
1535 throw NetmaskException("invalid address family");
1537 // no tree, no value
1538 if (node == nullptr) {
1542 for (; node && bits < key.getBits(); bits++) {
1543 bool vall = key.getBit(-1 - bits);
1544 if (bits >= node->d_bits) {
1545 // the end of the current node is reached; continue with the next
1547 node = node->right.get();
1550 node = node->left.get();
1554 if (bits >= node->node.first.getBits()) {
1555 // the matching branch ends here
1556 if (key.getBits() != node->node.first.getBits()) {
1561 bool valr = node->node.first.getBit(-1 - bits);
1563 // the branch matches just upto this point, yet continues in a different
1571 throw std::logic_error(
1572 "NetmaskTree::erase(): size of tree is zero before erase");
1575 node->assigned = false;
1576 node->node.second = value_type();
1578 if (node == d_left) {
1579 d_left = d_left->traverse_lnr_assigned();
1585 void erase(const string& key)
1587 erase(key_type(key));
1590 //<! checks whether the container is empty.
1591 [[nodiscard]] bool empty() const
1593 return (d_size == 0);
1596 //<! returns the number of elements
1597 [[nodiscard]] size_type size() const
1602 //<! See if given ComboAddress matches any prefix
1603 [[nodiscard]] bool match(const ComboAddress& value) const
1605 return (lookup(value) != nullptr);
1608 [[nodiscard]] bool match(const std::string& value) const
1610 return match(ComboAddress(value));
1613 //<! Clean out the tree
1616 d_root = make_unique<TreeNode>();
1621 //<! swaps the contents with another NetmaskTree
1622 void swap(NetmaskTree& rhs) noexcept
1624 std::swap(d_root, rhs.d_root);
1625 std::swap(d_left, rhs.d_left);
1626 std::swap(d_size, rhs.d_size);
1630 [[nodiscard]] node_type* lookupImpl(const key_type& value, uint8_t max_bits) const
1632 TreeNode* node = nullptr;
1634 if (value.isIPv4()) {
1635 node = d_root->left.get();
1637 else if (value.isIPv6()) {
1638 node = d_root->right.get();
1641 throw NetmaskException("invalid address family");
1643 if (node == nullptr) {
1647 node_type* ret = nullptr;
1650 for (; bits < max_bits; bits++) {
1651 bool vall = value.getBit(-1 - bits);
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)
1655 if (node->assigned && bits == node->node.first.getBits()) {
1662 node = node->right.get();
1668 node = node->left.get();
1672 if (bits >= node->node.first.getBits()) {
1673 // the matching branch ends here
1676 bool valr = node->node.first.getBit(-1 - bits);
1678 // the branch matches just upto this point, yet continues in a different
1683 // needed if we did not find one in loop
1684 if (node->assigned && bits == node->node.first.getBits()) {
1687 // this can be nullptr.
1691 unique_ptr<TreeNode> d_root; //<! Root of our tree
1693 size_type d_size{0};
1696 /** This class represents a group of supplemental Netmask classes. An IP address matches
1697 if it is matched by one or more of the Netmask objects within.
1702 NetmaskGroup() noexcept = default;
1704 //! If this IP address is matched by any of the classes within
1706 bool match(const ComboAddress* address) const
1708 const auto& ret = tree.lookup(*address);
1709 if (ret != nullptr) {
1715 [[nodiscard]] bool match(const ComboAddress& address) const
1717 return match(&address);
1720 bool lookup(const ComboAddress* address, Netmask* nmp) const
1722 const auto& ret = tree.lookup(*address);
1723 if (ret != nullptr) {
1724 if (nmp != nullptr) {
1732 bool lookup(const ComboAddress& address, Netmask* nmp) const
1734 return lookup(&address, nmp);
1737 //! Add this string to the list of possible matches
1738 void addMask(const string& address, bool positive = true)
1740 if (!address.empty() && address[0] == '!') {
1741 addMask(Netmask(address.substr(1)), false);
1744 addMask(Netmask(address), positive);
1748 //! Add this Netmask to the list of possible matches
1749 void addMask(const Netmask& netmask, bool positive = true)
1751 tree.insert(netmask).second = positive;
1754 void addMasks(const NetmaskGroup& group, boost::optional<bool> positive)
1756 for (const auto& entry : group.tree) {
1757 addMask(entry.first, positive ? *positive : entry.second);
1761 //! Delete this Netmask from the list of possible matches
1762 void deleteMask(const Netmask& netmask)
1764 tree.erase(netmask);
1767 void deleteMasks(const NetmaskGroup& group)
1769 for (const auto& entry : group.tree) {
1770 deleteMask(entry.first);
1774 void deleteMask(const std::string& address)
1776 if (!address.empty()) {
1777 deleteMask(Netmask(address));
1786 [[nodiscard]] bool empty() const
1788 return tree.empty();
1791 [[nodiscard]] size_t size() const
1796 [[nodiscard]] string toString() const
1799 for (auto iter = tree.begin(); iter != tree.end(); ++iter) {
1800 if (iter != tree.begin()) {
1803 if (!(iter->second)) {
1806 str << iter->first.toString();
1811 [[nodiscard]] std::vector<std::string> toStringVector() const
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());
1821 void toMasks(const string& ips)
1823 vector<string> parts;
1824 stringtok(parts, ips, ", \t");
1826 for (const auto& part : parts) {
1832 NetmaskTree<bool> tree;
1835 struct SComboAddress
1837 SComboAddress(const ComboAddress& orig) :
1840 bool operator<(const SComboAddress& rhs) const
1842 return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
1844 operator const ComboAddress&() const
1850 class NetworkError : public runtime_error
1853 NetworkError(const string& why = "Network Error") :
1854 runtime_error(why.c_str())
1856 NetworkError(const char* why = "Network Error") :
1861 class AddressAndPortRange
1864 AddressAndPortRange() :
1865 d_addrMask(0), d_portMask(0)
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
1871 AddressAndPortRange(ComboAddress address, uint8_t addrMask, uint8_t portMask = 0) :
1872 d_addr(address), d_addrMask(addrMask), d_portMask(portMask)
1874 if (!d_addr.isIPv4()) {
1878 uint16_t port = d_addr.getPort();
1879 if (d_portMask < 16) {
1880 auto mask = static_cast<uint16_t>(~(0xFFFF >> d_portMask));
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) + ")");
1888 d_addr = Netmask(d_addr, d_addrMask).getMaskedNetwork();
1890 d_addr.setPort(port);
1893 [[nodiscard]] uint8_t getFullBits() const
1895 return d_addr.getBits() + 16;
1898 [[nodiscard]] uint8_t getBits() const
1900 if (d_addrMask < d_addr.getBits()) {
1904 return d_addr.getBits() + d_portMask;
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.
1911 [[nodiscard]] bool getBit(int index) const
1913 if (index >= getFullBits()) {
1917 index = getFullBits() + index;
1921 /* we are into the port bits */
1922 uint16_t port = d_addr.getPort();
1923 return ((port & (1U << index)) != 0x0000);
1928 return d_addr.getBit(index);
1931 [[nodiscard]] bool isIPv4() const
1933 return d_addr.isIPv4();
1936 [[nodiscard]] bool isIPv6() const
1938 return d_addr.isIPv6();
1941 [[nodiscard]] AddressAndPortRange getNormalized() const
1943 return {d_addr, d_addrMask, d_portMask};
1946 [[nodiscard]] AddressAndPortRange getSuper(uint8_t bits) const
1948 if (bits <= d_addrMask) {
1949 return {d_addr, bits, 0};
1951 if (bits <= d_addrMask + d_portMask) {
1952 return {d_addr, d_addrMask, static_cast<uint8_t>(d_portMask - (bits - d_addrMask))};
1955 return {d_addr, d_addrMask, d_portMask};
1958 [[nodiscard]] const ComboAddress& getNetwork() const
1963 [[nodiscard]] string toString() const
1965 if (d_addrMask < d_addr.getBits() || d_portMask == 0) {
1966 return d_addr.toStringNoInterface() + "/" + std::to_string(d_addrMask);
1968 return d_addr.toStringNoInterface() + ":" + std::to_string(d_addr.getPort()) + "/" + std::to_string(d_portMask);
1971 [[nodiscard]] bool empty() const
1973 return d_addr.sin4.sin_family == 0;
1976 bool operator==(const AddressAndPortRange& rhs) const
1978 return std::tie(d_addr, d_addrMask, d_portMask) == std::tie(rhs.d_addr, rhs.d_addrMask, rhs.d_portMask);
1981 bool operator<(const AddressAndPortRange& rhs) const
1983 if (empty() && !rhs.empty()) {
1987 if (!empty() && rhs.empty()) {
1991 if (d_addrMask > rhs.d_addrMask) {
1995 if (d_addrMask < rhs.d_addrMask) {
1999 if (d_addr < rhs.d_addr) {
2003 if (d_addr > rhs.d_addr) {
2007 if (d_portMask > rhs.d_portMask) {
2011 if (d_portMask < rhs.d_portMask) {
2015 return d_addr.getPort() < rhs.d_addr.getPort();
2018 bool operator>(const AddressAndPortRange& rhs) const
2020 return rhs.operator<(*this);
2025 uint32_t operator()(const AddressAndPortRange& apr) const
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
2031 return burtle(reinterpret_cast<const unsigned char*>(&port), sizeof(port), hashOp(apr.d_addr)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
2036 ComboAddress d_addr;
2038 /* only used for v4 addresses */
2042 int SSocket(int family, int type, int flags);
2043 int SConnect(int sockfd, const ComboAddress& remote);
2044 /* tries to connect to remote for a maximum of timeout seconds.
2045 sockfd should be set to non-blocking beforehand.
2046 returns 0 on success (the socket is writable), throw a
2047 runtime_error otherwise */
2048 int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout);
2049 int SBind(int sockfd, const ComboAddress& local);
2050 int SAccept(int sockfd, ComboAddress& remote);
2051 int SListen(int sockfd, int limit);
2052 int SSetsockopt(int sockfd, int level, int opname, int value);
2053 void setSocketIgnorePMTU(int sockfd, int family);
2054 void setSocketForcePMTU(int sockfd, int family);
2055 bool setReusePort(int sockfd);
2057 #if defined(IP_PKTINFO)
2058 #define GEN_IP_PKTINFO IP_PKTINFO
2059 #elif defined(IP_RECVDSTADDR)
2060 #define GEN_IP_PKTINFO IP_RECVDSTADDR
2063 bool IsAnyAddress(const ComboAddress& addr);
2064 bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination);
2065 bool HarvestTimestamp(struct msghdr* msgh, struct timeval* timeval);
2066 void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
2067 int sendOnNBSocket(int fileDesc, const struct msghdr* msgh);
2068 size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
2070 /* requires a non-blocking, connected TCP socket */
2071 bool isTCPSocketUsable(int sock);
2073 extern template class NetmaskTree<bool>;
2074 ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
2076 std::set<std::string> getListOfNetworkInterfaces();
2077 std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& itf);
2078 std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf);
2080 /* These functions throw if the value was already set to a higher value,
2082 void setSocketBuffer(int fileDesc, int optname, uint32_t size);
2083 void setSocketReceiveBuffer(int fileDesc, uint32_t size);
2084 void setSocketSendBuffer(int fileDesc, uint32_t size);
2085 uint32_t raiseSocketReceiveBufferToMax(int socket);
2086 uint32_t raiseSocketSendBufferToMax(int socket);