Create a specific function for ratiotap parsing
[wifihood] / wifiscanner / 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 from ieee80211 import *
14
15 import time
16
17 max_time = 1
18 tstamp = time.time()
19 discovered = []
20
21 def parse_radiotap( radiotap , it_present ) :
22
23     fields = []
24     format , padstr = "<" , ""
25     for name,bit,fmt,pad in ratiotap_header_bits :
26 # What about  'it_present & ( 0x1 << bit )' ??
27         if it_present & pow(2,bit) == pow(2,bit) :
28             if not fmt :
29                 print "Unknown bit %s (%d) set" % ( name , bit )
30                 return
31             fields.append( name )
32             if fmt == "hh" :
33                 fields.append( "CHANNEL_BITMAP" )
34             format += fmt
35             if pad :
36                 padstr += "x"
37     values = struct.unpack(format+padstr,radiotap])
38
39     radio_hdr = {}
40     for i in range(len(fields)) :
41         radio_hdr[fields[i]] = values[i]
42
43     flags = []
44     for name,value in radiotap_flags :
45         if radio_hdr['FLAGS'] & value == value :
46             flags.append( name )
47     radio_hdr['_flags'] = flags
48     if radio_hdr['FLAGS'] != 16 and radio_hdr['FLAGS'] != 18 :
49         # 16 - FCS
50         # 18 - SHORTPRE , FCS
51         print 'WARNING : Unexpected flags : (%s) %s' % ( radio_hdr['FLAGS'] , " , ".join( flags ) )
52
53     channel = []
54     for name,value in channel_flags :
55         if radio_hdr['CHANNEL_BITMAP'] & value == value :
56             channel.append( name )
57     if radio_hdr['CHANNEL_BITMAP'] != 160 and radio_hdr['CHANNEL_BITMAP'] != 192 :
58         # 160 - CCK , 2GHZ
59         # 192 - OFDM , 2GHZ
60         print 'WARNING : Unexpected channel flags : (%s) %s' % ( radio_hdr['CHANNEL_BITMAP'] , " , ".join( channel ) )
61     radio_hdr['_channel_bitmap'] = channel
62
63     return radio_hdr
64
65
66 def dealWithPacket ( hdr , data ) :
67
68     if hdr.getlen() != hdr.getcaplen() :
69         print "Error in header : %d vs. %d" % ( hdr.getlen() , hdr.getcaplen() )
70         return
71     if len(data) != hdr.getlen() :
72         print "Data lenght does not match"
73         return
74
75     it_version , it_len , it_present = struct.unpack("<Bxhl",data[:8])
76     if it_version != 0 :
77         print "Bad version (%s), it is probably not radiotap header" % it_version
78         return
79     if it_len <= 0 :
80         print "Bad length on radiotap header"
81         return
82
83     radio_hdr = parse_radiotap( data[8:it_len] , it_present )
84     if not radio_hdr :
85         return
86
87     payload = data[it_len:]
88
89
90     pointer = 0
91     pcktlen = len(payload)
92
93     frame_ctl , frame_subtype , duration_id = struct.unpack("BBh",payload[:4])
94     pointer += 4
95     pcktlen -= 4
96
97     for name,value in frame_type :
98         if frame_ctl & 0x0c == value :
99             type = name
100             break
101     else :
102         print "Unknown frame type %s" % ( frame_ctl & 0x0c , )
103         return
104
105     if type == "MGT" :
106         for name,value in management_subtypes :
107             if frame_ctl & 0xf0 == value :
108                 subtype = name
109                 break
110         else :
111             print "Unknown MGT subtype %s" % ( frame_ctl & 0xf0 , )
112             return
113
114     elif type == "CTL" :
115         for name,value in control_subtypes :
116             if frame_ctl & 0xf0 == value :
117                 subtype = name
118                 break
119         else :
120             print "Unknown CTL subtype %s" % ( frame_ctl & 0xf0 , )
121             return
122
123     elif type == "DATA" :
124         _subtype = []
125         for name,value in data_subtypes :
126             if frame_ctl & 0xf0 == value :
127                 _subtype.append( name )
128         subtype = "-".join( _subtype )
129
130     for name,value in directions :
131         if frame_subtype & 0x03 == value :
132             direction = name
133             break
134     else :
135         print "Unknown direction %s" % ( frame_subtype & 0x03 , )
136         return
137
138
139     mac_str = "BBBBBB" # is leading '<' required
140     mac_fmt = "%02X:%02X:%02X:%02X:%02X:%02X"
141
142     maclist = []
143     for i in range(3) :
144         maclist.append( mac_fmt % struct.unpack( mac_str , payload[pointer:pointer+6] ) )
145         pointer += 6
146         pcktlen -= 6
147         # FIXME : only CTL/ACK have single address ???
148         # FIXME : Is this the same than pcktlen == 2
149         if pcktlen < 6 :
150             break
151
152     sequence = struct.unpack("BB",payload[pointer:pointer+2])
153     pointer += 2
154     pcktlen -= 2
155
156 #    print fields
157 #    print values
158 #    print "Radiotap flags : %s" % " ".join(flags)
159 #    print "Channel %d (%s)" % ( values[3] , " ".join(channel) )
160 ##    print "Control info",frame_ctl,frame_subtype,duration_id,"seq",sequence
161 #    print type,":",maclist,"->",pcktlen
162 #    print
163
164     global tstamp,max_time,discovered
165     for mac in maclist :
166         if not mac in discovered :
167             tstamp = time.time()
168             discovered.append( mac )
169     if time.time()-tstamp > max_time :
170         fd = open( "discovered.list" , "a" )
171         for mac in discovered :
172             fd.write( "%s\n" % mac )
173         fd.close()
174         raise Exception( "Neighborhoud scan completed" )
175
176     print "%4s %13s %6s %4d %4d from %4d" % (type,subtype,direction,values[3],pcktlen,len(payload))," ; %4d %4d "%sequence,":"+" %s"*len(maclist) % tuple(maclist)
177
178 packet_limit = -1 # infinite
179 pc.loop( packet_limit , dealWithPacket )
180