source: src/django_gheat/gheat/dataimport/netstumbler.py@ 9640

Last change on this file since 9640 was 9640, checked in by rick, 13 years ago

Cast the import logic to a special place, cause we are going to need it soon
when we want to auto-import files from the WEB (admin interface or form).

  • Property svn:executable set to *
File size: 4.3 KB
Line 
1#!/usr/bin/env python
2#
3# Reading NS1 files - http://www.stumbler.net/ns1files.html
4#
5# Rick van der Zwet <info@rickvanderzwet.nl>
6#
7import datetime
8from struct import unpack
9
10from collections import defaultdict
11import logging
12
13logger = logging.getLogger(__name__)
14
15def parse_ns1(fh):
16 def get_int32(size=1):
17 v = unpack('<' + 'i'*size,fh.read(4*size))
18 return v[0] if size == 1 else v
19
20 def get_uint32(size=1):
21 v = unpack('<' + 'I'*size,fh.read(4*size))
22 return v[0] if size == 1 else v
23
24 def get_uint64(size=1):
25 v = unpack('<' + 'Q'*size,fh.read(8*size))
26 return v[0] if size == 1 else v
27
28 def get_uint8(size=1):
29 v = unpack('<' + 'B'*size,fh.read(1*size))
30 return v[0] if size == 1 else v
31
32 def get_filetime():
33 _FILETIME_null_date = datetime.datetime(1601, 1, 1, 0, 0, 0)
34 ns = unpack('<Q',fh.read(8))[0] * 10
35 sec = ns / 10**8
36 d = datetime.timedelta(seconds=sec)
37 return _FILETIME_null_date + d
38
39 def get_char(size):
40 return fh.read(size)
41
42 def get_double(size=1):
43 v = unpack('<' + 'd'*size,fh.read(8*size))
44 return v[0] if size == 1 else v
45
46 def get_mac():
47 return ':'.join(["%02X" % x for x in unpack('BBBBBB',fh.read(6))])
48
49 data = {}
50
51 data["dwSignature"] = get_char(4)
52 data["dwFileVerunpack"] = get_uint32()
53 ApCount = get_uint32()
54 data["ApCount"] = ApCount
55
56 data["aps"] = []
57 for a in range(0,ApCount):
58 ap = {}
59 SSIDLength = get_uint8()
60 ap["SSIDLength"] = SSIDLength
61 ap["SSID"] = get_char(SSIDLength)
62 ap["BSSID"] = get_mac()
63 ap["MaxSignal"] = get_int32()
64 ap["MinNoise"] = get_int32()
65 ap["MaxSNR"] = get_int32()
66 ap["Flags"] = get_uint32()
67 ap["BeaconInterval"] = get_uint32()
68 ap["FirstSeen"] = get_filetime()
69 ap["LastSeen"] = get_filetime()
70 ap["BestLat"] = get_double()
71 ap["BestLong"] = get_double()
72 DataCount = get_uint32()
73 ap["DataCount"] = DataCount
74 ap["measurements"] = []
75 for c in range(0,DataCount):
76 ms = {}
77 ms["Time"] = get_filetime()
78 ms["Signal"] = get_int32()
79 ms["Noice"] = get_int32()
80 LocationSource = get_int32()
81 ms["LocationSource"] = LocationSource
82 if LocationSource == 1:
83 ms["Latitude"] = get_double()
84 ms["Longitude"] = get_double()
85 ms["Altitude"] = get_double()
86 ms["NumStats"] = get_uint32()
87 ms["Speed"] = get_double()
88 ms["Track"] = get_double()
89 ms["MagVariation"] = get_double()
90 ms["Hdop"] = get_double()
91 ap["measurements"].append(ms)
92 NameLength = get_uint8()
93 ap["NameLength"] = NameLength
94 ap["Name"] = get_char(NameLength)
95 ap["Channels"] = get_uint64()
96 ap["LastChannel"] = get_uint32()
97 ap["IPAddress"] = get_uint32()
98 ap["MinSignal"] = get_int32()
99 ap["MaxSignal"] = get_int32()
100 ap["DataRate"] = get_uint32()
101 ap["IPSubnet"] = get_uint32()
102 ap["IPMask"] = get_uint32()
103 ap["ApFlags"] = get_uint32()
104 IELength = get_uint32()
105 ap["IELength"] = IELength
106 ap["InformationElements"] = get_uint8(IELength)
107 data["aps"].append(ap)
108 return data
109
110def process_ns1(fh, counters):
111 data = parse_ns1(fh)
112
113
114 # Temponary holders
115 meting_pool = defaultdict(list)
116 ap_pool = {}
117
118 for ap in data['aps']:
119 # XXX: How is encryption coded?
120 encryption = False
121 ap_pool[ap['BSSID']]= (ap['SSID'], encryption)
122 for point in ap["measurements"]:
123 counters['meting_total'] += 1
124 if point['LocationSource'] == 0:
125 logger.debug("No GPS Coordinates found for BSSID %s @ %s",
126 ap['BSSID'], point['Time'])
127 counters['meting_ignored'] += 1
128 continue
129 # We store all values found, avg or max will be done later on
130 key = (ap['BSSID'], point["Latitude"], point["Longitude"])
131
132 # Known measurement error
133 if point['Signal'] == -32767: continue
134
135 # XXX: Signal need properly be a relation of signal_dbm and noice_dbm
136 signaal= 100 + point['Signal']
137 if signaal > 100 or signaal < 0:
138 logger.warning("Signal %s is not valid entry for BSSID %s @ %s",
139 point['Signal'], ap['BSSID'], point['Time'])
140 continue
141 meting_pool[key].append(signaal)
142
143 return (counters, ap_pool, None, meting_pool)
144if __name__ == '__main__':
145 import sys
146 import pprint
147 pp = pprint.PrettyPrinter(indent=2)
148 pp.pprint(parse_ns1(open(sys.argv[1],'r')))
Note: See TracBrowser for help on using the repository browser.