Skip to content

Commit

Permalink
Read all interfaces (IPv4 and IPv6) from getifaddrs
Browse files Browse the repository at this point in the history
  • Loading branch information
asias91 committed Nov 6, 2024
1 parent 17487fd commit 81a282c
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 428 deletions.
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
2 changes: 1 addition & 1 deletion libservice/headers/service/Aggregator.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Aggregator {
using ServiceStorage = std::unordered_map<ServiceKey, Service>;

public:
Aggregator(const service::IpAddressChecker& ipChecker);
explicit Aggregator(const service::IpAddressChecker& ipChecker);

void clear();
void newRequest(const httpparser::HttpRequest& request, const DiscoverySessionMeta& meta);
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 {
std::vector<in_addr_t> networkIpv4Addr;
in_addr_t networkMask;
std::optional<in_addr_t> 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 printNetworkInterfacesInfo();
[[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> ipv4Interfaces;
std::vector<Ipv6Network> ipv6Interfaces;

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

} // 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(in_addr_t 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& calls);

bool isV4AddressExternal(IPv4int addr) const override;
bool isV4AddressExternal(in_addr_t addr) const override;

bool isV6AddressExternal(const in6_addr& addr) const override;

Expand All @@ -42,24 +41,14 @@ 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_t& addrToCheck, const in_addr_t& interfaceIpv4Addr, const in_addr_t& 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;
InterfacesReader& interfacesReader;
std::vector<Ipv6Network> ipv6Networks;
std::unordered_map<int, bool> isLocalBridgeMap;
};
} // namespace service
2 changes: 1 addition & 1 deletion 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 Down
90 changes: 90 additions & 0 deletions libservice/src/InterfacesReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* 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::printNetworkInterfacesInfo() {
LOG_INFO("{} network IPv4 interfaces have been discovered:", ipv4Interfaces.size());
for (const auto& ifce : ipv4Interfaces) {
std::string ipAddresses{boost::algorithm::join(
ifce.networkIpv4Addr | boost::adaptors::transformed([](auto ip) {
char buff[16];
return std::string{inet_ntop(AF_INET, &ip, buff, sizeof(buff))};
}),
", ")};
LOG_INFO("IP addresses: {}", ipAddresses);
}
LOG_INFO("{} IPv6 networks have been discovered:", ipv6Interfaces.size());
for (const auto& ipv6Network : ipv6Interfaces) {
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;

ipv6Interfaces.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.s_addr;
auto mask = reinterpret_cast<sockaddr_in*>(ifa->ifa_netmask)->sin_addr.s_addr;
std::optional<in_addr_t> broadcast{};
if (ifa->ifa_flags & IFF_BROADCAST) {
broadcast = std::optional<in_addr_t>(reinterpret_cast<sockaddr_in*>(ifa->ifa_ifu.ifu_broadaddr)->sin_addr.s_addr);
}
ipv4Interfaces.emplace_back(Ipv4Network{{address}, mask, broadcast});
}
}
freeifaddrs(ifAddressStruct);
}

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

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

} // namespace service
Loading

0 comments on commit 81a282c

Please sign in to comment.