#include "WindowsPlatform.hh" #include "NetworkAddresses.hh" #include #include #ifndef PHOSG_WINDOWS #include #else #include #include #endif #include #include #include #include #include std::map get_local_addresses() { std::map ret; #ifndef PHOSG_WINDOWS struct ifaddrs* ifa_raw; if (getifaddrs(&ifa_raw)) { auto s = phosg::string_for_error(errno); throw std::runtime_error(std::format("failed to get interface addresses: {}", s)); } std::unique_ptr ifa(ifa_raw, freeifaddrs); for (struct ifaddrs* i = ifa.get(); i; i = i->ifa_next) { if (!i->ifa_addr) { continue; } auto* sin = reinterpret_cast(i->ifa_addr); if (sin->sin_family != AF_INET) { continue; } ret.emplace(i->ifa_name, ntohl(sin->sin_addr.s_addr)); } #else ULONG buffer_size = 0x1000; std::vector buffer(buffer_size); auto* adapters = reinterpret_cast(buffer.data()); DWORD result = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, adapters, &buffer_size); if (result == ERROR_BUFFER_OVERFLOW) { buffer.resize(buffer_size); adapters = reinterpret_cast(buffer.data()); result = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, adapters, &buffer_size); } if (result != NO_ERROR) { throw std::runtime_error(std::format("GetAdaptersAddresses failed: {}", result)); } for (IP_ADAPTER_ADDRESSES* adapter = adapters; adapter != nullptr; adapter = adapter->Next) { for (IP_ADAPTER_UNICAST_ADDRESS* ua = adapter->FirstUnicastAddress; ua != nullptr; ua = ua->Next) { if (ua->Address.lpSockaddr->sa_family == AF_INET) { sockaddr_in* sa_in = reinterpret_cast(ua->Address.lpSockaddr); ret.emplace(adapter->AdapterName, ntohl(sa_in->sin_addr.S_un.S_addr)); } } } #endif return ret; } bool is_loopback_address(uint32_t addr) { return ((addr & 0xFF000000) == 0x7F000000); // 127.0.0.0/8 } bool is_local_address(uint32_t addr) { return is_loopback_address(addr) || // 127.0.0.0/8 ((addr & 0xFF000000) == 0x0A000000) || // 10.0.0.0/8 ((addr & 0xFFF00000) == 0xAC100000) || // 172.16.0.0/12 ((addr & 0xFFFF0000) == 0xC0A80000) || // 192.168.0.0/16 ((addr & 0xFFFF0000) == 0xA9FE0000); // 169.254.0.0/16 } bool is_local_address(const sockaddr_storage& daddr) { if (daddr.ss_family != AF_INET) { return false; } const sockaddr_in* sin = reinterpret_cast(&daddr); return is_local_address(ntohl(sin->sin_addr.s_addr)); } std::string string_for_address(uint32_t address) { return std::format("{}.{}.{}.{}", static_cast(address >> 24), static_cast(address >> 16), static_cast(address >> 8), static_cast(address)); } uint32_t address_for_string(const char* address) { return ntohl(inet_addr(address)); } uint64_t devolution_phone_number_for_netloc(uint32_t addr, uint16_t port) { // It seems the address part of the number is fixed-width, but the port is not. Why did they do it this way? if (port & 0xF000) { return (static_cast(addr) << 16) | port; } else if (port & 0x0F00) { return (static_cast(addr) << 12) | port; } else if (port & 0x00F0) { return (static_cast(addr) << 8) | port; } else { return (static_cast(addr) << 4) | port; } }