/* platform_compat.c - Platform compatibility layer implementation */ #include "platform_compat.h" #include #include #include #include #include #ifdef _WIN32 #include #include #include #pragma comment(lib, "iphlpapi.lib") #ifndef STATUS_SUCCESS #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #endif #else #include #include #include #include #include #include #include #include #ifndef IFA_F_TEMPORARY #define IFA_F_TEMPORARY 0x01 #endif #endif /* * Generate cryptographically secure random bytes * Returns 0 on success, -1 on error */ int random_bytes(uint8_t *buffer, size_t len) { if (!buffer || len == 0) return -1; #ifdef _WIN32 NTSTATUS status = BCryptGenRandom(NULL, buffer, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); return (status == STATUS_SUCCESS) ? 0 : -1; #else int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) return -1; ssize_t ret = read(fd, buffer, len); close(fd); return (ret == (ssize_t)len) ? 0 : -1; #endif } #ifndef _WIN32 uint32_t get_interface_ip_by_index(uint32_t netif_index) { struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) return 0; uint32_t result = 0; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_name == NULL) continue; unsigned int idx = if_nametoindex(ifa->ifa_name); if (idx != netif_index) continue; if (ifa->ifa_addr->sa_family != AF_INET) continue; struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; result = addr->sin_addr.s_addr; break; } freeifaddrs(ifaddr); return result; } int get_interface_ipv6_by_index(uint32_t netif_index, int temporary, uint8_t* addr_out) { if (!addr_out) return -1; memset(addr_out, 0, 16); struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) return -1; int found = 0; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_name == NULL) continue; unsigned int idx = if_nametoindex(ifa->ifa_name); if (idx != netif_index) continue; if (ifa->ifa_addr->sa_family != AF_INET6) continue; // Skip link-local addresses (fe80::/10) struct sockaddr_in6* sin6 = (struct sockaddr_in6*)ifa->ifa_addr; if ((sin6->sin6_addr.s6_addr[0] & 0xfe) == 0xfe && sin6->sin6_addr.s6_addr[1] == 0x80) continue; int is_temporary = (ifa->ifa_flags & IFA_F_TEMPORARY) ? 1 : 0; if (temporary && is_temporary) { memcpy(addr_out, &sin6->sin6_addr, 16); found = 1; break; } if (!temporary && !is_temporary) { memcpy(addr_out, &sin6->sin6_addr, 16); found = 1; break; } } freeifaddrs(ifaddr); return found ? 0 : -1; } uint32_t get_default_route_netif_index(int family) { if (family != AF_INET && family != AF_INET6) return 0; int sock = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) return 0; struct sockaddr_storage bind_addr; memset(&bind_addr, 0, sizeof(bind_addr)); if (family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)&bind_addr; sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; } else { struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&bind_addr; sin6->sin6_family = AF_INET6; sin6->sin6_addr = in6addr_any; } socklen_t bind_len = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); if (bind(sock, (struct sockaddr*)&bind_addr, bind_len) != 0) { close(sock); return 0; } struct sockaddr_storage remote; memset(&remote, 0, sizeof(remote)); socklen_t remote_len; if (family == AF_INET) { struct sockaddr_in* sin = (struct sockaddr_in*)&remote; sin->sin_family = AF_INET; sin->sin_port = htons(53); inet_pton(AF_INET, "8.8.8.8", &sin->sin_addr); remote_len = sizeof(struct sockaddr_in); } else { struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&remote; sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(53); inet_pton(AF_INET6, "2001:4860:4860::8888", &sin6->sin6_addr); remote_len = sizeof(struct sockaddr_in6); } if (connect(sock, (struct sockaddr*)&remote, remote_len) != 0) { close(sock); return 0; } struct sockaddr_storage src; socklen_t src_len = sizeof(src); if (getsockname(sock, (struct sockaddr*)&src, &src_len) != 0) { close(sock); return 0; } close(sock); struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) return 0; uint32_t result = 0; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_addr->sa_family != family) continue; if (family == AF_INET) { struct sockaddr_in* src_sin = (struct sockaddr_in*)&src; struct sockaddr_in* ifa_sin = (struct sockaddr_in*)ifa->ifa_addr; if (src_sin->sin_addr.s_addr == ifa_sin->sin_addr.s_addr) { if (ifa->ifa_name) result = if_nametoindex(ifa->ifa_name); break; } } else { struct sockaddr_in6* src_sin6 = (struct sockaddr_in6*)&src; struct sockaddr_in6* ifa_sin6 = (struct sockaddr_in6*)ifa->ifa_addr; if (memcmp(&src_sin6->sin6_addr, &ifa_sin6->sin6_addr, 16) == 0) { if (ifa->ifa_name) result = if_nametoindex(ifa->ifa_name); break; } } } freeifaddrs(ifaddr); return result; } #else uint32_t get_interface_ip_by_index(uint32_t netif_index) { (void)netif_index; return 0; } int get_interface_ipv6_by_index(uint32_t netif_index, int temporary, uint8_t* addr_out) { (void)netif_index; (void)temporary; if (addr_out) memset(addr_out, 0, 16); return -1; } uint32_t get_default_route_netif_index(int family) { (void)family; return 0; } #endif