15
votes

I've been working on a way to have an OpenWRT router log WiFi probe requests to a MySQL db (it stores MAC address and RSSI info for each probe request packet along with other, router-specific data).

After researching libpcap quite a bit, I've been able to cobble together a basic little program that simply sniffs packets on a monitor interface (mon0) using a filter expression ('wlan subtype probe-req') and then prints out the raw packets in hex. With the info that's available online on libpcap this part was fairly straightforward.

Now here's where I'm stuck: How do I parse the WiFi packet to retrieve the info I'm looking for (RSSI and source MAC address)?

To be clear, I'm not asking for the code to do it (although I won't complain if you'd like to supply some :D). I'm just looking for some sort of guide for understanding which byte is which - a WiFi packet road map, if you will.

There are a few good tutorials out there for parsing packets that come in over ethernet, but I haven't been able to find anything to help with parsing headers spcifically related to WiFi. I assume it will be a pretty simple process - just grabbing the relevant bytes for RSSI and source MAC - but again, I haven't been able to find any documentation on which byte is which.

I know this has been done before but I'll be honest: I am completely lost when looking through the source code for tcpdump.

So, does anyone know of a good resource for how to parse WiFi packets?

Cheers

EDIT: More Specific Answer

RSSI is found in the RadioTap header (well, on Linux it is). Pulling the RSSI out of the packet is fairly straightforward using radiotap-parser.c along with the files it depends on (found in the same directory as the file I linked to). If anyone is having trouble with using the radiotap-parser.c functions feel free to get in touch.

Pulling out the source MAC address is made pretty easy by the radiotap functions because the radiotap header struct contains the length of the radiotap header (it_len), which is variable. Since I am parsing only probe requests, which have a fixed length (check out page 17 here) it's just a matter of making a pointer that points to packet + it_len + 10 (the source MAC address starts 10 bytes after the beginning of the MAC frame, which begins where the radiotap header ends). The 6 bytes that start at that pointer are addr2 in the 802.11 frame (again, see page 17 here).

4
radiotap-parser.c link is broken.haccks

4 Answers

3
votes

A Google search for "802.11 frame format" provides some promising links I believe. Here's a high-level overview that lays out the packet: http://www.technologyuk.net/telecommunications/networks/wireless_networks.shtml.

2
votes

If you are using pylibpcap, then you can grab the RSSI this way. This is crude and makes assumptions about the flags in the 802.11 frame (ie the flags must be 0x0000482F), but it worked for me. This is a python hack and I didn't want to go down the route of installing extra modules (dpkt and scapy have features to do this, but not well documented) when the hack is just one call to struct.unpack.

(len,data,timestamp) = p.get_next()

if data[0:8] =='\x00\x00\x22\x00\x2F\x48\x00\x00' and len(data) >= 50:
  type_subtype = ord(data[34])
  dest_mac     = data[38:38+6]
  src_mac      = data[44:44+6]
  rssi,        = struct.unpack("b",data[22])

If your flags aren't as above, then look at radiotap-parser.c in the OP's question, and figure out how to calculate the offset to the RSSI field (22 in this example). Each flag bit changes the offset by 1,2,4 or 8 bytes.

1
votes

I know this post is old but I came across it trying to do wifi parsing with no luck so Im hoping I might be able to help someone else!

There is a relatively new library but Its amazing for all levels of the stack. Its called libTins and will parse out packets at every layer of the stack for you. Its BSD licensed (as of 2015) and is super easy to do sniffing. Its built on top of lib pcap but will accept byte arrays if you want to do the sniffing yourself.

-1
votes

you can use the module tshark where you can retrieve specific fields.