From 0fbe5ecda6753d50cda5aa33eaa44ea81e1fbc5c Mon Sep 17 00:00:00 2001 From: Joanna Stencel Date: Wed, 20 Nov 2024 10:52:53 +0100 Subject: [PATCH] Read all interfaces (IPv4 and IPv6) from getifaddrs (#111) Unification of detecting if address is external for IPv4 and IPv6. All interfaces (IPv4 and IPv6) are read from getifaddrs. Removed special handling of bridges in IPv4. Address is detected as external if it does not belong to reserved private range and does not belong to network of local interfaces. --- .../headers/ebpfdiscovery/Discovery.h | 6 +- libservice/CMakeLists.txt | 4 +- .../{NetlinkCalls.h => InterfacesReader.h} | 37 +-- libservice/headers/service/IpAddress.h | 1 + libservice/headers/service/IpAddressChecker.h | 5 +- ...etlinkChecker.h => IpAddressCheckerImpl.h} | 28 +- libservice/src/Aggregator.cpp | 4 +- libservice/src/InterfacesReader.cpp | 88 ++++++ libservice/src/IpAddress.cpp | 4 + ...nkChecker.cpp => IpAddressCheckerImpl.cpp} | 111 +++----- libservice/src/NetlinkCalls.cpp | 264 ------------------ libservice/test/AggregatorTest.cpp | 6 +- ...linkCallsMock.h => InterfacesReaderMock.h} | 9 +- libservice/test/IpAddressCheckerTest.cpp | 215 +++++++------- test/component/test_discovery.py | 12 +- 15 files changed, 288 insertions(+), 506 deletions(-) rename libservice/headers/service/{NetlinkCalls.h => InterfacesReader.h} (62%) rename libservice/headers/service/{IpAddressNetlinkChecker.h => IpAddressCheckerImpl.h} (68%) create mode 100644 libservice/src/InterfacesReader.cpp rename libservice/src/{IpAddressNetlinkChecker.cpp => IpAddressCheckerImpl.cpp} (56%) delete mode 100644 libservice/src/NetlinkCalls.cpp rename libservice/test/{NetlinkCallsMock.h => InterfacesReaderMock.h} (72%) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/Discovery.h b/libebpfdiscovery/headers/ebpfdiscovery/Discovery.h index d692aec4..cdadb696 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/Discovery.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/Discovery.h @@ -22,7 +22,7 @@ #include "ebpfdiscoveryshared/Types.h" #include "httpparser/HttpRequestParser.h" #include "service/Aggregator.h" -#include "service/IpAddressNetlinkChecker.h" +#include "service/IpAddressCheckerImpl.h" #include #include @@ -73,8 +73,8 @@ class Discovery { DiscoveryBpfFds bpfFds; SavedSessionsCacheType savedSessions; - service::NetlinkCalls netlinkCalls; - service::IpAddressNetlinkChecker ipChecker{netlinkCalls}; + service::InterfacesReader interfacesReader; + service::IpAddressCheckerImpl ipChecker{interfacesReader}; service::Aggregator serviceAggregator; }; diff --git a/libservice/CMakeLists.txt b/libservice/CMakeLists.txt index 2cbcd214..2211f2dc 100644 --- a/libservice/CMakeLists.txt +++ b/libservice/CMakeLists.txt @@ -15,8 +15,8 @@ list(APPEND SOURCES src/Aggregator.cpp src/IpAddress.cpp - src/IpAddressNetlinkChecker.cpp - src/NetlinkCalls.cpp + src/IpAddressCheckerImpl.cpp + src/InterfacesReader.cpp src/NetlinkSocket.cpp) set(TARGET service) diff --git a/libservice/headers/service/NetlinkCalls.h b/libservice/headers/service/InterfacesReader.h similarity index 62% rename from libservice/headers/service/NetlinkCalls.h rename to libservice/headers/service/InterfacesReader.h index d29c5108..d7a4174f 100644 --- a/libservice/headers/service/NetlinkCalls.h +++ b/libservice/headers/service/InterfacesReader.h @@ -18,38 +18,41 @@ #include #include +#include +#include #include #include #include -#include struct sockaddr_nl; namespace service { -using IPv4int = uint32_t; +struct Ipv6Network { + in6_addr networkIpv6Addr; + in6_addr networkMask; +}; -struct IpIfce { - std::vector ip; - std::vector broadcast; - uint32_t mask; +struct Ipv4Network { + in_addr networkIpv4Addr; + in_addr networkMask; + std::optional broadcastAddr; }; -using IpInterfaces = std::unordered_map; -using BridgeIndices = std::vector; -class NetlinkCalls { +class InterfacesReader { public: - virtual ~NetlinkCalls() = default; + virtual ~InterfacesReader() = default; + void printNetworksInfo(); + [[nodiscard]] virtual std::vector getIpV4Interfaces() const; + [[nodiscard]] virtual std::vector getIpV6Interfaces() const; - struct Ipv6Network { - in6_addr networkIpv6Addr; - in6_addr networkMask; - }; + virtual void collectAllIpInterfaces(); + +private: + std::vector ipv4Networks; + std::vector ipv6Networks; - virtual IpInterfaces collectIpInterfaces() const; - virtual std::vector collectIpv6Networks() const; - virtual BridgeIndices collectBridgeIndices() const; }; } // namespace service diff --git a/libservice/headers/service/IpAddress.h b/libservice/headers/service/IpAddress.h index 1f4db78c..f535b5de 100644 --- a/libservice/headers/service/IpAddress.h +++ b/libservice/headers/service/IpAddress.h @@ -26,6 +26,7 @@ using IPv4bytes = uint8_t[4]; using IPv6bytes = uint8_t[16]; std::string ipv4ToString(const IPv4bytes addr); +std::string ipv4InAdrToString(const in_addr& addr); std::string ipv6ToString(const IPv6bytes addr); } // namespace service diff --git a/libservice/headers/service/IpAddressChecker.h b/libservice/headers/service/IpAddressChecker.h index d71953de..33aad2fc 100644 --- a/libservice/headers/service/IpAddressChecker.h +++ b/libservice/headers/service/IpAddressChecker.h @@ -17,6 +17,7 @@ #pragma once #include +#include "netinet/in.h" struct in6_addr; @@ -28,8 +29,8 @@ class IpAddressChecker { public: virtual ~IpAddressChecker() = default; - virtual bool isV4AddressExternal(IPv4int addr) const = 0; + [[nodiscard]] virtual bool isV4AddressExternal(const in_addr& addr) const = 0; - virtual bool isV6AddressExternal(const in6_addr& addr) const = 0; + [[nodiscard]] virtual bool isV6AddressExternal(const in6_addr& addr) const = 0; }; } // namespace service diff --git a/libservice/headers/service/IpAddressNetlinkChecker.h b/libservice/headers/service/IpAddressCheckerImpl.h similarity index 68% rename from libservice/headers/service/IpAddressNetlinkChecker.h rename to libservice/headers/service/IpAddressCheckerImpl.h index 7d949d48..545051a2 100644 --- a/libservice/headers/service/IpAddressNetlinkChecker.h +++ b/libservice/headers/service/IpAddressCheckerImpl.h @@ -16,21 +16,20 @@ #pragma once -#include #include -#include #include +#include #include "IpAddressChecker.h" -#include "NetlinkCalls.h" +#include "InterfacesReader.h" namespace service { -class IpAddressNetlinkChecker : public IpAddressChecker { +class IpAddressCheckerImpl : public IpAddressChecker { public: - explicit IpAddressNetlinkChecker(const NetlinkCalls& calls); + explicit IpAddressCheckerImpl(InterfacesReader& interfaceReader); - bool isV4AddressExternal(IPv4int addr) const override; + bool isV4AddressExternal(const in_addr& addr) const override; bool isV6AddressExternal(const in6_addr& addr) const override; @@ -42,24 +41,13 @@ class IpAddressNetlinkChecker : public IpAddressChecker { ipv6Range parseIpv6Range(const std::string& range) const; bool isInRange(const in6_addr& addr, const std::string& range) const; bool checkSubnet(const in6_addr& addrToCheck, const in6_addr& interfaceIpv6Addr, const in6_addr& interfaceMask) const; + bool checkSubnetIpv4(const in_addr& addrToCheck, const in_addr& interfaceIpv4Addr, const in_addr& interfaceMask) const; bool ipv6AddressContainsMappedIpv4Address(const in6_addr& addr) const; std::optional getMappedIPv4Addr(const in6_addr& addr) const; void readNetworks(); - void printNetworkInterfacesInfo(); - - bool isLocalBridge(int index) const { - if (const auto it{isLocalBridgeMap.find(index)}; it != isLocalBridgeMap.end()) { - return it->second; - } - - return false; - } - - const NetlinkCalls& netlink; - IpInterfaces ipInterfaces; - std::vector ipv6Networks; - std::unordered_map isLocalBridgeMap; + InterfacesReader& interfacesReader; + std::vector ipv6Networks; }; } // namespace service diff --git a/libservice/src/Aggregator.cpp b/libservice/src/Aggregator.cpp index fa4d92c0..1dfd7dbb 100644 --- a/libservice/src/Aggregator.cpp +++ b/libservice/src/Aggregator.cpp @@ -18,7 +18,7 @@ #include "logging/Logger.h" #include "service/IpAddress.h" -#include "service/IpAddressNetlinkChecker.h" +#include "service/IpAddressCheckerImpl.h" #include @@ -29,7 +29,7 @@ static std::string getEndpoint(const std::string& host, const std::string& url) } static bool isIpv4ClientExternal(const IpAddressChecker& ipChecker, const in_addr& clientAddrBinary) { - return ipChecker.isV4AddressExternal(clientAddrBinary.s_addr); + return ipChecker.isV4AddressExternal(clientAddrBinary); } static bool isIpv6ClientExternal(const IpAddressChecker& ipChecker, const in6_addr& clientAddrBinary) { diff --git a/libservice/src/InterfacesReader.cpp b/libservice/src/InterfacesReader.cpp new file mode 100644 index 00000000..fd41b5b5 --- /dev/null +++ b/libservice/src/InterfacesReader.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2023 Dynatrace LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "service/InterfacesReader.h" + +#include +#include +#include +#include +#include +#include + +#include "NetlinkSocket.h" +#include "logging/Logger.h" + +namespace service { + +void InterfacesReader::printNetworksInfo() { + LOG_INFO("{} IPv4 networks have been discovered:", ipv4Networks.size()); + for (const auto& ipv4Network : ipv4Networks) { + char ipv4NetworkAddrString[INET_ADDRSTRLEN]; + char ipv4NetworkMaskString[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ipv4Network.networkIpv4Addr), ipv4NetworkAddrString, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &(ipv4Network.networkMask), ipv4NetworkMaskString, INET_ADDRSTRLEN); + LOG_INFO("Detected IPv4 network: {}, Mask: {}", ipv4NetworkAddrString, ipv4NetworkMaskString); + } + LOG_INFO("{} IPv6 networks have been discovered:", ipv6Networks.size()); + for (const auto& ipv6Network : ipv6Networks) { + char ipv6NetworkAddrString[INET6_ADDRSTRLEN]; + char ipv6NetworkMaskString[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(ipv6Network.networkIpv6Addr), ipv6NetworkAddrString, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &(ipv6Network.networkMask), ipv6NetworkMaskString, INET6_ADDRSTRLEN); + LOG_INFO("Detected IPv6 network: {}, Mask: {}", ipv6NetworkAddrString, ipv6NetworkMaskString); + } +} + +void InterfacesReader::collectAllIpInterfaces() { + ifaddrs* ifAddressStruct = nullptr; + if (getifaddrs(&ifAddressStruct) != 0) { + LOG_WARN("Error while collecting IP interfaces, getifaddrs returned error: {}", strerror(errno)); + return; + } + for (const ifaddrs* ifa = ifAddressStruct; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == nullptr) { + continue; + } + if (ifa->ifa_addr->sa_family == AF_INET6) { + const in6_addr networkIpv6Addr = reinterpret_cast(ifa->ifa_addr)->sin6_addr; + const in6_addr networkMask = reinterpret_cast(ifa->ifa_netmask)->sin6_addr; + + ipv6Networks.emplace_back(Ipv6Network{networkIpv6Addr, networkMask}); + continue; + } + if (ifa->ifa_addr->sa_family == AF_INET) { + auto address = reinterpret_cast(ifa->ifa_addr)->sin_addr; + auto mask = reinterpret_cast(ifa->ifa_netmask)->sin_addr; + std::optional broadcast{}; + if (ifa->ifa_flags & IFF_BROADCAST) { + broadcast = std::optional(reinterpret_cast(ifa->ifa_ifu.ifu_broadaddr)->sin_addr); + } + ipv4Networks.emplace_back(Ipv4Network{{address}, mask, broadcast}); + } + } + freeifaddrs(ifAddressStruct); +} + +std::vector InterfacesReader::getIpV4Interfaces() const { + return ipv4Networks; +} + +std::vector InterfacesReader::getIpV6Interfaces() const { + return ipv6Networks; +} + +} // namespace service diff --git a/libservice/src/IpAddress.cpp b/libservice/src/IpAddress.cpp index d9d90f79..22520bd0 100644 --- a/libservice/src/IpAddress.cpp +++ b/libservice/src/IpAddress.cpp @@ -29,6 +29,10 @@ std::string ipv4ToString(const IPv4bytes addr) { return std::string(ipAddress); } +std::string ipv4InAdrToString(const in_addr& addr) { + return ipv4ToString(reinterpret_cast(addr)); +} + std::string ipv6ToString(const IPv6bytes addr) { char ipAddress[INET6_ADDRSTRLEN]; const auto res{inet_ntop(AF_INET6, addr, ipAddress, sizeof(ipAddress))}; diff --git a/libservice/src/IpAddressNetlinkChecker.cpp b/libservice/src/IpAddressCheckerImpl.cpp similarity index 56% rename from libservice/src/IpAddressNetlinkChecker.cpp rename to libservice/src/IpAddressCheckerImpl.cpp index 000e5a24..ac000f54 100644 --- a/libservice/src/IpAddressNetlinkChecker.cpp +++ b/libservice/src/IpAddressCheckerImpl.cpp @@ -14,60 +14,29 @@ * limitations under the License. */ -#include "service/IpAddressNetlinkChecker.h" +#include "service/IpAddressCheckerImpl.h" #include "logging/Logger.h" #include #include #include #include -#include #include +#include +#include namespace service { -IpAddressNetlinkChecker::IpAddressNetlinkChecker(const NetlinkCalls& calls) : netlink{calls} { +IpAddressCheckerImpl::IpAddressCheckerImpl(InterfacesReader& interfaceReader) : interfacesReader{interfaceReader} { readNetworks(); } -void IpAddressNetlinkChecker::readNetworks() { - ipInterfaces = netlink.collectIpInterfaces(); - - for (const auto& [index, ipIfce] : ipInterfaces) { - isLocalBridgeMap[index] = false; - } - - for (const auto& index : netlink.collectBridgeIndices()) { - isLocalBridgeMap[index] = true; - } - - ipv6Networks = netlink.collectIpv6Networks(); - - printNetworkInterfacesInfo(); -} - -void IpAddressNetlinkChecker::printNetworkInterfacesInfo() { - LOG_INFO("{} network interfaces have been discovered:", ipInterfaces.size()); - for (const auto& [index, ifce] : ipInterfaces) { - std::string ipAddresses{boost::algorithm::join( - ifce.ip | boost::adaptors::transformed([](auto ip) { - char buff[16]; - return std::string{inet_ntop(AF_INET, &ip, buff, sizeof(buff))}; - }), - ", ")}; - LOG_INFO("index: {}, IP addresses: {}{}", index, ipAddresses, isLocalBridge(index) ? " (local bridge)" : ""); - } - LOG_INFO("{} IPv6 networks have been discovered:", ipv6Networks.size()); - for (const auto& ipv6Network : ipv6Networks) { - char ipv6NetworkAddrString[INET6_ADDRSTRLEN]; - char ipv6NetworkMaskString[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &(ipv6Network.networkIpv6Addr), ipv6NetworkAddrString, INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, &(ipv6Network.networkMask), ipv6NetworkMaskString, INET6_ADDRSTRLEN); - LOG_INFO("Detected IPv6 network: {}, Mask: {}", ipv6NetworkAddrString, ipv6NetworkMaskString); - } +void IpAddressCheckerImpl::readNetworks() { + interfacesReader.collectAllIpInterfaces(); + interfacesReader.printNetworksInfo(); } -bool IpAddressNetlinkChecker::isV4AddressExternal(IPv4int addr) const { +bool IpAddressCheckerImpl::isV4AddressExternal(const in_addr& addr) const { // Special-Purpose IP Address Registries (https://datatracker.ietf.org/doc/html/rfc6890) static const struct { uint32_t network; @@ -93,40 +62,29 @@ bool IpAddressNetlinkChecker::isV4AddressExternal(IPv4int addr) const { }; for (const auto& [network, mask] : reservedRanges) { - if ((htonl(addr) & mask) == network) { + if ((ntohl(addr.s_addr) & mask) == network) { + LOG_DEBUG("Address {} internal, belonging to reserved range (network, mask): {:#x}, {:#x}", + ipv4InAdrToString(addr), + network, + mask); return false; } } - const bool srcLocal{std::any_of(ipInterfaces.begin(), ipInterfaces.end(), [addr, this](const auto& ipInterfaceEntry) { - const auto& [ipInterfaceIndex, ipInterface]{ipInterfaceEntry}; - return std::any_of(ipInterface.ip.begin(), ipInterface.ip.end(), [addr, index = ipInterfaceIndex, this](const auto& ip) { - return !isLocalBridge(index) && addr == ip; - }); - })}; - - if (srcLocal) { - return false; - } - - const bool bridgeRelated{std::any_of(ipInterfaces.begin(), ipInterfaces.end(), [addr, this](const auto& ipInterfaceEntry) { - const auto& [ipInterfaceIndex, ipInterface]{ipInterfaceEntry}; - return std::any_of( - ipInterface.ip.begin(), - ipInterface.ip.end(), - [addr, index = ipInterfaceIndex, mask = ipInterface.mask, this](const auto& ip) { - return isLocalBridge(index) && (addr & mask) == (ip & mask); - }); - })}; - - if (bridgeRelated) { - return false; + for (const auto& ipv4Network : interfacesReader.getIpV4Interfaces()) { + if (checkSubnetIpv4(addr, ipv4Network.networkIpv4Addr, ipv4Network.networkMask)) { + LOG_DEBUG("Address {} internal, belonging to local interface (addr, mask): {}, {}", + ipv4InAdrToString(addr), + ipv4InAdrToString(ipv4Network.networkIpv4Addr), + ipv4InAdrToString(ipv4Network.networkMask)); + return false; + } } return true; } -bool IpAddressNetlinkChecker::ipv6AddressContainsMappedIpv4Address(const in6_addr& addr) const { +bool IpAddressCheckerImpl::ipv6AddressContainsMappedIpv4Address(const in6_addr& addr) const { for (const auto& internalRange : {"::ffff:0:0/96", "::ffff:0:0:0/96", "64:ff9b::/96"}) { if (isInRange(addr, internalRange)) { return true; @@ -136,7 +94,7 @@ bool IpAddressNetlinkChecker::ipv6AddressContainsMappedIpv4Address(const in6_add return false; } -std::optional IpAddressNetlinkChecker::getMappedIPv4Addr(const in6_addr& addr) const { +std::optional IpAddressCheckerImpl::getMappedIPv4Addr(const in6_addr& addr) const { if (!ipv6AddressContainsMappedIpv4Address(addr)) { return std::nullopt; } @@ -145,7 +103,7 @@ std::optional IpAddressNetlinkChecker::getMappedIPv4Addr(const in6_addr return ipv4Binary; } -IpAddressNetlinkChecker::ipv6Range IpAddressNetlinkChecker::parseIpv6Range(const std::string& range) const { +IpAddressCheckerImpl::ipv6Range IpAddressCheckerImpl::parseIpv6Range(const std::string& range) const { ipv6Range rangeStruct; const auto slashPos{range.find('/')}; rangeStruct.ipv6Address = range.substr(0, slashPos); @@ -153,8 +111,8 @@ IpAddressNetlinkChecker::ipv6Range IpAddressNetlinkChecker::parseIpv6Range(const return rangeStruct; } -bool IpAddressNetlinkChecker::isInRange(const in6_addr& addr, const std::string& range) const { - auto rangeStruct{IpAddressNetlinkChecker::parseIpv6Range(range)}; +bool IpAddressCheckerImpl::isInRange(const in6_addr& addr, const std::string& range) const { + auto rangeStruct{IpAddressCheckerImpl::parseIpv6Range(range)}; in6_addr rangeIpv6Address{}; inet_pton(AF_INET6, rangeStruct.ipv6Address.c_str(), &rangeIpv6Address); @@ -183,7 +141,7 @@ bool IpAddressNetlinkChecker::isInRange(const in6_addr& addr, const std::string& return memcmp(&andResult, &rangeIpv6Address, sizeof(andResult)) == 0; } -bool IpAddressNetlinkChecker::checkSubnet( +bool IpAddressCheckerImpl::checkSubnet( const in6_addr& addrToCheck, const in6_addr& interfaceIpv6Addr, const in6_addr& interfaceMask) const { const auto s6Addr32ArraySize = sizeof(addrToCheck.s6_addr32) / sizeof(addrToCheck.s6_addr32[0]); for (size_t i = 0; i < s6Addr32ArraySize; ++i) { @@ -194,19 +152,26 @@ bool IpAddressNetlinkChecker::checkSubnet( return true; } -bool IpAddressNetlinkChecker::isV6AddressExternal(const in6_addr& addr) const { +bool IpAddressCheckerImpl::checkSubnetIpv4( + const in_addr& addrToCheck, const in_addr& interfaceIpv4Addr, const in_addr& interfaceMask) const { + if ((addrToCheck.s_addr & interfaceMask.s_addr) != (interfaceIpv4Addr.s_addr & interfaceMask.s_addr)) { + return false; + } + return true; +} +bool IpAddressCheckerImpl::isV6AddressExternal(const in6_addr& addr) const { if (auto mappedV4Addr = getMappedIPv4Addr(addr); mappedV4Addr) { - return isV4AddressExternal(*mappedV4Addr); + return isV4AddressExternal(static_cast(*mappedV4Addr)); } - for (auto& ipv6Network : ipv6Networks) { + for (auto& ipv6Network : interfacesReader.getIpV6Interfaces()) { if (checkSubnet(addr, ipv6Network.networkIpv6Addr, ipv6Network.networkMask)) { return false; } } for (const auto& internalRange : {"fc00::/7", "fec0::/10", "fe80::/10", "::1/128"}) { - if (IpAddressNetlinkChecker::isInRange(addr, internalRange)) { + if (isInRange(addr, internalRange)) { return false; } } diff --git a/libservice/src/NetlinkCalls.cpp b/libservice/src/NetlinkCalls.cpp deleted file mode 100644 index 5b4e6b81..00000000 --- a/libservice/src/NetlinkCalls.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2023 Dynatrace LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "service/NetlinkCalls.h" - -#include -#include -#include -#include -#include - -#include "NetlinkSocket.h" -#include "logging/Logger.h" - -namespace service { - -static constexpr uint32_t BUFFLEN{4096}; - -static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int dataLen) { - struct rtattr* rta; - int rta_length = RTA_LENGTH(dataLen); - - rta = reinterpret_cast((char*)nh + NLMSG_ALIGN(nh->nlmsg_len)); - - rta->rta_type = type; - rta->rta_len = rta_length; - nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + RTA_ALIGN(rta_length); - - memcpy(RTA_DATA(rta), data, dataLen); -} - -static int sendIpAddrRequest(const NetlinkSocket& netlinkSocket, sockaddr_nl* dst, int domain) { - std::array buf{}; - - nlmsghdr* nl; - nl = reinterpret_cast(buf.data()); - nl->nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg)); - nl->nlmsg_type = RTM_GETADDR; - nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; - - ifaddrmsg* ifa; - ifa = reinterpret_cast(NLMSG_DATA(nl)); - ifa->ifa_family = domain; // ipv4 or ipv6 - - iovec iov = {nl, nl->nlmsg_len}; - msghdr msg = {dst, sizeof(*dst), &iov, 1, NULL, 0, 0}; - - return netlinkSocket.send(&msg, 0); -} - -static int sendBridgesRequest(const NetlinkSocket& netlinkSocket, sockaddr_nl* dst, int domain) { - struct { - struct nlmsghdr n; - struct ifinfomsg i; - char _[1024]; // space for rtattr array - } r{}; - - const char* dev_type = "bridge"; - - r.n.nlmsg_len = NLMSG_LENGTH(sizeof(ifinfomsg)); - r.n.nlmsg_type = RTM_GETLINK; - r.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - r.i.ifi_family = AF_PACKET; - r.n.nlmsg_pid = 0; - r.n.nlmsg_seq = 0; - - rtattr* linkinfo = reinterpret_cast((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len)); - addNetlinkMsg(&r.n, IFLA_LINKINFO, NULL, 0); - addNetlinkMsg(&r.n, IFLA_INFO_KIND, dev_type, strlen(dev_type) + 1); - linkinfo->rta_len = (int)(reinterpret_cast(&r.n) + NLMSG_ALIGN(r.n.nlmsg_len) - reinterpret_cast(linkinfo)); - - iovec iov = {&r.n, r.n.nlmsg_len}; - msghdr msg = {dst, sizeof(*dst), &iov, 1, NULL, 0, 0}; - - return netlinkSocket.send(&msg, 0); -} - -static int receive(const NetlinkSocket& netlinkSocket, sockaddr_nl* dst, void* buf, size_t len) { - iovec iov; - msghdr msg{}; - iov.iov_base = buf; - iov.iov_len = len; - - msg.msg_name = dst; - msg.msg_namelen = sizeof(*dst); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - return netlinkSocket.receive(&msg, 0); -} - -static IpInterfaces::value_type parseIfceIPv4(void* data, size_t len) { - IpIfce ifce{}; - ifaddrmsg* ifa = reinterpret_cast(data); - ifce.mask = htonl(-1 << (32 - ifa->ifa_prefixlen)); - rtattr* rta = reinterpret_cast(IFA_RTA(data)); - - for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { - in_addr* addr = reinterpret_cast(RTA_DATA(rta)); - - if (rta->rta_type == IFA_ADDRESS) { - ifce.ip.push_back(addr->s_addr); - } - - if (rta->rta_type == IFA_BROADCAST) { - ifce.broadcast.push_back(addr->s_addr); - } - } - - return {ifa->ifa_index, ifce}; -} - -template -T parse(void* data, size_t len); - -template <> -IpInterfaces::value_type parse(void* data, size_t len) { - if (reinterpret_cast(data)->ifa_family != AF_INET) { - return {}; - } - - return parseIfceIPv4(data, len); -} - -template <> -BridgeIndices::value_type parse(void* data, size_t len) { - ifinfomsg* ifa = reinterpret_cast(data); - return ifa->ifi_index; -} - -template -struct ParseResult { - uint32_t nlMsgType; - Data data; -}; - -void insert(const IpInterfaces::value_type& data, IpInterfaces& ipInterfaces) { - ipInterfaces.emplace(data); -} - -void insert(const BridgeIndices::value_type& data, BridgeIndices& bridgeIndices) { - bridgeIndices.push_back(data); -} - -template -static ParseResult parseNlMsg(void* buf, size_t len) { - const nlmsghdr* nl = reinterpret_cast(buf); - ParseResult parseResult{.nlMsgType = nl->nlmsg_type}; - - for (; NLMSG_OK(nl, len) && nl->nlmsg_type != NLMSG_DONE; nl = NLMSG_NEXT(nl, len)) { - if (nl->nlmsg_type == NLMSG_ERROR) { - const auto err{reinterpret_cast(NLMSG_DATA(nl))}; - LOG_WARN("Error while receiving netlink message: {}", std::strerror(err->error)); - break; - } - - if (nl->nlmsg_type == RTM_NEWADDR || nl->nlmsg_type == RTM_NEWLINK) { - insert(parse(NLMSG_DATA(nl), IFA_PAYLOAD(nl)), parseResult.data); - } - } - - return parseResult; -} - -template -Data receive(const NetlinkSocket& netlinkSocket, sockaddr_nl* dst) { - Data result; - for (;;) { - std::array buf{}; - const auto len{receive(netlinkSocket, dst, buf.data(), BUFFLEN)}; - - if (len <= 0) { - LOG_WARN("Error while receiving netlink message: {}", strerror(errno)); - break; - } - - const auto [nlMsgType, data]{parseNlMsg(buf.data(), len)}; - - if (nlMsgType == NLMSG_ERROR) { - break; - } - - for (const auto& entry : data) { - insert(entry, result); - } - - if (nlMsgType == NLMSG_DONE) { - break; - } - } - - return result; -} - -IpInterfaces receiveIpAddr(const NetlinkSocket& netlinkSocket, sockaddr_nl* dst) { - return receive(netlinkSocket, dst); -} - -BridgeIndices receiveBridgeIndex(const NetlinkSocket& netlinkSocket, sockaddr_nl* dst) { - return receive(netlinkSocket, dst); -} - -template -Data handleNetlink(const Send& send, const Receive& receive, int domain) { - NetlinkSocket netlinkSocket; - if (!netlinkSocket) { - LOG_WARN("Error while opening netlink socket: {}", strerror(errno)); - return {}; - } - - sockaddr_nl sa{}; - sa.nl_family = AF_NETLINK; - - int len = send(netlinkSocket, &sa, domain); - if (len <= 0) { - LOG_WARN("Error while sending netlink request: {}", strerror(errno)); - return {}; - } - - return receive(netlinkSocket, &sa); -} - -IpInterfaces NetlinkCalls::collectIpInterfaces() const { - return handleNetlink(sendIpAddrRequest, receiveIpAddr, AF_INET); -} - -std::vector NetlinkCalls::collectIpv6Networks() const { - std::vector collectedIpv6Networks{}; - - ifaddrs* ifAddressStruct = nullptr; - if (getifaddrs(&ifAddressStruct) == 0) { - for (ifaddrs* ifa = ifAddressStruct; ifa != nullptr; ifa = ifa->ifa_next) { - if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == AF_INET6) { - in6_addr networkIpv6Addr = reinterpret_cast(ifa->ifa_addr)->sin6_addr; - in6_addr networkMask = reinterpret_cast(ifa->ifa_netmask)->sin6_addr; - - collectedIpv6Networks.emplace_back(Ipv6Network{networkIpv6Addr, networkMask}); - } - } - freeifaddrs(ifAddressStruct); - } - - return collectedIpv6Networks; -} - -BridgeIndices NetlinkCalls::collectBridgeIndices() const { - return handleNetlink( - sendBridgesRequest, receiveBridgeIndex, AF_INET); -} - -} // namespace service diff --git a/libservice/test/AggregatorTest.cpp b/libservice/test/AggregatorTest.cpp index 9d39f672..ed8167f8 100644 --- a/libservice/test/AggregatorTest.cpp +++ b/libservice/test/AggregatorTest.cpp @@ -16,7 +16,7 @@ #include "service/Aggregator.h" -#include "service/IpAddressNetlinkChecker.h" +#include "service/IpAddressCheckerImpl.h" #include #include @@ -33,7 +33,7 @@ void PrintTo(const Service& service, std::ostream* os) { class IpAddressCheckerMock : public IpAddressChecker { public: - MOCK_METHOD(bool, isV4AddressExternal, (IPv4int), (const)); + MOCK_METHOD(bool, isV4AddressExternal, (const in_addr&), (const)); MOCK_METHOD(bool, isV6AddressExternal, (const in6_addr&), (const)); }; @@ -61,7 +61,7 @@ struct ServiceAggregatorTest : public testing::Test { return {request, meta}; } - const NetlinkCalls netlink; + const InterfacesReader netlink; IpAddressCheckerMock ipCheckerMock; }; diff --git a/libservice/test/NetlinkCallsMock.h b/libservice/test/InterfacesReaderMock.h similarity index 72% rename from libservice/test/NetlinkCallsMock.h rename to libservice/test/InterfacesReaderMock.h index 4f9b3d14..3c9e5d87 100644 --- a/libservice/test/NetlinkCallsMock.h +++ b/libservice/test/InterfacesReaderMock.h @@ -18,15 +18,16 @@ #include -#include "service/NetlinkCalls.h" +#include "service/InterfacesReader.h" namespace service { -class NetlinkCallsMock : public NetlinkCalls { +class InterfacesReaderMock : public InterfacesReader { public: - MOCK_CONST_METHOD0(collectIpInterfaces, IpInterfaces()); - MOCK_CONST_METHOD0(collectBridgeIndices, BridgeIndices()); MOCK_CONST_METHOD0(collectIpv6Networks, std::vector()); + MOCK_CONST_METHOD0(getIpV4Interfaces, std::vector()); + MOCK_CONST_METHOD0(getIpV6Interfaces, std::vector()); + MOCK_METHOD(void, collectAllIpInterfaces, (), (override)); }; } // namespace service diff --git a/libservice/test/IpAddressCheckerTest.cpp b/libservice/test/IpAddressCheckerTest.cpp index dd7b80fa..4de0b122 100644 --- a/libservice/test/IpAddressCheckerTest.cpp +++ b/libservice/test/IpAddressCheckerTest.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "NetlinkCallsMock.h" -#include "service/IpAddressNetlinkChecker.h" +#include "InterfacesReaderMock.h" +#include "service/IpAddressCheckerImpl.h" #include #include @@ -26,243 +26,240 @@ using namespace ::testing; class IpAddressCheckerTest : public Test { public: - NiceMock netlinkMock; + NiceMock netlinkMock; }; +static in_addr getV4AddrBinary(const std::string& addr) { + in_addr clientAddrBinary{}; + inet_pton(AF_INET, addr.c_str(), &clientAddrBinary); + return clientAddrBinary; +} + // 0.0.0.0/8 TEST_F(IpAddressCheckerTest, Test0_0_0_0_8) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("0.0.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("0.255.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("0.0.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("0.255.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("0.54.189.245"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("0.128.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("0.54.189.245"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("0.128.0.1"))); } // 10.0.0.0/8 TEST_F(IpAddressCheckerTest, Test10_0_0_0_8) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("10.0.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("10.255.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("10.0.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("10.255.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("10.54.189.245"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("10.128.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("10.54.189.245"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("10.128.0.1"))); } // 100.64.0.0/10 TEST_F(IpAddressCheckerTest, Test100_64_0_0_10) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("100.64.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("100.127.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("100.64.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("100.127.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("100.64.128.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("100.66.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("100.64.128.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("100.66.0.1"))); } // 127.0.0.0/8 TEST_F(IpAddressCheckerTest, Test127_0_0_0_8) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("127.0.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("127.255.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("127.0.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("127.255.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("127.0.0.1"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("127.128.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("127.0.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("127.128.0.1"))); } // 169.254.0.0/16 TEST_F(IpAddressCheckerTest, Test169_254_0_0_16) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("169.254.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("169.254.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("169.254.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("169.254.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("169.254.128.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("169.254.192.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("169.254.128.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("169.254.192.1"))); } // 172.16.0.0/12 TEST_F(IpAddressCheckerTest, Test172_16_0_0_12) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("172.16.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("172.31.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("172.16.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("172.31.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("172.20.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("172.24.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("172.20.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("172.24.0.1"))); } // 192.0.0.0/24 TEST_F(IpAddressCheckerTest, Test192_0_0_0_24) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.0.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.0.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.0.128"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.0.128"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.0.1"))); } // 192.0.2.0/24 TEST_F(IpAddressCheckerTest, Test192_0_2_0_24) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.2.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.2.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.2.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.2.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.2.128"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.0.2.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.2.128"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.0.2.1"))); } // 192.88.99.0/24 TEST_F(IpAddressCheckerTest, Test192_88_99_0_24) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.88.99.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.88.99.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.88.99.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.88.99.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.88.99.128"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.88.99.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.88.99.128"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.88.99.1"))); } // 192.168.0.0/ TEST_F(IpAddressCheckerTest, Test192_168_0_0_16) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.168.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.168.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.168.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.168.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.168.128.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("192.168.192.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.168.128.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("192.168.192.1"))); } // 198.18.0.0/15 TEST_F(IpAddressCheckerTest, Test198_18_0_0_15) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.18.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.19.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.18.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.19.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.18.128.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.18.192.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.18.128.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.18.192.1"))); } // 198.51.100.0/24 TEST_F(IpAddressCheckerTest, Test198_51_100_0_24) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.51.100.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.51.100.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.51.100.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.51.100.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.51.100.128"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("198.51.100.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.51.100.128"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("198.51.100.1"))); } // 203.0.113.0/24 TEST_F(IpAddressCheckerTest, Test203_0_113_0_24) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("203.0.113.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("203.0.113.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("203.0.113.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("203.0.113.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("203.0.113.128"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("203.0.113.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("203.0.113.128"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("203.0.113.1"))); } // 224.0.0.0/4 TEST_F(IpAddressCheckerTest, Test224_0_0_0_4) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("224.0.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("239.255.255.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("224.0.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("239.255.255.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("225.128.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("230.0.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("225.128.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("230.0.0.1"))); } // 233.252.0.0/24 TEST_F(IpAddressCheckerTest, Test233_252_0_0_24) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("233.252.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("233.252.0.255"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("233.252.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("233.252.0.255"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("233.252.0.128"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("233.252.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("233.252.0.128"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("233.252.0.1"))); } // 240.0.0.0/4 TEST_F(IpAddressCheckerTest, Test240_0_0_0_4) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // Range boundaries - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("240.0.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("255.255.255.254"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("240.0.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("255.255.255.254"))); // Middle of the range - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("241.128.0.0"))); - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("248.0.0.1"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("241.128.0.0"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("248.0.0.1"))); } // 255.255.255.255/32 TEST_F(IpAddressCheckerTest, Test255_255_255_255_32) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; - - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("255.255.255.255"))); -} - -TEST_F(IpAddressCheckerTest, LocalBridgeIp) { - EXPECT_CALL(netlinkMock, collectIpInterfaces).WillOnce(Return(IpInterfaces{{0, IpIfce{{inet_addr("142.15.4.0")}, {}, 0x0000ffff}}})); - EXPECT_CALL(netlinkMock, collectBridgeIndices).WillOnce(Return(BridgeIndices{0})); - - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("142.15.6.5"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("255.255.255.255"))); } TEST_F(IpAddressCheckerTest, LocalIfceIpSrc) { - EXPECT_CALL(netlinkMock, collectIpInterfaces) - .WillOnce(Return(IpInterfaces{ - {0, IpIfce{{inet_addr("115.89.3.7")}, {}, 0x0000ffff}}, - })); - EXPECT_CALL(netlinkMock, collectBridgeIndices).WillOnce(Return(BridgeIndices{})); + EXPECT_CALL(netlinkMock, collectAllIpInterfaces); + EXPECT_CALL(netlinkMock,getIpV4Interfaces ) + .WillOnce(Return(std::vector{ + {{getV4AddrBinary("115.89.3.7")},{0x0000ffff}, {}} + })); - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; - EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(inet_addr("115.89.3.7"))); + EXPECT_FALSE(ipAddressNetlinkChecker.isV4AddressExternal(getV4AddrBinary("115.89.3.7"))); } static in6_addr getV6AddrBinary(const std::string& addr) { @@ -273,7 +270,7 @@ static in6_addr getV6AddrBinary(const std::string& addr) { // IPv4 mapped to IPv6 TEST_F(IpAddressCheckerTest, TestMapped) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; // mapped IPv4 EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("::FFFF:192.168.0.5"))); @@ -295,7 +292,7 @@ TEST_F(IpAddressCheckerTest, TestMapped) { // unique local address (prefix fc00::/7) TEST_F(IpAddressCheckerTest, UniqueLocalAddress) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("fc00::1"))); EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); @@ -305,7 +302,7 @@ TEST_F(IpAddressCheckerTest, UniqueLocalAddress) { // site local addresses (fec0::/10 - deprecated) TEST_F(IpAddressCheckerTest, SiteLocalAddress) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("fec0::"))); EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); @@ -314,7 +311,7 @@ TEST_F(IpAddressCheckerTest, SiteLocalAddress) { // link local addresses (fe80::/10) TEST_F(IpAddressCheckerTest, LinkLocalAddress) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("fe80::"))); EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); @@ -323,7 +320,7 @@ TEST_F(IpAddressCheckerTest, LinkLocalAddress) { // loopback addresses (::1/128) TEST_F(IpAddressCheckerTest, LoopbackAddress) { - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("::1"))); EXPECT_TRUE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("::"))); @@ -338,11 +335,9 @@ TEST_F(IpAddressCheckerTest, Ipv6NetworkSubnet) { inet_pton(AF_INET6, "2001:db8:85a3::8a2e:370:7336", &ipv6NetworkAddr); inet_pton(AF_INET6, "ffff:ffff:ffff:ffff::", &ipv6NetworkMask); - EXPECT_CALL(netlinkMock, collectIpv6Networks).WillOnce(Return(std::vector{{service::NetlinkCalls::Ipv6Network{ipv6NetworkAddr, ipv6NetworkMask}}})); - EXPECT_CALL(netlinkMock, collectIpInterfaces).WillOnce(Return(IpInterfaces{0})); - EXPECT_CALL(netlinkMock, collectBridgeIndices).WillOnce(Return(BridgeIndices{0})); + EXPECT_CALL(netlinkMock, getIpV6Interfaces).WillRepeatedly(Return(std::vector{{Ipv6Network{ipv6NetworkAddr, ipv6NetworkMask}}})); - IpAddressNetlinkChecker ipAddressNetlinkChecker{netlinkMock}; + IpAddressCheckerImpl ipAddressNetlinkChecker{netlinkMock}; EXPECT_FALSE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("2001:0db8:85a3:0000:0000:0000:0000:0000"))); EXPECT_TRUE(ipAddressNetlinkChecker.isV6AddressExternal(getV6AddrBinary("2001:0db8:85a3:0001:0000:0000:0000:0000"))); diff --git a/test/component/test_discovery.py b/test/component/test_discovery.py index 7644edc4..0c8b66c3 100644 --- a/test/component/test_discovery.py +++ b/test/component/test_discovery.py @@ -102,8 +102,8 @@ def test_request_forwarded_to_local_interface_with_public_ip(network_interfaces, expected_external_ipv4_24_networks=0, expected_external_ipv6_networks=0) -@pytest.mark.parametrize('network_interfaces', [[('dummy', 'eth16', '113.56.3.22', 16)]], indirect=True) -def test_request_forwarded_to_public_ip_matching_local_interface_mask(network_interfaces, run_ebpf_discovery, run_http_service): +@pytest.mark.parametrize('network_interfaces', [[('dummy', 'eth16', '113.56.3.22', 24)]], indirect=True) +def test_request_forwarded_to_public_ip_not_matching_local_interface_mask(network_interfaces, run_ebpf_discovery, run_http_service): url = run_http_service + "/forwarded" send_http_requests(url, 1, "113.56.1.57:8080") assert discovered_service_has_expected_clients(run_ebpf_discovery, url, @@ -231,10 +231,10 @@ def test_request_forwarded_to_public_ip_matching_local_interface_mask(network_in url = run_http_service + "/forwarded" send_http_requests(url, 1, "113.56.1.57:8080") assert discovered_service_has_expected_clients(run_ebpf_discovery_with_network_counters, url, - expected_internal_clients=0, - expected_external_clients=1, - expected_external_ipv4_16_networks=1, - expected_external_ipv4_24_networks=1, + expected_internal_clients=1, + expected_external_clients=0, + expected_external_ipv4_16_networks=0, + expected_external_ipv4_24_networks=0, expected_external_ipv6_networks=0) @pytest.mark.parametrize('network_interfaces', [[('dummy', 'eth19', '2001:db8:85a3::8a2e:370:7336', 64)]], indirect=True)