From Python on Linux I would like to sniff 802.11 management 'probe-request' frames. This is possible from Scapy like so:
# -*- coding: utf-8 -*-
from scapy.all import *
def proc(p):
if ( p.haslayer(Dot11ProbeReq) ):
mac=re.sub(':','',p.addr2)
ssid=p[Dot11Elt].info
ssid=ssid.decode('utf-8','ignore')
if ssid == "":
ssid="<BROADCAST>"
print "%s:%s" %(mac,ssid)
sniff(iface="mon0",prn=proc)
Or from tshark like so:
tshark -n -i mon0 subtype probereq -R 'wlan.fc.type_subtype eq 4' -T fields -e wlan.sa -e wlan_mgt.ssid
We could redirect the output from tshark, and slurp it up with some Python (not pretty, but it works).
However, both of these options have GPL licensing, which makes potential commercial projects tricky. I'm therefore trying to figure out a 'lower level' solution in Python for this specific problem. From Google I've managed to work out two potential directions to try:
Pcap libraries: There seem to be three pcap libraries available for Python: pylibpcap, pypcap, and pcapy. I'm not too sure how to approach incorporating the above functionality into these. Any sample code or solutions would be great.
Raw sockets: PF_PACKET: "Packet sockets are used to receive or send raw packets at the device driver (OSI Layer 2) level. They allow the user to implement protocol modules in user space on top of the physical layer."
This sounds like it could be another option, bypassing pcap altogether. I've heard comments that this may even be a better approach, removing the overhead of pcap libraries. I'm not sure where to start tackling this, though.
Any help in solving this would be greatly appreciated.
I've managed to work this out. Here's the process I went through:
Capture some 802.11 management 'probe-request' frames:
tshark -n -i mon0 subtype probereq -c 5 -w probe.pcap
Understand RadioTap
Reading RadioTap documentation, I realised that RadioTap frames are comprised of the following fields:
it_version (2 bytes) - major version of the radiotap header is in use. Currently, this is always 0
it_pad (2 bytes) - currently unused
it_len (4 bytes) - entire length of the radiotap data, including the radiotap header
it_present (8 byte) - bitmask of the radiotap data fields that follows the radiotap header
Therefore the it_len allows us to locate the beginning of the 802.11 frame that follows the radiotap data.
Coding solution in Python
I chose to use pylibpcap from three pcap library options I found in my previous post, and discovered the dpkt module for parsing 802.11 frames. Documentation was very thin, so by playing in the Python interpreter I managed to work out the following code to extract MAC, probe SSID, and signal strength from our capture file:
f = open('probe.pcap')
pc = dpkt.pcap.Reader(f)
dl=pc.datalink()
if pc.datalink() == 127: #Check if RadioTap
for timestamp, rawdata in pc:
tap = dpkt.radiotap.Radiotap(rawdata)
signal_ssi=-(256-tap.ant_sig.db) #Calculate signal strength
t_len=binascii.hexlify(rawdata[2:3]) #t_len field indicates the entire length of the radiotap data, including the radiotap header.
t_len=int(t_len,16) #Convert to decimal
wlan = dpkt.ieee80211.IEEE80211(rawdata[t_len:])
if wlan.type == 0 and wlan.subtype == 4: # Indicates a probe request
ssid = wlan.ies[0].info
mac=binascii.hexlify(wlan.mgmt.src)
print "%s, %s (%d dBm)"%(mac,ssid,signal_ssi)