WiFi Promiscuous Mode ile Cihaz Varlığı/MAC Analizi
Proje Amacı
ESP32'nin WiFi çipini 'promiscuous mode'a alarak, kendisine yönelik olmayan tüm WiFi paketlerini (yönetim/beacon çerçeveleri dahil) pasif olarak dinlemeyi ve ortamdaki telefon/laptop gibi cihazların MAC adreslerini ve sinyal gücünü (RSSI) tespit etmeyi öğretir — kalabalık yoğunluğu tahmini veya varlık algılama gibi gerçek uygulamalarda kullanılan bir tekniktir. ESP32'nin WiFi baseband çipi, düşük seviyeli esp_wifi_set_promiscuous() API'siyle normalde işletim sisteminin gizlediği ham 802.11 çerçevelerine erişim sağlar. Bu erişim Arduino Uno'da mümkün değildir: kartın dinleyecek hiçbir WiFi radyosu yoktur.
Gerekli Malzemeler
- ESP32 DevKit V1 (38 pin)
- SSD1306 0.96" I2C OLED ekran (isteğe bağlı, canlı sayaç göstermek için)
- Breadboard
- Jumper kablolar
Gerekli Kütüphaneler
esp_wifi.h, WiFi.h (ikisi de ESP32 core ile gelir). Adafruit_SSD1306 + Adafruit_GFX (OLED kullanılıyorsa).
Pin Bağlantıları
| Bileşen Pini | Bağlantı |
|---|---|
| OLED SDA (isteğe bağlı) | GPIO21 |
| OLED SCL (isteğe bağlı) | GPIO22 |
| OLED VCC | 3V3 |
| OLED GND | GND |
Devre Şeması
ESP32 Kodu
| 1 | #include <WiFi.h> |
| 2 | #include <esp_wifi.h> |
| 3 | |
| 4 | #define MAX_CIHAZ 50 |
| 5 | uint8_t gorulenMac[MAX_CIHAZ][6]; |
| 6 | int gorulenSayisi = 0; |
| 7 | uint8_t kanal = 1; |
| 8 | unsigned long sonKanalDegisim = 0; |
| 9 | |
| 10 | bool macBilinen(const uint8_t* mac) { |
| 11 | for (int i = 0; i < gorulenSayisi; i++) { |
| 12 | if (memcmp(gorulenMac[i], mac, 6) == 0) return true; |
| 13 | } |
| 14 | return false; |
| 15 | } |
| 16 | |
| 17 | // Ham 802.11 çerçevesi geldiğinde ESP-IDF tarafından çağrılan callback. |
| 18 | // KRİTİK: bu fonksiyon bir ISR/callback bağlamında çalışır, içine |
| 19 | // Serial.print DIŞINDA ağır işlem (delay, WiFi çağrısı vb.) KONULMAMALIDIR. |
| 20 | void IRAM_ATTR paketYakalandi(void* buf, wifi_promiscuous_pkt_type_t tur) { |
| 21 | const wifi_promiscuous_pkt_t* paket = (wifi_promiscuous_pkt_t*)buf; |
| 22 | const uint8_t* gonderenMac = paket->payload + 10; // 802.11 çerçeve header'ında gönderen MAC ofseti |
| 23 | |
| 24 | if (!macBilinen(gonderenMac) && gorulenSayisi < MAX_CIHAZ) { |
| 25 | memcpy(gorulenMac[gorulenSayisi], gonderenMac, 6); |
| 26 | gorulenSayisi++; |
| 27 | Serial.printf("Yeni cihaz #%d: %02X:%02X:%02X:%02X:%02X:%02X RSSI:%d dBm Kanal:%d\n", |
| 28 | gorulenSayisi, gonderenMac[0], gonderenMac[1], gonderenMac[2], |
| 29 | gonderenMac[3], gonderenMac[4], gonderenMac[5], |
| 30 | paket->rx_ctrl.rssi, kanal); |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | void setup() { |
| 35 | Serial.begin(115200); |
| 36 | WiFi.mode(WIFI_MODE_NULL); // normal STA/AP bağlantısını kapat, sadece dinleme yapılacak |
| 37 | |
| 38 | esp_wifi_set_promiscuous(true); |
| 39 | esp_wifi_set_promiscuous_rx_cb(&paketYakalandi); |
| 40 | esp_wifi_set_channel(kanal, WIFI_SECOND_CHAN_NONE); |
| 41 | |
| 42 | Serial.println("Promiscuous mod aktif — MAC/RSSI taraması başladı."); |
| 43 | Serial.println("UYARI: Bu proje SADECE kendi ağınızda/izinli ortamda, eğitim"); |
| 44 | Serial.println("amaçlı kullanılmalıdır. Başkalarının cihazlarını izinsiz izlemek"); |
| 45 | Serial.println("gizlilik ihlali ve birçok ülkede yasa dışıdır."); |
| 46 | } |
| 47 | |
| 48 | void loop() { |
| 49 | // 2.4GHz'in 1-13 kanalları arasında dolaşarak (channel hopping) daha |
| 50 | // geniş bir alan taranır — tek kanalda kalmaktan çok daha etkilidir. |
| 51 | if (millis() - sonKanalDegisim > 500) { |
| 52 | sonKanalDegisim = millis(); |
| 53 | kanal = (kanal % 13) + 1; |
| 54 | esp_wifi_set_channel(kanal, WIFI_SECOND_CHAN_NONE); |
| 55 | } |
| 56 | } |
Çalışma Açıklaması
Bu proje yalnızca kendi sahip olduğunuz ağ/cihazlar üzerinde veya açık izin alınmış ortamlarda (örn. kendi evinizde kaç cihaz olduğunu sayma) kullanılmalıdır. MAC adresi rastgeleleştirme (MAC randomization) özelliği açık modern telefonlarda (iOS 14+/Android 10+ varsayılan) her taramada farklı bir MAC göstereceğinden, bu teknik güncel telefonlarda gerçek ve kalıcı bir kimlik tespiti yapamaz — bu, kullanıcıları koruyan bilinçli bir gizlilik önlemidir ve projenin beklenen bir sınırlamasıdır.
Test Bilgisi
Kodu yükleyip Seri Monitör'ü (115200 baud) açın. Yakınlarda telefonunuzun WiFi'sini açık tutun (bağlı olmasa da telefonlar periyodik 'probe request' çerçeveleri yayınlar); birkaç saniye içinde MAC adreslerinin ve RSSI değerlerinin loglandığını görmelisiniz. Telefonu yaklaştırıp uzaklaştırarak RSSI değerinin (örn. -40'tan -80'e) mesafeyle mantıklı şekilde değiştiğini doğrulayın; bu, sinyal gücü ile mesafe arasındaki ilişkiyi somut olarak gözlemlemenizi sağlar.
Olası Sorunlar ve Çözümleri
Hiç paket yakalanmıyorsa: WiFi.mode(WIFI_MODE_NULL) çağrısının promiscuous mode'dan önce yapıldığından emin olun, aktif bir STA/AP bağlantısıyla çakışabilir. Cihaz donuyor veya resetleniyorsa: paketYakalandi() callback'i içine Serial.printf dışında ağır kod eklemeyin (örn. delay, malloc veya bir WiFi fonksiyonu çağırmak ISR bağlamında çökmeye neden olur). Sadece kendi cihazınızın MAC'i görünüyorsa: kanal tarama (channel hopping) döngüsünün çalıştığını ve yakındaki cihazların gerçekten WiFi taraması yaptığını (ekranı açık tutmak genelde probe request'i tetikler) kontrol edin.
Alternatif Çözümler
Ham MAC adresleri yerine sadece 'şu an ortamda tahmini N cihaz var' sayısı gösterilerek gizlilik açısından daha nötr bir 'kalabalık yoğunluğu sayacı' yapılabilir. Yakalanan veriler bir zaman damgasıyla SD karta (proje #18) kaydedilip, mağaza veya etkinlik yoğunluk analizinde kullanılabilir. Sabit kanal tarama yerine, belirli bir SSID'nin (kendi ağınızın) beacon çerçevelerini filtreleyerek sadece o ağa bağlı cihazları izleyen daha odaklı ve amaca özel bir analiz yapılabilir.
Benzer Projeler
Fog Computing: Çoklu Sensör Düğümünden Veri Toplayan Ağ Geçidi
Birden fazla uzak sensör düğümünden ESP-NOW ile gelen ham verileri tek bir 'gateway' ESP32 üzerinde toplayıp, yerel olarak filtreleyip/özetleyerek (fog computing — buluta göndermeden önce kenar/yerel işleme yapmak), sonucu bir OLED ekranda göstermeyi ve toplu halde WiFi ile buluta iletmeyi öğretir. ESP32'nin hem ESP-NOW alıcısını hem WiFi istemcisini hem de I2C ekran sürücüsünü aynı anda, tek çip üzerinde çalıştırabilecek yeterli RAM'i ve iki çekirdeği vardır. Bu çok görevlilik Arduino Uno'da kurulamaz: ne ESP-NOW/WiFi radyosu ne de birden fazla eşzamanlı veri akışını (çoklu düğüm + ekran + bulut gönderimi) işleyecek 2KB RAM'i bulunur.
FreeRTOS Dual-Core Görev Paylaşımlı Veri Toplama
xTaskCreatePinnedToCore() ile iki farklı sensör okuma görevini ESP32'nin iki fiziksel çekirdeğine (Core 0 ve Core 1) sabitleyerek tamamen paralel çalıştırmayı öğretir — biri yavaş ve bloklayıcı DHT22'yi okurken diğeri hızlı analog LDR okumaya kesintisiz devam eder, ikisi birbirini beklemez. ESP32, iki bağımsız Xtensa LX6 çekirdeğine sahiptir; Arduino sketch'i normalde sadece Core 1'de çalışır, Core 0 ise bilinçli olarak görev atanarak devreye alınabilir. Bu paralellik Arduino Uno'da kurulamaz: ATmega328P tek çekirdekli 8-bit bir mikrodenetleyicidir, ikinci bir çekirdeğe görev atamak donanımsal olarak mümkün değildir ve kart FreeRTOS gibi bir RTOS da çalıştıramaz.
ESPAsyncWebServer ile Bloklamayan Çoklu İstemci REST API
Birden fazla tarayıcı veya istemcinin aynı anda, birbirini bloklamadan bağlanıp iki rölenin durumunu okuyup değiştirebildiği asenkron (event-driven) bir REST API sunmayı öğretir — akıllı ev panelleri ve endüstriyel kontrol arayüzlerinde tercih edilen mimarinin küçük ölçekli bir örneğidir. ESPAsyncWebServer, gelen her isteği ayrı ayrı bekletmeden (non-blocking) LwIP ağ yığınıyla doğrudan çalışır; bunun için ESP32'nin ikinci çekirdeği ve yeterli RAM'i (520KB SRAM) devreye girer. Bu mimari Arduino Uno'da kurulamaz: WiFi donanımı yoktur; harici bir WiFi shield eklense bile klasik senkron 'WiFiServer' modeli her isteği sırayla işler ve 2KB RAM, birden fazla eşzamanlı bağlantı arabelleğini aynı anda tutmaya yetmez.