Validate instance construction and retain the global log path safely

This commit is contained in:
evgeny committed 2026-10-26 09:08:24 +01:00
1 parent 372b7d7f65
commit 7ea1fa9954
1 file changed
+54 -65
+54 -65
View File
@@ -51,10 +51,6 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <unistd.h>
#include <sys/stat.h>
#include "../lib/platform_compat.h"
#include "../lib/mem.h"
@@ -64,12 +60,11 @@
// Forward declarations
static uint32_t get_dest_ip(const uint8_t *packet, size_t len);
static int mkdir_recursive(const char* path);
static void instance_destroy(struct UTUN_INSTANCE* instance, int owns_config);
// Global instance for signal handlers
static struct UTUN_INSTANCE *g_instance = NULL;
// Путь глобального logger должен переживать config/instance, поскольку debug API заимствует строку.
static char g_config_log_path[256];
// Global flag to control TUN initialization (disabled by default)
static int g_tun_init_enabled = 0;
@@ -138,8 +133,11 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
/* Always verify node_id matches pubkey, fix if mismatched */
{
uint8_t pub_bin[SC_PUBKEY_SIZE];
sc_compute_public_key_from_private(instance->my_keys.private_key, pub_bin);
if (sc_compute_public_key_from_private(instance->my_keys.private_key, pub_bin) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "cannot compute instance X25519 public key"); return -1;
}
uint64_t derived = sc_derive_node_id_from_pubkey(pub_bin);
if (!derived) { DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "instance identity derived zero node_id"); return -1; }
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "node_id check: config=%016llx derived=%016llx match=%d",
(unsigned long long)instance->node_id, (unsigned long long)derived,
(instance->node_id == derived));
@@ -158,7 +156,9 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
}
{
uint8_t ed_priv_hash[SHA512_DIGEST_LENGTH];
SHA512(instance->my_keys.private_key, SC_PRIVKEY_SIZE, ed_priv_hash);
if (!SHA512(instance->my_keys.private_key, SC_PRIVKEY_SIZE, ed_priv_hash)) {
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "cannot derive instance Ed25519 seed"); return -1;
}
memcpy(instance->my_ed25519_privkey, ed_priv_hash, SC_PRIVKEY_SIZE);
}
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "Ed25519 pubkey derived successfully");
@@ -173,7 +173,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
// Initialize connection queue
instance->connections = queue_new(ua, 256, 0, 8, "connections");
if (!instance->connections) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create connections queue"); return -1; }
instance->tcp_connections = queue_new(ua, sizeof(struct tcp_conn_entry), sizeof(uint64_t), 8, "tcpconn");
instance->tcp_connections = queue_new(ua, 256, offsetof(struct tcp_conn_entry, node_id), sizeof(uint64_t), "tcpconn");
if (!instance->tcp_connections) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create tcp_connections queue"); return -1; }
struct CFG_NETWORK *net = config->networks;
while (net) {
@@ -184,15 +184,15 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
}
struct NETWORK_ENTRY *ne = (struct NETWORK_ENTRY*)entry->data;
ne->id = net->id & 0x00FFFFFFFFFFFFFFULL;
for (int i = 0; i < SC_PUBKEY_SIZE; i++) {
unsigned int b; sscanf(net->pubkey_hex + i * 2, "%2x", &b); ne->pubkey[i] = (uint8_t)b;
}
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) {
unsigned int b; sscanf(net->signing_key_hex + i * 2, "%2x", &b); ne->signing_key[i] = (uint8_t)b;
if (sc_hex_to_binary(net->pubkey_hex, ne->pubkey, sizeof(ne->pubkey)) != SC_OK ||
sc_hex_to_binary(net->signing_key_hex, ne->signing_key, sizeof(ne->signing_key)) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "invalid keys for network %s", net->name); queue_entry_free(entry); return -1;
}
strncpy(ne->name, net->name, sizeof(ne->name) - 1);
ne->name[sizeof(ne->name) - 1] = '\0';
queue_data_put_with_index(instance->networks, entry);
if (queue_data_put_with_index(instance->networks, entry) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "cannot index configured network %s", net->name); return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Network added: [%s] id=%012llx", ne->name, (unsigned long long)ne->id);
net = net->next;
}
@@ -217,7 +217,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Socket initialization failed: result=%d", socket_result);
return -1;
}
if (config->global.db_path[0]) mkdir_recursive(config->global.db_path);
if (config->global.db_path[0] && mkdir_recursive(config->global.db_path) < 0) return -1;
if (g_topo_group_enabled) {
instance->topo_groups = topo_groups_init(instance);
if (!instance->topo_groups) {
@@ -322,6 +322,9 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
// Create and initialize root instance from config file
struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config_file) {
if (!ua || !config_file || !*config_file) {
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "instance create requires uasync and a config path"); return NULL;
}
// Ensure keys and node_id exist in config (generates them if missing)
if (config_ensure_keys_and_node_id(config_file) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to ensure keys and node_id in config: %s", config_file);
@@ -335,38 +338,8 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
return NULL;
}
// Open log file only if not using global debug system output
if (config->global.log_file[0]) {
debug_set_output_file(config->global.log_file);
}
// Apply debug level from config
if (config->global.debug_level[0]) {
debug_apply_global_level(config->global.debug_level);
}
// Apply per-category debug levels from [debug] section
for (int i = 0; i < config->global.debug_levels.count; i++) {
debug_apply_category_config(
config->global.debug_levels.category[i],
config->global.debug_levels.level[i]
);
}
// Allocate instance
struct UTUN_INSTANCE *instance = u_calloc(1, sizeof(struct UTUN_INSTANCE));
if (!instance) {
free_config(config);
return NULL;
}
instance->etcp_connect_timeout_tb = 20000;
// Initialize using common function
if (instance_init_common(instance, ua, config) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Core creation failed; releasing all initialized resources");
instance_destroy(instance, 1);
return NULL;
}
struct UTUN_INSTANCE* instance = utun_instance_create_from_config(ua, config);
if (!instance) { free_config(config); return NULL; }
// Log instance info
if (instance->name[0] != '\0') {
@@ -382,10 +355,14 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
// Create instance from existing config structure (config ownership transfers to instance)
struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct utun_config* config) {
if (!config) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "NULL config");
if (!ua || !config) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "instance create requires uasync and config");
return NULL;
}
if (config->global.log_file[0]) {
snprintf(g_config_log_path, sizeof(g_config_log_path), "%s", config->global.log_file);
debug_set_output_file(g_config_log_path);
}
if (config->global.debug_level[0])
debug_apply_global_level(config->global.debug_level);
@@ -412,15 +389,23 @@ struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct
// Create instance from config text string (writes to temp file, parses, cleans up)
struct UTUN_INSTANCE* utun_instance_create_from_str(struct UASYNC* ua, const char* config_text) {
if (!config_text) return NULL;
if (!ua || !config_text) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "instance create requires uasync and config text"); return NULL; }
char tmp_path[] = "/tmp/utun_cfg_XXXXXX";
int fd = mkstemp(tmp_path);
if (fd < 0) return NULL;
if (fd < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "cannot create temporary config: %s", strerror(errno)); return NULL; }
size_t len = strlen(config_text);
if (write(fd, config_text, len) != (ssize_t)len) { close(fd); unlink(tmp_path); return NULL; }
close(fd);
size_t written = 0;
int failed = 0;
while (written < len) {
ssize_t n = write(fd, config_text + written, len - written);
if (n < 0 && errno == EINTR) continue;
if (n <= 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "temporary config write failed at %zu: %s", written, strerror(errno)); failed = 1; break; }
written += (size_t)n;
}
if (close(fd)) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "temporary config close failed: %s", strerror(errno)); failed = 1; }
if (failed) { if (unlink(tmp_path)) DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "temporary config cleanup failed: %s", strerror(errno)); return NULL; }
struct UTUN_INSTANCE* inst = utun_instance_create(ua, tmp_path);
unlink(tmp_path);
if (unlink(tmp_path)) DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "temporary config cleanup failed: %s", strerror(errno));
return inst;
}
@@ -623,11 +608,6 @@ static void instance_destroy(struct UTUN_INSTANCE* instance, int owns_config) {
// This allows sharing uasync between multiple instances
instance->ua = NULL;
// Clear global instance
if (g_instance == instance) {
g_instance = NULL;
}
// Free the instance memory
DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Freeing instance memory");
@@ -679,11 +659,20 @@ void utun_instance_stop(struct UTUN_INSTANCE *instance) {
static int mkdir_recursive(const char *path) {
char tmp[512]; int len = snprintf(tmp, sizeof(tmp), "%s", path);
if (len <= 0 || (size_t)len >= sizeof(tmp)) return -1;
for (char *p = tmp + 1; *p; p++) {
if (*p == '/') { *p = '\0'; utun_mkdir(tmp, 0755); *p = '/'; }
if (len <= 0 || (size_t)len >= sizeof(tmp)) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "invalid database directory length=%d", len); return -1; }
for (char *p = tmp + 1;; p++) {
if (*p && *p != '/') continue;
if (*p == '/' && p == tmp + 2 && tmp[1] == ':') continue; // Windows drive root
char saved = *p; *p = '\0';
if (utun_mkdir(tmp, 0755) < 0) {
int err = errno; struct stat st;
if (err != EEXIST || stat(tmp, &st) < 0 || !S_ISDIR(st.st_mode)) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "cannot create database directory %s: %s", tmp, strerror(err)); return -1;
}
}
*p = saved; if (!saved) break;
}
return utun_mkdir(tmp, 0755);
return 0;
}
int utun_core_start(struct UTUN_INSTANCE *instance) {