You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
6.2 KiB
198 lines
6.2 KiB
/* platform_compat.c - Platform compatibility layer implementation */ |
|
|
|
#include "platform_compat.h" |
|
#include <stddef.h> |
|
#include <stdint.h> |
|
#include <string.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
|
|
#ifdef _WIN32 |
|
#include <windows.h> |
|
#include <bcrypt.h> |
|
#include <iphlpapi.h> |
|
#pragma comment(lib, "iphlpapi.lib") |
|
#ifndef STATUS_SUCCESS |
|
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) |
|
#endif |
|
#else |
|
#include <fcntl.h> |
|
#include <unistd.h> |
|
#include <sys/types.h> |
|
#include <sys/socket.h> |
|
#include <netinet/in.h> |
|
#include <arpa/inet.h> |
|
#include <ifaddrs.h> |
|
#include <net/if.h> |
|
#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
|
|
|