diff --git a/lib/platform_compat.h b/lib/platform_compat.h index 42b85fc3..d144c18f 100644 --- a/lib/platform_compat.h +++ b/lib/platform_compat.h @@ -2,6 +2,12 @@ * platform_compat — общие заголовки POSIX/Windows и адаптеры отсутствующих POSIX-функций. * Также предоставляет криптографический random_bytes, адреса интерфейсов, выбор default route * и классификацию публичных IPv4. Сокетные типы/ошибки и nonblocking API — в socket_compat.h. + * Подключать этот заголовок вместо прямых POSIX includes для общего кода. + * Windows: htobe*/be*toh через byteswap, strcasecmp/strncasecmp через _stricmp/_strnicmp, + * memmem через inline-поиск (пустой образец возвращает начало), poll через WSAPoll, mkdir через _mkdir. + * utun_gettimeofday — календарное Unix-время (не монотонное); Windows игнорирует tz. + * Windows pipe — _pipe(4096, _O_BINARY). fcntl: F_GETFL возвращает 0, F_SETFL с O_NONBLOCK включает + * неблокирующий режим; остальные флаги игнорируются, обратное переключение этим адаптером не выполняется. */ #ifndef PLATFORM_COMPAT_H @@ -178,12 +184,12 @@ extern "C" { #include -// Generate cryptographically secure random bytes -// Returns 0 on success, -1 on error +// Заполняет buffer криптографическими случайными байтами: POSIX /dev/urandom, Windows BCryptGenRandom. +// buffer не NULL, len > 0 (Windows: помещается в ULONG). 0 — всё заполнено, -1 — ошибка/неполное чтение. int random_bytes(uint8_t *buffer, size_t len); // Get IPv4 address of interface by its index (ifindex) -// Returns IPv4 address in network byte order, 0 on error +// POSIX: getifaddrs; Windows: IP Helper. Адрес в network byte order, 0 при ошибке/отсутствии адреса. uint32_t get_interface_ip_by_index(uint32_t netif_index); // Get IPv6 address of interface by its index (ifindex) @@ -200,15 +206,14 @@ int get_interface_ipv6_by_index(uint32_t netif_index, int temporary, uint8_t* ad int get_interface_ipv6_addr_nl(uint32_t netif_index, int prefer_stable, uint8_t* addr_out); // Determine the interface index for the default route (outgoing traffic) -// POSIX: UDP connect к фиксированному внешнему адресу, затем сопоставление локального IP с getifaddrs(). +// POSIX: UDP connect к 8.8.8.8:53 или [2001:4860:4860::8888]:53, сопоставление локального IP с getifaddrs(). // Windows: GetBestInterfaceEx к тому же адресу. Результат — выбранный маршрут к этому адресу, // который может отличаться от default route при более специфичных маршрутах. // family: AF_INET or AF_INET6, returns ifindex (0 on failure) uint32_t get_default_route_netif_index(int family); -// Классифицирует IPv4-адрес (network byte order): -// 1 = глобальный/публичный (маршрутизируемый в интернете), -// 0 = приватный, CGNAT, loopback, link-local, multicast или зарезервированный. +// Классифицирует IPv4 (network byte order) по встроенному списку: 0 для 0/8, 10/8, 127/8, 169.254/16, +// 172.16/12, 192.168/16, 100.64/10, 224/4 и 240/4; 1 для остальных. Это не проверка достижимости адреса. int ip_is_public(uint32_t addr_be); diff --git a/lib/platform_compat_doc.md b/lib/platform_compat_doc.md deleted file mode 100644 index b7720461..00000000 --- a/lib/platform_compat_doc.md +++ /dev/null @@ -1,81 +0,0 @@ -# platform_compat — Cross-platform compatibility layer - -## 1. Назначение -Унифицирует различия между POSIX (Linux/FreeBSD) и Windows (MSYS2 UCRT64) на уровне системных вызовов и типов. Предоставляет единый API для байтового порядка, строковых функций, энтропии, работы с сетевыми интерфейсами и времени. Полностью заголовочный (inline) для макросов и тривиальных обёрток, `.c` только для нетривиальных реализаций. - -## 2. Как пользоваться -Подключить `"platform_compat.h"` — всё остальное разрешается автоматически в зависимости от `_WIN32`. - -### Байтовый порядок -```c -uint16_t v16 = htobe16(x); // host → big-endian -uint32_t v32 = be32toh(x); // big-endian → host -uint64_t v64 = be64toh(x); // big-endian → host -// На Linux использует , на Windows — _byteswap_* -``` - -### Криптостойкий random -```c -uint8_t salt[8]; -if (random_bytes(salt, sizeof(salt)) != 0) { /* ошибка */ } -// Linux: /dev/urandom, Windows: BCryptGenRandom -``` - -### Сетевые интерфейсы -```c -// Определить интерфейс маршрута по умолчанию -uint32_t ifidx = get_default_route_netif_index(AF_INET); // или AF_INET6 - -// Получить IPv4 адрес интерфейса по индексу -uint32_t ipv4 = get_interface_ip_by_index(ifidx); // network byte order - -// Получить IPv6 адрес (постоянный или временный) -uint8_t ipv6[16]; -if (get_interface_ipv6_by_index(ifidx, 1, ipv6) == 0) { // temporary=1 - // ipv6 содержит 16 байт адреса -} -``` -**Windows**: `get_interface_ip_by_index`, `get_interface_ipv6_by_index`, `get_default_route_netif_index` — заглушки (возвращают 0/-1). - -### Время -```c -struct timeval tv; -utun_gettimeofday(&tv, NULL); // макрос: на Linux → gettimeofday, на Windows → inline-реализация -``` - -### Прочее -- `strcasecmp`/`strncasecmp` — на Windows `_stricmp`/`_strnicmp` -- `memmem` — на Windows inline-реализация `compat_memmem` -- `pipe` — на Windows `_pipe` с `_O_BINARY` -- `poll` — на Windows `WSAPoll`, флаги `POLLIN`/`POLLOUT` и т.д. определены если отсутствуют -- `ssize_t` — определён если отсутствует -- `fcntl` — на Windows упрощённая реализация только для `F_SETFL`/`O_NONBLOCK` -- `utun_mkdir` — кроссплатформенный `mkdir` - -### Ограничения -- Функции сетевых интерфейсов работают только на POSIX, на Windows — заглушки -- `get_default_route_netif_index` создаёт временный UDP-сокет к `8.8.8.8` (IPv4) или `2001:4860:4860::8888` (IPv6) для определения интерфейса -- Только IPv4/IPv6; `family` только `AF_INET` или `AF_INET6` - -## 3. API - -### Байтовый порядок -| Макрос | Назначение | -|--------|------------| -| `htobe16(x)` / `be16toh(x)` | 16-bit host ↔ big-endian | -| `htobe32(x)` / `be32toh(x)` | 32-bit host ↔ big-endian | -| `htobe64(x)` / `be64toh(x)` | 64-bit host ↔ big-endian | - -### Основные функции -| Функция | Назначение | -|---------|------------| -| `random_bytes(buffer, len)` | Криптостойкие случайные байты. 0 — успех, -1 — ошибка | -| `get_interface_ip_by_index(ifindex)` | IPv4 адрес интерфейса в network byte order, 0 при ошибке | -| `get_interface_ipv6_by_index(ifindex, temporary, out)` | IPv6 адрес (temporary=1 — временный privacy-адрес), 0 — успех | -| `get_default_route_netif_index(family)` | ifindex дефолтного маршрута через connect() к внешнему IP | - -### Макросы-заменители (условные) -| Макрос | Назначение | -|--------|------------| -| `utun_gettimeofday(tv, tz)` | gettimeofday (inline на Windows) | -| `utun_mkdir(path, mode)` | mkdir |