|
|
|
|
@ -13,6 +13,7 @@
|
|
|
|
|
#include <unistd.h> |
|
|
|
|
#include <fcntl.h> |
|
|
|
|
#include <sys/stat.h> |
|
|
|
|
#include <errno.h> |
|
|
|
|
#include "../lib/mem.h" |
|
|
|
|
|
|
|
|
|
#define PRIV_HEXKEY_LEN 65 // 32 bytes * 2 hex chars + null
|
|
|
|
|
@ -53,48 +54,6 @@ static int is_valid_node_id(uint64_t node_id) {
|
|
|
|
|
return node_id != 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int read_file_to_mem(const char *filename, char **buffer, size_t *size) { |
|
|
|
|
FILE *fp = fopen(filename, "r"); |
|
|
|
|
|
|
|
|
|
if (!fp) return -1; |
|
|
|
|
|
|
|
|
|
fseek(fp, 0, SEEK_END); |
|
|
|
|
|
|
|
|
|
long file_size = ftell(fp); |
|
|
|
|
|
|
|
|
|
if (file_size < 0) { |
|
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
fseek(fp, 0, SEEK_SET); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*buffer = u_malloc(file_size + 1); |
|
|
|
|
|
|
|
|
|
if (!*buffer) { |
|
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size_t read_size = fread(*buffer, 1, file_size, fp); |
|
|
|
|
|
|
|
|
|
if (read_size != (size_t)file_size) { |
|
|
|
|
u_free(*buffer); |
|
|
|
|
|
|
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
(*buffer)[file_size] = '\0'; |
|
|
|
|
*size = file_size; |
|
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int write_mem_to_file(const char *filename, const char *buffer, size_t size) { |
|
|
|
|
FILE *fp = fopen(filename, "w"); |
|
|
|
|
|
|
|
|
|
@ -261,30 +220,35 @@ static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_cap
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int config_ensure_keys_and_node_id(const char *filename) { |
|
|
|
|
struct utun_config *config = parse_config(filename); |
|
|
|
|
|
|
|
|
|
if (!config) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to parse config: %s", filename); |
|
|
|
|
|
|
|
|
|
// ── Read config file into memory (single open) ──
|
|
|
|
|
FILE *fp = fopen(filename, "rb"); |
|
|
|
|
if (!fp) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to open config file: %s (errno=%d)", filename, errno); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fseek(fp, 0, SEEK_END); long fsz = ftell(fp); fseek(fp, 0, SEEK_SET); |
|
|
|
|
if (fsz < 0) { fclose(fp); return -1; } |
|
|
|
|
size_t file_size = (size_t)fsz; |
|
|
|
|
char *file_buf = u_malloc(file_size + 1); |
|
|
|
|
if (!file_buf || fread(file_buf, 1, file_size, fp) != file_size) { u_free(file_buf); fclose(fp); return -1; } |
|
|
|
|
file_buf[file_size] = '\0'; |
|
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
|
|
struct utun_config *config = parse_config_from_buf(file_buf, file_size, filename); |
|
|
|
|
if (!config) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to parse config from buffer: %s", filename); u_free(file_buf); return -1; } |
|
|
|
|
|
|
|
|
|
struct global_config *global = &config->global; |
|
|
|
|
|
|
|
|
|
// Debug: print what we found
|
|
|
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "Checking config - priv_key='%s' (len=%zu), pub_key='%s' (len=%zu), node_id=%016llx", |
|
|
|
|
global->my_private_key_hex[0] ? global->my_private_key_hex : "NULL", |
|
|
|
|
global->my_private_key_hex[0] ? strlen(global->my_private_key_hex) : 0, |
|
|
|
|
global->my_public_key_hex[0] ? global->my_public_key_hex : "NULL",
|
|
|
|
|
global->my_public_key_hex[0] ? global->my_public_key_hex : "NULL", |
|
|
|
|
global->my_public_key_hex[0] ? strlen(global->my_public_key_hex) : 0, |
|
|
|
|
(unsigned long long)global->my_node_id); |
|
|
|
|
|
|
|
|
|
// Check if we need to generate anything
|
|
|
|
|
int need_priv_key = !is_valid_priv_key(global->my_private_key_hex); |
|
|
|
|
int need_pub_key = 0; |
|
|
|
|
int need_node_id = 0; |
|
|
|
|
|
|
|
|
|
// Generate keys if needed
|
|
|
|
|
char new_priv_key[PRIV_HEXKEY_LEN] = {0}; |
|
|
|
|
char new_pub_key[PUB_HEXKEY_LEN] = {0}; |
|
|
|
|
uint64_t new_node_id = 0; |
|
|
|
|
@ -294,34 +258,21 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
|
|
|
|
if (need_priv_key) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Generating NEW keypair — private key was invalid/missing in %s", filename); |
|
|
|
|
struct SC_MYKEYS mykeys; |
|
|
|
|
if (sc_generate_keypair(&mykeys) != SC_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to generate keypair"); |
|
|
|
|
free_config(config); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (sc_generate_keypair(&mykeys) != SC_OK) { free_config(config); u_free(file_buf); return -1; } |
|
|
|
|
bytes_to_hex(mykeys.private_key, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); |
|
|
|
|
memcpy(priv_bin, mykeys.private_key, SC_PRIVKEY_SIZE); |
|
|
|
|
} else { |
|
|
|
|
// Convert existing privkey hex → binary
|
|
|
|
|
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { |
|
|
|
|
unsigned int byte; |
|
|
|
|
if (sscanf(global->my_private_key_hex + i * 2, "%2x", &byte) != 1) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid private key hex format"); |
|
|
|
|
free_config(config); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (sscanf(global->my_private_key_hex + i * 2, "%2x", &byte) != 1) { free_config(config); u_free(file_buf); return -1; } |
|
|
|
|
priv_bin[i] = (uint8_t)byte; |
|
|
|
|
} |
|
|
|
|
bytes_to_hex(priv_bin, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ── Step 2: derive pubkey from privkey (always check) ──
|
|
|
|
|
// ── Step 2: derive pubkey from privkey ──
|
|
|
|
|
uint8_t pub_bin[SC_PUBKEY_SIZE]; |
|
|
|
|
if (sc_compute_public_key_from_private(priv_bin, pub_bin) != SC_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to compute public key from private key"); |
|
|
|
|
free_config(config); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (sc_compute_public_key_from_private(priv_bin, pub_bin) != SC_OK) { free_config(config); u_free(file_buf); return -1; } |
|
|
|
|
bytes_to_hex(pub_bin, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); |
|
|
|
|
if (!is_valid_pub_key(global->my_public_key_hex) || strcmp(global->my_public_key_hex, new_pub_key) != 0) { |
|
|
|
|
need_pub_key = 1; |
|
|
|
|
@ -330,15 +281,8 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ── Step 3: derive node_id from privkey via SHA-256 ──
|
|
|
|
|
{ |
|
|
|
|
uint8_t sha_hash[32]; |
|
|
|
|
SC_SHA256_CTX ctx; |
|
|
|
|
sc_sha256_init(&ctx); |
|
|
|
|
sc_sha256_update(&ctx, priv_bin, SC_PRIVKEY_SIZE); |
|
|
|
|
sc_sha256_final(&ctx, sha_hash); |
|
|
|
|
memcpy(&new_node_id, sha_hash, 8); |
|
|
|
|
new_node_id &= 0x7FFFFFFFFFFFFFFFULL; |
|
|
|
|
} |
|
|
|
|
{ uint8_t sha_hash[32]; SC_SHA256_CTX ctx; sc_sha256_init(&ctx); sc_sha256_update(&ctx, priv_bin, SC_PRIVKEY_SIZE); sc_sha256_final(&ctx, sha_hash); |
|
|
|
|
memcpy(&new_node_id, sha_hash, 8); new_node_id &= 0x7FFFFFFFFFFFFFFFULL; } |
|
|
|
|
if (!is_valid_node_id(global->my_node_id) || global->my_node_id != new_node_id) { |
|
|
|
|
need_node_id = 1; |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Node_id mismatch (or missing), fixing: config=%016llx derived=%016llx file=%s", |
|
|
|
|
@ -348,36 +292,17 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "Validation results - need_priv_key=%d, need_pub_key=%d, need_node_id=%d", |
|
|
|
|
need_priv_key, need_pub_key, need_node_id); |
|
|
|
|
|
|
|
|
|
if (!need_priv_key && !need_pub_key && !need_node_id) { |
|
|
|
|
free_config(config); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (!need_priv_key && !need_pub_key && !need_node_id) { free_config(config); u_free(file_buf); return 0; } |
|
|
|
|
|
|
|
|
|
free_config(config); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Read entire config file to memory
|
|
|
|
|
char *file_buf = NULL; |
|
|
|
|
size_t file_size = 0; |
|
|
|
|
if (read_file_to_mem(filename, &file_buf, &file_size) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to read config file: %s", filename); |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update config file
|
|
|
|
|
// ── Modify file buffer in place ──
|
|
|
|
|
size_t buf_capacity = file_size + 1024; |
|
|
|
|
char *work_buf = u_malloc(buf_capacity); |
|
|
|
|
|
|
|
|
|
if (!work_buf) { |
|
|
|
|
u_free(file_buf); |
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
if (!work_buf) { u_free(file_buf); return -1; } |
|
|
|
|
memcpy(work_buf, file_buf, file_size); |
|
|
|
|
|
|
|
|
|
u_free(file_buf); |
|
|
|
|
size_t work_len = file_size; |
|
|
|
|
|
|
|
|
|
int ret = 0; |
|
|
|
|
int write_keys = (need_priv_key || need_pub_key || need_node_id); |
|
|
|
|
|
|
|
|
|
@ -385,43 +310,25 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
|
|
|
|
char node_id_hex[HEXNODEID_LEN + 1]; |
|
|
|
|
snprintf(node_id_hex, sizeof(node_id_hex), "%016llx", (unsigned long long)new_node_id); |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Writing my_node_id=%s to %s", node_id_hex, filename); |
|
|
|
|
|
|
|
|
|
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_node_id", node_id_hex) < 0) { |
|
|
|
|
ret = -1; |
|
|
|
|
} |
|
|
|
|
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_node_id", node_id_hex) < 0) ret = -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (write_keys && ret == 0) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Writing my_private_key to %s", filename); |
|
|
|
|
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_private_key", new_priv_key) < 0) { |
|
|
|
|
ret = -1; |
|
|
|
|
} |
|
|
|
|
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_private_key", new_priv_key) < 0) ret = -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (write_keys && ret == 0) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Writing my_public_key to %s", filename); |
|
|
|
|
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_public_key", new_pub_key) < 0) { |
|
|
|
|
ret = -1; |
|
|
|
|
} |
|
|
|
|
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_public_key", new_pub_key) < 0) ret = -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ret == 0) { |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "Writing updated config file, work_len=%zu", work_len); |
|
|
|
|
|
|
|
|
|
if (ret == 0) { |
|
|
|
|
if (write_mem_to_file(filename, work_buf, work_len) < 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to write updated config file: %s", filename); |
|
|
|
|
|
|
|
|
|
ret = -1; |
|
|
|
|
} else { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Config file updated: %s (gen_priv=%d gen_pub=%d gen_nodeid=%d)", filename, need_priv_key, need_pub_key, need_node_id); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
u_free(file_buf); |
|
|
|
|
|
|
|
|
|
u_free(work_buf); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|