feat: add ESP32 embedded agent + namespace VRF reference docs + update android-agent submodule

- 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
This commit is contained in:
datadunia
2026-09-13 14:39:24 +07:00
parent 88fa60901e
commit e523398fa8
31 changed files with 6766 additions and 1 deletions
+264
View File
@@ -0,0 +1,264 @@
/**
* @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;
}