【ESP8266】ESP8266 sniffer使用示例(基于NONOS SDK)

前言

想接觸ESP8266 sniffer也是比較巧合,因為看到國外論壇一篇文章激發(fā)了我的興趣,他是使用ESPduino開發(fā)環(huán)境的,但我習(xí)慣于官方SDK開發(fā),就想著能不能找到相關(guān)API接口。一查資料,還真的有。就是ESP8266 sniffer。

根據(jù)樂鑫官網(wǎng)顯示,2017年05月05日ESP8266 NONOS SDK已經(jīng)升級到2.1.0版本了。版本都迭代更新到2.1了,發(fā)現(xiàn)自己對Sniffer 相關(guān)接口還沒有一定的了解,所以特此寫下本文記錄,也方便后來者學(xué)習(xí)參考。

建議

建議閱讀本文前請確定自己具備以下基礎(chǔ),否則可能會有看不懂的地方,包括但不限于:

  • 閱讀ESP8266 NONOS SDK源碼的基礎(chǔ)能力
  • ESP8266開發(fā)環(huán)境的搭建、燒錄和調(diào)試

Sniffer介紹

那么什么是snffer呢?sniffer可以翻譯為混雜模式,ESP8266可以進入該模式,接收空中的 IEEE802.11 包。SDK主要提供的接口有:

接口 說明
wifi_promiscuous_enable 開啟混雜模式
wifi_promiscuous_set_mac 設(shè)置 sniffer 模式時的 MAC 地址過濾
wifi_set_promiscuous_rx_cb 注冊混雜模式下的接收數(shù)據(jù)回調(diào)函數(shù),每收到一包數(shù)據(jù),都會進入注冊的回調(diào)函數(shù)。
wifi_get_channel 獲取信道號
wifi_set_channel 設(shè)置信道號,用于混雜模式

更具體的詳細說明可以看文檔。

核心代碼

下面放上核心代碼,文件是sniffer.c,主要有兩個初始化:sniffer_initsniffer_init_in_system_init_done,sniffer_init是在user_init里面調(diào)用,做一些定時器的初始化,sniffer_init_in_system_init_done是放在ESP8266底層系統(tǒng)初始化后的回調(diào)函數(shù)(相關(guān)API:system_init_done_cb),如果不放在這里調(diào)用可能會導(dǎo)致sniffer功能初始化不成功。

channelHop函數(shù)和promisc_cb函數(shù)是定時器回調(diào)函數(shù)。

channelHop每調(diào)用一次會改變ESP8266掃描WiFi的channel,可在include/sniffer.h修改CHANNEL_HOP_INTERVAL數(shù)值,博主工程默認是3000ms。

promisc_cb函數(shù)則可以參考SDK文檔的wifi_set_promiscuous_rx_cb API函數(shù)說明:「每收到一包數(shù)據(jù),都會進入注冊的回調(diào)函數(shù)」。該函數(shù)就是對這些數(shù)據(jù)包進行處理,然后打印出Client的MAC和AP的MAC。

//省略……

void ICACHE_FLASH_ATTR
channelHop(void *arg)
{
    // 1 - 13 channel hopping
    uint8 new_channel = wifi_get_channel() % 12 + 1;
    os_printf("** hop to %d **\t    Client MAC\t\t    AP MAC\r\n", new_channel);
    wifi_set_channel(new_channel);
}

//省略……

static void ICACHE_FLASH_ATTR
promisc_cb(uint8_t *buf, uint16_t len)
{
    if (len == 12){
        struct RxControl *sniffer = (struct RxControl*) buf;
    } else if (len == 128) {
        struct sniffer_buf2 *sniffer = (struct sniffer_buf2*) buf;
    } else {
        struct sniffer_buf *sniffer = (struct sniffer_buf*) buf;
        int i=0;
        // Check MACs

        // 如果MAC地址和上一次一樣就返回
        if(0==os_memcmp(temp_mac, &sniffer->buf[4], 6)){
            return;
        }

        // 緩存上次的MAC,避免重復(fù)打印
        for (i=0; i<6; i++){
            temp_mac[i] = sniffer->buf[i+4];
        }

        #if SNIFFER_TEST
            os_printf("-> %3d: %d", wifi_get_channel(), len);
            printmac(sniffer->buf, 4);
            printmac(sniffer->buf, 10);
            os_printf("\n");
        #endif

        // 判斷client
        for (i=0; i<6; i++) if (sniffer->buf[i+4] != client[i]) return;
        printmac(sniffer->buf, 4);

        os_printf("\r\n");
        os_printf("\trssi:%d\r\n", sniffer->rx_ctrl.rssi);
        os_printf("\tchannel:%d\r\n", sniffer->rx_ctrl.channel);
        os_printf("\trate:%d\r\n", sniffer->rx_ctrl.rate);
        os_printf("\tsig_mode:%d\r\n",sniffer->rx_ctrl.sig_mode);

        // 判斷AP
        //for (i=0; i<6; i++) if (sniffer->buf[i+10] != ap[i]) return;
        //printmac(sniffer->buf, 10);

        //os_timer_disarm(&channelHop_timer);
    }
}

void ICACHE_FLASH_ATTR
sniffer_init(void)
{
    // Promiscuous works only with station mode
    wifi_set_opmode(STATION_MODE);
    
    //省略……

    os_timer_disarm(&channelHop_timer);
    os_timer_setfn(&channelHop_timer, (os_timer_func_t *) channelHop, NULL);
    os_timer_arm(&channelHop_timer, CHANNEL_HOP_INTERVAL, 1);
}

void ICACHE_FLASH_ATTR
sniffer_init_in_system_init_done(void)
{
    // Set up promiscuous callback
    wifi_set_channel(1);
    wifi_promiscuous_enable(0);
    wifi_set_promiscuous_rx_cb(promisc_cb);
    wifi_promiscuous_enable(1);
}

user_main.c初始化代碼如下:

void ICACHE_FLASH_ATTR
system_init_done(void)
{
    sniffer_init_in_system_init_done();
}

void ICACHE_FLASH_ATTR
user_init()
{
    uart_init(115200, 115200);
    os_printf("\r\n\r\nSDK version:%s\n", system_get_sdk_version());
    
    sniffer_init();

    // Continue to 'sniffer_system_init_done'
    system_init_done_cb(system_init_done);
}

另外,如果有時間的話,會考慮分析一下源文件中WiFi相關(guān)的結(jié)構(gòu)體(比如struct RxControl),隨后會更新本文。

示例工程

那么下面就放上我測試通過的sniffer使用示例工程??垂こ虒W(xué)習(xí)使用是最快速的方法。使用本工程可以抓取Client和AP的MAC地址。另外博主已經(jīng)能成功抓到自己手機的MAC了。

示例工程:

本工程效果圖:

效果圖
效果圖

本文最后編輯時間:2017年6月
本文首發(fā)于CSDN:http://blog.csdn.net/yannanxiu/article/details/72778688

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容