Initial version of monitor mode scanner
authorjaviplx <javiplx@gmail.com>
Sun, 10 Oct 2010 20:28:00 +0000 (20:28 +0000)
committerjaviplx <javiplx@gmail.com>
Sun, 10 Oct 2010 20:28:00 +0000 (20:28 +0000)
git-svn-id: file:///svnroot/wifihood/trunk/wifiscanner@45 c51dfc6a-5949-4919-9c8e-f207a149c383

wiviz.py [new file with mode: 0755]

diff --git a/wiviz.py b/wiviz.py
new file mode 100755 (executable)
index 0000000..5710393
--- /dev/null
+++ b/wiviz.py
@@ -0,0 +1,199 @@
+#!/usr/bin/python
+
+import pcapy
+import struct
+
+iface = 'wlan0'
+
+max_bytes = 1024
+promiscuous = False
+read_timeout = 100 # in milliseconds
+pc = pcapy.open_live(iface, max_bytes, promiscuous, read_timeout)
+
+# Removed leading IEEE80211_RADIOTAP_
+ratiotap_header_bits = (
+( "TSFT" , 0 , "q" , False ) ,
+( "FLAGS" , 1 , "B" , True ) ,
+( "RATE" , 2 , "B" , True ) ,
+( "CHANNEL" , 3 , "hh" , False ) ,
+( "FHSS" , 4 , "h" , False ) ,
+( "DBM_ANTSIGNAL" , 5 , "b" , True ) ,
+( "DBM_ANTNOISE" , 6 , "b" , True ) ,
+( "LOCK_QUALITY" , 7 , "h" , False ) ,
+( "TX_ATTENUATION" , 8 , "h" , False ) ,
+( "DB_TX_ATTENUATION" , 9 , "h" , False ) ,
+( "DBM_TX_POWER" , 10 , "b" , True ) ,
+( "ANTENNA" , 11 , "B" , True ) ,
+( "DB_ANTSIGNAL" , 12 , "B" , True ) ,
+( "DB_ANTNOISE" , 13 , "B" , True ) ,
+( "RX_FLAGS" , 14 , "h" , False ) ,
+( "TX_FLAGS" , 15 , "h" , False ) ,
+( "RTS_RETRIES" , 16 , "B" , True ) ,
+( "DATA_RETRIES" , 17 , "B" , True ) ,
+( "EXT" , 31 , "" , False )
+) 
+
+# Removed leading IEEE80211_CHAN_
+channel_flags = (
+( "TURBO"   , 0x0010 ) , # Turbo channel
+( "CCK"     , 0x0020 ) , # CCK channel
+( "OFDM"    , 0x0040 ) , # OFDM channel
+( "2GHZ"    , 0x0080 ) , # 2 GHz spectrum channel.
+( "5GHZ"    , 0x0100 ) , # 5 GHz spectrum channel
+( "PASSIVE" , 0x0200 ) , # Only passive scan allowed
+( "DYN"     , 0x0400 ) , # Dynamic CCK-OFDM channel
+( "GFSK"    , 0x0800 )   # GFSK channel (FHSS PHY)
+)
+# IEEE80211_CHAN_A  = IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM
+# IEEE80211_CHAN_B  = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK
+# IEEE80211_CHAN_G  = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN
+# IEEE80211_CHAN_TA = IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO
+# IEEE80211_CHAN_TG = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN  | IEEE80211_CHAN_TURBO
+
+# Removed leading IEEE80211_RADIOTAP_F_
+radiotap_flags = (
+( "CFP"      , 0x01 ) , # sent/received during CFP
+( "SHORTPRE" , 0x02 ) , # sent/received with short preamble
+( "WEP"      , 0x04 ) , # sent/received with WEP encryption
+( "FRAG"     , 0x08 ) , # sent/received with fragmentation
+( "FCS"      , 0x10 ) , # frame includes FCS
+( "DATAPAD"  , 0x20 )   # frame has padding between 802.11 header and payload (to 32-bit boundary)
+)
+
+# Removed leading IEEE80211_RADIOTAP_F_RX_
+radiotap_rx_flags = (
+( "BADFCS" , 0x0001 )   # frame failed crc check
+)
+
+# Removed leading IEEE80211_RADIOTAP_F_TX_
+radiotap_tx_flags = (
+( "FAIL" , 0x0001 ) , # failed due to excessive retries
+( "CTS"  , 0x0002 ) , # used cts 'protection'
+( "RTS"  , 0x0004 )   # used rts/cts handshake
+)
+
+
+# Unknown origin
+# Removed leading IEEE80211_STYPE_
+management_flags = (
+( "ASSOC_REQ"    , 0x0000 ) ,
+( "ASSOC_RESP"   , 0x0010 ) ,
+( "REASSOC_REQ"  , 0x0020 ) ,
+( "REASSOC_RESP" , 0x0030 ) ,
+( "PROBE_REQ"    , 0x0040 ) ,
+( "PROBE_RESP"   , 0x0050 ) ,
+( "BEACON"       , 0x0080 ) ,
+( "ATIM"         , 0x0090 ) ,
+( "DISASSOC"     , 0x00A0 ) ,
+( "AUTH"         , 0x00B0 ) ,
+( "DEAUTH"       , 0x00C0 ) ,
+( "ACTION"       , 0x00D0 )
+)
+
+
+import time
+
+max_time = 1
+tstamp = time.time()
+discovered = []
+
+def dealWithPacket ( hdr , data ) :
+
+    if hdr.getlen() != hdr.getcaplen() :
+        print "Error in header : %d vs. %d" % ( hdr.getlen() , hdr.getcaplen() )
+        return
+    if len(data) != hdr.getlen() :
+        print "Data lenght does not match"
+        return
+
+    it_version , it_len , it_present = struct.unpack("<Bxhl",data[:8])
+    if it_version != 0 :
+        print "Bad version (%s), it is probably not radiotap header" % it_version
+        return
+    if it_len <= 0 :
+        print "Bad length on radiotap header"
+        return
+
+    radiotap = data[:it_len]
+    payload = data[it_len:]
+
+    format , padstr = "<" , ""
+    fields = []
+    for name,bit,fmt,pad in ratiotap_header_bits :
+# What about  'it_present & ( 0x1 << bit )' ??
+        if it_present & pow(2,bit) == pow(2,bit) :
+            if not fmt :
+                print "Unknown bit %s (%d) set" % ( name , bit )
+                return
+            fields.append( name )
+            if fmt == "hh" :
+                fields.append( "CHANNEL_BITMAP" )
+            if pad :
+                padstr += "x"
+            format += fmt
+    values = struct.unpack(format+padstr,radiotap[8:])
+
+    flags = []
+    for name,value in radiotap_flags :
+        if values[1] & value == value :
+            flags.append( name )
+
+    channel = []
+    for name,value in channel_flags :
+        if values[4] & value == value :
+            channel.append( name )
+
+    pointer = 0
+    pcktlen = len(payload)
+
+    frame_ctl , duration_id = struct.unpack("<hh",payload[:4])
+    pointer += 4
+    pcktlen -= 4
+    for name,value in management_flags :
+        if frame_ctl == value :
+            type = name
+            break
+    else :
+        type = "unknown_%s" % frame_ctl
+
+    mac_str = "<BBBBBB"
+    mac_fmt = "%02X:%02X:%02X:%02X:%02X:%02X"
+
+    maclist = []
+    for i in range(4) :
+        maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
+        pointer += 6
+        pcktlen -= 6
+        if pcktlen < 6 :
+            unknowns = { 'unknown_212':12 , 'unknown_180':20 , 'unknown_196':12 , 'unknown_148':32 , 'unknown_4308':12 , 'unknown_4260':20 }
+            if type in unknowns.keys() :
+                if len(payload) == unknowns[type] :
+                    break
+            raise Exception( "Unhandled type %s with length %d" % ( type , len(payload) ) )
+
+#    print fields
+#    print values
+#    print "Radiotap flags : %s" % " ".join(flags)
+#    print "Channel %d (%s)" % ( values[3] , " ".join(channel) )
+##    print "Control info",frame_ctl,duration_id
+#    print type,":",maclist,"->",pcktlen
+#    print
+
+    print "%20s %4d %5d" % (type,values[3],len(payload)),":"+" %s"*len(maclist) % tuple(maclist)
+    global tstamp,max_time,discovered
+    for mac in maclist :
+        if not type.startswith( "unknown_" ) and not mac in discovered :
+            if mac.startswith( "00:" ) :
+                tstamp = time.time()
+                discovered.append( mac )
+    if time.time()-tstamp > max_time :
+        fd = open( "discovered.list" , "a" )
+        for mac in discovered :
+            fd.write( "%s\n" % mac )
+        fd.close()
+        raise Exception( "Neighborhoud scan completed" )
+
+
+packet_limit = -1 # infinite
+pc.loop( packet_limit , dealWithPacket )
+