I am currently trying to determine how the ESP8266 WifiSniffer program by Kalanda works.
Here is the source code:
#include <Arduino.h>
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 {
//THESE HAVE AN EFFECT
// signed rssi:8; // signal intensity of packet
// unsigned rate:4;
// unsigned is_group:1;
// unsigned:1;
// unsigned legacy_length:12; // if not 11n packet, shows length of packet. NOT THIS
// unsigned MCS:7; // if is 11n packet, shows the modulation and code used (range from 0 to 76)
// unsigned Smoothing:1;
// unsigned Not_Sounding:1;
// unsigned:1;
// unsigned Aggregation:1;
// unsigned STBC:2;
// unsigned rxend_state:8;
// unsigned ampdu_cnt:8;
// unsigned channel:4; //which channel this packet in.
//THESE HAVE NO EFFECT
// unsigned sig_mode:2; // 0:is 11n packet; 1:is not 11n packet;
// unsigned damatch0:1;
// unsigned damatch1:1;
// unsigned bssidmatch0:1;
// unsigned bssidmatch1:1;
// 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. NOT THIS
//unsigned FEC_CODING:1; // if is 11n packet, shows if is LDPC packet or not.
//unsigned SGI:1;
//unsigned:12; //HAS NO EFFECT
};
struct SnifferPacket{
struct RxControl rx_ctrl; //RxControl is just a name, can be named anything (as long as you change other things)
uint8_t data[DATA_LENGTH]; //DOES NOT HAVE EFFECT
// uint16_t cnt; //THIS HAS NO EFFECT
// uint16_t len; //THIS HAS NO EFFECT
};
// Declare each custom function (excluding built-in, such as setup and loop) before it will be called.
// https://docs.platformio.org/en/latest/faq.html#convert-arduino-file-to-c-manually
//static void showMetadata(SnifferPacket *snifferPacket);
//static void sniffer_callback(uint8_t *buffer, uint16_t length);
static void printDataSpan(uint16_t start, uint16_t size, uint8_t* data);
static void getMAC(char *addr, uint8_t* data, uint16_t offset);
void channelHop();
/**
* Callback for promiscuous mode
*/
static void sniffer_callback(uint8_t *buffer, uint16_t length) {
struct SnifferPacket *snifferPacket;
snifferPacket = (struct SnifferPacket*) buffer;
Serial.print("buffer size: ");
Serial.print(sizeof(buffer));
Serial.print(" length size: ");
Serial.print(sizeof(length));
Serial.print(" snifferPacket size: ");
Serial.print(sizeof(snifferPacket));
Serial.print(" START OF BUFFER OG: ");
for (int i = 0; i < 20; i++){
Serial.print((unsigned int) buffer[i], BIN);
Serial.print(" ");
}
Serial.print(" END OF BUFFER OG ");
showMetadata(snifferPacket);
}
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;
uint8_t moreFragments = (frameControl & 0b0000010000000000) >> 10;
uint8_t retry = (frameControl & 0b0000100000000000) >> 11;
uint8_t powerMgmt = (frameControl & 0b0001000000000000) >> 12;
uint8_t moreData = (frameControl & 0b0010000000000000) >> 13;
uint8_t protectedFrame = (frameControl & 0b0100000000000000) >> 14;
uint8_t htcOrder = (frameControl & 0b1000000000000000) >> 15;
Serial.print(" START OF BUFFER: ");
for (int i = 0; i < 20; i++){
Serial.print((unsigned int)snifferPacket->data[i], BIN);
Serial.print(" ");
}
Serial.print(" END OF BUFFER ");
Serial.print(" DATASPAN START: ");
printDataSpan;
Serial.print(" DATASPAN END ");
Serial.print(" frameControl: ");
Serial.print(frameControl);
Serial.print(" version: ");
Serial.print(version);
Serial.print(" Type: ");
Serial.print(frameType);
Serial.print(" frameSubType: ");
Serial.print(frameSubType);
Serial.print(" toDS: ");
Serial.print(toDS);
Serial.print(" fromDS: ");
Serial.print(fromDS);
Serial.print(" moreFragments: ");
Serial.print(moreFragments);
Serial.print(" retry: ");
Serial.print(retry);
Serial.print(" powerMgmt: ");
Serial.print(powerMgmt);
Serial.print(" moreData: ");
Serial.print(moreData);
Serial.print(" protectedFrame: ");
Serial.print(protectedFrame);
Serial.print(" htcOrder: ");
Serial.print(htcOrder);
Serial.print(" Ch: ");
Serial.print(wifi_get_channel());
// Serial.print(" rssi: ");
// Serial.print(snifferPacket->rx_ctrl.rssi, BIN);
// Serial.print(" RSSI: ");
// Serial.print(snifferPacket->rx_ctrl.rssi, DEC);
//Only look for probe request packets
// if (frameType != TYPE_MANAGEMENT ||
// frameSubType != SUBTYPE_PROBE_REQUEST)
// //Serial.println();
// 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
// printDataSpan(26, SSID_length, snifferPacket->data);
Serial.println();
}
static void printDataSpan(uint16_t start, uint16_t size, uint8_t* data) {
for(uint16_t x = start; x < DATA_LENGTH && x < start+size; x++) {
Serial.print(data[x]);
//Serial.write(data[x]);
}
}
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 100
static os_timer_t channelHop_timer;
/**
* Callback for channel hoping
*/
void channelHop()
{
// hoping channels 1-13
uint8 new_channel = wifi_get_channel() + 1;
if (new_channel > 13) {
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);
// 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);
}
I have noticed the Serial.print
output directly from the buffer
differs to the Serial.print
output for the variable snifferPacket
which is given attributes of the struct RxControl
.
When the code is configured as normal, the raw buffer output (BUFFER OG) has 12 additional elements compared to the snifferPacket (BUFFER) output. Here is an example:
buffer size: 4 length size: 2 snifferPacket size: 4 START OF BUFFER OG: 10100010 10000 11100110 1010000 0 0 0 0 0 0 1 0 10000000 0 0 0 11111111 11111111 11111111 11111111 END OF BUFFER OG START OF BUFFER: 10000000 0 0 0 11111111 11111111 11111111 11111111 11111111 11111111 11011000 111 10110110 11010 10100010 1000001 11011000 111 10110110 11010 END OF BUFFER DATASPAN START: DATASPAN END frameControl: 128 version: 0 Type: 0 frameSubType: 8 toDS: 0 fromDS: 0 moreFragments: 0 retry: 0 powerMgmt: 0 moreData: 0 protectedFrame: 0 htcOrder: 0 Ch: 1 Ch: 1 Peer MAC: d8:07:b6:1a:a2:41
Comparing just the two buffer outputs:
- BUFFER OG: 10100010 10000 11100110 1010000 0 0 0 0 0 0 1 0 10000000 0
0 0 11111111 11111111 11111111 11111111
- BUFFER: 10000000 0 0 0 11111111 11111111 11111111 11111111...
I've been able to identify parts of the first 12 elements:
1. 10100010 -> RCPI (RSSI) in two's complement format
2. 10000 -> Unknown
3. 11100110 -> Unknown
4. 1010000 -> Unknown
5. 0 -> Unknown, but constant
6. 0 -> Unknown, but constant
7. 0 -> Unknown, but constant
8. 0 -> Unknown, but constant
9. 0 -> Unknown, but constant
10. 0 -> Unknown, but constant
11. 1 -> Wi-Fi channel (in this example it's channel 1)
12. 0 -> Unknown, but constant
These 12 elements come before the 802.11 packet (starting with the frame header which begins at 10000000)
Through trial and error, I've been able to the identify parts of the code that effect the snifferPacket output. These are:
14 attributes in the
RxControl
struct, titled asTHESE HAVE AN EFFECT
.a. Commenting between 1-8 of any attributes: The last 4 elements appear in the
snifferPacket
output (0 0 1 0
)b. Commenting between 9-13 of any attributes: The last 8 elements appear in the
snifferPacket
output (0 0 0 0 0 0 1 0
)c. Commenting all 14 attributes: The last 11 elements appear in the snifferPacket output (
10000 11100110 1010000 0 0 0 0 0 0 1 0
)struct RxControl rx_ctrl;
, understruct SnifferPacket
a. Commenting out: All 12 elements appear in the snifferPacket output (
10100010 10000 11100110 1010000 0 0 0 0 0 0 1 0
)
So it's clear that there is an association between defining attributes and their exclusion from the snifferPacket output.
Note that leading 0s are part of an element are ignored are part of the output. For example:
- 0100 = 100
- 0000 = 0
- 1000 = 1000
So my questions are:
- What do each of the 12 elements represent?
- Why is there a difference in the output between the output of the raw
buffer
andsnifferPacket
? - Why do only certain attributes effect the output of
snifferPacket
? - Why does commenting a greater number of attributes result in a greater number of elements reappearing, no matter which attributes are commented?
Thanks in advance.