Validate instance construction and retain the global log path safely
This commit is contained in:
1 parent
372b7d7f65
commit
7ea1fa9954
1 file changed
+54
-65
+54
-65
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user