Move command registry from components/command/ into components/core/. New modules: mod_canbus, mod_honeypot, mod_fallback, mod_redteam, mod_ota. Replace mod_proxy with tun_core (multiplexed SOCKS5 tunnel). Kconfig extended with per-module settings and async worker config.
455 lines
12 KiB
C
455 lines
12 KiB
C
/*
|
|
* fb_config.c
|
|
* NVS-backed storage for known WiFi networks and C2 fallback addresses.
|
|
* Namespace: "fb_cfg" — auto-migrates from old "rt_cfg" on first boot.
|
|
*/
|
|
#include "sdkconfig.h"
|
|
#include "fb_config.h"
|
|
|
|
#ifdef CONFIG_MODULE_FALLBACK
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "nvs_flash.h"
|
|
#include "nvs.h"
|
|
#include "esp_log.h"
|
|
#include "esp_wifi.h"
|
|
|
|
static const char *TAG = "FB_CFG";
|
|
static const char *NVS_NS = "fb_cfg";
|
|
|
|
/* ============================================================
|
|
* NVS migration from old rt_cfg namespace
|
|
* ============================================================ */
|
|
|
|
static void migrate_from_rt_cfg(void)
|
|
{
|
|
nvs_handle_t old_h, new_h;
|
|
if (nvs_open("rt_cfg", NVS_READONLY, &old_h) != ESP_OK)
|
|
return; /* No old data */
|
|
|
|
if (nvs_open(NVS_NS, NVS_READWRITE, &new_h) != ESP_OK) {
|
|
nvs_close(old_h);
|
|
return;
|
|
}
|
|
|
|
/* Check if already migrated */
|
|
int32_t new_count = -1;
|
|
if (nvs_get_i32(new_h, "fb_count", &new_count) == ESP_OK && new_count >= 0) {
|
|
nvs_close(old_h);
|
|
nvs_close(new_h);
|
|
return;
|
|
}
|
|
|
|
/* Copy network count */
|
|
int32_t old_count = 0;
|
|
nvs_get_i32(old_h, "rt_count", &old_count);
|
|
nvs_set_i32(new_h, "fb_count", old_count);
|
|
|
|
/* Copy each network entry */
|
|
char key[16];
|
|
for (int i = 0; i < old_count && i < CONFIG_FB_MAX_KNOWN_NETWORKS; i++) {
|
|
char buf[FB_PASS_MAX_LEN];
|
|
size_t len;
|
|
|
|
snprintf(key, sizeof(key), "n_%d", i);
|
|
len = FB_SSID_MAX_LEN;
|
|
memset(buf, 0, sizeof(buf));
|
|
if (nvs_get_str(old_h, key, buf, &len) == ESP_OK)
|
|
nvs_set_str(new_h, key, buf);
|
|
|
|
snprintf(key, sizeof(key), "p_%d", i);
|
|
len = FB_PASS_MAX_LEN;
|
|
memset(buf, 0, sizeof(buf));
|
|
if (nvs_get_str(old_h, key, buf, &len) == ESP_OK)
|
|
nvs_set_str(new_h, key, buf);
|
|
}
|
|
|
|
/* Copy C2 fallbacks */
|
|
int32_t c2_count = 0;
|
|
nvs_get_i32(old_h, "c2_count", &c2_count);
|
|
nvs_set_i32(new_h, "c2_count", c2_count);
|
|
|
|
for (int i = 0; i < c2_count && i < CONFIG_FB_MAX_C2_FALLBACKS; i++) {
|
|
char buf[FB_ADDR_MAX_LEN];
|
|
size_t len = FB_ADDR_MAX_LEN;
|
|
snprintf(key, sizeof(key), "c2_%d", i);
|
|
memset(buf, 0, sizeof(buf));
|
|
if (nvs_get_str(old_h, key, buf, &len) == ESP_OK)
|
|
nvs_set_str(new_h, key, buf);
|
|
}
|
|
|
|
/* Copy original MAC */
|
|
uint8_t mac[6];
|
|
size_t mac_len = 6;
|
|
if (nvs_get_blob(old_h, "orig_mac", mac, &mac_len) == ESP_OK)
|
|
nvs_set_blob(new_h, "orig_mac", mac, 6);
|
|
|
|
nvs_commit(new_h);
|
|
nvs_close(old_h);
|
|
nvs_close(new_h);
|
|
|
|
ESP_LOGI(TAG, "Migrated %d networks + %d C2 fallbacks from rt_cfg",
|
|
(int)old_count, (int)c2_count);
|
|
}
|
|
|
|
/* ============================================================
|
|
* Init
|
|
* ============================================================ */
|
|
void fb_config_init(void)
|
|
{
|
|
migrate_from_rt_cfg();
|
|
|
|
nvs_handle_t h;
|
|
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
|
|
if (err == ESP_OK) {
|
|
nvs_close(h);
|
|
ESP_LOGI(TAG, "NVS namespace '%s' ready", NVS_NS);
|
|
} else {
|
|
ESP_LOGE(TAG, "NVS open failed: %s", esp_err_to_name(err));
|
|
}
|
|
}
|
|
|
|
/* ============================================================
|
|
* Known WiFi networks
|
|
* ============================================================ */
|
|
|
|
static void net_key_ssid(int idx, char *out, size_t len)
|
|
{
|
|
snprintf(out, len, "n_%d", idx);
|
|
}
|
|
|
|
static void net_key_pass(int idx, char *out, size_t len)
|
|
{
|
|
snprintf(out, len, "p_%d", idx);
|
|
}
|
|
|
|
int fb_config_net_count(void)
|
|
{
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READONLY, &h) != ESP_OK)
|
|
return 0;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "fb_count", &count);
|
|
nvs_close(h);
|
|
return (int)count;
|
|
}
|
|
|
|
int fb_config_net_list(fb_network_t *out, int max_count)
|
|
{
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READONLY, &h) != ESP_OK)
|
|
return 0;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "fb_count", &count);
|
|
if (count > max_count) count = max_count;
|
|
if (count > CONFIG_FB_MAX_KNOWN_NETWORKS) count = CONFIG_FB_MAX_KNOWN_NETWORKS;
|
|
|
|
char key[16];
|
|
for (int i = 0; i < count; i++) {
|
|
memset(&out[i], 0, sizeof(fb_network_t));
|
|
|
|
net_key_ssid(i, key, sizeof(key));
|
|
size_t len = FB_SSID_MAX_LEN;
|
|
nvs_get_str(h, key, out[i].ssid, &len);
|
|
|
|
net_key_pass(i, key, sizeof(key));
|
|
len = FB_PASS_MAX_LEN;
|
|
nvs_get_str(h, key, out[i].pass, &len);
|
|
}
|
|
|
|
nvs_close(h);
|
|
return (int)count;
|
|
}
|
|
|
|
bool fb_config_net_add(const char *ssid, const char *pass)
|
|
{
|
|
if (!ssid || !ssid[0]) return false;
|
|
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READWRITE, &h) != ESP_OK)
|
|
return false;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "fb_count", &count);
|
|
|
|
/* Check if SSID already exists → update */
|
|
char key[16];
|
|
for (int i = 0; i < count; i++) {
|
|
net_key_ssid(i, key, sizeof(key));
|
|
char existing[FB_SSID_MAX_LEN] = {0};
|
|
size_t len = FB_SSID_MAX_LEN;
|
|
if (nvs_get_str(h, key, existing, &len) == ESP_OK) {
|
|
if (strcmp(existing, ssid) == 0) {
|
|
net_key_pass(i, key, sizeof(key));
|
|
nvs_set_str(h, key, pass ? pass : "");
|
|
nvs_commit(h);
|
|
nvs_close(h);
|
|
ESP_LOGI(TAG, "Updated network '%s'", ssid);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count >= CONFIG_FB_MAX_KNOWN_NETWORKS) {
|
|
nvs_close(h);
|
|
ESP_LOGW(TAG, "Known networks full (%d)", (int)count);
|
|
return false;
|
|
}
|
|
|
|
net_key_ssid(count, key, sizeof(key));
|
|
nvs_set_str(h, key, ssid);
|
|
|
|
net_key_pass(count, key, sizeof(key));
|
|
nvs_set_str(h, key, pass ? pass : "");
|
|
|
|
count++;
|
|
nvs_set_i32(h, "fb_count", count);
|
|
nvs_commit(h);
|
|
nvs_close(h);
|
|
|
|
ESP_LOGI(TAG, "Added network '%s' (total: %d)", ssid, (int)count);
|
|
return true;
|
|
}
|
|
|
|
bool fb_config_net_remove(const char *ssid)
|
|
{
|
|
if (!ssid || !ssid[0]) return false;
|
|
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READWRITE, &h) != ESP_OK)
|
|
return false;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "fb_count", &count);
|
|
|
|
int found = -1;
|
|
char key[16];
|
|
for (int i = 0; i < count; i++) {
|
|
net_key_ssid(i, key, sizeof(key));
|
|
char existing[FB_SSID_MAX_LEN] = {0};
|
|
size_t len = FB_SSID_MAX_LEN;
|
|
if (nvs_get_str(h, key, existing, &len) == ESP_OK) {
|
|
if (strcmp(existing, ssid) == 0) {
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found < 0) {
|
|
nvs_close(h);
|
|
return false;
|
|
}
|
|
|
|
/* Shift entries down */
|
|
for (int i = found; i < count - 1; i++) {
|
|
char src_key[16], dst_key[16];
|
|
char buf[FB_PASS_MAX_LEN];
|
|
size_t len;
|
|
|
|
net_key_ssid(i + 1, src_key, sizeof(src_key));
|
|
net_key_ssid(i, dst_key, sizeof(dst_key));
|
|
len = FB_SSID_MAX_LEN;
|
|
memset(buf, 0, sizeof(buf));
|
|
nvs_get_str(h, src_key, buf, &len);
|
|
nvs_set_str(h, dst_key, buf);
|
|
|
|
net_key_pass(i + 1, src_key, sizeof(src_key));
|
|
net_key_pass(i, dst_key, sizeof(dst_key));
|
|
len = FB_PASS_MAX_LEN;
|
|
memset(buf, 0, sizeof(buf));
|
|
nvs_get_str(h, src_key, buf, &len);
|
|
nvs_set_str(h, dst_key, buf);
|
|
}
|
|
|
|
net_key_ssid(count - 1, key, sizeof(key));
|
|
nvs_erase_key(h, key);
|
|
net_key_pass(count - 1, key, sizeof(key));
|
|
nvs_erase_key(h, key);
|
|
|
|
count--;
|
|
nvs_set_i32(h, "fb_count", count);
|
|
nvs_commit(h);
|
|
nvs_close(h);
|
|
|
|
ESP_LOGI(TAG, "Removed network '%s' (total: %d)", ssid, (int)count);
|
|
return true;
|
|
}
|
|
|
|
/* ============================================================
|
|
* C2 fallback addresses
|
|
* ============================================================ */
|
|
|
|
int fb_config_c2_count(void)
|
|
{
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READONLY, &h) != ESP_OK)
|
|
return 0;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "c2_count", &count);
|
|
nvs_close(h);
|
|
return (int)count;
|
|
}
|
|
|
|
int fb_config_c2_list(fb_c2_addr_t *out, int max_count)
|
|
{
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READONLY, &h) != ESP_OK)
|
|
return 0;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "c2_count", &count);
|
|
if (count > max_count) count = max_count;
|
|
if (count > CONFIG_FB_MAX_C2_FALLBACKS) count = CONFIG_FB_MAX_C2_FALLBACKS;
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
memset(&out[i], 0, sizeof(fb_c2_addr_t));
|
|
char key[16];
|
|
snprintf(key, sizeof(key), "c2_%d", i);
|
|
size_t len = FB_ADDR_MAX_LEN;
|
|
nvs_get_str(h, key, out[i].addr, &len);
|
|
}
|
|
|
|
nvs_close(h);
|
|
return (int)count;
|
|
}
|
|
|
|
bool fb_config_c2_add(const char *addr)
|
|
{
|
|
if (!addr || !addr[0]) return false;
|
|
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READWRITE, &h) != ESP_OK)
|
|
return false;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "c2_count", &count);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
char key[16];
|
|
snprintf(key, sizeof(key), "c2_%d", i);
|
|
char existing[FB_ADDR_MAX_LEN] = {0};
|
|
size_t len = FB_ADDR_MAX_LEN;
|
|
if (nvs_get_str(h, key, existing, &len) == ESP_OK) {
|
|
if (strcmp(existing, addr) == 0) {
|
|
nvs_close(h);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count >= CONFIG_FB_MAX_C2_FALLBACKS) {
|
|
nvs_close(h);
|
|
ESP_LOGW(TAG, "C2 fallbacks full (%d)", (int)count);
|
|
return false;
|
|
}
|
|
|
|
char key[16];
|
|
snprintf(key, sizeof(key), "c2_%d", (int)count);
|
|
nvs_set_str(h, key, addr);
|
|
|
|
count++;
|
|
nvs_set_i32(h, "c2_count", count);
|
|
nvs_commit(h);
|
|
nvs_close(h);
|
|
|
|
ESP_LOGI(TAG, "Added C2 fallback '%s' (total: %d)", addr, (int)count);
|
|
return true;
|
|
}
|
|
|
|
bool fb_config_c2_remove(const char *addr)
|
|
{
|
|
if (!addr || !addr[0]) return false;
|
|
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READWRITE, &h) != ESP_OK)
|
|
return false;
|
|
|
|
int32_t count = 0;
|
|
nvs_get_i32(h, "c2_count", &count);
|
|
|
|
int found = -1;
|
|
for (int i = 0; i < count; i++) {
|
|
char key[16];
|
|
snprintf(key, sizeof(key), "c2_%d", i);
|
|
char existing[FB_ADDR_MAX_LEN] = {0};
|
|
size_t len = FB_ADDR_MAX_LEN;
|
|
if (nvs_get_str(h, key, existing, &len) == ESP_OK) {
|
|
if (strcmp(existing, addr) == 0) {
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found < 0) {
|
|
nvs_close(h);
|
|
return false;
|
|
}
|
|
|
|
for (int i = found; i < count - 1; i++) {
|
|
char src_key[16], dst_key[16], buf[FB_ADDR_MAX_LEN];
|
|
size_t len = FB_ADDR_MAX_LEN;
|
|
snprintf(src_key, sizeof(src_key), "c2_%d", i + 1);
|
|
snprintf(dst_key, sizeof(dst_key), "c2_%d", i);
|
|
memset(buf, 0, sizeof(buf));
|
|
nvs_get_str(h, src_key, buf, &len);
|
|
nvs_set_str(h, dst_key, buf);
|
|
}
|
|
|
|
char key[16];
|
|
snprintf(key, sizeof(key), "c2_%d", (int)(count - 1));
|
|
nvs_erase_key(h, key);
|
|
|
|
count--;
|
|
nvs_set_i32(h, "c2_count", count);
|
|
nvs_commit(h);
|
|
nvs_close(h);
|
|
|
|
ESP_LOGI(TAG, "Removed C2 fallback '%s' (total: %d)", addr, (int)count);
|
|
return true;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Original MAC storage
|
|
* ============================================================ */
|
|
|
|
void fb_config_save_orig_mac(void)
|
|
{
|
|
uint8_t mac[6];
|
|
if (esp_wifi_get_mac(WIFI_IF_STA, mac) != ESP_OK) {
|
|
ESP_LOGW(TAG, "Failed to read STA MAC");
|
|
return;
|
|
}
|
|
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READWRITE, &h) != ESP_OK)
|
|
return;
|
|
|
|
nvs_set_blob(h, "orig_mac", mac, 6);
|
|
nvs_commit(h);
|
|
nvs_close(h);
|
|
|
|
ESP_LOGI(TAG, "Saved original MAC: %02X:%02X:%02X:%02X:%02X:%02X",
|
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
}
|
|
|
|
bool fb_config_get_orig_mac(uint8_t mac[6])
|
|
{
|
|
nvs_handle_t h;
|
|
if (nvs_open(NVS_NS, NVS_READONLY, &h) != ESP_OK)
|
|
return false;
|
|
|
|
size_t len = 6;
|
|
esp_err_t err = nvs_get_blob(h, "orig_mac", mac, &len);
|
|
nvs_close(h);
|
|
return (err == ESP_OK && len == 6);
|
|
}
|
|
|
|
#endif /* CONFIG_MODULE_FALLBACK */
|