Skip to content

Commit

Permalink
Read all interfaces (IPv4 and IPv6) from getifaddrs (#111)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
asias91 authored Nov 20, 2024
1 parent 57009a2 commit 0fbe5ec
Show file tree
Hide file tree
Showing 15 changed files with 288 additions and 506 deletions.
6 changes: 3 additions & 3 deletions libebpfdiscovery/headers/ebpfdiscovery/Discovery.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <atomic>
#include <chrono>
Expand Down Expand Up @@ -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;
};

Expand Down
4 changes: 2 additions & 2 deletions libservice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,41 @@

#include <cstdint>
#include <memory>
#include <netinet/in.h>
#include <optional>
#include <stddef.h>
#include <unordered_map>
#include <vector>
#include <netinet/in.h>

struct sockaddr_nl;

namespace service {

using IPv4int = uint32_t;
struct Ipv6Network {
in6_addr networkIpv6Addr;
in6_addr networkMask;
};

struct IpIfce {
std::vector<IPv4int> ip;
std::vector<IPv4int> broadcast;
uint32_t mask;
struct Ipv4Network {
in_addr networkIpv4Addr;
in_addr networkMask;
std::optional<in_addr> broadcastAddr;
};

using IpInterfaces = std::unordered_map<int, IpIfce>;
using BridgeIndices = std::vector<int>;

class NetlinkCalls {
class InterfacesReader {
public:
virtual ~NetlinkCalls() = default;
virtual ~InterfacesReader() = default;
void printNetworksInfo();
[[nodiscard]] virtual std::vector<Ipv4Network> getIpV4Interfaces() const;
[[nodiscard]] virtual std::vector<Ipv6Network> getIpV6Interfaces() const;

struct Ipv6Network {
in6_addr networkIpv6Addr;
in6_addr networkMask;
};
virtual void collectAllIpInterfaces();

private:
std::vector<Ipv4Network> ipv4Networks;
std::vector<Ipv6Network> ipv6Networks;

virtual IpInterfaces collectIpInterfaces() const;
virtual std::vector<Ipv6Network> collectIpv6Networks() const;
virtual BridgeIndices collectBridgeIndices() const;
};

} // namespace service
1 change: 1 addition & 0 deletions libservice/headers/service/IpAddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 3 additions & 2 deletions libservice/headers/service/IpAddressChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include <cstdint>
#include "netinet/in.h"

struct in6_addr;

Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,20 @@

#pragma once

#include <string>
#include <netinet/in.h>
#include <linux/netfilter.h>
#include <optional>
#include <string>

#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;

Expand All @@ -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<IPv4int> 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<NetlinkCalls::Ipv6Network> ipv6Networks;
std::unordered_map<int, bool> isLocalBridgeMap;
InterfacesReader& interfacesReader;
std::vector<Ipv6Network> ipv6Networks;
};
} // namespace service
4 changes: 2 additions & 2 deletions libservice/src/Aggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#include "logging/Logger.h"
#include "service/IpAddress.h"
#include "service/IpAddressNetlinkChecker.h"
#include "service/IpAddressCheckerImpl.h"

#include <arpa/inet.h>

Expand All @@ -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) {
Expand Down
88 changes: 88 additions & 0 deletions libservice/src/InterfacesReader.cpp
Original file line number Diff line number Diff line change
@@ -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 <arpa/inet.h>
#include <array>
#include <cstring>
#include <ifaddrs.h>
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>

#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<sockaddr_in6*>(ifa->ifa_addr)->sin6_addr;
const in6_addr networkMask = reinterpret_cast<sockaddr_in6*>(ifa->ifa_netmask)->sin6_addr;

ipv6Networks.emplace_back(Ipv6Network{networkIpv6Addr, networkMask});
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET) {
auto address = reinterpret_cast<sockaddr_in*>(ifa->ifa_addr)->sin_addr;
auto mask = reinterpret_cast<sockaddr_in*>(ifa->ifa_netmask)->sin_addr;
std::optional<in_addr> broadcast{};
if (ifa->ifa_flags & IFF_BROADCAST) {
broadcast = std::optional<in_addr>(reinterpret_cast<sockaddr_in*>(ifa->ifa_ifu.ifu_broadaddr)->sin_addr);
}
ipv4Networks.emplace_back(Ipv4Network{{address}, mask, broadcast});
}
}
freeifaddrs(ifAddressStruct);
}

std::vector<Ipv4Network> InterfacesReader::getIpV4Interfaces() const {
return ipv4Networks;
}

std::vector<Ipv6Network> InterfacesReader::getIpV6Interfaces() const {
return ipv6Networks;
}

} // namespace service
4 changes: 4 additions & 0 deletions libservice/src/IpAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const IPv4bytes&>(addr));
}

std::string ipv6ToString(const IPv6bytes addr) {
char ipAddress[INET6_ADDRSTRLEN];
const auto res{inet_ntop(AF_INET6, addr, ipAddress, sizeof(ipAddress))};
Expand Down
Loading

0 comments on commit 0fbe5ec

Please sign in to comment.