5710393b6947f884c07f7fce035b3d2d723c7d2a
[wifihood] / wiviz.py
1 #!/usr/bin/python
2
3 import pcapy
4 import struct
5
6 iface = 'wlan0'
7
8 max_bytes = 1024
9 promiscuous = False
10 read_timeout = 100 # in milliseconds
11 pc = pcapy.open_live(iface, max_bytes, promiscuous, read_timeout)
12
13 # Removed leading IEEE80211_RADIOTAP_
14 ratiotap_header_bits = (
15 ( "TSFT" , 0 , "q" , False ) ,
16 ( "FLAGS" , 1 , "B" , True ) ,
17 ( "RATE" , 2 , "B" , True ) ,
18 ( "CHANNEL" , 3 , "hh" , False ) ,
19 ( "FHSS" , 4 , "h" , False ) ,
20 ( "DBM_ANTSIGNAL" , 5 , "b" , True ) ,
21 ( "DBM_ANTNOISE" , 6 , "b" , True ) ,
22 ( "LOCK_QUALITY" , 7 , "h" , False ) ,
23 ( "TX_ATTENUATION" , 8 , "h" , False ) ,
24 ( "DB_TX_ATTENUATION" , 9 , "h" , False ) ,
25 ( "DBM_TX_POWER" , 10 , "b" , True ) ,
26 ( "ANTENNA" , 11 , "B" , True ) ,
27 ( "DB_ANTSIGNAL" , 12 , "B" , True ) ,
28 ( "DB_ANTNOISE" , 13 , "B" , True ) ,
29 ( "RX_FLAGS" , 14 , "h" , False ) ,
30 ( "TX_FLAGS" , 15 , "h" , False ) ,
31 ( "RTS_RETRIES" , 16 , "B" , True ) ,
32 ( "DATA_RETRIES" , 17 , "B" , True ) ,
33 ( "EXT" , 31 , "" , False )
34
35
36 # Removed leading IEEE80211_CHAN_
37 channel_flags = (
38 ( "TURBO"   , 0x0010 ) , # Turbo channel
39 ( "CCK"     , 0x0020 ) , # CCK channel
40 ( "OFDM"    , 0x0040 ) , # OFDM channel
41 ( "2GHZ"    , 0x0080 ) , # 2 GHz spectrum channel.
42 ( "5GHZ"    , 0x0100 ) , # 5 GHz spectrum channel
43 ( "PASSIVE" , 0x0200 ) , # Only passive scan allowed
44 ( "DYN"     , 0x0400 ) , # Dynamic CCK-OFDM channel
45 ( "GFSK"    , 0x0800 )   # GFSK channel (FHSS PHY)
46 )
47 # IEEE80211_CHAN_A  = IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM
48 # IEEE80211_CHAN_B  = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK
49 # IEEE80211_CHAN_G  = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN
50 # IEEE80211_CHAN_TA = IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO
51 # IEEE80211_CHAN_TG = IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN  | IEEE80211_CHAN_TURBO
52
53 # Removed leading IEEE80211_RADIOTAP_F_
54 radiotap_flags = (
55 ( "CFP"      , 0x01 ) , # sent/received during CFP
56 ( "SHORTPRE" , 0x02 ) , # sent/received with short preamble
57 ( "WEP"      , 0x04 ) , # sent/received with WEP encryption
58 ( "FRAG"     , 0x08 ) , # sent/received with fragmentation
59 ( "FCS"      , 0x10 ) , # frame includes FCS
60 ( "DATAPAD"  , 0x20 )   # frame has padding between 802.11 header and payload (to 32-bit boundary)
61 )
62
63 # Removed leading IEEE80211_RADIOTAP_F_RX_
64 radiotap_rx_flags = (
65 ( "BADFCS" , 0x0001 )   # frame failed crc check
66 )
67
68 # Removed leading IEEE80211_RADIOTAP_F_TX_
69 radiotap_tx_flags = (
70 ( "FAIL" , 0x0001 ) , # failed due to excessive retries
71 ( "CTS"  , 0x0002 ) , # used cts 'protection'
72 ( "RTS"  , 0x0004 )   # used rts/cts handshake
73 )
74
75
76 # Unknown origin
77 # Removed leading IEEE80211_STYPE_
78 management_flags = (
79 ( "ASSOC_REQ"    , 0x0000 ) ,
80 ( "ASSOC_RESP"   , 0x0010 ) ,
81 ( "REASSOC_REQ"  , 0x0020 ) ,
82 ( "REASSOC_RESP" , 0x0030 ) ,
83 ( "PROBE_REQ"    , 0x0040 ) ,
84 ( "PROBE_RESP"   , 0x0050 ) ,
85 ( "BEACON"       , 0x0080 ) ,
86 ( "ATIM"         , 0x0090 ) ,
87 ( "DISASSOC"     , 0x00A0 ) ,
88 ( "AUTH"         , 0x00B0 ) ,
89 ( "DEAUTH"       , 0x00C0 ) ,
90 ( "ACTION"       , 0x00D0 )
91 )
92
93
94 import time
95
96 max_time = 1
97 tstamp = time.time()
98 discovered = []
99
100 def dealWithPacket ( hdr , data ) :
101
102     if hdr.getlen() != hdr.getcaplen() :
103         print "Error in header : %d vs. %d" % ( hdr.getlen() , hdr.getcaplen() )
104         return
105     if len(data) != hdr.getlen() :
106         print "Data lenght does not match"
107         return
108
109     it_version , it_len , it_present = struct.unpack("<Bxhl",data[:8])
110     if it_version != 0 :
111         print "Bad version (%s), it is probably not radiotap header" % it_version
112         return
113     if it_len <= 0 :
114         print "Bad length on radiotap header"
115         return
116
117     radiotap = data[:it_len]
118     payload = data[it_len:]
119
120     format , padstr = "<" , ""
121     fields = []
122     for name,bit,fmt,pad in ratiotap_header_bits :
123 # What about  'it_present & ( 0x1 << bit )' ??
124         if it_present & pow(2,bit) == pow(2,bit) :
125             if not fmt :
126                 print "Unknown bit %s (%d) set" % ( name , bit )
127                 return
128             fields.append( name )
129             if fmt == "hh" :
130                 fields.append( "CHANNEL_BITMAP" )
131             if pad :
132                 padstr += "x"
133             format += fmt
134     values = struct.unpack(format+padstr,radiotap[8:])
135
136     flags = []
137     for name,value in radiotap_flags :
138         if values[1] & value == value :
139             flags.append( name )
140
141     channel = []
142     for name,value in channel_flags :
143         if values[4] & value == value :
144             channel.append( name )
145
146     pointer = 0
147     pcktlen = len(payload)
148
149     frame_ctl , duration_id = struct.unpack("<hh",payload[:4])
150     pointer += 4
151     pcktlen -= 4
152     for name,value in management_flags :
153         if frame_ctl == value :
154             type = name
155             break
156     else :
157         type = "unknown_%s" % frame_ctl
158
159     mac_str = "<BBBBBB"
160     mac_fmt = "%02X:%02X:%02X:%02X:%02X:%02X"
161
162     maclist = []
163     for i in range(4) :
164         maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
165         pointer += 6
166         pcktlen -= 6
167         if pcktlen < 6 :
168             unknowns = { 'unknown_212':12 , 'unknown_180':20 , 'unknown_196':12 , 'unknown_148':32 , 'unknown_4308':12 , 'unknown_4260':20 }
169             if type in unknowns.keys() :
170                 if len(payload) == unknowns[type] :
171                     break
172             raise Exception( "Unhandled type %s with length %d" % ( type , len(payload) ) )
173
174 #    print fields
175 #    print values
176 #    print "Radiotap flags : %s" % " ".join(flags)
177 #    print "Channel %d (%s)" % ( values[3] , " ".join(channel) )
178 ##    print "Control info",frame_ctl,duration_id
179 #    print type,":",maclist,"->",pcktlen
180 #    print
181
182     print "%20s %4d %5d" % (type,values[3],len(payload)),":"+" %s"*len(maclist) % tuple(maclist)
183     global tstamp,max_time,discovered
184     for mac in maclist :
185         if not type.startswith( "unknown_" ) and not mac in discovered :
186             if mac.startswith( "00:" ) :
187                 tstamp = time.time()
188                 discovered.append( mac )
189     if time.time()-tstamp > max_time :
190         fd = open( "discovered.list" , "a" )
191         for mac in discovered :
192             fd.write( "%s\n" % mac )
193         fd.close()
194         raise Exception( "Neighborhoud scan completed" )
195
196
197 packet_limit = -1 # infinite
198 pc.loop( packet_limit , dealWithPacket )
199