139 lines
3.2 KiB
C
139 lines
3.2 KiB
C
/* 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>
|
|
#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
|
|
static uint32_t get_default_route_ip_linux(void) {
|
|
FILE *f = fopen("/proc/net/route", "r");
|
|
if (!f) return 0;
|
|
|
|
char line[256];
|
|
char *ifname = NULL;
|
|
unsigned int dest, gw;
|
|
|
|
if (!fgets(line, sizeof(line), f)) {
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
while (fgets(line, sizeof(line), f)) {
|
|
int items = sscanf(line, "%ms %x %x", &ifname, &dest, &gw);
|
|
if (items != 3) {
|
|
free(ifname);
|
|
continue;
|
|
}
|
|
|
|
if (dest == 0) {
|
|
free(ifname);
|
|
break;
|
|
}
|
|
free(ifname);
|
|
ifname = NULL;
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
if (!ifname) return 0;
|
|
|
|
struct ifaddrs *ifaddr, *ifa;
|
|
if (getifaddrs(&ifaddr) == -1) {
|
|
free(ifname);
|
|
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;
|
|
if (strcmp(ifa->ifa_name, ifname) != 0) 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);
|
|
free(ifname);
|
|
return result;
|
|
}
|
|
#else
|
|
static uint32_t get_default_route_ip_windows(void) {
|
|
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (s == INVALID_SOCKET) return 0;
|
|
|
|
struct sockaddr_in remote;
|
|
remote.sin_family = AF_INET;
|
|
remote.sin_port = htons(53);
|
|
remote.sin_addr.s_addr = inet_addr("8.8.8.8");
|
|
|
|
if (connect(s, (struct sockaddr *)&remote, sizeof(remote)) == SOCKET_ERROR) {
|
|
closesocket(s);
|
|
return 0;
|
|
}
|
|
|
|
struct sockaddr_in local;
|
|
int len = sizeof(local);
|
|
if (getsockname(s, (struct sockaddr *)&local, &len) == SOCKET_ERROR) {
|
|
closesocket(s);
|
|
return 0;
|
|
}
|
|
|
|
closesocket(s);
|
|
return local.sin_addr.s_addr;
|
|
}
|
|
#endif
|
|
|
|
uint32_t get_default_route_ip(void) {
|
|
#ifdef _WIN32
|
|
return get_default_route_ip_windows();
|
|
#else
|
|
return get_default_route_ip_linux();
|
|
#endif
|
|
}
|