You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
2.6 KiB
C++

// SPDX-FileCopyrightText: 2026 Reion Wong <reionwong@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "networkmanager/inet.h"
#include <arpa/inet.h>
#include <cctype>
#include <cstring>
namespace cutefish::networkmanager::inet {
std::optional<uint32_t> parseIpv4(const std::string& text)
{
uint32_t result = 0;
size_t position = 0;
for (int part = 0; part < 4; ++part) {
if (part > 0) {
if (position >= text.size() || text[position] != '.')
return std::nullopt;
++position;
}
size_t digits = 0;
uint32_t byte = 0;
while (position < text.size() && std::isdigit(static_cast<unsigned char>(text[position])) && digits < 3) {
byte = byte * 10 + uint32_t(text[position] - '0');
++position;
++digits;
}
if (digits == 0 || byte > 255)
return std::nullopt;
result = (result << 8) | byte;
}
if (position != text.size())
return std::nullopt;
return result;
}
std::optional<std::array<uint8_t, 16>> parseIpv6(const std::string& text)
{
std::array<uint8_t, 16> address{};
if (text.find(':') == std::string::npos || inet_pton(AF_INET6, text.c_str(), address.data()) != 1)
return std::nullopt;
return address;
}
std::string formatIpv4(uint32_t address)
{
return std::to_string(address >> 24) + "." + std::to_string((address >> 16) & 0xff) + "."
+ std::to_string((address >> 8) & 0xff) + "." + std::to_string(address & 0xff);
}
std::string formatIpv6(const std::array<uint8_t, 16>& address)
{
char text[INET6_ADDRSTRLEN] = {};
if (!inet_ntop(AF_INET6, address.data(), text, sizeof(text)))
return {};
return text;
}
std::string formatIpv6Bytes(const std::string& bytes)
{
if (bytes.size() != 16)
return {};
std::array<uint8_t, 16> address{};
std::memcpy(address.data(), bytes.data(), 16);
return formatIpv6(address);
}
int family(const std::string& text)
{
if (parseIpv4(text))
return 4;
if (parseIpv6(text))
return 6;
return 0;
}
std::string normalized(const std::string& text)
{
if (const auto v4 = parseIpv4(text))
return formatIpv4(*v4);
if (const auto v6 = parseIpv6(text))
return formatIpv6(*v6);
return {};
}
bool isLinkLocal(const std::string& text)
{
if (const auto v4 = parseIpv4(text))
return (*v4 & 0xffff0000u) == 0xa9fe0000u;
if (const auto v6 = parseIpv6(text))
return (*v6)[0] == 0xfe && ((*v6)[1] & 0xc0) == 0x80;
return false;
}
} // namespace cutefish::networkmanager::inet