From 3d2dfeda844defd3c68b4eb161716e5c6b2324a9 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Mon, 18 Sep 2023 11:25:45 +0200 Subject: [PATCH 01/22] Added Utility to termine whether ipv4 is external local --- libebpfdiscovery/CMakeLists.txt | 6 +- .../headers/ebpfdiscovery/IpUtils.h | 29 ++ libebpfdiscovery/src/IpUtils.cpp | 264 ++++++++++++++++++ libebpfdiscovery/test/IpUtilsTest.cpp | 58 ++++ 4 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h create mode 100644 libebpfdiscovery/src/IpUtils.cpp create mode 100644 libebpfdiscovery/test/IpUtilsTest.cpp diff --git a/libebpfdiscovery/CMakeLists.txt b/libebpfdiscovery/CMakeLists.txt index 8cf81a6d..2ab72d4a 100644 --- a/libebpfdiscovery/CMakeLists.txt +++ b/libebpfdiscovery/CMakeLists.txt @@ -3,6 +3,7 @@ list( SOURCES src/Config.cpp src/Discovery.cpp + src/IpUtils.cpp src/Log.cpp src/Session.cpp src/StringFunctions.cpp @@ -11,7 +12,8 @@ set(TARGET ebpfdiscovery) add_library(${TARGET} STATIC ${SOURCES}) -target_include_directories(${TARGET} PRIVATE src PUBLIC headers) +target_include_directories(${TARGET} PRIVATE src PUBLIC headers /home/sten/.conan/data/elfutils/0.182.20220704-091150/ci/stable/package/849fae388172c7f2ee94c3a40101d1388f490a52/include /home/sten/.conan/data/gsl/2.0.0.20220628-132757/ci/stable/package/67a7e4f791f896d5af818c657f6da6304cdfff51/include ) + target_link_libraries(${TARGET} bpfload) target_link_libraries(${TARGET} ebpfdiscoveryshared) target_link_libraries(${TARGET} ebpfdiscoveryskel) @@ -20,7 +22,7 @@ target_link_libraries(${TARGET} httpparser) target_link_libraries(${TARGET} ebpfdiscoveryproto) if(BUILD_TESTS) - list(APPEND TEST_SOURCES test/StringFunctionsTest.cpp test/LRUCacheTest.cpp) + list(APPEND TEST_SOURCES test/StringFunctionsTest.cpp test/LRUCacheTest.cpp test/IpUtilsTest.cpp) set(TEST_TARGET test${TARGET}) add_executable(${TEST_TARGET} ${TEST_SOURCES}) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h new file mode 100644 index 00000000..ed3dfe11 --- /dev/null +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h @@ -0,0 +1,29 @@ +#include +#include + +using IPv4 = uint32_t; + +struct IpIfce { + std::vector ip; + std::vector broadcast; + uint32_t mask; + int index; + bool isLocalBridge; +}; + +class IpUtils { +protected: + std::vector localNetsIpv4; + std::vector::iterator bridgeEnd = localNetsIpv4.end(); + bool readAllIpAddrs(); + bool markLocalBridges(); + std::vector::iterator moveBridges(); + +public: + IpUtils() = default; + bool isAddresExternalLocal(IPv4 add); + void addIpIfce(IpIfce&& ifce); + void markBridge(int idx); + void printAll(); + bool readNetworks(); +}; diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpUtils.cpp new file mode 100644 index 00000000..23b9fcc7 --- /dev/null +++ b/libebpfdiscovery/src/IpUtils.cpp @@ -0,0 +1,264 @@ +#include "ebpfdiscovery/IpUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static constexpr uint32_t BUFLEN = 4096; +static constexpr uint32_t ipC = 0x0000a8c0; // 192.168.*.* +static constexpr uint32_t maskC = 0x0000ffff; +static constexpr uint32_t ipB = 0x000010ac; // 172.16-31.*.* +static constexpr uint32_t maskB = 0x0000f0ff; +static constexpr uint32_t ipA = 0x0000000a; // 10.*.*.* +static constexpr uint32_t maskA = 0x000000ff; + +static void logError(std::string_view prefix) { + std::cout << prefix << ": " << strerror(errno) << "\n"; +} + +static int get_ip(int fd, struct sockaddr_nl* sa, int domain) { + std::array buf{}; + + struct nlmsghdr* nl; + nl = (struct nlmsghdr*)buf.data(); + nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + nl->nlmsg_type = RTM_GETADDR; + nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + + struct ifaddrmsg* ifa; + ifa = (struct ifaddrmsg*)NLMSG_DATA(nl); + ifa->ifa_family = domain; // ipv4 or ipv6 + + struct iovec iov = {nl, nl->nlmsg_len}; + struct msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; + + return sendmsg(fd, &msg, 0); +} + +static void add_netlink_msg(struct nlmsghdr* nh, int type, const void* data, int raw_data_length) { + struct rtattr* rta; + int rta_length = RTA_LENGTH(raw_data_length); + + rta = (struct rtattr*)((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, raw_data_length); +} + +static int get_bridges(int fd, struct sockaddr_nl* sa, int domain) { + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char _[1024]; // required + } r; + + memset(&r, 0, sizeof(r)); + const char* dev_type = "bridge"; + + r.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct 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; + + struct rtattr* linkinfo = (struct rtattr*)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len)); + add_netlink_msg(&r.n, IFLA_LINKINFO, NULL, 0); + add_netlink_msg(&r.n, IFLA_INFO_KIND, dev_type, strlen(dev_type) + 1); + linkinfo->rta_len = (int)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len) - (char*)linkinfo); + + struct iovec iov = {&r.n, r.n.nlmsg_len}; + struct msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; + + return sendmsg(fd, &msg, 0); +} + +bool IpUtils::readNetworks() { + const bool ret = readAllIpAddrs(); + if (markLocalBridges()) { + bridgeEnd = moveBridges(); + } else { + bridgeEnd = localNetsIpv4.end(); + } + + return ret; +} + +std::vector::iterator IpUtils::moveBridges() { + return std::partition(localNetsIpv4.begin(), localNetsIpv4.end(), [](const auto& it) { return it.isLocalBridge; }); +} + +static int receive(int fd, struct sockaddr_nl* sa, void* buf, size_t len) { + struct iovec iov; + struct msghdr msg {}; + iov.iov_base = buf; + iov.iov_len = len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = sa; + msg.msg_namelen = sizeof(*sa); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + return recvmsg(fd, &msg, 0); +} + +static IpIfce parse_ifce(void* data, size_t len) { + IpIfce ifce{}; + struct ifaddrmsg* ifa = (struct ifaddrmsg*)data; + if (ifa->ifa_family != AF_INET) { + return {}; + } + + ifce.index = ifa->ifa_index; + ifce.mask = htonl(-1 << (32 - ifa->ifa_prefixlen)); + // int family = ifa->ifa_family; + struct rtattr* rta = (struct rtattr*)IFA_RTA(data); + + for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + struct in_addr* addr = (in_addr*)RTA_DATA(rta); + + if (rta->rta_type == IFA_ADDRESS) { + ifce.ip.push_back(addr->s_addr); + } + /* + if (rta->rta_type == IFA_LOCAL) { + printf("local address:\t%s\n", inet_ntop(family, addr, ips, INET_ADDRSTRLEN)); + }*/ + + if (rta->rta_type == IFA_BROADCAST) { + ifce.broadcast.push_back(addr->s_addr); + } + } + + return ifce; +} + +static int parse_ifi(void* data, size_t len) { + struct ifinfomsg* ifa = (struct ifinfomsg*)data; + return ifa->ifi_index; +} + +template +static uint32_t parse_nl_msg(void* buf, size_t len, F parse) { + const struct nlmsghdr* nl = (struct nlmsghdr*)buf; + + for (; NLMSG_OK(nl, len) && nl->nlmsg_type != NLMSG_DONE; nl = NLMSG_NEXT(nl, len)) { + if (nl->nlmsg_type == NLMSG_ERROR) { + printf("error"); + return -1; + } + + if (nl->nlmsg_type == RTM_NEWADDR || nl->nlmsg_type == RTM_NEWLINK) { + parse(NLMSG_DATA(nl), IFA_PAYLOAD(nl)); + continue; + } + } + return nl->nlmsg_type; +} + +template +static bool handleNetlink(S send, F f) { + + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd < 0) { + logError("socket"); + return false; + } + + auto const _ = gsl::finally([fd]() { ::close(fd); }); + struct sockaddr_nl sa; + memset(&sa, 0, sizeof(sa)); + sa.nl_family = AF_NETLINK; + + int len = send(fd, &sa, AF_INET); // To get ipv6, use AF_INET6 instead + if (len <= 0) { + logError("send"); + return false; + } + + uint32_t nl_msg_type; + do { + std::array buf{}; + len = receive(fd, &sa, buf.data(), BUFLEN); + if (len <= 0) { + logError("receive"); + break; + } + + nl_msg_type = parse_nl_msg(buf.data(), len, f); + + } while (nl_msg_type != NLMSG_DONE && nl_msg_type != NLMSG_ERROR); + + return true; +} + +bool IpUtils::readAllIpAddrs() { + return handleNetlink( + [](int fd, struct sockaddr_nl* sa, int domain) { return get_ip(fd, sa, AF_INET); }, + [this](void* buf, size_t len) { addIpIfce(parse_ifce(buf, len)); }); +} + +bool IpUtils::markLocalBridges() { + return handleNetlink( + [](int fd, struct sockaddr_nl* sa, int domain) { return get_bridges(fd, sa, AF_INET); }, + [this](void* buf, size_t len) { markBridge(parse_ifi(buf, len)); }); +} + +void IpUtils::addIpIfce(IpIfce&& ifce) { + char ifname[IF_NAMESIZE]; + if_indextoname(ifce.index, ifname); + if (strcmp(ifname, "lo") == 0) { + return; + } + localNetsIpv4.push_back(ifce); +} + +void IpUtils::markBridge(int idx) { + auto ifc = std::find_if(localNetsIpv4.begin(), localNetsIpv4.end(), [idx](const auto& it) { return it.index == idx; }); + if (ifc == localNetsIpv4.end()) { + return; + } + + ifc->isLocalBridge = true; +} + +void IpUtils::printAll() { + for (const auto& el : localNetsIpv4) { + std::cout << el.index << " " << std::hex << "0x" << el.mask << " " << el.isLocalBridge << " "; + for (const auto addr : el.ip) { + char ips[INET6_ADDRSTRLEN]; + std::cout << inet_ntop(AF_INET, &addr, ips, INET6_ADDRSTRLEN) << " " << std::hex << addr; + } + std::cout << "\n"; + } +} + +bool IpUtils::isAddresExternalLocal(IPv4 ip) { + + if ((ip & maskA) != ipA && (ip & maskB) != ipB && (ip & maskC) != ipC) { + return false; + } + + const bool bridgeRelated = std::any_of(localNetsIpv4.begin(), bridgeEnd, [ip](const auto& it) { + return std::any_of(it.ip.begin(), it.ip.end(), [ip, mask = it.mask](const auto& ip2) { return (ip & mask) == (ip2 & mask); }); + }); + + if (bridgeRelated) { + return false; + } + + return true; +} diff --git a/libebpfdiscovery/test/IpUtilsTest.cpp b/libebpfdiscovery/test/IpUtilsTest.cpp new file mode 100644 index 00000000..ce63e6b3 --- /dev/null +++ b/libebpfdiscovery/test/IpUtilsTest.cpp @@ -0,0 +1,58 @@ +#include +#include +#include "ebpfdiscovery/IpUtils.h" +#include + +class IpUtilsTest : public IpUtils { +protected: +public: + using IpUtils::IpUtils; + void addIfceConfig(std::initializer_list config) { + localNetsIpv4.insert(localNetsIpv4.end(), config.begin(), config.end()); + bridgeEnd = moveBridges(); + } +}; + + +TEST(IpUtils, RawTest) { + IpUtils u; + u.readNetworks(); + u.printAll(); + const char* ip = "10.2.4.5"; + std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; + ip = "172.17.4.5"; + std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; + ip = "172.16.4.5"; + std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; + ip = "192.168.4.5"; + std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; + EXPECT_TRUE(true); +} + +TEST(IpUtils, LocalBridgeIp) { + IpUtilsTest u; + u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); + u.printAll(); + EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("10.2.6.5"))); +} + +TEST(IpUtils, NOTLocalBridgeIp) { + IpUtilsTest u; + u.addIfceConfig({{{inet_addr("10.2..6.5")}, {}, 0x0000ffff, 0, true}}); + EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.3.34.2"))); +} + +TEST(IpUtils, SimpleClassATest) { + IpUtilsTest u; + EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("192.168.1.2"))); +} + +TEST(IpUtils, SimpleClassBTest) { + IpUtilsTest u; + EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("172.20.21.2"))); +} + +TEST(IpUtils, SimpleClassCtest) { + IpUtilsTest u; + EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.2.4.5"))); +} From 902275735b7c5ecca621948168e78ee3c49cd8f0 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Tue, 19 Sep 2023 11:05:36 +0200 Subject: [PATCH 02/22] Review fixes --- .../headers/ebpfdiscovery/IpUtils.h | 5 + libebpfdiscovery/src/IpUtils.cpp | 108 +++++++++--------- libebpfdiscovery/test/IpUtilsTest.cpp | 4 +- 3 files changed, 62 insertions(+), 55 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h index ed3dfe11..3a1f8dc0 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h @@ -1,6 +1,9 @@ +#pragma once #include #include +namespace ebpfdiscovery { + using IPv4 = uint32_t; struct IpIfce { @@ -27,3 +30,5 @@ class IpUtils { void printAll(); bool readNetworks(); }; +} + diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpUtils.cpp index 23b9fcc7..5e7347e3 100644 --- a/libebpfdiscovery/src/IpUtils.cpp +++ b/libebpfdiscovery/src/IpUtils.cpp @@ -25,30 +25,30 @@ static void logError(std::string_view prefix) { std::cout << prefix << ": " << strerror(errno) << "\n"; } -static int get_ip(int fd, struct sockaddr_nl* sa, int domain) { +static int getIp(int fd, sockaddr_nl* sa, int domain) { std::array buf{}; - struct nlmsghdr* nl; - nl = (struct nlmsghdr*)buf.data(); + nlmsghdr* nl; + nl = (nlmsghdr*) buf.data(); nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); nl->nlmsg_type = RTM_GETADDR; nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; - struct ifaddrmsg* ifa; - ifa = (struct ifaddrmsg*)NLMSG_DATA(nl); + ifaddrmsg* ifa; + ifa = (ifaddrmsg*)NLMSG_DATA(nl); ifa->ifa_family = domain; // ipv4 or ipv6 - struct iovec iov = {nl, nl->nlmsg_len}; - struct msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; + iovec iov = {nl, nl->nlmsg_len}; + msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; return sendmsg(fd, &msg, 0); } -static void add_netlink_msg(struct nlmsghdr* nh, int type, const void* data, int raw_data_length) { +static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int raw_data_length) { struct rtattr* rta; int rta_length = RTA_LENGTH(raw_data_length); - rta = (struct rtattr*)((char*)nh + NLMSG_ALIGN(nh->nlmsg_len)); + rta = (rtattr*)((char*)nh + NLMSG_ALIGN(nh->nlmsg_len)); rta->rta_type = type; rta->rta_len = rta_length; @@ -57,56 +57,40 @@ static void add_netlink_msg(struct nlmsghdr* nh, int type, const void* data, int memcpy(RTA_DATA(rta), data, raw_data_length); } -static int get_bridges(int fd, struct sockaddr_nl* sa, int domain) { +static int getBridges(int fd, sockaddr_nl* sa, int domain) { struct { struct nlmsghdr n; struct ifinfomsg i; char _[1024]; // required - } r; + } r{}; - memset(&r, 0, sizeof(r)); const char* dev_type = "bridge"; - r.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + 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; - struct rtattr* linkinfo = (struct rtattr*)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len)); - add_netlink_msg(&r.n, IFLA_LINKINFO, NULL, 0); - add_netlink_msg(&r.n, IFLA_INFO_KIND, dev_type, strlen(dev_type) + 1); + rtattr* linkinfo = (rtattr*)((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)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len) - (char*)linkinfo); - struct iovec iov = {&r.n, r.n.nlmsg_len}; - struct msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; + iovec iov = {&r.n, r.n.nlmsg_len}; + msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; return sendmsg(fd, &msg, 0); } -bool IpUtils::readNetworks() { - const bool ret = readAllIpAddrs(); - if (markLocalBridges()) { - bridgeEnd = moveBridges(); - } else { - bridgeEnd = localNetsIpv4.end(); - } - return ret; -} - -std::vector::iterator IpUtils::moveBridges() { - return std::partition(localNetsIpv4.begin(), localNetsIpv4.end(), [](const auto& it) { return it.isLocalBridge; }); -} - -static int receive(int fd, struct sockaddr_nl* sa, void* buf, size_t len) { - struct iovec iov; - struct msghdr msg {}; +static int receive(int fd, sockaddr_nl* sa, void* buf, size_t len) { + iovec iov; + msghdr msg {}; iov.iov_base = buf; iov.iov_len = len; - memset(&msg, 0, sizeof(msg)); msg.msg_name = sa; msg.msg_namelen = sizeof(*sa); msg.msg_iov = &iov; @@ -115,9 +99,9 @@ static int receive(int fd, struct sockaddr_nl* sa, void* buf, size_t len) { return recvmsg(fd, &msg, 0); } -static IpIfce parse_ifce(void* data, size_t len) { - IpIfce ifce{}; - struct ifaddrmsg* ifa = (struct ifaddrmsg*)data; +static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { + ebpfdiscovery::IpIfce ifce{}; + ifaddrmsg* ifa = (ifaddrmsg*)data; if (ifa->ifa_family != AF_INET) { return {}; } @@ -125,10 +109,10 @@ static IpIfce parse_ifce(void* data, size_t len) { ifce.index = ifa->ifa_index; ifce.mask = htonl(-1 << (32 - ifa->ifa_prefixlen)); // int family = ifa->ifa_family; - struct rtattr* rta = (struct rtattr*)IFA_RTA(data); + rtattr* rta = (rtattr*)IFA_RTA(data); for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { - struct in_addr* addr = (in_addr*)RTA_DATA(rta); + in_addr* addr = (in_addr*)RTA_DATA(rta); if (rta->rta_type == IFA_ADDRESS) { ifce.ip.push_back(addr->s_addr); @@ -146,14 +130,30 @@ static IpIfce parse_ifce(void* data, size_t len) { return ifce; } -static int parse_ifi(void* data, size_t len) { - struct ifinfomsg* ifa = (struct ifinfomsg*)data; +static int parseIfi(void* data, size_t len) { + ifinfomsg* ifa = (ifinfomsg*)data; return ifa->ifi_index; } +namespace ebpfdiscovery { +bool IpUtils::readNetworks() { + const bool ret = readAllIpAddrs(); + if (markLocalBridges()) { + bridgeEnd = moveBridges(); + } else { + bridgeEnd = localNetsIpv4.end(); + } + + return ret; +} + +std::vector::iterator IpUtils::moveBridges() { + return std::partition(localNetsIpv4.begin(), localNetsIpv4.end(), [](const auto& it) { return it.isLocalBridge; }); +} + template -static uint32_t parse_nl_msg(void* buf, size_t len, F parse) { - const struct nlmsghdr* nl = (struct nlmsghdr*)buf; +static uint32_t parseNlMsg(void* buf, size_t len, F parse) { + const nlmsghdr* nl = (nlmsghdr*)buf; for (; NLMSG_OK(nl, len) && nl->nlmsg_type != NLMSG_DONE; nl = NLMSG_NEXT(nl, len)) { if (nl->nlmsg_type == NLMSG_ERROR) { @@ -170,7 +170,7 @@ static uint32_t parse_nl_msg(void* buf, size_t len, F parse) { } template -static bool handleNetlink(S send, F f) { +static bool handleNetlink(S send, F f, int domain) { int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { @@ -179,11 +179,10 @@ static bool handleNetlink(S send, F f) { } auto const _ = gsl::finally([fd]() { ::close(fd); }); - struct sockaddr_nl sa; - memset(&sa, 0, sizeof(sa)); + sockaddr_nl sa{}; sa.nl_family = AF_NETLINK; - int len = send(fd, &sa, AF_INET); // To get ipv6, use AF_INET6 instead + int len = send(fd, &sa, domain); if (len <= 0) { logError("send"); return false; @@ -198,7 +197,7 @@ static bool handleNetlink(S send, F f) { break; } - nl_msg_type = parse_nl_msg(buf.data(), len, f); + nl_msg_type = parseNlMsg(buf.data(), len, f); } while (nl_msg_type != NLMSG_DONE && nl_msg_type != NLMSG_ERROR); @@ -207,14 +206,14 @@ static bool handleNetlink(S send, F f) { bool IpUtils::readAllIpAddrs() { return handleNetlink( - [](int fd, struct sockaddr_nl* sa, int domain) { return get_ip(fd, sa, AF_INET); }, - [this](void* buf, size_t len) { addIpIfce(parse_ifce(buf, len)); }); + [](int fd, sockaddr_nl* sa, int domain) { return getIp(fd, sa, AF_INET); }, + [this](void* buf, size_t len) { addIpIfce(parseIfce(buf, len)); }, AF_INET); } bool IpUtils::markLocalBridges() { return handleNetlink( - [](int fd, struct sockaddr_nl* sa, int domain) { return get_bridges(fd, sa, AF_INET); }, - [this](void* buf, size_t len) { markBridge(parse_ifi(buf, len)); }); + [](int fd, sockaddr_nl* sa, int domain) { return getBridges(fd, sa, AF_INET); }, + [this](void* buf, size_t len) { markBridge(parseIfi(buf, len)); }, AF_INET); } void IpUtils::addIpIfce(IpIfce&& ifce) { @@ -262,3 +261,4 @@ bool IpUtils::isAddresExternalLocal(IPv4 ip) { return true; } +} diff --git a/libebpfdiscovery/test/IpUtilsTest.cpp b/libebpfdiscovery/test/IpUtilsTest.cpp index ce63e6b3..1821f52d 100644 --- a/libebpfdiscovery/test/IpUtilsTest.cpp +++ b/libebpfdiscovery/test/IpUtilsTest.cpp @@ -1,8 +1,10 @@ +#include "ebpfdiscovery/IpUtils.h" #include #include -#include "ebpfdiscovery/IpUtils.h" #include +using namespace ebpfdiscovery; + class IpUtilsTest : public IpUtils { protected: public: From 91a0fac5d8f5bc18763889582b45b61c202248fa Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Thu, 21 Sep 2023 09:08:20 +0200 Subject: [PATCH 03/22] CMakeLists cleanup --- libebpfdiscovery/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libebpfdiscovery/CMakeLists.txt b/libebpfdiscovery/CMakeLists.txt index 2ab72d4a..beccc29e 100644 --- a/libebpfdiscovery/CMakeLists.txt +++ b/libebpfdiscovery/CMakeLists.txt @@ -12,7 +12,7 @@ set(TARGET ebpfdiscovery) add_library(${TARGET} STATIC ${SOURCES}) -target_include_directories(${TARGET} PRIVATE src PUBLIC headers /home/sten/.conan/data/elfutils/0.182.20220704-091150/ci/stable/package/849fae388172c7f2ee94c3a40101d1388f490a52/include /home/sten/.conan/data/gsl/2.0.0.20220628-132757/ci/stable/package/67a7e4f791f896d5af818c657f6da6304cdfff51/include ) +target_include_directories(${TARGET} PRIVATE src PUBLIC headers) target_link_libraries(${TARGET} bpfload) target_link_libraries(${TARGET} ebpfdiscoveryshared) From 46c889372b059799b99ee9682b47c52bb3a8ac01 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Thu, 21 Sep 2023 10:58:56 +0200 Subject: [PATCH 04/22] Added gsl to conanfile --- CMakeLists.txt | 5 +++++ conanfile.txt | 1 + 2 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfb6a14d..d5e9f8f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,11 @@ endif(NOT TARGET fmt) find_package(Protobuf REQUIRED) +find_package(gsl REQUIRED) +if(gsl_FOUND) + include_directories(${gsl_INCLUDE_DIRS}) +endif() + if(BUILD_TESTS) include(FetchContent) FetchContent_Declare(googletest URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip) diff --git a/conanfile.txt b/conanfile.txt index b87a7d88..44949d63 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,6 +1,7 @@ [requires] protobuf/3.21.9 protobuf-c/1.4.1 +gsl/2.0.0.20220628-132757@ci/stable [generators] CMakeDeps CMakeToolchain From 3214d30a1eddb03bb7c9b9be013fa573dadc03f3 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Thu, 21 Sep 2023 11:07:09 +0200 Subject: [PATCH 05/22] Cleanup --- libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h | 2 +- libebpfdiscovery/src/IpUtils.cpp | 12 ++++-------- libebpfdiscovery/test/IpUtilsTest.cpp | 16 ---------------- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h index 3a1f8dc0..db3d11a9 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h @@ -24,7 +24,7 @@ class IpUtils { public: IpUtils() = default; - bool isAddresExternalLocal(IPv4 add); + bool isAddresExternalLocal(IPv4 addr); void addIpIfce(IpIfce&& ifce); void markBridge(int idx); void printAll(); diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpUtils.cpp index 5e7347e3..a0a77d51 100644 --- a/libebpfdiscovery/src/IpUtils.cpp +++ b/libebpfdiscovery/src/IpUtils.cpp @@ -117,10 +117,6 @@ static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { if (rta->rta_type == IFA_ADDRESS) { ifce.ip.push_back(addr->s_addr); } - /* - if (rta->rta_type == IFA_LOCAL) { - printf("local address:\t%s\n", inet_ntop(family, addr, ips, INET_ADDRSTRLEN)); - }*/ if (rta->rta_type == IFA_BROADCAST) { ifce.broadcast.push_back(addr->s_addr); @@ -245,14 +241,14 @@ void IpUtils::printAll() { } } -bool IpUtils::isAddresExternalLocal(IPv4 ip) { +bool IpUtils::isAddresExternalLocal(IPv4 addr) { - if ((ip & maskA) != ipA && (ip & maskB) != ipB && (ip & maskC) != ipC) { + if ((addr & maskA) != ipA && (addr & maskB) != ipB && (addr & maskC) != ipC) { return false; } - const bool bridgeRelated = std::any_of(localNetsIpv4.begin(), bridgeEnd, [ip](const auto& it) { - return std::any_of(it.ip.begin(), it.ip.end(), [ip, mask = it.mask](const auto& ip2) { return (ip & mask) == (ip2 & mask); }); + const bool bridgeRelated = std::any_of(localNetsIpv4.begin(), bridgeEnd, [addr](const auto& it) { + return std::any_of(it.ip.begin(), it.ip.end(), [addr, mask = it.mask](const auto& ip) { return (addr & mask) == (ip & mask); }); }); if (bridgeRelated) { diff --git a/libebpfdiscovery/test/IpUtilsTest.cpp b/libebpfdiscovery/test/IpUtilsTest.cpp index 1821f52d..17ea600b 100644 --- a/libebpfdiscovery/test/IpUtilsTest.cpp +++ b/libebpfdiscovery/test/IpUtilsTest.cpp @@ -15,22 +15,6 @@ class IpUtilsTest : public IpUtils { } }; - -TEST(IpUtils, RawTest) { - IpUtils u; - u.readNetworks(); - u.printAll(); - const char* ip = "10.2.4.5"; - std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; - ip = "172.17.4.5"; - std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; - ip = "172.16.4.5"; - std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; - ip = "192.168.4.5"; - std::cout << "E " << ip << " " << u.isAddresExternalLocal(inet_addr(ip)) << "\n"; - EXPECT_TRUE(true); -} - TEST(IpUtils, LocalBridgeIp) { IpUtilsTest u; u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); From b37586927d8aebac035196f51a71156655772ce2 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Thu, 21 Sep 2023 11:48:21 +0200 Subject: [PATCH 06/22] Added recognizing ipv4 link local addresses --- libebpfdiscovery/src/IpUtils.cpp | 6 ++++++ libebpfdiscovery/test/IpUtilsTest.cpp | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpUtils.cpp index a0a77d51..46cd418a 100644 --- a/libebpfdiscovery/src/IpUtils.cpp +++ b/libebpfdiscovery/src/IpUtils.cpp @@ -20,6 +20,8 @@ static constexpr uint32_t ipB = 0x000010ac; // 172.16-31.*.* static constexpr uint32_t maskB = 0x0000f0ff; static constexpr uint32_t ipA = 0x0000000a; // 10.*.*.* static constexpr uint32_t maskA = 0x000000ff; +static constexpr uint32_t ipLinkLocal = 0x0000fea9; // 169.254.*.* +static constexpr uint32_t maskLinkLocal = 0x0000ffff; static void logError(std::string_view prefix) { std::cout << prefix << ": " << strerror(errno) << "\n"; @@ -247,6 +249,10 @@ bool IpUtils::isAddresExternalLocal(IPv4 addr) { return false; } + if ((addr & maskLinkLocal) == ipLinkLocal) { + return false; + } + const bool bridgeRelated = std::any_of(localNetsIpv4.begin(), bridgeEnd, [addr](const auto& it) { return std::any_of(it.ip.begin(), it.ip.end(), [addr, mask = it.mask](const auto& ip) { return (addr & mask) == (ip & mask); }); }); diff --git a/libebpfdiscovery/test/IpUtilsTest.cpp b/libebpfdiscovery/test/IpUtilsTest.cpp index 17ea600b..f751a42e 100644 --- a/libebpfdiscovery/test/IpUtilsTest.cpp +++ b/libebpfdiscovery/test/IpUtilsTest.cpp @@ -15,6 +15,7 @@ class IpUtilsTest : public IpUtils { } }; + TEST(IpUtils, LocalBridgeIp) { IpUtilsTest u; u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); @@ -24,7 +25,7 @@ TEST(IpUtils, LocalBridgeIp) { TEST(IpUtils, NOTLocalBridgeIp) { IpUtilsTest u; - u.addIfceConfig({{{inet_addr("10.2..6.5")}, {}, 0x0000ffff, 0, true}}); + u.addIfceConfig({{{inet_addr("10.2.6.5")}, {}, 0x0000ffff, 0, true}}); EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.3.34.2"))); } @@ -42,3 +43,14 @@ TEST(IpUtils, SimpleClassCtest) { IpUtilsTest u; EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.2.4.5"))); } + +TEST(IpUtils, SimpleLinkLocal) { + IpUtilsTest u; + EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("169.254.76.6"))); +} + + +TEST(IpUtils, SimplePublicIp) { + IpUtilsTest u; + EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("170.254.76.6"))); +} From 2a6619c18cea8f5a9196278120bc4f5e6abf9b96 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Thu, 21 Sep 2023 13:41:04 +0200 Subject: [PATCH 07/22] Review cleanup, changed naming --- .../headers/ebpfdiscovery/IpUtils.h | 5 +- libebpfdiscovery/src/IpUtils.cpp | 60 +++++++++---------- libebpfdiscovery/test/IpUtilsTest.cpp | 19 +++--- 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h index db3d11a9..229a53a7 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 #pragma once #include #include @@ -14,7 +15,7 @@ struct IpIfce { bool isLocalBridge; }; -class IpUtils { +class IpAddressChecker { protected: std::vector localNetsIpv4; std::vector::iterator bridgeEnd = localNetsIpv4.end(); @@ -23,7 +24,7 @@ class IpUtils { std::vector::iterator moveBridges(); public: - IpUtils() = default; + IpAddressChecker() = default; bool isAddresExternalLocal(IPv4 addr); void addIpIfce(IpIfce&& ifce); void markBridge(int idx); diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpUtils.cpp index 46cd418a..77074f09 100644 --- a/libebpfdiscovery/src/IpUtils.cpp +++ b/libebpfdiscovery/src/IpUtils.cpp @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 #include "ebpfdiscovery/IpUtils.h" #include @@ -23,21 +24,21 @@ static constexpr uint32_t maskA = 0x000000ff; static constexpr uint32_t ipLinkLocal = 0x0000fea9; // 169.254.*.* static constexpr uint32_t maskLinkLocal = 0x0000ffff; -static void logError(std::string_view prefix) { +static void logErrorFromErrno(std::string_view prefix) { std::cout << prefix << ": " << strerror(errno) << "\n"; } -static int getIp(int fd, sockaddr_nl* sa, int domain) { +static int sendIpAddrRequest(int fd, sockaddr_nl* sa, int domain) { std::array buf{}; nlmsghdr* nl; - nl = (nlmsghdr*) buf.data(); + nl = reinterpret_cast(buf.data()); nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); nl->nlmsg_type = RTM_GETADDR; nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; ifaddrmsg* ifa; - ifa = (ifaddrmsg*)NLMSG_DATA(nl); + ifa = reinterpret_cast(NLMSG_DATA(nl)); ifa->ifa_family = domain; // ipv4 or ipv6 iovec iov = {nl, nl->nlmsg_len}; @@ -50,7 +51,7 @@ static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int raw_data struct rtattr* rta; int rta_length = RTA_LENGTH(raw_data_length); - rta = (rtattr*)((char*)nh + NLMSG_ALIGN(nh->nlmsg_len)); + rta = reinterpret_cast((char*)nh + NLMSG_ALIGN(nh->nlmsg_len)); rta->rta_type = type; rta->rta_len = rta_length; @@ -59,7 +60,7 @@ static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int raw_data memcpy(RTA_DATA(rta), data, raw_data_length); } -static int getBridges(int fd, sockaddr_nl* sa, int domain) { +static int sendBridgesRequest(int fd, sockaddr_nl* sa, int domain) { struct { struct nlmsghdr n; struct ifinfomsg i; @@ -75,7 +76,7 @@ static int getBridges(int fd, sockaddr_nl* sa, int domain) { r.n.nlmsg_pid = 0; r.n.nlmsg_seq = 0; - rtattr* linkinfo = (rtattr*)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len)); + 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)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len) - (char*)linkinfo); @@ -103,7 +104,7 @@ static int receive(int fd, sockaddr_nl* sa, void* buf, size_t len) { static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { ebpfdiscovery::IpIfce ifce{}; - ifaddrmsg* ifa = (ifaddrmsg*)data; + ifaddrmsg* ifa = reinterpret_cast(data); if (ifa->ifa_family != AF_INET) { return {}; } @@ -111,10 +112,10 @@ static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { ifce.index = ifa->ifa_index; ifce.mask = htonl(-1 << (32 - ifa->ifa_prefixlen)); // int family = ifa->ifa_family; - rtattr* rta = (rtattr*)IFA_RTA(data); + rtattr* rta = reinterpret_cast(IFA_RTA(data)); for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { - in_addr* addr = (in_addr*)RTA_DATA(rta); + in_addr* addr = reinterpret_cast(RTA_DATA(rta)); if (rta->rta_type == IFA_ADDRESS) { ifce.ip.push_back(addr->s_addr); @@ -128,13 +129,13 @@ static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { return ifce; } -static int parseIfi(void* data, size_t len) { - ifinfomsg* ifa = (ifinfomsg*)data; +static int getIfIndex(void* data, size_t len) { + ifinfomsg* ifa = reinterpret_cast(data); return ifa->ifi_index; } namespace ebpfdiscovery { -bool IpUtils::readNetworks() { +bool IpAddressChecker::readNetworks() { const bool ret = readAllIpAddrs(); if (markLocalBridges()) { bridgeEnd = moveBridges(); @@ -145,17 +146,16 @@ bool IpUtils::readNetworks() { return ret; } -std::vector::iterator IpUtils::moveBridges() { +std::vector::iterator IpAddressChecker::moveBridges() { return std::partition(localNetsIpv4.begin(), localNetsIpv4.end(), [](const auto& it) { return it.isLocalBridge; }); } template static uint32_t parseNlMsg(void* buf, size_t len, F parse) { - const nlmsghdr* nl = (nlmsghdr*)buf; + const nlmsghdr* nl = reinterpret_cast(buf); for (; NLMSG_OK(nl, len) && nl->nlmsg_type != NLMSG_DONE; nl = NLMSG_NEXT(nl, len)) { if (nl->nlmsg_type == NLMSG_ERROR) { - printf("error"); return -1; } @@ -169,10 +169,9 @@ static uint32_t parseNlMsg(void* buf, size_t len, F parse) { template static bool handleNetlink(S send, F f, int domain) { - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { - logError("socket"); + logErrorFromErrno("socket"); return false; } @@ -182,7 +181,7 @@ static bool handleNetlink(S send, F f, int domain) { int len = send(fd, &sa, domain); if (len <= 0) { - logError("send"); + logErrorFromErrno("send"); return false; } @@ -191,7 +190,7 @@ static bool handleNetlink(S send, F f, int domain) { std::array buf{}; len = receive(fd, &sa, buf.data(), BUFLEN); if (len <= 0) { - logError("receive"); + logErrorFromErrno("receive"); break; } @@ -202,19 +201,19 @@ static bool handleNetlink(S send, F f, int domain) { return true; } -bool IpUtils::readAllIpAddrs() { +bool IpAddressChecker::readAllIpAddrs() { return handleNetlink( - [](int fd, sockaddr_nl* sa, int domain) { return getIp(fd, sa, AF_INET); }, + [](int fd, sockaddr_nl* sa, int domain) { return sendIpAddrRequest(fd, sa, AF_INET); }, [this](void* buf, size_t len) { addIpIfce(parseIfce(buf, len)); }, AF_INET); } -bool IpUtils::markLocalBridges() { +bool IpAddressChecker::markLocalBridges() { return handleNetlink( - [](int fd, sockaddr_nl* sa, int domain) { return getBridges(fd, sa, AF_INET); }, - [this](void* buf, size_t len) { markBridge(parseIfi(buf, len)); }, AF_INET); + [](int fd, sockaddr_nl* sa, int domain) { return sendBridgesRequest(fd, sa, AF_INET); }, + [this](void* buf, size_t len) { markBridge(getIfIndex(buf, len)); }, AF_INET); } -void IpUtils::addIpIfce(IpIfce&& ifce) { +void IpAddressChecker::addIpIfce(IpIfce&& ifce) { char ifname[IF_NAMESIZE]; if_indextoname(ifce.index, ifname); if (strcmp(ifname, "lo") == 0) { @@ -223,7 +222,7 @@ void IpUtils::addIpIfce(IpIfce&& ifce) { localNetsIpv4.push_back(ifce); } -void IpUtils::markBridge(int idx) { +void IpAddressChecker::markBridge(int idx) { auto ifc = std::find_if(localNetsIpv4.begin(), localNetsIpv4.end(), [idx](const auto& it) { return it.index == idx; }); if (ifc == localNetsIpv4.end()) { return; @@ -232,7 +231,7 @@ void IpUtils::markBridge(int idx) { ifc->isLocalBridge = true; } -void IpUtils::printAll() { +void IpAddressChecker::printAll() { for (const auto& el : localNetsIpv4) { std::cout << el.index << " " << std::hex << "0x" << el.mask << " " << el.isLocalBridge << " "; for (const auto addr : el.ip) { @@ -243,9 +242,10 @@ void IpUtils::printAll() { } } -bool IpUtils::isAddresExternalLocal(IPv4 addr) { +bool IpAddressChecker::isAddresExternalLocal(IPv4 addr) { + const bool isPublic = ((addr & maskA) != ipA) && ((addr & maskB) != ipB) && ((addr & maskC) != ipC); - if ((addr & maskA) != ipA && (addr & maskB) != ipB && (addr & maskC) != ipC) { + if (isPublic) { return false; } diff --git a/libebpfdiscovery/test/IpUtilsTest.cpp b/libebpfdiscovery/test/IpUtilsTest.cpp index f751a42e..20df713b 100644 --- a/libebpfdiscovery/test/IpUtilsTest.cpp +++ b/libebpfdiscovery/test/IpUtilsTest.cpp @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 #include "ebpfdiscovery/IpUtils.h" #include #include @@ -5,10 +6,10 @@ using namespace ebpfdiscovery; -class IpUtilsTest : public IpUtils { +class IpAddressCheckerTest : public IpAddressChecker { protected: public: - using IpUtils::IpUtils; + using IpAddressChecker::IpAddressChecker; void addIfceConfig(std::initializer_list config) { localNetsIpv4.insert(localNetsIpv4.end(), config.begin(), config.end()); bridgeEnd = moveBridges(); @@ -17,40 +18,40 @@ class IpUtilsTest : public IpUtils { TEST(IpUtils, LocalBridgeIp) { - IpUtilsTest u; + IpAddressCheckerTest u; u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); u.printAll(); EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("10.2.6.5"))); } TEST(IpUtils, NOTLocalBridgeIp) { - IpUtilsTest u; + IpAddressCheckerTest u; u.addIfceConfig({{{inet_addr("10.2.6.5")}, {}, 0x0000ffff, 0, true}}); EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.3.34.2"))); } TEST(IpUtils, SimpleClassATest) { - IpUtilsTest u; + IpAddressCheckerTest u; EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("192.168.1.2"))); } TEST(IpUtils, SimpleClassBTest) { - IpUtilsTest u; + IpAddressCheckerTest u; EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("172.20.21.2"))); } TEST(IpUtils, SimpleClassCtest) { - IpUtilsTest u; + IpAddressCheckerTest u; EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.2.4.5"))); } TEST(IpUtils, SimpleLinkLocal) { - IpUtilsTest u; + IpAddressCheckerTest u; EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("169.254.76.6"))); } TEST(IpUtils, SimplePublicIp) { - IpUtilsTest u; + IpAddressCheckerTest u; EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("170.254.76.6"))); } From c2995143841e03e4cfdbe182801978e5152effb4 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Fri, 22 Sep 2023 11:52:13 +0200 Subject: [PATCH 08/22] Naming changed --- libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h | 2 +- libebpfdiscovery/src/IpUtils.cpp | 2 +- libebpfdiscovery/test/IpUtilsTest.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h index 229a53a7..78660c5f 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h @@ -25,7 +25,7 @@ class IpAddressChecker { public: IpAddressChecker() = default; - bool isAddresExternalLocal(IPv4 addr); + bool isAddressExternalLocal(IPv4 addr); void addIpIfce(IpIfce&& ifce); void markBridge(int idx); void printAll(); diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpUtils.cpp index 77074f09..f0273101 100644 --- a/libebpfdiscovery/src/IpUtils.cpp +++ b/libebpfdiscovery/src/IpUtils.cpp @@ -242,7 +242,7 @@ void IpAddressChecker::printAll() { } } -bool IpAddressChecker::isAddresExternalLocal(IPv4 addr) { +bool IpAddressChecker::isAddressExternalLocal(IPv4 addr) { const bool isPublic = ((addr & maskA) != ipA) && ((addr & maskB) != ipB) && ((addr & maskC) != ipC); if (isPublic) { diff --git a/libebpfdiscovery/test/IpUtilsTest.cpp b/libebpfdiscovery/test/IpUtilsTest.cpp index 20df713b..2500d26d 100644 --- a/libebpfdiscovery/test/IpUtilsTest.cpp +++ b/libebpfdiscovery/test/IpUtilsTest.cpp @@ -21,37 +21,37 @@ TEST(IpUtils, LocalBridgeIp) { IpAddressCheckerTest u; u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); u.printAll(); - EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("10.2.6.5"))); + EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("10.2.6.5"))); } TEST(IpUtils, NOTLocalBridgeIp) { IpAddressCheckerTest u; u.addIfceConfig({{{inet_addr("10.2.6.5")}, {}, 0x0000ffff, 0, true}}); - EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.3.34.2"))); + EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("10.3.34.2"))); } TEST(IpUtils, SimpleClassATest) { IpAddressCheckerTest u; - EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("192.168.1.2"))); + EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("192.168.1.2"))); } TEST(IpUtils, SimpleClassBTest) { IpAddressCheckerTest u; - EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("172.20.21.2"))); + EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("172.20.21.2"))); } TEST(IpUtils, SimpleClassCtest) { IpAddressCheckerTest u; - EXPECT_TRUE(u.isAddresExternalLocal(inet_addr("10.2.4.5"))); + EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("10.2.4.5"))); } TEST(IpUtils, SimpleLinkLocal) { IpAddressCheckerTest u; - EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("169.254.76.6"))); + EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("169.254.76.6"))); } TEST(IpUtils, SimplePublicIp) { IpAddressCheckerTest u; - EXPECT_FALSE(u.isAddresExternalLocal(inet_addr("170.254.76.6"))); + EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("170.254.76.6"))); } From 49c5dccb321392a08c8b7d26169b765c319fd63f Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Fri, 22 Sep 2023 14:52:32 +0200 Subject: [PATCH 09/22] Function split --- libebpfdiscovery/src/IpUtils.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpUtils.cpp index f0273101..a62e657f 100644 --- a/libebpfdiscovery/src/IpUtils.cpp +++ b/libebpfdiscovery/src/IpUtils.cpp @@ -102,16 +102,11 @@ static int receive(int fd, sockaddr_nl* sa, void* buf, size_t len) { return recvmsg(fd, &msg, 0); } -static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { +static ebpfdiscovery::IpIfce parseIfceIPv4(void* data, size_t len) { ebpfdiscovery::IpIfce ifce{}; ifaddrmsg* ifa = reinterpret_cast(data); - if (ifa->ifa_family != AF_INET) { - return {}; - } - ifce.index = ifa->ifa_index; ifce.mask = htonl(-1 << (32 - ifa->ifa_prefixlen)); - // int family = ifa->ifa_family; rtattr* rta = reinterpret_cast(IFA_RTA(data)); for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { @@ -129,6 +124,14 @@ static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { return ifce; } +static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { + if (reinterpret_cast(data)->ifa_family != AF_INET) { + return {}; + } + + return parseIfceIPv4(data, len); +} + static int getIfIndex(void* data, size_t len) { ifinfomsg* ifa = reinterpret_cast(data); return ifa->ifi_index; From fcdab860b3e61643fb30ad70986bb024180b4beb Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Mon, 25 Sep 2023 10:13:10 +0200 Subject: [PATCH 10/22] Conanfile gsl changed name originated from conan.io, File rename --- conanfile.txt | 2 +- libebpfdiscovery/CMakeLists.txt | 4 ++-- .../headers/ebpfdiscovery/{IpUtils.h => IpAddressChecker.h} | 0 libebpfdiscovery/src/{IpUtils.cpp => IpAddressChecker.cpp} | 2 +- .../test/{IpUtilsTest.cpp => IpAddressCheckerTest.cpp} | 3 +-- 5 files changed, 5 insertions(+), 6 deletions(-) rename libebpfdiscovery/headers/ebpfdiscovery/{IpUtils.h => IpAddressChecker.h} (100%) rename libebpfdiscovery/src/{IpUtils.cpp => IpAddressChecker.cpp} (99%) rename libebpfdiscovery/test/{IpUtilsTest.cpp => IpAddressCheckerTest.cpp} (97%) diff --git a/conanfile.txt b/conanfile.txt index 44949d63..a83c7fe1 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,7 +1,7 @@ [requires] protobuf/3.21.9 protobuf-c/1.4.1 -gsl/2.0.0.20220628-132757@ci/stable +ms-gsl/4.0.0 [generators] CMakeDeps CMakeToolchain diff --git a/libebpfdiscovery/CMakeLists.txt b/libebpfdiscovery/CMakeLists.txt index beccc29e..51e66aaf 100644 --- a/libebpfdiscovery/CMakeLists.txt +++ b/libebpfdiscovery/CMakeLists.txt @@ -3,7 +3,7 @@ list( SOURCES src/Config.cpp src/Discovery.cpp - src/IpUtils.cpp + src/IpAddressChecker.cpp src/Log.cpp src/Session.cpp src/StringFunctions.cpp @@ -22,7 +22,7 @@ target_link_libraries(${TARGET} httpparser) target_link_libraries(${TARGET} ebpfdiscoveryproto) if(BUILD_TESTS) - list(APPEND TEST_SOURCES test/StringFunctionsTest.cpp test/LRUCacheTest.cpp test/IpUtilsTest.cpp) + list(APPEND TEST_SOURCES test/StringFunctionsTest.cpp test/LRUCacheTest.cpp test/IpAddressCheckerTest.cpp) set(TEST_TARGET test${TARGET}) add_executable(${TEST_TARGET} ${TEST_SOURCES}) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h similarity index 100% rename from libebpfdiscovery/headers/ebpfdiscovery/IpUtils.h rename to libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h diff --git a/libebpfdiscovery/src/IpUtils.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp similarity index 99% rename from libebpfdiscovery/src/IpUtils.cpp rename to libebpfdiscovery/src/IpAddressChecker.cpp index a62e657f..4dad5c53 100644 --- a/libebpfdiscovery/src/IpUtils.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -#include "ebpfdiscovery/IpUtils.h" +#include "ebpfdiscovery/IpAddressChecker.h" #include #include diff --git a/libebpfdiscovery/test/IpUtilsTest.cpp b/libebpfdiscovery/test/IpAddressCheckerTest.cpp similarity index 97% rename from libebpfdiscovery/test/IpUtilsTest.cpp rename to libebpfdiscovery/test/IpAddressCheckerTest.cpp index 2500d26d..c407ce6b 100644 --- a/libebpfdiscovery/test/IpUtilsTest.cpp +++ b/libebpfdiscovery/test/IpAddressCheckerTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -#include "ebpfdiscovery/IpUtils.h" +#include "ebpfdiscovery/IpAddressChecker.h" #include #include #include @@ -16,7 +16,6 @@ class IpAddressCheckerTest : public IpAddressChecker { } }; - TEST(IpUtils, LocalBridgeIp) { IpAddressCheckerTest u; u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); From 605f5284a3b5b6d2a762da6d16b03884c63074e8 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Mon, 25 Sep 2023 11:06:47 +0200 Subject: [PATCH 11/22] GSL package name fix --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11216dd0..87ebfc34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,9 +73,9 @@ endif(NOT TARGET fmt) find_package(Protobuf REQUIRED) -find_package(gsl REQUIRED) -if(gsl_FOUND) - include_directories(${gsl_INCLUDE_DIRS}) +find_package(Microsoft.GSL REQUIRED) +if(Microsoft.GSL_FOUND) + include_directories(${Microsoft.GSL_INCLUDE_DIRS}) endif() if(BUILD_TESTS) From e6e7354f62d42b925463ddcdc47f7bd8e42dfc3a Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Mon, 25 Sep 2023 11:32:29 +0200 Subject: [PATCH 12/22] Cleanup --- libebpfdiscovery/test/IpAddressCheckerTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libebpfdiscovery/test/IpAddressCheckerTest.cpp b/libebpfdiscovery/test/IpAddressCheckerTest.cpp index c407ce6b..05e92879 100644 --- a/libebpfdiscovery/test/IpAddressCheckerTest.cpp +++ b/libebpfdiscovery/test/IpAddressCheckerTest.cpp @@ -19,7 +19,6 @@ class IpAddressCheckerTest : public IpAddressChecker { TEST(IpUtils, LocalBridgeIp) { IpAddressCheckerTest u; u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); - u.printAll(); EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("10.2.6.5"))); } From 8cb216ce738ab39080e169286e860d45c0e092e5 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Mon, 25 Sep 2023 11:35:58 +0200 Subject: [PATCH 13/22] Cleanup --- .../headers/ebpfdiscovery/IpAddressChecker.h | 1 - libebpfdiscovery/src/IpAddressChecker.cpp | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h index 78660c5f..e28f33f9 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h @@ -28,7 +28,6 @@ class IpAddressChecker { bool isAddressExternalLocal(IPv4 addr); void addIpIfce(IpIfce&& ifce); void markBridge(int idx); - void printAll(); bool readNetworks(); }; } diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index 4dad5c53..c42cc131 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -234,17 +234,6 @@ void IpAddressChecker::markBridge(int idx) { ifc->isLocalBridge = true; } -void IpAddressChecker::printAll() { - for (const auto& el : localNetsIpv4) { - std::cout << el.index << " " << std::hex << "0x" << el.mask << " " << el.isLocalBridge << " "; - for (const auto addr : el.ip) { - char ips[INET6_ADDRSTRLEN]; - std::cout << inet_ntop(AF_INET, &addr, ips, INET6_ADDRSTRLEN) << " " << std::hex << addr; - } - std::cout << "\n"; - } -} - bool IpAddressChecker::isAddressExternalLocal(IPv4 addr) { const bool isPublic = ((addr & maskA) != ipA) && ((addr & maskB) != ipB) && ((addr & maskC) != ipC); From 82308b43fe03359d56621b2febccd5e5149d8b00 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Mon, 25 Sep 2023 11:40:44 +0200 Subject: [PATCH 14/22] Review fix --- libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h | 2 +- libebpfdiscovery/src/IpAddressChecker.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h index e28f33f9..8321f1bc 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h @@ -30,5 +30,5 @@ class IpAddressChecker { void markBridge(int idx); bool readNetworks(); }; -} +} // namespace ebpfdiscovery diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index c42cc131..9c2cea43 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -255,4 +255,4 @@ bool IpAddressChecker::isAddressExternalLocal(IPv4 addr) { return true; } -} +} // namespace ebpfdiscovery From 6517126343e5a3f017bfa1ebc0a1130afc2f892d Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Mon, 25 Sep 2023 12:26:27 +0200 Subject: [PATCH 15/22] Warning fix --- libebpfdiscovery/src/IpAddressChecker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index 9c2cea43..952bf696 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ static int sendBridgesRequest(int fd, sockaddr_nl* sa, int domain) { struct { struct nlmsghdr n; struct ifinfomsg i; - char _[1024]; // required + char _[1024]; // space for rtattr array } r{}; const char* dev_type = "bridge"; From ed32e3aff4917b406f942591cea79ccfb0079c85 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Wed, 27 Sep 2023 16:07:38 +0200 Subject: [PATCH 16/22] Review fixes --- .../headers/ebpfdiscovery/IpAddressChecker.h | 17 ++-- libebpfdiscovery/src/IpAddressChecker.cpp | 88 +++++++++++-------- .../test/IpAddressCheckerTest.cpp | 12 +-- 3 files changed, 64 insertions(+), 53 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h index 8321f1bc..f94c68be 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once #include +#include #include namespace ebpfdiscovery { @@ -16,18 +17,20 @@ struct IpIfce { }; class IpAddressChecker { -protected: - std::vector localNetsIpv4; - std::vector::iterator bridgeEnd = localNetsIpv4.end(); + std::vector interfaces; + std::vector::iterator bridgeEnd = interfaces.end(); + bool readAllIpAddrs(); bool markLocalBridges(); - std::vector::iterator moveBridges(); - + bool isLoopback(const IpIfce&); + void addIpIfce(IpIfce&& ifce); + void markBridge(int idx); +protected: + void moveBridges(); public: IpAddressChecker() = default; + IpAddressChecker(std::initializer_list config); bool isAddressExternalLocal(IPv4 addr); - void addIpIfce(IpIfce&& ifce); - void markBridge(int idx); bool readNetworks(); }; } // namespace ebpfdiscovery diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index 952bf696..fced2000 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -14,22 +14,24 @@ #include #include -static constexpr uint32_t BUFLEN = 4096; -static constexpr uint32_t ipC = 0x0000a8c0; // 192.168.*.* -static constexpr uint32_t maskC = 0x0000ffff; -static constexpr uint32_t ipB = 0x000010ac; // 172.16-31.*.* -static constexpr uint32_t maskB = 0x0000f0ff; -static constexpr uint32_t ipA = 0x0000000a; // 10.*.*.* -static constexpr uint32_t maskA = 0x000000ff; -static constexpr uint32_t ipLinkLocal = 0x0000fea9; // 169.254.*.* -static constexpr uint32_t maskLinkLocal = 0x0000ffff; +static constexpr uint32_t BUFFLEN{4096}; +static constexpr uint32_t IP_CLASS_C{0x0000a8c0}; // 192.168.*.* +static constexpr uint32_t MASK_CLASS_C{0x0000ffff}; +static constexpr uint32_t IP_CLASS_B{0x000010ac}; // 172.16-31.*.* +static constexpr uint32_t MASK_CLASS_B{0x0000f0ff}; +static constexpr uint32_t IP_CLASS_A{0x0000000a}; // 10.*.*.* +static constexpr uint32_t MASK_CLASS_A{0x000000ff}; +static constexpr uint32_t IP_LINK_LOCAL{0x0000fea9}; // 169.254.*.* +static constexpr uint32_t MASK_LINK_LOCAL{0x0000ffff}; +static constexpr uint32_t IP_LOOPBACK{0x000000ff}; // 127.0..*.* +static constexpr uint32_t MASK_LOOPBACK{0x00ffffff}; static void logErrorFromErrno(std::string_view prefix) { std::cout << prefix << ": " << strerror(errno) << "\n"; } static int sendIpAddrRequest(int fd, sockaddr_nl* sa, int domain) { - std::array buf{}; + std::array buf{}; nlmsghdr* nl; nl = reinterpret_cast(buf.data()); @@ -47,9 +49,9 @@ static int sendIpAddrRequest(int fd, sockaddr_nl* sa, int domain) { return sendmsg(fd, &msg, 0); } -static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int raw_data_length) { +static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int dataLen) { struct rtattr* rta; - int rta_length = RTA_LENGTH(raw_data_length); + int rta_length = RTA_LENGTH(dataLen); rta = reinterpret_cast((char*)nh + NLMSG_ALIGN(nh->nlmsg_len)); @@ -57,7 +59,7 @@ static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int raw_data rta->rta_len = rta_length; nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + RTA_ALIGN(rta_length); - memcpy(RTA_DATA(rta), data, raw_data_length); + memcpy(RTA_DATA(rta), data, dataLen); } static int sendBridgesRequest(int fd, sockaddr_nl* sa, int domain) { @@ -132,29 +134,34 @@ static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { return parseIfceIPv4(data, len); } -static int getIfIndex(void* data, size_t len) { +static int getIfIndex(void* data) { ifinfomsg* ifa = reinterpret_cast(data); return ifa->ifi_index; } namespace ebpfdiscovery { + +IpAddressChecker::IpAddressChecker(std::initializer_list config) { + interfaces.insert(interfaces.end(), config.begin(), config.end()); +} + bool IpAddressChecker::readNetworks() { const bool ret = readAllIpAddrs(); if (markLocalBridges()) { - bridgeEnd = moveBridges(); + moveBridges(); } else { - bridgeEnd = localNetsIpv4.end(); + bridgeEnd = interfaces.end(); } return ret; } -std::vector::iterator IpAddressChecker::moveBridges() { - return std::partition(localNetsIpv4.begin(), localNetsIpv4.end(), [](const auto& it) { return it.isLocalBridge; }); +void IpAddressChecker::moveBridges() { + bridgeEnd = std::partition(interfaces.begin(), interfaces.end(), [](const auto& it) { return it.isLocalBridge; }); } -template -static uint32_t parseNlMsg(void* buf, size_t len, F parse) { +template +static uint32_t parseNlMsg(void* buf, size_t len, P parse) { const nlmsghdr* nl = reinterpret_cast(buf); for (; NLMSG_OK(nl, len) && nl->nlmsg_type != NLMSG_DONE; nl = NLMSG_NEXT(nl, len)) { @@ -167,11 +174,12 @@ static uint32_t parseNlMsg(void* buf, size_t len, F parse) { continue; } } + return nl->nlmsg_type; } -template -static bool handleNetlink(S send, F f, int domain) { +template +static bool handleNetlink(S send, P parse, int domain) { int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { logErrorFromErrno("socket"); @@ -188,18 +196,18 @@ static bool handleNetlink(S send, F f, int domain) { return false; } - uint32_t nl_msg_type; + uint32_t nlMsgType; do { - std::array buf{}; - len = receive(fd, &sa, buf.data(), BUFLEN); + std::array buf{}; + len = receive(fd, &sa, buf.data(), BUFFLEN); if (len <= 0) { logErrorFromErrno("receive"); break; } - nl_msg_type = parseNlMsg(buf.data(), len, f); + nlMsgType = parseNlMsg(buf.data(), len, parse); - } while (nl_msg_type != NLMSG_DONE && nl_msg_type != NLMSG_ERROR); + } while (nlMsgType != NLMSG_DONE && nlMsgType != NLMSG_ERROR); return true; } @@ -213,39 +221,43 @@ bool IpAddressChecker::readAllIpAddrs() { bool IpAddressChecker::markLocalBridges() { return handleNetlink( [](int fd, sockaddr_nl* sa, int domain) { return sendBridgesRequest(fd, sa, AF_INET); }, - [this](void* buf, size_t len) { markBridge(getIfIndex(buf, len)); }, AF_INET); + [this](void* buf, size_t len) { markBridge(getIfIndex(buf)); }, AF_INET); } void IpAddressChecker::addIpIfce(IpIfce&& ifce) { - char ifname[IF_NAMESIZE]; - if_indextoname(ifce.index, ifname); - if (strcmp(ifname, "lo") == 0) { - return; + if(!isLoopback(ifce)){ + interfaces.push_back(ifce); } - localNetsIpv4.push_back(ifce); } void IpAddressChecker::markBridge(int idx) { - auto ifc = std::find_if(localNetsIpv4.begin(), localNetsIpv4.end(), [idx](const auto& it) { return it.index == idx; }); - if (ifc == localNetsIpv4.end()) { + auto ifc = std::find_if(interfaces.begin(), interfaces.end(), [idx](const auto& it) { return it.index == idx; }); + if (ifc == interfaces.end()) { return; } ifc->isLocalBridge = true; } +bool IpAddressChecker::isLoopback(const IpIfce& ifce) { + + return std::all_of(ifce.ip.begin(), ifce.ip.end(), [](const auto& ipv4) { + return ((ipv4 & MASK_LOOPBACK) == IP_LOOPBACK); + }); +} + bool IpAddressChecker::isAddressExternalLocal(IPv4 addr) { - const bool isPublic = ((addr & maskA) != ipA) && ((addr & maskB) != ipB) && ((addr & maskC) != ipC); + const bool isPublic = ((addr & MASK_CLASS_A) != IP_CLASS_A) && ((addr & MASK_CLASS_B) != IP_CLASS_B) && ((addr & MASK_CLASS_C) != IP_CLASS_C); if (isPublic) { return false; } - if ((addr & maskLinkLocal) == ipLinkLocal) { + if ((addr & MASK_LINK_LOCAL) == IP_LINK_LOCAL) { return false; } - const bool bridgeRelated = std::any_of(localNetsIpv4.begin(), bridgeEnd, [addr](const auto& it) { + const bool bridgeRelated = std::any_of(interfaces.begin(), bridgeEnd, [addr](const auto& it) { return std::any_of(it.ip.begin(), it.ip.end(), [addr, mask = it.mask](const auto& ip) { return (addr & mask) == (ip & mask); }); }); diff --git a/libebpfdiscovery/test/IpAddressCheckerTest.cpp b/libebpfdiscovery/test/IpAddressCheckerTest.cpp index 05e92879..c6d58bb7 100644 --- a/libebpfdiscovery/test/IpAddressCheckerTest.cpp +++ b/libebpfdiscovery/test/IpAddressCheckerTest.cpp @@ -2,7 +2,6 @@ #include "ebpfdiscovery/IpAddressChecker.h" #include #include -#include using namespace ebpfdiscovery; @@ -10,21 +9,18 @@ class IpAddressCheckerTest : public IpAddressChecker { protected: public: using IpAddressChecker::IpAddressChecker; - void addIfceConfig(std::initializer_list config) { - localNetsIpv4.insert(localNetsIpv4.end(), config.begin(), config.end()); - bridgeEnd = moveBridges(); + IpAddressCheckerTest(std::initializer_list config): IpAddressChecker(config) { + moveBridges(); } }; TEST(IpUtils, LocalBridgeIp) { - IpAddressCheckerTest u; - u.addIfceConfig({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); + IpAddressCheckerTest u({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("10.2.6.5"))); } TEST(IpUtils, NOTLocalBridgeIp) { - IpAddressCheckerTest u; - u.addIfceConfig({{{inet_addr("10.2.6.5")}, {}, 0x0000ffff, 0, true}}); + IpAddressCheckerTest u({{{inet_addr("10.2.6.5")}, {}, 0x0000ffff, 0, true}}); EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("10.3.34.2"))); } From 6a1b0634612dcdeb8f4b2f9ff9f19a3b3002025b Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Thu, 28 Sep 2023 10:54:42 +0200 Subject: [PATCH 17/22] Review fix --- libebpfdiscovery/src/IpAddressChecker.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index fced2000..18c3b233 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -30,7 +30,7 @@ static void logErrorFromErrno(std::string_view prefix) { std::cout << prefix << ": " << strerror(errno) << "\n"; } -static int sendIpAddrRequest(int fd, sockaddr_nl* sa, int domain) { +static int sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) { std::array buf{}; nlmsghdr* nl; @@ -44,7 +44,7 @@ static int sendIpAddrRequest(int fd, sockaddr_nl* sa, int domain) { ifa->ifa_family = domain; // ipv4 or ipv6 iovec iov = {nl, nl->nlmsg_len}; - msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; + msghdr msg = {dst, sizeof(*dst), &iov, 1, NULL, 0, 0}; return sendmsg(fd, &msg, 0); } @@ -62,7 +62,7 @@ static void addNetlinkMsg(nlmsghdr* nh, int type, const void* data, int dataLen) memcpy(RTA_DATA(rta), data, dataLen); } -static int sendBridgesRequest(int fd, sockaddr_nl* sa, int domain) { +static int sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) { struct { struct nlmsghdr n; struct ifinfomsg i; @@ -84,20 +84,20 @@ static int sendBridgesRequest(int fd, sockaddr_nl* sa, int domain) { linkinfo->rta_len = (int)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len) - (char*)linkinfo); iovec iov = {&r.n, r.n.nlmsg_len}; - msghdr msg = {sa, sizeof(*sa), &iov, 1, NULL, 0, 0}; + msghdr msg = {dst, sizeof(*dst), &iov, 1, NULL, 0, 0}; return sendmsg(fd, &msg, 0); } -static int receive(int fd, sockaddr_nl* sa, void* buf, size_t len) { +static int receive(int fd, sockaddr_nl* dst, void* buf, size_t len) { iovec iov; msghdr msg {}; iov.iov_base = buf; iov.iov_len = len; - msg.msg_name = sa; - msg.msg_namelen = sizeof(*sa); + msg.msg_name = dst; + msg.msg_namelen = sizeof(*dst); msg.msg_iov = &iov; msg.msg_iovlen = 1; @@ -206,7 +206,6 @@ static bool handleNetlink(S send, P parse, int domain) { } nlMsgType = parseNlMsg(buf.data(), len, parse); - } while (nlMsgType != NLMSG_DONE && nlMsgType != NLMSG_ERROR); return true; From 898c2aa53a225e539e1c1a182a98bac28d338b98 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Tue, 3 Oct 2023 10:35:10 +0200 Subject: [PATCH 18/22] Added UT for netlink layer --- libebpfdiscovery/CMakeLists.txt | 2 +- .../headers/ebpfdiscovery/IpAddressChecker.h | 15 ++- libebpfdiscovery/src/IpAddressChecker.cpp | 124 +++++++++--------- .../test/IpAddressCheckerTest.cpp | 74 ++++++++--- 4 files changed, 137 insertions(+), 78 deletions(-) diff --git a/libebpfdiscovery/CMakeLists.txt b/libebpfdiscovery/CMakeLists.txt index 87b5796a..79c9a9bf 100644 --- a/libebpfdiscovery/CMakeLists.txt +++ b/libebpfdiscovery/CMakeLists.txt @@ -25,7 +25,7 @@ if(BUILD_TESTS) set(TEST_TARGET test${TARGET}) add_executable(${TEST_TARGET} ${TEST_SOURCES}) - target_link_libraries(${TEST_TARGET} GTest::gtest_main ${TARGET}) + target_link_libraries(${TEST_TARGET} GTest::gtest_main GTest::gmock_main ${TARGET}) target_include_directories(${TEST_TARGET} PRIVATE src) gtest_discover_tests(${TEST_TARGET}) endif() diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h index f94c68be..0b7c6e4e 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h @@ -4,6 +4,8 @@ #include #include +struct sockaddr_nl; + namespace ebpfdiscovery { using IPv4 = uint32_t; @@ -16,9 +18,17 @@ struct IpIfce { bool isLocalBridge; }; +class NetlinkCalls { +public: + virtual int sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) const; + virtual int sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) const; + virtual int receive(int fd, sockaddr_nl* dst, void* buf, size_t len) const; +}; + class IpAddressChecker { std::vector interfaces; std::vector::iterator bridgeEnd = interfaces.end(); + const NetlinkCalls& netlink; bool readAllIpAddrs(); bool markLocalBridges(); @@ -28,10 +38,11 @@ class IpAddressChecker { protected: void moveBridges(); public: - IpAddressChecker() = default; - IpAddressChecker(std::initializer_list config); + IpAddressChecker(const NetlinkCalls &calls); + IpAddressChecker(std::initializer_list config, const NetlinkCalls &calls); bool isAddressExternalLocal(IPv4 addr); bool readNetworks(); }; + } // namespace ebpfdiscovery diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index 18c3b233..bb3f78b1 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -23,14 +23,66 @@ static constexpr uint32_t IP_CLASS_A{0x0000000a}; // 10.*.*.* static constexpr uint32_t MASK_CLASS_A{0x000000ff}; static constexpr uint32_t IP_LINK_LOCAL{0x0000fea9}; // 169.254.*.* static constexpr uint32_t MASK_LINK_LOCAL{0x0000ffff}; -static constexpr uint32_t IP_LOOPBACK{0x000000ff}; // 127.0..*.* +static constexpr uint32_t IP_LOOPBACK{0x0000007f}; // 127.0.*.* static constexpr uint32_t MASK_LOOPBACK{0x00ffffff}; static void logErrorFromErrno(std::string_view prefix) { std::cout << prefix << ": " << strerror(errno) << "\n"; } -static int sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) { + +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 ebpfdiscovery::IpIfce parseIfceIPv4(void* data, size_t len) { + ebpfdiscovery::IpIfce ifce{}; + ifaddrmsg* ifa = reinterpret_cast(data); + ifce.index = ifa->ifa_index; + 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 ifce; +} + +static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { + if (reinterpret_cast(data)->ifa_family != AF_INET) { + return {}; + } + + return parseIfceIPv4(data, len); +} + +static int getIfIndex(void* data) { + ifinfomsg* ifa = reinterpret_cast(data); + return ifa->ifi_index; +} + +namespace ebpfdiscovery { + +int NetlinkCalls::sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) const{ std::array buf{}; nlmsghdr* nl; @@ -49,20 +101,7 @@ static int sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) { return sendmsg(fd, &msg, 0); } -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 sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) { +int NetlinkCalls::sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) const{ struct { struct nlmsghdr n; struct ifinfomsg i; @@ -89,8 +128,7 @@ static int sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) { return sendmsg(fd, &msg, 0); } - -static int receive(int fd, sockaddr_nl* dst, void* buf, size_t len) { +int NetlinkCalls::receive(int fd, sockaddr_nl* dst, void* buf, size_t len) const { iovec iov; msghdr msg {}; iov.iov_base = buf; @@ -104,45 +142,11 @@ static int receive(int fd, sockaddr_nl* dst, void* buf, size_t len) { return recvmsg(fd, &msg, 0); } -static ebpfdiscovery::IpIfce parseIfceIPv4(void* data, size_t len) { - ebpfdiscovery::IpIfce ifce{}; - ifaddrmsg* ifa = reinterpret_cast(data); - ifce.index = ifa->ifa_index; - 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 ifce; -} - -static ebpfdiscovery::IpIfce parseIfce(void* data, size_t len) { - if (reinterpret_cast(data)->ifa_family != AF_INET) { - return {}; - } - - return parseIfceIPv4(data, len); -} - -static int getIfIndex(void* data) { - ifinfomsg* ifa = reinterpret_cast(data); - return ifa->ifi_index; +IpAddressChecker::IpAddressChecker(std::initializer_list config, const NetlinkCalls &calls) :netlink(calls) { + interfaces.insert(interfaces.end(), config.begin(), config.end()); } -namespace ebpfdiscovery { - -IpAddressChecker::IpAddressChecker(std::initializer_list config) { - interfaces.insert(interfaces.end(), config.begin(), config.end()); +IpAddressChecker::IpAddressChecker(const NetlinkCalls &calls) :netlink(calls) { } bool IpAddressChecker::readNetworks() { @@ -178,8 +182,8 @@ static uint32_t parseNlMsg(void* buf, size_t len, P parse) { return nl->nlmsg_type; } -template -static bool handleNetlink(S send, P parse, int domain) { +template +static bool handleNetlink(S send, R receive, P parse, int domain) { int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { logErrorFromErrno("socket"); @@ -213,13 +217,15 @@ static bool handleNetlink(S send, P parse, int domain) { bool IpAddressChecker::readAllIpAddrs() { return handleNetlink( - [](int fd, sockaddr_nl* sa, int domain) { return sendIpAddrRequest(fd, sa, AF_INET); }, + [this](int fd, sockaddr_nl* sa, int domain) { return netlink.sendIpAddrRequest(fd, sa, AF_INET); }, + [this](int fd, sockaddr_nl* dst, void* buf, size_t len) { return netlink.receive(fd, dst, buf, len); }, [this](void* buf, size_t len) { addIpIfce(parseIfce(buf, len)); }, AF_INET); } bool IpAddressChecker::markLocalBridges() { return handleNetlink( - [](int fd, sockaddr_nl* sa, int domain) { return sendBridgesRequest(fd, sa, AF_INET); }, + [this](int fd, sockaddr_nl* sa, int domain) { return netlink.sendBridgesRequest(fd, sa, AF_INET); }, + [this](int fd, sockaddr_nl* dst, void* buf, size_t len) { return netlink.receive(fd, dst, buf, len); }, [this](void* buf, size_t len) { markBridge(getIfIndex(buf)); }, AF_INET); } diff --git a/libebpfdiscovery/test/IpAddressCheckerTest.cpp b/libebpfdiscovery/test/IpAddressCheckerTest.cpp index c6d58bb7..d248cfd7 100644 --- a/libebpfdiscovery/test/IpAddressCheckerTest.cpp +++ b/libebpfdiscovery/test/IpAddressCheckerTest.cpp @@ -1,51 +1,93 @@ // SPDX-License-Identifier: Apache-2.0 #include "ebpfdiscovery/IpAddressChecker.h" #include +#include #include using namespace ebpfdiscovery; +using namespace ::testing; + +class NetlinkCallsMock : public NetlinkCalls { +public: + MOCK_METHOD(int, sendIpAddrRequest, (int fd, sockaddr_nl* dst, int domain), (const, override)); + MOCK_METHOD(int, sendBridgesRequest, (int fd, sockaddr_nl* dst, int domain), (const, override)); + MOCK_METHOD(int, receive, (int fd, sockaddr_nl* dst, void* buf, size_t len), (const, override)); +}; class IpAddressCheckerTest : public IpAddressChecker { protected: public: using IpAddressChecker::IpAddressChecker; - IpAddressCheckerTest(std::initializer_list config): IpAddressChecker(config) { + IpAddressCheckerTest(std::initializer_list config, const NetlinkCallsMock& mc) : IpAddressChecker(config, mc) { moveBridges(); } }; -TEST(IpUtils, LocalBridgeIp) { - IpAddressCheckerTest u({{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}); +TEST(TestAddressChecker, LocalBridgeIp) { + const NetlinkCallsMock netlinkMock; + IpAddressCheckerTest u( + {{{inet_addr("10.2.4.5")}, {}, 0x0000ffff, 0, true}, {{inet_addr("10.7.4.5")}, {}, 0x0000ffff, 0, false}}, netlinkMock); EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("10.2.6.5"))); } -TEST(IpUtils, NOTLocalBridgeIp) { - IpAddressCheckerTest u({{{inet_addr("10.2.6.5")}, {}, 0x0000ffff, 0, true}}); +TEST(TestAddressChecker, NoReadIfSendFailed) { + const NetlinkCallsMock netlinkMock; + EXPECT_CALL(netlinkMock, sendIpAddrRequest).WillOnce(Return(-1)); + EXPECT_CALL(netlinkMock, sendBridgesRequest).WillOnce(Return(-1)); + IpAddressCheckerTest u({}, netlinkMock); + u.readNetworks(); +} + +TEST(TestAddressChecker, ReadAfterSuccessfullSend) { + const NetlinkCallsMock netlinkMock; + EXPECT_CALL(netlinkMock, sendIpAddrRequest).WillOnce(Return(1)); + EXPECT_CALL(netlinkMock, sendBridgesRequest).WillOnce(Return(1)); + EXPECT_CALL(netlinkMock, receive).Times(2).WillRepeatedly(Return(0)); + IpAddressCheckerTest u({}, netlinkMock); + u.readNetworks(); +} + +TEST(TestAddressChecker, ReadUntilGreaterThan0) { + const NetlinkCallsMock netlinkMock; + EXPECT_CALL(netlinkMock, sendIpAddrRequest).WillOnce(Return(1)); + EXPECT_CALL(netlinkMock, sendBridgesRequest).WillOnce(Return(1)); + EXPECT_CALL(netlinkMock, receive).WillOnce(Return(1)).WillOnce(Return(0)).WillOnce(Return(1)).WillOnce(Return(0)); + IpAddressCheckerTest u({}, netlinkMock); + u.readNetworks(); +} + +TEST(TestAddressChecker, NOTLocalBridgeIp) { + const NetlinkCallsMock netlinkMock; + IpAddressCheckerTest u({{{inet_addr("10.2.6.5")}, {}, 0x0000ffff, 0, true}}, netlinkMock); EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("10.3.34.2"))); } -TEST(IpUtils, SimpleClassATest) { - IpAddressCheckerTest u; +TEST(TestAddressChecker, SimpleClassATest) { + NetlinkCalls calls; + IpAddressCheckerTest u(calls); EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("192.168.1.2"))); } -TEST(IpUtils, SimpleClassBTest) { - IpAddressCheckerTest u; +TEST(TestAddressChecker, SimpleClassBTest) { + NetlinkCalls calls; + IpAddressCheckerTest u(calls); EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("172.20.21.2"))); } -TEST(IpUtils, SimpleClassCtest) { - IpAddressCheckerTest u; +TEST(TestAddressChecker, SimpleClassCtest) { + NetlinkCalls calls; + IpAddressCheckerTest u(calls); EXPECT_TRUE(u.isAddressExternalLocal(inet_addr("10.2.4.5"))); } -TEST(IpUtils, SimpleLinkLocal) { - IpAddressCheckerTest u; +TEST(TestAddressChecker, SimpleLinkLocal) { + NetlinkCalls calls; + IpAddressCheckerTest u(calls); EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("169.254.76.6"))); } - -TEST(IpUtils, SimplePublicIp) { - IpAddressCheckerTest u; +TEST(TestAddressChecker, SimplePublicIp) { + NetlinkCalls calls; + IpAddressCheckerTest u(calls); EXPECT_FALSE(u.isAddressExternalLocal(inet_addr("170.254.76.6"))); } From 791fe2fcc087de6743157b47119f3895b07419ec Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Tue, 3 Oct 2023 12:48:16 +0200 Subject: [PATCH 19/22] c-style cast removed --- libebpfdiscovery/src/IpAddressChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index bb3f78b1..b9101e04 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -120,7 +120,7 @@ int NetlinkCalls::sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) const 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)((char*)&r.n + NLMSG_ALIGN(r.n.nlmsg_len) - (char*)linkinfo); + 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}; From be6dee2aa2135cc770f856ef8214efec9255b7fe Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Tue, 3 Oct 2023 12:54:23 +0200 Subject: [PATCH 20/22] Build fix --- libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h index 0b7c6e4e..59363c32 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once #include +#include #include #include From b43731bbeba03c0256ac60ef8ace6d94b6acf390 Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Wed, 4 Oct 2023 12:17:08 +0200 Subject: [PATCH 21/22] File NetlinkCalls added --- libebpfdiscovery/CMakeLists.txt | 1 + .../headers/ebpfdiscovery/IpAddressChecker.h | 12 +-- .../headers/ebpfdiscovery/NetlinkCalls.h | 17 ++++ libebpfdiscovery/src/IpAddressChecker.cpp | 74 ---------------- libebpfdiscovery/src/NetlinkCalls.cpp | 84 +++++++++++++++++++ 5 files changed, 103 insertions(+), 85 deletions(-) create mode 100644 libebpfdiscovery/headers/ebpfdiscovery/NetlinkCalls.h create mode 100644 libebpfdiscovery/src/NetlinkCalls.cpp diff --git a/libebpfdiscovery/CMakeLists.txt b/libebpfdiscovery/CMakeLists.txt index 79c9a9bf..6f5c0ff0 100644 --- a/libebpfdiscovery/CMakeLists.txt +++ b/libebpfdiscovery/CMakeLists.txt @@ -4,6 +4,7 @@ list( src/Config.cpp src/Discovery.cpp src/IpAddressChecker.cpp + src/NetlinkCalls.cpp src/Session.cpp src/StringFunctions.cpp ) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h index 59363c32..89720082 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h @@ -1,11 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once -#include -#include +#include "ebpfdiscovery/NetlinkCalls.h" #include #include -struct sockaddr_nl; namespace ebpfdiscovery { @@ -19,13 +17,6 @@ struct IpIfce { bool isLocalBridge; }; -class NetlinkCalls { -public: - virtual int sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) const; - virtual int sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) const; - virtual int receive(int fd, sockaddr_nl* dst, void* buf, size_t len) const; -}; - class IpAddressChecker { std::vector interfaces; std::vector::iterator bridgeEnd = interfaces.end(); @@ -44,6 +35,5 @@ class IpAddressChecker { bool isAddressExternalLocal(IPv4 addr); bool readNetworks(); }; - } // namespace ebpfdiscovery diff --git a/libebpfdiscovery/headers/ebpfdiscovery/NetlinkCalls.h b/libebpfdiscovery/headers/ebpfdiscovery/NetlinkCalls.h new file mode 100644 index 00000000..3b114cbb --- /dev/null +++ b/libebpfdiscovery/headers/ebpfdiscovery/NetlinkCalls.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once +#include +#include + +struct sockaddr_nl; + +namespace ebpfdiscovery { + +class NetlinkCalls { +public: + virtual int sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) const; + virtual int sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) const; + virtual int receive(int fd, sockaddr_nl* dst, void* buf, size_t len) const; +}; +} // namespace ebpfdiscovery + diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index b9101e04..4f705aa0 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -31,20 +30,6 @@ static void logErrorFromErrno(std::string_view prefix) { } -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 ebpfdiscovery::IpIfce parseIfceIPv4(void* data, size_t len) { ebpfdiscovery::IpIfce ifce{}; ifaddrmsg* ifa = reinterpret_cast(data); @@ -82,65 +67,6 @@ static int getIfIndex(void* data) { namespace ebpfdiscovery { -int NetlinkCalls::sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) const{ - std::array buf{}; - - nlmsghdr* nl; - nl = reinterpret_cast(buf.data()); - nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct 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 sendmsg(fd, &msg, 0); -} - -int NetlinkCalls::sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) const{ - 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 sendmsg(fd, &msg, 0); -} - -int NetlinkCalls::receive(int fd, sockaddr_nl* dst, void* buf, size_t len) const { - 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 recvmsg(fd, &msg, 0); -} IpAddressChecker::IpAddressChecker(std::initializer_list config, const NetlinkCalls &calls) :netlink(calls) { interfaces.insert(interfaces.end(), config.begin(), config.end()); diff --git a/libebpfdiscovery/src/NetlinkCalls.cpp b/libebpfdiscovery/src/NetlinkCalls.cpp new file mode 100644 index 00000000..a6c91057 --- /dev/null +++ b/libebpfdiscovery/src/NetlinkCalls.cpp @@ -0,0 +1,84 @@ +#include "ebpfdiscovery/NetlinkCalls.h" +#include +#include +#include +#include +#include + +namespace ebpfdiscovery { + +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); +} + +int NetlinkCalls::sendIpAddrRequest(int fd, sockaddr_nl* dst, int domain) const { + 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 sendmsg(fd, &msg, 0); +} + +int NetlinkCalls::sendBridgesRequest(int fd, sockaddr_nl* dst, int domain) const { + 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 sendmsg(fd, &msg, 0); +} + +int NetlinkCalls::receive(int fd, sockaddr_nl* dst, void* buf, size_t len) const { + 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 recvmsg(fd, &msg, 0); +} +} // namespace ebpfdiscovery From cc946568af2dd3cb8b85776551d0fd4f93efa35c Mon Sep 17 00:00:00 2001 From: Pawel Stenka Date: Thu, 5 Oct 2023 11:03:46 +0200 Subject: [PATCH 22/22] Review fixes --- .../headers/ebpfdiscovery/IpAddressChecker.h | 8 ++++---- libebpfdiscovery/src/IpAddressChecker.cpp | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h index 89720082..c55408a6 100644 --- a/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h +++ b/libebpfdiscovery/headers/ebpfdiscovery/IpAddressChecker.h @@ -7,11 +7,11 @@ namespace ebpfdiscovery { -using IPv4 = uint32_t; +using IPv4int = uint32_t; struct IpIfce { - std::vector ip; - std::vector broadcast; + std::vector ip; + std::vector broadcast; uint32_t mask; int index; bool isLocalBridge; @@ -32,7 +32,7 @@ class IpAddressChecker { public: IpAddressChecker(const NetlinkCalls &calls); IpAddressChecker(std::initializer_list config, const NetlinkCalls &calls); - bool isAddressExternalLocal(IPv4 addr); + bool isAddressExternalLocal(IPv4int addr); bool readNetworks(); }; } // namespace ebpfdiscovery diff --git a/libebpfdiscovery/src/IpAddressChecker.cpp b/libebpfdiscovery/src/IpAddressChecker.cpp index 4f705aa0..e75ff06e 100644 --- a/libebpfdiscovery/src/IpAddressChecker.cpp +++ b/libebpfdiscovery/src/IpAddressChecker.cpp @@ -13,7 +13,7 @@ #include #include -static constexpr uint32_t BUFFLEN{4096}; +static constexpr uint32_t BUFLEN{4096}; static constexpr uint32_t IP_CLASS_C{0x0000a8c0}; // 192.168.*.* static constexpr uint32_t MASK_CLASS_C{0x0000ffff}; static constexpr uint32_t IP_CLASS_B{0x000010ac}; // 172.16-31.*.* @@ -29,7 +29,6 @@ static void logErrorFromErrno(std::string_view prefix) { std::cout << prefix << ": " << strerror(errno) << "\n"; } - static ebpfdiscovery::IpIfce parseIfceIPv4(void* data, size_t len) { ebpfdiscovery::IpIfce ifce{}; ifaddrmsg* ifa = reinterpret_cast(data); @@ -67,7 +66,6 @@ static int getIfIndex(void* data) { namespace ebpfdiscovery { - IpAddressChecker::IpAddressChecker(std::initializer_list config, const NetlinkCalls &calls) :netlink(calls) { interfaces.insert(interfaces.end(), config.begin(), config.end()); } @@ -128,8 +126,8 @@ static bool handleNetlink(S send, R receive, P parse, int domain) { uint32_t nlMsgType; do { - std::array buf{}; - len = receive(fd, &sa, buf.data(), BUFFLEN); + std::array buf{}; + len = receive(fd, &sa, buf.data(), BUFLEN); if (len <= 0) { logErrorFromErrno("receive"); break; @@ -177,7 +175,7 @@ bool IpAddressChecker::isLoopback(const IpIfce& ifce) { }); } -bool IpAddressChecker::isAddressExternalLocal(IPv4 addr) { +bool IpAddressChecker::isAddressExternalLocal(IPv4int addr) { const bool isPublic = ((addr & MASK_CLASS_A) != IP_CLASS_A) && ((addr & MASK_CLASS_B) != IP_CLASS_B) && ((addr & MASK_CLASS_C) != IP_CLASS_C); if (isPublic) {