Bugfixes
[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
16 max_time = 15 * 60
17 tstamp = time.time()
18
19 logfile = open( "wifilogger.log" , "a" )
20
21 max_bytes = 1024
22 promiscuous = False
23 read_timeout = 100 # in milliseconds
24 pc = pcapy.open_live(iface, max_bytes, promiscuous, read_timeout)
25
26
27 channel_hop = [ 30.0 , False ]
28
29 def channel_change ( ) :
30     try :
31         wlan["channel"] = ( wlan["channel"] ) % 12 + 1
32     except pyiw.error, error:
33         print "PYIW error : %s" % error
34     else :
35         if channel_hop[0] :
36             channel_hop[1] = threading.Timer( channel_hop[0] , channel_change ) 
37             channel_hop[1].start()
38
39
40 def parse_radiotap( radiotap , it_present ) :
41
42     fields = []
43     rfmt , padstr = "<" , ""
44     for name,bit,fmt,pad in ratiotap_header_bits :
45         if it_present & ( 0x1 << bit ) :
46             if not fmt :
47                 print "ERROR : unknown bit %s (%d) set" % ( name , bit )
48                 return
49             fields.append( name )
50             if fmt == "hh" :
51                 fields.append( "CHANNEL_BITMAP" )
52             rfmt += fmt
53             if pad :
54                 padstr += "x"
55     values = struct.unpack(rfmt+padstr,radiotap)
56
57     radio_hdr = {}
58     for i in range(len(fields)) :
59         radio_hdr[fields[i]] = values[i]
60
61     flags = []
62     for name,value in radiotap_flags :
63         if radio_hdr['FLAGS'] & value == value :
64             flags.append( name )
65     if radio_hdr['FLAGS'] != 16 and radio_hdr['FLAGS'] != 18 :
66         # 16 - FCS
67         # 18 - SHORTPRE , FCS
68         print 'WARNING : Unexpected flags : (%s) %s' % ( radio_hdr['FLAGS'] , " , ".join( flags ) )
69     radio_hdr['_flags'] = flags
70
71     channel = []
72     for name,value in channel_flags :
73         if radio_hdr['CHANNEL_BITMAP'] & value == value :
74             channel.append( name )
75     if radio_hdr['CHANNEL_BITMAP'] != 160 and radio_hdr['CHANNEL_BITMAP'] != 192 :
76         # 160 - CCK , 2GHZ
77         # 192 - OFDM , 2GHZ
78         print 'WARNING : Unexpected channel flags : (%s) %s' % ( radio_hdr['CHANNEL_BITMAP'] , " , ".join( channel ) )
79     radio_hdr['_channel_bitmap'] = channel
80
81     return radio_hdr
82
83
84 class CaptureEnd ( Exception ) : pass
85
86
87 def dealWithPacket ( hdr , data ) :
88
89     if hdr.getlen() != hdr.getcaplen() :
90         print "ERROR : bad sizes in header : %d vs. %d" % ( hdr.getlen() , hdr.getcaplen() )
91         return
92     if len(data) != hdr.getlen() :
93         print "ERROR : Data lenght does not match"
94         return
95
96     it_version , it_len , it_present = struct.unpack("<Bxhl",data[:8])
97     if it_version != 0 :
98         print "ERROR : Bad version (%s), it is probably not radiotap header" % it_version
99         return
100     if it_len <= 0 :
101         print "ERROR : Bad length on radiotap header"
102         return
103     if it_len != 32 :
104         print "ERROR : Strange length on radiotap header"
105         return
106
107     radio_hdr = parse_radiotap( data[8:it_len] , it_present )
108     if not radio_hdr :
109         return
110
111
112     payload = data[it_len:]
113
114     pcktlen = len(payload)
115
116     frame_ctl , frame_ctl2 , duration_id = struct.unpack("BBh",payload[:4])
117     pointer  = 4
118     pcktlen -= 4
119
120
121     for name,value in frame_types :
122         if frame_ctl & 0x0c == value :
123             frame_type = name
124             break
125     else :
126         print "ERROR : unknown frame type %s" % ( frame_ctl & 0x0c , )
127         return
128
129     if frame_type == "MGT" :
130         for name,value in management_subtypes :
131             if frame_ctl & 0xf0 == value :
132                 frame_subtype = name
133                 break
134         else :
135             print "ERROR : unknown MGT subtype %s" % ( frame_ctl & 0xf0 , )
136             return
137
138     elif frame_type == "CTL" :
139         for name,value in control_subtypes :
140             if frame_ctl & 0xf0 == value :
141                 frame_subtype = name
142                 break
143         else :
144             if frame_ctl & 0xf0 == 144 :
145                 frame_subtype = "CF_END_ACK"
146             elif frame_ctl & 0xf0 == 128 :
147                 frame_subtype = "UNKNOWN_1"
148             else :
149                 print "ERROR : unknown CTL subtype %s" % ( frame_ctl & 0xf0 , )
150                 return
151
152     elif frame_type == "DATA" :
153         _subtype = []
154         for name,value in data_subtypes :
155             if frame_ctl & 0xf0 == value :
156                 _subtype.append( name )
157         frame_subtype = "-".join( _subtype )
158
159     else :
160         print "Handling of frame type %s not implemented" % frame_type
161         return
162
163
164     for name,value in directions : # Only for DATA frames ???
165         if frame_ctl2 & 0x03 == value :
166             direction = name
167             break
168     else :
169         print "ERROR : unknown direction %s" % ( frame_ctl2 & 0x03 , )
170         return
171
172
173     mac_str = "BBBBBB" # is leading '<' required
174     mac_fmt = "%02X:%02X:%02X:%02X:%02X:%02X"
175
176     maclist = []
177     for i in range(3) :
178         maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
179         pointer += 6
180         pcktlen -= 6
181         if pcktlen < 6 :
182             break
183
184
185     if frame_type != "CTL" :
186         sequence = struct.unpack("BB",payload[pointer:pointer+2])
187         pointer += 2
188         pcktlen -= 2
189     else :
190         sequence = ( -1 , -1 )
191
192
193     if frame_type == "DATA" and pcktlen > 6 :
194         maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
195         pointer += 6
196         pcktlen -= 6
197
198
199     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) )
200     logfile.write( " = %s %s " % ( radio_hdr['DBM_ANTSIGNAL'] , radio_hdr['DBM_ANTNOISE'] ) )
201     logfile.write( " ; %4d %4d " % sequence )
202     logfile.write( " - %4d :" % duration_id )
203     logfile.write( " %s"*len(maclist) % tuple(maclist) )
204     logfile.write( "\n" )
205
206     curtime = time.time()
207     if curtime - tstamp > max_time :
208         channel_hop[0] = 0
209         raise CaptureEnd( "Neighborhoud scan completed" )
210
211
212 if channel_hop[0]  :
213     channel_hop[1] = threading.Timer( channel_hop[0] , channel_change ) 
214     channel_hop[1].start()
215
216
217 packet_limit = -1 # infinite
218 try :
219     pc.loop( packet_limit , dealWithPacket )
220 except CaptureEnd , ex :
221     print "FINISED : %s" % ex
222 except Exception , ex :
223     channel_hop[0] = 0
224     print "ERROR : %s" % ex
225
226 logfile.close()
227