e523398fa8
- apps/device-agent-embedded/: ESP32 WireGuard agent (C, ESP-IDF, mbedTLS) - reference/namespace-vrf/: Linux namespace/VRF network isolation docs - apps/android-agent: VPN permission check, StartResult sealed class
265 lines
7.8 KiB
C
265 lines
7.8 KiB
C
/**
|
|
* @file config.c
|
|
* @brief NVS Configuration Management
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "config.h"
|
|
#include "nvs_flash.h"
|
|
#include "nvs.h"
|
|
#include "esp_log.h"
|
|
|
|
static const char *TAG = "nexus_config";
|
|
|
|
/* NVS namespace */
|
|
static const char *NVS_NAMESPACE = "nexusguard";
|
|
|
|
/* NVS keys (all < 15 chars per NVS limit) */
|
|
static const char *KEY_DEVICE_ID = "device_id";
|
|
static const char *KEY_PRIVATE_KEY = "private_key";
|
|
static const char *KEY_PRESHARED_KEY = "preshared_key";
|
|
static const char *KEY_INTERNAL_IP = "internal_ip";
|
|
static const char *KEY_SERVER_PUB = "server_pub";
|
|
static const char *KEY_ENDPOINT = "endpoint";
|
|
static const char *KEY_DNS = "dns";
|
|
static const char *KEY_ALLOWED_IPS = "allowed_ips";
|
|
static const char *KEY_SERVER_WG_IP = "server_wgip";
|
|
static const char *KEY_CONFIG_HASH = "config_hash";
|
|
|
|
/* NVS handle (open once, reuse) */
|
|
static nvs_handle_t s_nvs_handle = 0;
|
|
static bool s_nvs_open = false;
|
|
|
|
/**
|
|
* @brief Helper: write string to NVS
|
|
*/
|
|
static esp_err_t nvs_write_str(const char *key, const char *value)
|
|
{
|
|
if (!s_nvs_open) {
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
esp_err_t err = nvs_set_str(s_nvs_handle, key, value);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to write NVS key '%s': %s", key, esp_err_to_name(err));
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief Helper: read string from NVS into buffer
|
|
*/
|
|
static esp_err_t nvs_read_str(const char *key, char *buf, size_t buf_len)
|
|
{
|
|
if (!s_nvs_open) {
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
size_t required_size = 0;
|
|
esp_err_t err = nvs_get_str(s_nvs_handle, key, NULL, &required_size);
|
|
if (err != ESP_OK) {
|
|
return err;
|
|
}
|
|
if (required_size > buf_len) {
|
|
ESP_LOGE(TAG, "NVS key '%s' value too large (%zu > %zu)", key, required_size, buf_len);
|
|
return ESP_ERR_NVS_INVALID_LENGTH;
|
|
}
|
|
err = nvs_get_str(s_nvs_handle, key, buf, &buf_len);
|
|
return err;
|
|
}
|
|
|
|
esp_err_t config_init(void)
|
|
{
|
|
ESP_LOGI(TAG, "Initializing NVS config module...");
|
|
|
|
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &s_nvs_handle);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to open NVS namespace '%s': %s", NVS_NAMESPACE, esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
s_nvs_open = true;
|
|
|
|
ESP_LOGI(TAG, "NVS config module initialized");
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t config_save(const wg_config_t *config)
|
|
{
|
|
if (config == NULL) {
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Saving config for device: %s", config->device_id);
|
|
|
|
esp_err_t err;
|
|
esp_err_t final_err = ESP_OK;
|
|
|
|
err = nvs_write_str(KEY_DEVICE_ID, config->device_id);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_PRIVATE_KEY, config->private_key);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_PRESHARED_KEY, config->preshared_key);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_INTERNAL_IP, config->internal_ip);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_SERVER_PUB, config->server_pub);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_ENDPOINT, config->endpoint);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_DNS, config->dns);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_ALLOWED_IPS, config->allowed_ips);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_SERVER_WG_IP, config->server_wg_ip);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_write_str(KEY_CONFIG_HASH, config->config_hash);
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
if (final_err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to save config");
|
|
return final_err;
|
|
}
|
|
|
|
/* Commit to flash */
|
|
err = nvs_commit(s_nvs_handle);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to commit NVS: %s", esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Config saved successfully");
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t config_load(wg_config_t *config)
|
|
{
|
|
if (config == NULL) {
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
/* Zero out the struct first */
|
|
memset(config, 0, sizeof(wg_config_t));
|
|
|
|
ESP_LOGI(TAG, "Loading config from NVS...");
|
|
|
|
esp_err_t err;
|
|
esp_err_t final_err = ESP_OK;
|
|
|
|
err = nvs_read_str(KEY_DEVICE_ID, config->device_id, sizeof(config->device_id));
|
|
if (err != ESP_OK) {
|
|
ESP_LOGW(TAG, "No device_id in NVS (first boot?)");
|
|
return err;
|
|
}
|
|
|
|
err = nvs_read_str(KEY_PRIVATE_KEY, config->private_key, sizeof(config->private_key));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_PRESHARED_KEY, config->preshared_key, sizeof(config->preshared_key));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_INTERNAL_IP, config->internal_ip, sizeof(config->internal_ip));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_SERVER_PUB, config->server_pub, sizeof(config->server_pub));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_ENDPOINT, config->endpoint, sizeof(config->endpoint));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_DNS, config->dns, sizeof(config->dns));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_ALLOWED_IPS, config->allowed_ips, sizeof(config->allowed_ips));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_SERVER_WG_IP, config->server_wg_ip, sizeof(config->server_wg_ip));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
err = nvs_read_str(KEY_CONFIG_HASH, config->config_hash, sizeof(config->config_hash));
|
|
if (err != ESP_OK) final_err = err;
|
|
|
|
if (final_err != ESP_OK) {
|
|
ESP_LOGW(TAG, "Config loaded with errors");
|
|
return final_err;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Config loaded successfully for device: %s", config->device_id);
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t config_clear(void)
|
|
{
|
|
ESP_LOGI(TAG, "Clearing all NexusGuard NVS keys...");
|
|
|
|
if (!s_nvs_open) {
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
esp_err_t err;
|
|
esp_err_t final_err = ESP_OK;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_DEVICE_ID);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_PRIVATE_KEY);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_PRESHARED_KEY);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_INTERNAL_IP);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_SERVER_PUB);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_ENDPOINT);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_DNS);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_ALLOWED_IPS);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_SERVER_WG_IP);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
err = nvs_erase_key(s_nvs_handle, KEY_CONFIG_HASH);
|
|
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) final_err = err;
|
|
|
|
/* Commit erases to flash */
|
|
err = nvs_commit(s_nvs_handle);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to commit NVS erase: %s", esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Config cleared");
|
|
return final_err;
|
|
}
|
|
|
|
bool config_is_valid(const wg_config_t *config)
|
|
{
|
|
if (config == NULL) {
|
|
return false;
|
|
}
|
|
|
|
/* device_id and private_key must be non-empty */
|
|
if (strlen(config->device_id) == 0) {
|
|
return false;
|
|
}
|
|
if (strlen(config->private_key) == 0) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|