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