First implementation for detected wifi cards database
[wifihood] / wifisniffer / wifilogger.py
1 #!/usr/bin/python
2
3 import pcapy
4 import struct
5
6 import pyiw
7 import threading
8
9 iface = 'wlan0'
10 wlan = pyiw.WirelessInterface(iface)
11
12 import time
13
14 from ieee80211 import *
15 from wificards import *
16
17 max_time = 15 * 60
18 tstamp = time.time()
19
20 logfile = open( "wifilogger.log" , "a" )
21
22 max_bytes = 1024
23 promiscuous = False
24 read_timeout = 100 # in milliseconds
25 pc = pcapy.open_live(iface, max_bytes, promiscuous, read_timeout)
26
27
28 fd = open( "discovered.list" )
29 for line in fd.readlines() :
30     items = line[:-1].split()
31     mac = items.pop(0)
32     discovered[ mac ] = card( mac )
33     discovered[mac].from_string( items )
34     if discovered[mac].tipo not in ( 'AP' , 'STA' , 'CELL' ) :
35         print "Unknwon type '%s' for %s" % ( discovered[mac].tipo , mac )
36 fd.close()
37
38
39 channel_hop = [ 30.0 , False ]
40
41 def channel_change ( ) :
42     try :
43         wlan["channel"] = ( wlan["channel"] ) % 12 + 1
44     except pyiw.error, error:
45         print "PYIW error : %s" % error
46     else :
47         if channel_hop[0] :
48             channel_hop[1] = threading.Timer( channel_hop[0] , channel_change ) 
49             channel_hop[1].start()
50
51
52 def parse_radiotap( radiotap , it_present ) :
53
54     fields = []
55     rfmt , padstr = "<" , ""
56     for name,bit,fmt,pad in ratiotap_header_bits :
57         if it_present & ( 0x1 << bit ) :
58             if not fmt :
59                 print "ERROR : unknown bit %s (%d) set" % ( name , bit )
60                 return
61             fields.append( name )
62             if fmt == "hh" :
63                 fields.append( "CHANNEL_BITMAP" )
64             rfmt += fmt
65             if pad :
66                 padstr += "x"
67     values = struct.unpack(rfmt+padstr,radiotap)
68
69     radio_hdr = {}
70     for i in range(len(fields)) :
71         radio_hdr[fields[i]] = values[i]
72
73     flags = []
74     for name,value in radiotap_flags :
75         if radio_hdr['FLAGS'] & value == value :
76             flags.append( name )
77     if radio_hdr['FLAGS'] != 16 and radio_hdr['FLAGS'] != 18 :
78         # 16 - FCS
79         # 18 - SHORTPRE , FCS
80         print 'WARNING : Unexpected flags : (%s) %s' % ( radio_hdr['FLAGS'] , " , ".join( flags ) )
81     radio_hdr['_flags'] = flags
82
83     channel = []
84     for name,value in channel_flags :
85         if radio_hdr['CHANNEL_BITMAP'] & value == value :
86             channel.append( name )
87     if radio_hdr['CHANNEL_BITMAP'] != 160 and radio_hdr['CHANNEL_BITMAP'] != 192 :
88         # 160 - CCK , 2GHZ
89         # 192 - OFDM , 2GHZ
90         print 'WARNING : Unexpected channel flags : (%s) %s' % ( radio_hdr['CHANNEL_BITMAP'] , " , ".join( channel ) )
91     radio_hdr['_channel_bitmap'] = channel
92
93     return radio_hdr
94
95
96 class CaptureEnd ( Exception ) : pass
97
98
99 def dealWithPacket ( hdr , data ) :
100
101     if hdr.getlen() != hdr.getcaplen() :
102         print "ERROR : bad sizes in header : %d vs. %d" % ( hdr.getlen() , hdr.getcaplen() )
103         return
104     if len(data) != hdr.getlen() :
105         print "ERROR : Data lenght does not match"
106         return
107
108     it_version , it_len , it_present = struct.unpack("<Bxhl",data[:8])
109     if it_version != 0 :
110         print "ERROR : Bad version (%s), it is probably not radiotap header" % it_version
111         return
112     if it_len <= 0 :
113         print "ERROR : Bad length on radiotap header"
114         return
115     if it_len != 32 :
116         print "ERROR : Strange length on radiotap header"
117         return
118
119     radio_hdr = parse_radiotap( data[8:it_len] , it_present )
120     if not radio_hdr :
121         return
122
123
124     payload = data[it_len:]
125
126     pcktlen = len(payload)
127
128     frame_ctl , frame_ctl2 , duration_id = struct.unpack("BBh",payload[:4])
129     pointer  = 4
130     pcktlen -= 4
131
132
133     for name,value in frame_types :
134         if frame_ctl & 0x0c == value :
135             frame_type = name
136             break
137     else :
138         print "ERROR : unknown frame type %s" % ( frame_ctl & 0x0c , )
139         return
140
141     if frame_type == "MGT" :
142         for name,value in management_subtypes :
143             if frame_ctl & 0xf0 == value :
144                 frame_subtype = name
145                 break
146         else :
147             print "ERROR : unknown MGT subtype %s" % ( frame_ctl & 0xf0 , )
148             return
149
150     elif frame_type == "CTL" :
151         for name,value in control_subtypes :
152             if frame_ctl & 0xf0 == value :
153                 frame_subtype = name
154                 break
155         else :
156             if frame_ctl & 0xf0 == 144 :
157                 frame_subtype = "CF_END_ACK"
158             elif frame_ctl & 0xf0 == 128 :
159                 frame_subtype = "UNKNOWN_1"
160             else :
161                 print "ERROR : unknown CTL subtype %s" % ( frame_ctl & 0xf0 , )
162                 return
163
164     elif frame_type == "DATA" :
165         _subtype = []
166         for name,value in data_subtypes :
167             if frame_ctl & 0xf0 == value :
168                 _subtype.append( name )
169         frame_subtype = "-".join( _subtype )
170
171     else :
172         print "Handling of frame type %s not implemented" % frame_type
173         return
174
175
176     for name,value in directions : # Only for DATA frames ???
177         if frame_ctl2 & 0x03 == value :
178             direction = name
179             break
180     else :
181         print "ERROR : unknown direction %s" % ( frame_ctl2 & 0x03 , )
182         return
183
184
185     mac_str = "BBBBBB" # is leading '<' required
186     mac_fmt = "%02X:%02X:%02X:%02X:%02X:%02X"
187
188     maclist = []
189     for i in range(3) :
190         maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
191         pointer += 6
192         pcktlen -= 6
193         if pcktlen < 6 :
194             break
195
196
197     if frame_type != "CTL" :
198         sequence = struct.unpack("BB",payload[pointer:pointer+2])
199         pointer += 2
200         pcktlen -= 2
201     else :
202         sequence = ( -1 , -1 )
203
204
205     if frame_type == "DATA" and pcktlen > 6 :
206         maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
207         pointer += 6
208         pcktlen -= 6
209
210
211     if frame_type == "MGT" : # addresses : dest orig BSSID
212         if len(maclist) != 3 :
213             print "ERROR : insuficientes macs (%d) en un MGT",len(maclist),pcktlen," %s"*len(maclist) % tuple(maclist)
214         else :
215             if frame_subtype == "BEACON" :
216                 if maclist[0] == "FF:FF:FF:FF:FF:FF" :
217                     add_full_card ( maclist[1] , 'AP' , frame_subtype , radio_hdr )
218                     discovered[ maclist[1] ].add_rssi( radio_hdr )
219                     if maclist[1] != maclist[2] :
220                         add_full_card ( maclist[2] , 'CELL' , frame_subtype , radio_hdr )
221                         if maclist[1] not in discovered[ maclist[2] ].sta :
222                             discovered[ maclist[2] ].add_sta( maclist[1] )
223                 else :
224                     print "ERROR : non broadcast BEACON : %s %s %s" % tuple(maclist)
225             elif frame_subtype == "PROBE_REQ" : # Pueden ser al broadcast o una "reasociacion ??
226                 if maclist[0] == maclist[2] :
227                     add_full_card ( maclist[1] , 'STA' , frame_subtype , radio_hdr )
228                     discovered[ maclist[1] ].add_rssi( radio_hdr )
229                     if maclist[0] != "FF:FF:FF:FF:FF:FF" :
230                         add_full_card ( maclist[0] , 'AP' , frame_subtype , radio_hdr )
231                         if maclist[1] not in discovered[ maclist[0] ].sta :
232                             discovered[ maclist[0] ].add_sta( maclist[1] )
233                 else :
234                     print "ERROR : broken PROBE_REQ : %s %s %s" % tuple(maclist)
235             else :
236                 print "WARNING : unhandled MGT subtype %s" % frame_subtype
237
238
239     logfile.write( "%4s %13s %6s %4d [ %2d %2d ] read %4d missing %4d" % (frame_type,frame_subtype,direction,radio_hdr['CHANNEL'],radio_hdr['FLAGS'],radio_hdr['CHANNEL_BITMAP'],pointer,pcktlen) )
240     logfile.write( " = %s %s " % ( radio_hdr['DBM_ANTSIGNAL'] , radio_hdr['DBM_ANTNOISE'] ) )
241     logfile.write( " ; %4d %4d " % sequence )
242     logfile.write( " - %4d :" % duration_id )
243     logfile.write( " %s"*len(maclist) % tuple(maclist) )
244     logfile.write( "\n" )
245
246     curtime = time.time()
247     if curtime - tstamp > max_time :
248         channel_hop[0] = 0
249         raise CaptureEnd( "Neighborhoud scan completed" )
250
251
252 if channel_hop[0]  :
253     channel_hop[1] = threading.Timer( channel_hop[0] , channel_change ) 
254     channel_hop[1].start()
255
256
257 packet_limit = -1 # infinite
258 try :
259     pc.loop( packet_limit , dealWithPacket )
260 except CaptureEnd , ex :
261     print "FINISED : %s" % ex
262 except Exception , ex :
263     channel_hop[0] = 0
264     print "ERROR : %s" % ex
265
266 logfile.close()
267
268 fd = open( "discovered.list" , "w" )
269 for mac in discovered.keys() :
270     fd.write( "%s\n" % discovered[mac] )
271 fd.close()
272