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.
260 lines
7.1 KiB
C
260 lines
7.1 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/semphr.h"
|
|
|
|
#include "esp_log.h"
|
|
#include "esp_err.h"
|
|
#include "nvs_flash.h"
|
|
|
|
#include "esp_bt.h"
|
|
#include "esp_gap_ble_api.h"
|
|
#include "esp_bt_main.h"
|
|
|
|
#include "esp_http_client.h"
|
|
|
|
#include "utils.h"
|
|
|
|
/* ============================================================
|
|
* CONFIG
|
|
* ============================================================ */
|
|
#define TAG "BLE_TRILAT"
|
|
|
|
#define TRILAT_ID "ESP3"
|
|
#define X_POS 10.0
|
|
#define Y_POS 0.0
|
|
|
|
#define MAX_BUFFER_SIZE 4096
|
|
#define POST_INTERVAL_MS 10000
|
|
#define MAX_LEN 128
|
|
|
|
/* ============================================================
|
|
* STATE
|
|
* ============================================================ */
|
|
static uint8_t target_mac[6];
|
|
static char target_url[MAX_LEN];
|
|
static char auth_bearer[MAX_LEN];
|
|
static char auth_header[MAX_LEN];
|
|
|
|
static char data_buffer[MAX_BUFFER_SIZE];
|
|
static size_t buffer_len = 0;
|
|
|
|
static SemaphoreHandle_t buffer_mutex = NULL;
|
|
static TaskHandle_t post_task_handle = NULL;
|
|
static bool trilat_running = false;
|
|
|
|
/* ============================================================
|
|
* UTILS
|
|
* ============================================================ */
|
|
static bool parse_mac_str(const char *input, uint8_t *mac_out)
|
|
{
|
|
char clean[13] = {0};
|
|
int j = 0;
|
|
|
|
for (int i = 0; input[i] && j < 12; i++) {
|
|
if (input[i] == ':' || input[i] == '-' || input[i] == ' ')
|
|
continue;
|
|
if (!isxdigit((unsigned char)input[i]))
|
|
return false;
|
|
clean[j++] = toupper((unsigned char)input[i]);
|
|
}
|
|
|
|
if (j != 12) return false;
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
char b[3] = { clean[i*2], clean[i*2+1], 0 };
|
|
mac_out[i] = (uint8_t)strtol(b, NULL, 16);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* ============================================================
|
|
* HTTP
|
|
* ============================================================ */
|
|
static esp_err_t http_evt(esp_http_client_event_t *evt)
|
|
{
|
|
return ESP_OK;
|
|
}
|
|
|
|
static void send_http_post(const char *data)
|
|
{
|
|
esp_http_client_config_t cfg = {
|
|
.url = target_url,
|
|
.timeout_ms = 10000,
|
|
.event_handler = http_evt,
|
|
};
|
|
|
|
esp_http_client_handle_t cli = esp_http_client_init(&cfg);
|
|
esp_http_client_set_method(cli, HTTP_METHOD_POST);
|
|
esp_http_client_set_header(cli, "Content-Type", "text/plain");
|
|
esp_http_client_set_header(cli, "Authorization", auth_header);
|
|
esp_http_client_set_post_field(cli, data, strlen(data));
|
|
|
|
esp_err_t err = esp_http_client_perform(cli);
|
|
if (err == ESP_OK) {
|
|
msg_info(TAG, "HTTP POST sent", NULL);
|
|
} else {
|
|
msg_error(TAG, "HTTP POST failed", NULL);
|
|
}
|
|
|
|
esp_http_client_cleanup(cli);
|
|
}
|
|
|
|
/* ============================================================
|
|
* BLE CALLBACK
|
|
* ============================================================ */
|
|
static void ble_scan_cb(esp_gap_ble_cb_event_t event,
|
|
esp_ble_gap_cb_param_t *param)
|
|
{
|
|
if (!trilat_running) return;
|
|
|
|
if (event != ESP_GAP_BLE_SCAN_RESULT_EVT ||
|
|
param->scan_rst.search_evt != ESP_GAP_SEARCH_INQ_RES_EVT)
|
|
return;
|
|
|
|
if (memcmp(param->scan_rst.bda, target_mac, 6) != 0)
|
|
return;
|
|
|
|
char line[96];
|
|
snprintf(line, sizeof(line),
|
|
"%s;(%.1f,%.1f);%d\n",
|
|
TRILAT_ID, X_POS, Y_POS,
|
|
param->scan_rst.rssi);
|
|
|
|
xSemaphoreTake(buffer_mutex, portMAX_DELAY);
|
|
if (buffer_len + strlen(line) < MAX_BUFFER_SIZE) {
|
|
strcat(data_buffer, line);
|
|
buffer_len += strlen(line);
|
|
}
|
|
xSemaphoreGive(buffer_mutex);
|
|
}
|
|
|
|
/* ============================================================
|
|
* POST TASK
|
|
* ============================================================ */
|
|
static void post_task(void *arg)
|
|
{
|
|
while (trilat_running) {
|
|
vTaskDelay(pdMS_TO_TICKS(POST_INTERVAL_MS));
|
|
|
|
xSemaphoreTake(buffer_mutex, portMAX_DELAY);
|
|
if (buffer_len > 0) {
|
|
send_http_post(data_buffer);
|
|
buffer_len = 0;
|
|
data_buffer[0] = 0;
|
|
}
|
|
xSemaphoreGive(buffer_mutex);
|
|
}
|
|
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
/* ============================================================
|
|
* BLE INIT
|
|
* ============================================================ */
|
|
static void ble_init(void)
|
|
{
|
|
esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
|
|
|
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
|
ESP_ERROR_CHECK(esp_bt_controller_init(&cfg));
|
|
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
|
|
ESP_ERROR_CHECK(esp_bluedroid_init());
|
|
ESP_ERROR_CHECK(esp_bluedroid_enable());
|
|
|
|
ESP_ERROR_CHECK(esp_ble_gap_register_callback(ble_scan_cb));
|
|
|
|
esp_ble_scan_params_t scan = {
|
|
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
|
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
|
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
|
.scan_interval = 0x50,
|
|
.scan_window = 0x30,
|
|
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE
|
|
};
|
|
|
|
ESP_ERROR_CHECK(esp_ble_gap_set_scan_params(&scan));
|
|
}
|
|
|
|
/* ============================================================
|
|
* COMMANDS
|
|
* ============================================================ */
|
|
static esp_err_t cmd_trilat_start(int argc, char **argv, const char *request_id, void *ctx)
|
|
{
|
|
if (argc != 3)
|
|
return msg_error(TAG, "usage: trilat start <mac> <url> <bearer>", request_id);
|
|
|
|
if (trilat_running)
|
|
return msg_error(TAG, "already running", request_id);
|
|
|
|
ESP_ERROR_CHECK(nvs_flash_init());
|
|
|
|
if (!parse_mac_str(argv[0], target_mac))
|
|
return msg_error(TAG, "invalid MAC", request_id);
|
|
|
|
strncpy(target_url, argv[1], MAX_LEN-1);
|
|
strncpy(auth_bearer, argv[2], MAX_LEN-1);
|
|
snprintf(auth_header, sizeof(auth_header), "Bearer %s", auth_bearer);
|
|
|
|
if (!buffer_mutex)
|
|
buffer_mutex = xSemaphoreCreateMutex();
|
|
data_buffer[0] = 0;
|
|
buffer_len = 0;
|
|
|
|
ble_init();
|
|
esp_ble_gap_start_scanning(0);
|
|
|
|
trilat_running = true;
|
|
xTaskCreate(post_task, "trilat_post", 4096, NULL, 5, &post_task_handle);
|
|
|
|
msg_info(TAG, "trilat started", request_id);
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t cmd_trilat_stop(int argc, char **argv, const char *request_id, void *ctx)
|
|
{
|
|
if (!trilat_running)
|
|
return msg_error(TAG, "not running", request_id);
|
|
|
|
trilat_running = false;
|
|
esp_ble_gap_stop_scanning();
|
|
|
|
msg_info(TAG, "trilat stopped", request_id);
|
|
return ESP_OK;
|
|
}
|
|
|
|
/* ============================================================
|
|
* REGISTER
|
|
* ============================================================ */
|
|
static const command_t cmd_trilat_start_def = {
|
|
.name = "trilat",
|
|
.sub = "start",
|
|
.help = "Start BLE trilateration",
|
|
.handler = cmd_trilat_start,
|
|
.ctx = NULL,
|
|
.async = false,
|
|
.min_args = 3,
|
|
.max_args = 3
|
|
};
|
|
|
|
static const command_t cmd_trilat_stop_def = {
|
|
.name = "trilat",
|
|
.sub = "stop",
|
|
.help = "Stop BLE trilateration",
|
|
.handler = cmd_trilat_stop,
|
|
.ctx = NULL,
|
|
.async = false,
|
|
.min_args = 0,
|
|
.max_args = 0
|
|
};
|
|
|
|
void mod_ble_trilat_register_commands(void)
|
|
{
|
|
command_register(&cmd_trilat_start_def);
|
|
command_register(&cmd_trilat_stop_def);
|
|
}
|