httprequest - ESP8266 嗅探和发送 Mac 地址

标签 httprequest sniffing arduino-esp8266 access-point

我试图让我的 ESP8266 嗅探附近的设备,然后通过 HTTP 请求发布它们。目的是记录我和我的室友什么时候在家。然后在将来,无论我们在家与否,都可以触发某些任务,例如开/关灯。我根本不关心数据包内容,只是 mac 地址。

到目前为止,我找到了这个脚本,它可以打印附近设备的 mac 地址,由 kalanda 创建:esp8266-sniffer .
以及这个 HTTP 发布脚本 ESP8266 http get requests .

我试图将这两者结合起来,并在回调函数中让 ESP 发送找到的数据,但看起来不像 ESP 建立了 wifi 连接。

我尝试使用不同的 WIFI 模式:STATION_MODE、SOFTAP_MODE、STATIONAP_MODE。它们都没有同时用于嗅探和 http 请求。我知道 STATIONAP_MODE 确实有一些缺陷。我发现它必须以某种方式切换两者,但不幸的是我不是 ESP 专家,不知道如何做到这一点。

这是我的代码(请原谅我身边的任何垃圾编码):

#include <ESP8266WiFi.h>       // added this
#include <ESP8266HTTPClient.h> // added this

const char* ssid     = "**********";  // Wifi SSID
const char* password = "**********";  // Wifi Password
String main_url      = "http://*********.php?"; // Website url to post the information
String temp_url      = "";                      // Url with information

extern "C" {
  #include <user_interface.h>
}

#define DATA_LENGTH           112

#define TYPE_MANAGEMENT       0x00
#define TYPE_CONTROL          0x01
#define TYPE_DATA             0x02
#define SUBTYPE_PROBE_REQUEST 0x04


struct RxControl {
 signed rssi:8; // signal intensity of packet
 unsigned rate:4;
 unsigned is_group:1;
 unsigned:1;
 unsigned sig_mode:2; // 0:is 11n packet; 1:is not 11n packet;
 unsigned legacy_length:12; // if not 11n packet, shows length of packet.
 unsigned damatch0:1;
 unsigned damatch1:1;
 unsigned bssidmatch0:1;
 unsigned bssidmatch1:1;
 unsigned MCS:7; // if is 11n packet, shows the modulation and code used (range from 0 to 76)
 unsigned CWB:1; // if is 11n packet, shows if is HT40 packet or not
 unsigned HT_length:16;// if is 11n packet, shows length of packet.
 unsigned Smoothing:1;
 unsigned Not_Sounding:1;
 unsigned:1;
 unsigned Aggregation:1;
 unsigned STBC:2;
 unsigned FEC_CODING:1; // if is 11n packet, shows if is LDPC packet or not.
 unsigned SGI:1;
 unsigned rxend_state:8;
 unsigned ampdu_cnt:8;
 unsigned channel:4; //which channel this packet in.
 unsigned:12;
};

struct SnifferPacket{
    struct RxControl rx_ctrl;
    uint8_t data[DATA_LENGTH];
    uint16_t cnt;
    uint16_t len;
};

static void showMetadata(SnifferPacket *snifferPacket) {

  unsigned int frameControl = ((unsigned int)snifferPacket->data[1] << 8) + snifferPacket->data[0];

  uint8_t version      = (frameControl & 0b0000000000000011) >> 0;
  uint8_t frameType    = (frameControl & 0b0000000000001100) >> 2;
  uint8_t frameSubType = (frameControl & 0b0000000011110000) >> 4;
  uint8_t toDS         = (frameControl & 0b0000000100000000) >> 8;
  uint8_t fromDS       = (frameControl & 0b0000001000000000) >> 9;

  // Only look for probe request packets
  if (frameType != TYPE_MANAGEMENT ||
      frameSubType != SUBTYPE_PROBE_REQUEST)
        return;

  Serial.print("RSSI: ");
  Serial.print(snifferPacket->rx_ctrl.rssi, DEC);

  Serial.print(" Ch: ");
  Serial.print(wifi_get_channel());

  char addr[] = "00:00:00:00:00:00";
  getMAC(addr, snifferPacket->data, 10);
  Serial.print(" Peer MAC: ");
  Serial.print(addr);

  uint8_t SSID_length = snifferPacket->data[25];
  Serial.print(" SSID: ");
  printDataSpan(26, SSID_length, snifferPacket->data);



  Serial.println();
  if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status 
  { 

    HTTPClient http;  //Declare an object of class HTTPClient
    temp_url = main_url;
    temp_url = temp_url + "mac=30:a8:db:96:a4:75";
    temp_url = temp_url + "&rssi=-90";
    temp_url = temp_url + "&ssid=none";
    http.begin(temp_url);  //Specify request destination
    int httpCode = http.GET();                                                                  //Send the request
    temp_url = "";

    if (httpCode > 0) 
    { //Check the returning code

      String payload = http.getString();   //Get the request response payload
      Serial.println(payload);                     //Print the response payload

    }

    http.end();   //Close connection

  }
  else
  {
    Serial.println("Wifi connection failed"); //Prints out this
  }

}

/**
 * Callback for promiscuous mode
 */
static void ICACHE_FLASH_ATTR sniffer_callback(uint8_t *buffer, uint16_t length) {
  struct SnifferPacket *snifferPacket = (struct SnifferPacket*) buffer;
  showMetadata(snifferPacket);
}

static void printDataSpan(uint16_t start, uint16_t size, uint8_t* data) {
  for(uint16_t i = start; i < DATA_LENGTH && i < start+size; i++) {
    Serial.write(data[i]);    
  }
}

static void getMAC(char *addr, uint8_t* data, uint16_t offset) {
  sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", data[offset+0], data[offset+1], data[offset+2], data[offset+3], data[offset+4], data[offset+5]);
}

#define CHANNEL_HOP_INTERVAL_MS   1000
static os_timer_t channelHop_timer;

/**
 * Callback for channel hoping
 */
void channelHop()
{
  // hoping channels 1-14
  uint8 new_channel = wifi_get_channel() + 1;
  if (new_channel > 14)
    new_channel = 1;
  wifi_set_channel(new_channel);
}

#define DISABLE 0
#define ENABLE  1

void setup() {
  // set the WiFi chip to "promiscuous" mode aka monitor mode
  Serial.begin(115200);



  delay(10);
  wifi_set_opmode(STATION_MODE);
  wifi_set_channel(1);
  wifi_promiscuous_enable(DISABLE);
  delay(10);
  wifi_set_promiscuous_rx_cb(sniffer_callback);
  delay(10);
  wifi_promiscuous_enable(ENABLE);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(1000);
    Serial.print("Connecting..");

  }
  Serial.println("");
  Serial.println("Connected..");

  // setup the channel hoping callback timer
  os_timer_disarm(&channelHop_timer);
  os_timer_setfn(&channelHop_timer, (os_timer_func_t *) channelHop, NULL);
  os_timer_arm(&channelHop_timer, CHANNEL_HOP_INTERVAL_MS, 1);
}

void loop() {
  delay(10);  
}

最佳答案

这是将探测请求(MAC 地址和 RSSI)聚合 3 秒,然后使用 json(WIFI_AP_STA 模式)将它们发送到指定服务器端点的代码:

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
#include <vector>

const char* apSsid     = "ap-ssid";
const char* apPassword = "ap-password";
const char* clientSsid     = "client-ssid";
const char* clientPassword = "client-password";

HTTPClient http;

WiFiEventHandler probeRequestPrintHandler;

String macToString(const unsigned char* mac) {
  char buf[20];
  snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  return String(buf);
}

std::vector<WiFiEventSoftAPModeProbeRequestReceived> myList;

void onProbeRequestPrint(const WiFiEventSoftAPModeProbeRequestReceived& evt) {
  myList.push_back(evt);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Hello!");

  // Don't save WiFi configuration in flash - optional
  WiFi.persistent(false);

  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP(apSsid, apPassword);
  WiFi.begin(clientSsid, clientPassword);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }
  Serial.println("");
  probeRequestPrintHandler = WiFi.onSoftAPModeProbeRequestReceived(&onProbeRequestPrint);
}

void loop() {
  delay(3000);
  String json = "";
  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  JsonArray& probes = root.createNestedArray("probes");
  for(WiFiEventSoftAPModeProbeRequestReceived w : myList){
    JsonObject& probe = probes.createNestedObject();
    probe["address"] = macToString(w.mac);
    probe["rssi"] = w.rssi;
  }
  myList.clear();
  root.printTo(json);
  Serial.println("json:" + json);

  http.begin("http://example.com/api/v1/probe");
  http.addHeader("Content-Type", "application/json");
  http.POST(json);
  http.end();
}

请记住使用 arduino-esp8266 库的最新版本(实际上是预发布版 - 2.4.0-rc1 或更新版本),因为这些 WiFiEvents 是最近添加的。

如果您还没有,您可以使用库管​​理器(草图 -> 包含库 -> 管理库...)下载 ArduinoJson 库。

关于httprequest - ESP8266 嗅探和发送 Mac 地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45089986/

相关文章:

Javascript 在请求期间禁用按钮

android - 处理来自 HttpRequest 的错误 XML

serial-port - Windows x64的串行/Com端口监视器

c++ - AES 加密解密输出不正确

java - 连接官方 Clash Royale API 时出现错误 403

python - python Flask 形式的所有链接的行为都类似于提交

python - 在相同的Python代码中发送数据包和嗅探

sockets - 套接字安全无视嗅探

c - 如何修复无法从 esp8266 响应读取serial.find ("OK")

arduino - WeMos D1 Mini esptool.FatalError : Timed out waiting for packet header