feat: Add probe request capture and mDNS service advertisement
- Capture WiFi probe requests (subtype 0x04) in promiscuous callback - Parse SSID from tagged parameters, emit PROBE_DATA via UDP - Per-MAC deduplication (10s cooldown) to limit probe flood - Advertise _esp-csi._udp mDNS service for sensor discovery
This commit is contained in:
@@ -689,7 +689,7 @@ static void ota_task(void *arg)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/* --- Promiscuous mode: deauth/disassoc detection --- */
|
||||
/* --- Promiscuous mode: deauth/disassoc detection + probe request capture --- */
|
||||
|
||||
typedef struct {
|
||||
uint16_t frame_ctrl;
|
||||
@@ -700,6 +700,41 @@ typedef struct {
|
||||
uint16_t seq_ctrl;
|
||||
} __attribute__((packed)) wifi_ieee80211_mac_hdr_t;
|
||||
|
||||
/* Probe request deduplication: report each MAC at most once per 10 seconds */
|
||||
#define PROBE_DEDUP_SIZE 32
|
||||
#define PROBE_DEDUP_US 10000000LL
|
||||
|
||||
static struct {
|
||||
uint8_t mac[6];
|
||||
int64_t ts;
|
||||
} s_probe_seen[PROBE_DEDUP_SIZE];
|
||||
|
||||
static bool probe_dedup_check(const uint8_t *mac)
|
||||
{
|
||||
int64_t now = esp_timer_get_time();
|
||||
int oldest_idx = 0;
|
||||
int64_t oldest_ts = INT64_MAX;
|
||||
|
||||
for (int i = 0; i < PROBE_DEDUP_SIZE; i++) {
|
||||
if (memcmp(s_probe_seen[i].mac, mac, 6) == 0) {
|
||||
if (now - s_probe_seen[i].ts < PROBE_DEDUP_US) {
|
||||
return true; /* seen recently, skip */
|
||||
}
|
||||
s_probe_seen[i].ts = now;
|
||||
return false; /* cooldown expired */
|
||||
}
|
||||
if (s_probe_seen[i].ts < oldest_ts) {
|
||||
oldest_ts = s_probe_seen[i].ts;
|
||||
oldest_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* New MAC — replace oldest entry */
|
||||
memcpy(s_probe_seen[oldest_idx].mac, mac, 6);
|
||||
s_probe_seen[oldest_idx].ts = now;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wifi_promiscuous_cb(void *buf, wifi_promiscuous_pkt_type_t type)
|
||||
{
|
||||
if (type != WIFI_PKT_MGMT) return;
|
||||
@@ -708,41 +743,71 @@ static void wifi_promiscuous_cb(void *buf, wifi_promiscuous_pkt_type_t type)
|
||||
const wifi_ieee80211_mac_hdr_t *hdr = (wifi_ieee80211_mac_hdr_t *)pkt->payload;
|
||||
|
||||
uint8_t subtype = (hdr->frame_ctrl >> 4) & 0x0F;
|
||||
const char *type_str = NULL;
|
||||
|
||||
if (subtype == 0x0C) {
|
||||
type_str = "deauth";
|
||||
} else if (subtype == 0x0A) {
|
||||
type_str = "disassoc";
|
||||
} else {
|
||||
/* Deauth (0x0C) / Disassoc (0x0A) */
|
||||
if (subtype == 0x0C || subtype == 0x0A) {
|
||||
const char *type_str = (subtype == 0x0C) ? "deauth" : "disassoc";
|
||||
|
||||
char alert[160];
|
||||
int len = snprintf(alert, sizeof(alert),
|
||||
"ALERT_DATA,%s,%s,"
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x,"
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x,"
|
||||
"%d\n",
|
||||
s_hostname, type_str,
|
||||
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
|
||||
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
|
||||
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
|
||||
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
|
||||
pkt->rx_ctrl.rssi);
|
||||
|
||||
if (s_udp_socket >= 0) {
|
||||
sendto(s_udp_socket, alert, len, 0,
|
||||
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "ALERT: %s from " MACSTR " -> " MACSTR " rssi=%d",
|
||||
type_str,
|
||||
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
|
||||
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
|
||||
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
|
||||
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
|
||||
pkt->rx_ctrl.rssi);
|
||||
return;
|
||||
}
|
||||
|
||||
char alert[160];
|
||||
int len = snprintf(alert, sizeof(alert),
|
||||
"ALERT_DATA,%s,%s,"
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x,"
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x,"
|
||||
"%d\n",
|
||||
s_hostname, type_str,
|
||||
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
|
||||
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
|
||||
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
|
||||
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
|
||||
pkt->rx_ctrl.rssi);
|
||||
/* Probe request (0x04) */
|
||||
if (subtype == 0x04) {
|
||||
/* Dedup: skip if this MAC was reported recently */
|
||||
if (probe_dedup_check(hdr->addr2)) return;
|
||||
|
||||
if (s_udp_socket >= 0) {
|
||||
sendto(s_udp_socket, alert, len, 0,
|
||||
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
|
||||
/* Parse SSID from tagged parameters after MAC header */
|
||||
const uint8_t *body = pkt->payload + sizeof(wifi_ieee80211_mac_hdr_t);
|
||||
int body_len = pkt->rx_ctrl.sig_len - sizeof(wifi_ieee80211_mac_hdr_t);
|
||||
|
||||
char ssid[33] = "";
|
||||
if (body_len >= 2 && body[0] == 0) { /* Tag 0 = SSID */
|
||||
int ssid_len = body[1];
|
||||
if (ssid_len > 0 && ssid_len <= 32 && ssid_len + 2 <= body_len) {
|
||||
memcpy(ssid, &body[2], ssid_len);
|
||||
ssid[ssid_len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char probe[192];
|
||||
int len = snprintf(probe, sizeof(probe),
|
||||
"PROBE_DATA,%s,%02x:%02x:%02x:%02x:%02x:%02x,%d,%s\n",
|
||||
s_hostname,
|
||||
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
|
||||
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
|
||||
pkt->rx_ctrl.rssi,
|
||||
ssid);
|
||||
|
||||
if (s_udp_socket >= 0) {
|
||||
sendto(s_udp_socket, probe, len, 0,
|
||||
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "ALERT: %s from " MACSTR " -> " MACSTR " rssi=%d",
|
||||
type_str,
|
||||
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
|
||||
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
|
||||
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
|
||||
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
|
||||
pkt->rx_ctrl.rssi);
|
||||
}
|
||||
|
||||
static void wifi_promiscuous_init(void)
|
||||
@@ -753,7 +818,7 @@ static void wifi_promiscuous_init(void)
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filt));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
|
||||
ESP_LOGI(TAG, "Promiscuous mode: deauth/disassoc detection enabled");
|
||||
ESP_LOGI(TAG, "Promiscuous mode: deauth/disassoc/probe detection enabled");
|
||||
}
|
||||
|
||||
/* --- Command handler --- */
|
||||
@@ -1125,11 +1190,12 @@ void app_main()
|
||||
}
|
||||
#endif
|
||||
|
||||
/* mDNS: announce as <hostname>.local */
|
||||
/* mDNS: announce as <hostname>.local with _esp-csi._udp service */
|
||||
ESP_ERROR_CHECK(mdns_init());
|
||||
mdns_hostname_set(s_hostname);
|
||||
mdns_instance_name_set("ESP32 CSI Sensor");
|
||||
ESP_LOGI(TAG, "mDNS hostname: %s.local", s_hostname);
|
||||
mdns_service_add(NULL, "_esp-csi", "_udp", s_target_port, NULL, 0);
|
||||
ESP_LOGI(TAG, "mDNS hostname: %s.local (_esp-csi._udp:%d)", s_hostname, s_target_port);
|
||||
|
||||
/* Watchdog: 30s timeout, auto-reboot on hang */
|
||||
esp_task_wdt_config_t wdt_cfg = {
|
||||
|
||||
Reference in New Issue
Block a user