Wardriving is the act of searching for Wi-Fi wireless networks by a person usually in a moving vehicle, using a laptop or smartphone.


I recently built a portable wardriver out of two D1 Mini Pro (ESP8266-based) modules with external antennas, a GPS6MV2 GPS module, and an SD card writer. The reason for using two D1 Mini Pro modules is so that I can run two WiFi scans simultaneously to theoretically reduce the amount of missed broadcasts.

I have been sending the data my device creates to Wigle.net which is a website designed for crowdsourcing WiFi data. At the time of writing, my wardriver has ‘seen’ a total of 87,580 unique WiFi Networks and 53,151 of those had not been seen by Wigle before (presumably because not many people wardrive near where I live). Here is a screenshot of the Wigle worldmap zoomed into part of the United Kingdom showing every WiFi hotspot I have found as a dot.

Map showing discovered WiFi Networks on Wigle.net; Click to enlarge


At the moment, I am rewriting the code to use the promiscuous/monitor mode options on the ESP8266 instead of the basic standard WiFi scan library. The standard library has worked very well for me so far, but it has some limitations such as being unable to specifically choose the timings of each channel scan. For example, I think it would be beneficial to spend longer listening on the common channels (1, 6, 11)  and then doing a quick sweep of the remaining channels whereas the standard library seems to spend an equal amount of time per channel (approximately 210ms).

The most significant issue with the standard library is that it returns all of its findings at once instead of as the networks are discovered. This means that each discovered network could be anywhere between 0 and 3000ms old when it is returned by the function. If the device is travelling at 120km/h and a WiFi network is discovered at the very beginning of a scan and returned once the function completes, the device could have moved up to 100 metres after the network was found. The function doesn’t return any timing information, so it is impossible to know exactly how out of sync the data is with the GPS readings. This means that all discovered networks get grouped together into 3 second clusters which can be seen below:

Map showing discovered WiFi Networks on a single road; Click to enlarge

As shown above, multiple networks are pinpointed on a single set of coordinates instead of being spaced apart accurately. This doesn’t matter when travelling at low speeds but can cause large clusters when travelling quickly through a WiFi-dense area.

Promiscuous/Monitor mode returns every packet the radio receives without any processing done beforehand. It is simple to determine the type of packet received so unwanted packets can be quickly disregarded to free up processor time. Eg,

if (buf[12] == 0x80){ //beacon }
if (buf[12] == 0x50){ //probe response }

Where buf is the buffer created by the promiscuous mode callback function. This allows us to ignore everything that isn’t a beacon or a probe response (the two types of packets sent by WiFi APs to announce their presence). I have created some basic test code which simply returns the BSSID, SSID, channel, and country code by handling the raw packets as they are received by the radio in real time. I still need to determine the RSSI of each packet as this helps Wigle triangulate signals better. Once that is complete, I should be able to merge it with the rest of the code (GPS handling, SD card writing, etc) in order to start creating more accurate data for Wigle.

I have been pleasantly surprised by how well this device is performing, it draws significantly less power than a Raspberry Pi (or a laptop), and it seems to gather a similar amount of data. I can generally get a minimum of 32 hours out of a 5200mAH powerbank before I need to consider recharging and due to the size of the device, I can go for a walk with it in my back pocket (and the powerbank in my other back pocket) without it being particularly uncomfortable. Thanks to being USB powered, it is also very easy to charge/use in a car for long journeys.

Once I am happy with the updated code I will make another post with a build tutorial for anybody else who wants a power-efficient portable wardriver.

Categories: HardwareSoftware


Leave a Reply

Your email address will not be published. Required fields are marked *