[9600] | 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 | #
|
---|
| 7 | import datetime
|
---|
[9618] | 8 | from struct import unpack
|
---|
[9600] | 9 |
|
---|
[9623] | 10 | from collections import defaultdict
|
---|
| 11 | import logging
|
---|
| 12 |
|
---|
| 13 | logger = logging.getLogger(__name__)
|
---|
| 14 |
|
---|
| 15 | def parse_ns1(fh):
|
---|
[9601] | 16 | def get_int32(size=1):
|
---|
[9602] | 17 | v = unpack('<' + 'i'*size,fh.read(4*size))
|
---|
| 18 | return v[0] if size == 1 else v
|
---|
[9601] | 19 |
|
---|
| 20 | def get_uint32(size=1):
|
---|
[9602] | 21 | v = unpack('<' + 'I'*size,fh.read(4*size))
|
---|
| 22 | return v[0] if size == 1 else v
|
---|
[9601] | 23 |
|
---|
| 24 | def get_uint64(size=1):
|
---|
[9602] | 25 | v = unpack('<' + 'Q'*size,fh.read(8*size))
|
---|
| 26 | return v[0] if size == 1 else v
|
---|
[9601] | 27 |
|
---|
| 28 | def get_uint8(size=1):
|
---|
[9602] | 29 | v = unpack('<' + 'B'*size,fh.read(1*size))
|
---|
| 30 | return v[0] if size == 1 else v
|
---|
[9601] | 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):
|
---|
[9602] | 43 | v = unpack('<' + 'd'*size,fh.read(8*size))
|
---|
| 44 | return v[0] if size == 1 else v
|
---|
[9601] | 45 |
|
---|
[9618] | 46 | def get_mac():
|
---|
| 47 | return ':'.join(["%02X" % x for x in unpack('BBBBBB',fh.read(6))])
|
---|
| 48 |
|
---|
[9601] | 49 | data = {}
|
---|
| 50 |
|
---|
| 51 | data["dwSignature"] = get_char(4)
|
---|
| 52 | data["dwFileVerunpack"] = get_uint32()
|
---|
[9602] | 53 | ApCount = get_uint32()
|
---|
[9601] | 54 | data["ApCount"] = ApCount
|
---|
| 55 |
|
---|
| 56 | data["aps"] = []
|
---|
| 57 | for a in range(0,ApCount):
|
---|
| 58 | ap = {}
|
---|
[9602] | 59 | SSIDLength = get_uint8()
|
---|
[9601] | 60 | ap["SSIDLength"] = SSIDLength
|
---|
| 61 | ap["SSID"] = get_char(SSIDLength)
|
---|
[9618] | 62 | ap["BSSID"] = get_mac()
|
---|
[9601] | 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()
|
---|
[9602] | 72 | DataCount = get_uint32()
|
---|
[9601] | 73 | ap["DataCount"] = DataCount
|
---|
[9618] | 74 | ap["measurements"] = []
|
---|
[9601] | 75 | for c in range(0,DataCount):
|
---|
| 76 | ms = {}
|
---|
| 77 | ms["Time"] = get_filetime()
|
---|
| 78 | ms["Signal"] = get_int32()
|
---|
| 79 | ms["Noice"] = get_int32()
|
---|
[9602] | 80 | LocationSource = get_int32()
|
---|
[9618] | 81 | ms["LocationSource"] = LocationSource
|
---|
[9601] | 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()
|
---|
[9618] | 91 | ap["measurements"].append(ms)
|
---|
[9602] | 92 | NameLength = get_uint8()
|
---|
[9601] | 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()
|
---|
[9602] | 104 | IELength = get_uint32()
|
---|
[9601] | 105 | ap["IELength"] = IELength
|
---|
| 106 | ap["InformationElements"] = get_uint8(IELength)
|
---|
| 107 | data["aps"].append(ap)
|
---|
| 108 | return data
|
---|
[9600] | 109 |
|
---|
[9623] | 110 | def 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)
|
---|
[9618] | 144 | if __name__ == '__main__':
|
---|
| 145 | import sys
|
---|
| 146 | import pprint
|
---|
| 147 | pp = pprint.PrettyPrinter(indent=2)
|
---|
[9623] | 148 | pp.pprint(parse_ns1(open(sys.argv[1],'r')))
|
---|