Browse Source

Windows: Исправлен запуск utun - TUN, логирование, права администратора

- Добавлен platform_compat.c с кроссплатформенной генерацией случайных чисел
- Исправлена генерация ключей и node_id на Windows (вместо /dev/urandom)
- PID файл отключен по умолчанию на Windows
- Добавлено двойное логирование: файл utun.log + консоль
- Добавлен манифест Windows для запроса прав администратора
- Исправлено завершение программы при ошибках отправки (Network unreachable)
- TUN инициализация включена по умолчанию
- Исправлен main loop (instance->running = 1)
nodeinfo-routing-update
jeka 2 months ago
parent
commit
4a3c5724b7
  1. 1
      lib/Makefile.am
  2. 75
      lib/debug_config.c
  3. 17
      lib/debug_config.h
  4. 37
      lib/platform_compat.c
  5. 4
      lib/platform_compat.h
  6. 6
      src/Makefile.am
  7. 22
      src/config_updater.c
  8. 40
      src/secure_channel.c
  9. 65
      src/utun.c
  10. 12
      src/utun.manifest
  11. 3
      src/utun_instance.c

1
lib/Makefile.am

@ -15,6 +15,7 @@ libuasync_a_SOURCES = \
sha256.h \
socket_compat.c \
socket_compat.h \
platform_compat.c \
platform_compat.h
libuasync_a_CFLAGS = \

75
lib/debug_config.c

@ -108,21 +108,21 @@ static debug_category_t get_category_by_name(const char* name) {
/* Global debug configuration */
debug_config_t g_debug_config;
FILE* debug_output_file = NULL;
/* Initialize debug system with default settings */
void debug_config_init(void) {
g_debug_config.level = DEBUG_LEVEL_ERROR;
g_debug_config.level = DEBUG_LEVEL_TRACE; // Global level
g_debug_config.categories = DEBUG_CATEGORY_ALL;
g_debug_config.timestamp_enabled = 1;
g_debug_config.function_name_enabled = 1;
g_debug_config.file_line_enabled = 1;
g_debug_config.output_file = NULL;
if (debug_output_file && debug_output_file != stdout && debug_output_file != stderr) {
fclose(debug_output_file);
}
debug_output_file = stdout;
// Dual output defaults
g_debug_config.file_output = NULL; // No file by default
g_debug_config.file_level = DEBUG_LEVEL_TRACE; // File gets everything
g_debug_config.console_level = DEBUG_LEVEL_INFO; // Console gets INFO+
g_debug_config.console_enabled = 1; // Console enabled
}
/* Set debug level */
@ -158,14 +158,57 @@ void debug_enable_file_line(int enable) {
}
void debug_set_output_file(const char* file_path) {
if (debug_output_file) return;// уже установлен, кто первый того и тапки
if (g_debug_config.file_output) return;// уже установлен, кто первый того и тапки
FILE* new_file = fopen(file_path, "a");
if (new_file) {
debug_output_file = new_file;
g_debug_config.file_output = new_file;
g_debug_config.output_file = file_path;
}
}
/* Set console log level */
void debug_set_console_level(debug_level_t level) {
g_debug_config.console_level = level;
}
/* Set file log level */
void debug_set_file_level(debug_level_t level) {
g_debug_config.file_level = level;
}
/* Enable/disable console output */
void debug_enable_console(int enable) {
g_debug_config.console_enabled = enable;
}
/* Enable file output with optional truncation */
void debug_enable_file_output(const char* file_path, int truncate) {
if (!file_path) return;
// Close existing file if open
if (g_debug_config.file_output) {
fclose(g_debug_config.file_output);
g_debug_config.file_output = NULL;
}
// Open new file
const char* mode = truncate ? "w" : "a";
FILE* new_file = fopen(file_path, mode);
if (new_file) {
g_debug_config.file_output = new_file;
g_debug_config.output_file = file_path;
}
}
/* Disable file output */
void debug_disable_file_output(void) {
if (g_debug_config.file_output) {
fclose(g_debug_config.file_output);
g_debug_config.file_output = NULL;
g_debug_config.output_file = NULL;
}
}
/* Check if debug output should be shown for given level and category */
int debug_should_output(debug_level_t level, debug_category_t category) {
@ -212,8 +255,6 @@ void debug_output(debug_level_t level, debug_category_t category,
va_list args;
va_start(args, format);
FILE* output = debug_output_file ? debug_output_file : stdout;
/* Add timestamp with microseconds: hh:mm:ss-xxx.yyy */
struct timeval tv;
gettimeofday(&tv, NULL);
@ -260,9 +301,17 @@ void debug_output(debug_level_t level, debug_category_t category,
va_end(args);
/* Output the entire line at once */
fprintf(output, "%s", buffer);
fflush(output);
/* Output to console if enabled and level is sufficient */
if (g_debug_config.console_enabled && level <= g_debug_config.console_level) {
fprintf(stdout, "%s", buffer);
fflush(stdout);
}
/* Output to file if open and level is sufficient */
if (g_debug_config.file_output && level <= g_debug_config.file_level) {
fprintf(g_debug_config.file_output, "%s", buffer);
fflush(g_debug_config.file_output);
}
#undef BUFFER_SIZE
}

17
lib/debug_config.h

@ -16,6 +16,7 @@
#include <stdint.h>
#include <stddef.h>
#include <time.h>
#include <stdio.h> // FILE
#ifdef __cplusplus
extern "C" {
@ -59,6 +60,12 @@ typedef struct {
int function_name_enabled; // Include function names
int file_line_enabled; // Include file:line info
const char* output_file; // NULL = stdout, otherwise file path
// Dual output support
FILE* file_output; // File handle for log file (NULL if not open)
debug_level_t file_level; // Log level for file output
debug_level_t console_level; // Log level for console output
int console_enabled; // Enable console output
} debug_config_t;
/* Global debug configuration */
@ -84,15 +91,19 @@ void debug_enable_function_name(int enable);
void debug_enable_file_line(int enable);
void debug_set_output_file(const char* file_path);
/* Dual output configuration */
void debug_set_console_level(debug_level_t level);
void debug_set_file_level(debug_level_t level);
void debug_enable_file_output(const char* file_path, int truncate);
void debug_disable_file_output(void);
void debug_enable_console(int enable);
// вывод struct sockaddr_storage как текст
size_t addr_to_string(const struct sockaddr_storage *addr, char *buf, size_t buflen);
// hex dump в лог
void log_dump(const char* prefix, const uint8_t* data, size_t len);
#include <stdio.h>
extern FILE* debug_output_file;
/* Check if debug output should be shown for given level and category */
int debug_should_output(debug_level_t level, debug_category_t category);

37
lib/platform_compat.c

@ -0,0 +1,37 @@
/* platform_compat.c - Platform compatibility layer implementation */
#include "platform_compat.h"
#include <stddef.h>
#include <stdint.h>
#ifdef _WIN32
#include <windows.h>
#include <bcrypt.h>
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#else
#include <fcntl.h>
#include <unistd.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
}

4
lib/platform_compat.h

@ -133,4 +133,8 @@
#include <poll.h>
#endif
// Generate cryptographically secure random bytes
// Returns 0 on success, -1 on error
int random_bytes(uint8_t *buffer, size_t len);
#endif // PLATFORM_COMPAT_H

6
src/Makefile.am

@ -21,7 +21,7 @@ utun_CORE_SOURCES = \
# Platform-specific TUN sources
if OS_WINDOWS
utun_TUN_SOURCES = tun_windows.c
utun_TUN_LIBS = -liphlpapi -lws2_32 -ladvapi32
utun_TUN_LIBS = -liphlpapi -lws2_32 -ladvapi32 -lbcrypt
else
utun_TUN_SOURCES = tun_linux.c
utun_TUN_LIBS =
@ -134,6 +134,10 @@ all-local: copy-to-root
copy-to-root: utun$(EXEEXT)
@cp -f utun$(EXEEXT) $(top_srcdir)/
@cp -f $(top_srcdir)/lib/wintun.dll $(top_srcdir)/ 2>/dev/null || echo "Warning: wintun.dll not found in lib/"
if OS_WINDOWS
@cp -f $(srcdir)/utun.manifest $(top_srcdir)/utun.exe.manifest 2>/dev/null || true
endif
# Clean
clean-local:

22
src/config_updater.c

@ -4,6 +4,7 @@
#include "config_parser.h"
#include "secure_channel.h"
#include "debug_config.h"
#include "../lib/platform_compat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -334,26 +335,11 @@ int config_ensure_keys_and_node_id(const char *filename) {
}
if (need_node_id) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
printf( "Failed to open /dev/urandom");
free_config(config);
return -1;
}
if (read(fd, &new_node_id, sizeof(new_node_id)) != sizeof(new_node_id)) {
close(fd);
printf( "Failed to read random bytes for node_id");
if (random_bytes((uint8_t*)&new_node_id, sizeof(new_node_id)) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to generate random node_id");
free_config(config);
return -1;
}
close(fd);
new_node_id &= 0x7FFFFFFFFFFFFFFF;
}
@ -386,7 +372,7 @@ int config_ensure_keys_and_node_id(const char *filename) {
if (need_node_id) {
char node_id_hex[HEXNODEID_LEN + 1];
snprintf(node_id_hex, sizeof(node_id_hex), "%llx", (unsigned long long)new_node_id);
snprintf(node_id_hex, sizeof(node_id_hex), "%016llx", (unsigned long long)new_node_id);
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_node_id", node_id_hex) < 0) {
ret = -1;

40
src/secure_channel.c

@ -6,6 +6,7 @@
#include "secure_channel.h"
#include "../lib/debug_config.h"
#include "../lib/platform_compat.h"
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
@ -41,13 +42,8 @@ static int sc_urandom_initialized = 0;
static void sc_init_random_seed(void)
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd >= 0) {
ssize_t ret = read(fd, sc_urandom_seed, 8);
close(fd);
if (ret == 8) {
sc_urandom_initialized = 1;
}
if (random_bytes(sc_urandom_seed, 8) == 0) {
sc_urandom_initialized = 1;
}
}
@ -135,17 +131,15 @@ static sc_status_t verify_and_strip_crc32(uint8_t *plaintext_with_crc, size_t to
// OpenSSL-specific implementations
static int sc_rng(uint8_t *dest, unsigned size) {
// OpenSSL has its own RNG, but for consistency with original, mix urandom + pid + time
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
return 0;
}
ssize_t ret = read(fd, dest, size);
close(fd);
if (ret != size) {
if (random_bytes(dest, size) != 0) {
return 0;
}
/* Mix in PID and microtime for additional entropy */
#ifdef _WIN32
DWORD pid = GetCurrentProcessId();
#else
pid_t pid = getpid();
#endif
struct timeval tv;
gettimeofday(&tv, NULL);
for (unsigned i = 0; i < size; i++) {
@ -511,28 +505,22 @@ static const struct uECC_Curve_t *curve = NULL;
static int sc_rng(uint8_t *dest, unsigned size)
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
return 0;
}
ssize_t ret = read(fd, dest, size);
close(fd);
if (ret != size) {
if (random_bytes(dest, size) != 0) {
return 0;
}
/* Mix in PID and microtime for additional entropy */
#ifdef _WIN32
DWORD pid = GetCurrentProcessId();
#else
pid_t pid = getpid();
#endif
struct timeval tv;
gettimeofday(&tv, NULL);
for (unsigned i = 0; i < size; i++) {
dest[i] ^= ((pid >> (i % (sizeof(pid) * 8))) & 0xFF);
dest[i] ^= ((tv.tv_sec >> (i % (sizeof(tv.tv_sec) * 8))) & 0xFF);
dest[i] ^= ((tv.tv_usec >> (i % (sizeof(tv.tv_usec) * 8))) & 0xFF);
}
return 1;
}

65
src/utun.c

@ -20,6 +20,13 @@
#include <getopt.h>
#include "../lib/platform_compat.h"
#ifdef _WIN32
#include <windows.h>
#define SECURITY_WIN32
#include <security.h>
#include <sddl.h>
#endif
/*
Архитектура:
@ -72,7 +79,11 @@ static uint32_t get_dest_ip(const uint8_t *packet, size_t len) {
static void parse_args(int argc, char *argv[], cmd_args_t *args) {
memset(args, 0, sizeof(*args));
args->config_file = DEFAULT_CONFIG;
#ifdef _WIN32
args->pid_file = NULL; // Windows: no default PID file
#else
args->pid_file = DEFAULT_PIDFILE;
#endif
args->log_file = NULL;
args->debug_config = NULL;
args->foreground = 0;
@ -125,14 +136,18 @@ static void print_usage(const char *progname) {
printf("Secure VPN tunnel over UDP with TUN interface\n\n");
printf("Options:\n");
printf(" -c, --config FILE Configuration file (default: %s)\n", DEFAULT_CONFIG);
#ifdef _WIN32
printf(" -p, --pidfile FILE PID file (default: none, use -p to specify)\n");
#else
printf(" -p, --pidfile FILE PID file (default: %s)\n", DEFAULT_PIDFILE);
printf(" -l, --log FILE Log file (default: stderr)\n");
#endif
printf(" -l, --log FILE Log file (default: utun.log)\n");
printf(" -d, --debug CONFIG Debug configuration (e.g., \"etcp:debug,routing:info\")\n");
printf(" -f, --foreground Run in foreground (don't daemonize)\n");
printf(" -h, --help Show this help\n");
printf("\nExamples:\n");
printf(" %s -c myconfig.conf\n", progname);
printf(" %s --config server.conf --pidfile /var/run/utun.pid\n", progname);
printf(" %s --config server.conf\n", progname);
}
// Write PID file
@ -255,10 +270,33 @@ int main(int argc, char *argv[]) {
if (args.debug_config) {
debug_parse_config(args.debug_config);
}
if (args.log_file) {
debug_set_output_file(args.log_file);
}
// Enable file logging (default: utun.log, truncate on start)
const char* log_file = args.log_file ? args.log_file : "utun.log";
debug_enable_file_output(log_file, 1);
#ifdef _WIN32
// Check for administrator privileges
{
BOOL is_admin = FALSE;
PSID administrators_group = NULL;
SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&nt_authority, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
&administrators_group)) {
CheckTokenMembership(NULL, administrators_group, &is_admin);
FreeSid(administrators_group);
}
if (!is_admin) {
fprintf(stderr, "FATAL ERROR: Administrator privileges required\n");
fprintf(stderr, "Please run utun.exe as Administrator (right-click -> Run as administrator)\n");
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Administrator privileges required");
return 1;
}
}
#endif
// Create uasync instance
struct UASYNC* ua = uasync_create();
@ -268,6 +306,19 @@ int main(int argc, char *argv[]) {
return 1;
}
#ifdef _WIN32
// Check for wintun.dll before enabling TUN
if (access("wintun.dll", F_OK) != 0) {
fprintf(stderr, "FATAL ERROR: wintun.dll not found in current directory\n");
fprintf(stderr, "Please ensure wintun.dll is located in the same directory as utun.exe\n");
uasync_destroy(ua, 0);
return 1;
}
#endif
// Enable TUN initialization for VPN functionality
utun_instance_set_tun_init_enabled(1);
// Create and initialize instance
struct UTUN_INSTANCE *instance = utun_instance_create(ua, args.config_file);
if (!instance) {
@ -305,8 +356,8 @@ int main(int argc, char *argv[]) {
}
}
// Write PID file
if (write_pidfile(args.pid_file) < 0) {
// Write PID file (only if specified)
if (args.pid_file && write_pidfile(args.pid_file) < 0) {
utun_instance_destroy(instance);
return 1;
}

12
src/utun.manifest

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="utun.exe" type="win32"/>
<description>uTun VPN Tunnel</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

3
src/utun_instance.c

@ -319,6 +319,9 @@ int utun_instance_init(struct UTUN_INSTANCE *instance) {
fprintf(stderr, "DEBUG: Connections initialized successfully, count=%d\n", instance->connections_count);
fflush(stderr);
// Start the main loop
instance->running = 1;
return 0;
}

Loading…
Cancel
Save