def latest(): '''returns latest probe requests''' format = request.args.get('format') if format is None: format = 'text' cur = get_db().cursor() # to store temp table and indices in memory sql = 'pragma temp_store = 2;' cur.execute(sql) sql = '''select date, mac.address, vendor.name, ssid.name, rssi from probemon inner join mac on probemon.mac=mac.id inner join ssid on probemon.ssid=ssid.id inner join vendor on mac.vendor=vendor.id order by date desc limit 100''' sql_args = None try: cur.execute(sql) except sqlite3.OperationalError as e: return jsonify({ 'status': 'error', 'message': 'sqlite3 db is not accessible' }), 500 # extract data from db text = '' for t, mac, vs, ssid, rssi in cur.fetchall(): t = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(t)) d = (t, int(rssi), ssid) if is_local_bit_set(mac): mac += ' (LAA)' text += f'{t}\t{mac}\t{int(rssi)}\t{vs}\n' resp = make_response('\n'.join(reversed(text.strip().split('\n')))) resp.headers['Content-Type'] = 'text/plain' return resp
def stats(): '''returns stats for given macs between timestamp''' after = request.args.get('after') if after is not None: try: after = time.mktime(time.strptime(after, '%Y-%m-%dT%H:%M:%S')) except ValueError as v: raise InvalidUsage('Invalid after parameter') before = request.args.get('before') if before is not None: try: before = time.mktime(time.strptime(before, '%Y-%m-%dT%H:%M:%S')) except ValueError as v: raise InvalidUsage('Invalid before parameter') macs = request.args.getlist('macs') rssi, zero, day = None, False, False cur = get_db().cursor() # to store temp table and indices in memory sql = 'pragma temp_store = 2;' cur.execute(sql) sql, sql_args = build_sql_query(after, before, macs, rssi, zero, day) try: cur.execute(sql, sql_args) except sqlite3.OperationalError as e: return jsonify({ 'status': 'error', 'message': 'sqlite3 db is not accessible' }), 500 # gather stats about each mac, same code as in stats.py # TODO: just import that macs = {} for row in cur.fetchall(): mac = row[1] if is_local_bit_set(mac): # create virtual mac for LAA mac address mac = 'LAA' if mac not in macs: macs[mac] = { 'vendor': row[2], 'ssid': [], 'rssi': [], 'last': row[0], 'first': row[0] } d = macs[mac] if row[3] != '' and row[3] not in d['ssid']: d['ssid'].append(row[3]) if row[0] > d['last']: d['last'] = row[0] if row[0] < d['first']: d['first'] = row[0] if row[4] != 0: d['rssi'].append(row[4]) # sort on frequency of appearence of a mac tmp = [(k, len(v['rssi'])) for k, v in macs.items()] tmp = [m for m, _ in reversed(sorted(tmp, key=lambda k: k[1]))] data = [] # dump our stats for m in tmp: v = macs[m] first = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(v['first'])) last = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(v['last'])) t = { 'mac': m, 'vendor': v['vendor'], 'ssids': sorted(v['ssid']), 'first': first, 'last': last } rssi = v['rssi'] if rssi != []: t.update({ 'rssi': { 'count': len(rssi), 'min': min(rssi), 'max': max(rssi), 'avg': sum(rssi) / len(rssi), 'median': int(median(rssi)) } }) data.append(t) return jsonify(data)
def probes(): '''returns list of probe requests for given macs between timestamps''' after = request.args.get('after') if after is not None: try: after = time.mktime(time.strptime(after, '%Y-%m-%dT%H:%M:%S')) except ValueError as v: raise InvalidUsage('Invalid after parameter') before = request.args.get('before') if before is not None: try: before = time.mktime(time.strptime(before, '%Y-%m-%dT%H:%M:%S')) except ValueError as v: raise InvalidUsage('Invalid before parameter') rssi = request.args.get('rssi') if rssi is not None: try: rssi = int(rssi) except ValueError as v: raise InvalidUsage('Invalid rssi value') macs = request.args.get('macs') zero = request.args.get('zero') today = request.args.get('today') output = request.args.get('output', default='json') cur = get_db().cursor() # to store temp table and indices in memory sql = 'pragma temp_store = 2;' cur.execute(sql) now = time.time() sql, sql_args = build_sql_query(after, before, macs, rssi, zero, today) try: cur.execute(sql, sql_args) except sqlite3.OperationalError as e: return jsonify({ 'status': 'error', 'message': 'sqlite3 db is not accessible' }), 500 vendor = {} ts = {} if after is not None: starting_ts = int(after * 1000) elif today: starting_ts = int((now - 24 * 60 * 60) * 1000) else: sql = 'select date from probemon order by date limit 1;' c.execute(sql) starting_ts = int(c.fetchone()[0] * 1000) # extract data from db for t, mac, vs, ssid, rssi in cur.fetchall(): #t = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(t)) d = (int(t * 1000 - starting_ts), int(rssi), ssid) if is_local_bit_set(mac): mac = 'LAA' if mac not in ts.keys(): ts[mac] = [d] vendor[mac] = vs else: ts[mac].append(d) data = [] # recollection for m in ts.keys(): if m == 'LAA' or m.startswith(config['merged']): continue # will deal with them later known = m in config['knownmac'] ssids = list(set(f[2] for f in ts[m])) t = { 'mac': m, 'known': known, 'vendor': vendor[m], 'ssids': ssids, 'starting_ts': starting_ts, 'probereq': [{ 'ts': f[0], 'rssi': f[1], 'ssid': ssids.index(f[2]) } for f in ts[m]] } if len(t['probereq']) > 3: data.append(t) data.sort(key=lambda x: len(x['probereq']), reverse=True) # LAA if 'LAA' in ts.keys(): ssids = list(set(f[2] for f in ts['LAA'])) t = { 'mac': 'LAA', 'vendor': u'UNKNOWN', 'ssids': ssids, 'starting_ts': starting_ts, 'probereq': [{ 'ts': f[0], 'rssi': f[1], 'ssid': ssids.index(f[2]) } for f in ts['LAA']] } data.append(t) # MERGED for m in config['merged']: mm = [ma for ma in ts.keys() if ma.startswith(m)] p = [] for n in mm: p.extend(ts[n]) ssids = list(set(f[2] for f in p)) if len(p) == 0: continue p.sort(key=lambda x: x[0]) t = { 'mac': m, 'vendor': u'UNKNOWN', 'ssids': ssids, 'starting_ts': starting_ts, 'probereq': [{ 'ts': f[0], 'rssi': f[1], 'ssid': ssids.index(f[2]) } for f in p] } data.append(t) if output == 'json': resp = make_response(jsonify(data)) elif output == 'protobuf': res = probe_pb2.MyData() for t in data: p = res.probes.add() p.mac = t['mac'] p.vendor = t['vendor'] p.starting_ts = t['starting_ts'] for s in t['ssids']: sl = p.ssids.add() sl.name = s try: p.known = t['known'] except KeyError as k: p.known = False for f in t['probereq']: pr = p.probereq.add() pr.timestamp = f['ts'] pr.rssi = f['rssi'] pr.ssid = f['ssid'] resp = make_response(res.SerializeToString()) resp.headers['Content-Type'] = 'application/x-protobuf' if not today: resp.headers['Cache-Control'] = 'max-age=21600' return resp
def probes(): '''returns list of probe requests for given macs between timestamps''' after = request.args.get('after') if after is not None: try: after = time.mktime(time.strptime(after, '%Y-%m-%dT%H:%M:%S')) except ValueError as v: raise InvalidUsage('Invalid after parameter') before = request.args.get('before') if before is not None: try: before = time.mktime(time.strptime(before, '%Y-%m-%dT%H:%M:%S')) except ValueError as v: raise InvalidUsage('Invalid before parameter') rssi = request.args.get('rssi') if rssi is not None: try: rssi = int(rssi) except ValueError as v: raise InvalidUsage('Invalid rssi value') macs = request.args.get('macs') zero = request.args.get('zero') today = request.args.get('today') cur = get_db().cursor() # to store temp table and indices in memory sql = 'pragma temp_store = 2;' cur.execute(sql) sql, sql_args = build_sql_query(after, before, macs, rssi, zero, today) try: cur.execute(sql, sql_args) except sqlite3.OperationalError as e: return jsonify({ 'status': 'error', 'message': 'sqlite3 db is not accessible' }), 500 vendor = {} ts = {} # extract data from db for t, mac, vs, ssid, rssi in cur.fetchall(): #t = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(t)) d = (t, int(rssi), ssid) if is_local_bit_set(mac): mac = 'LAA' if mac not in ts.keys(): ts[mac] = [d] vendor[mac] = vs else: ts[mac].append(d) data = [] # recollection for m in ts.keys(): if m == 'LAA' or m.startswith(config.MERGED): continue # will deal with them later known = m in config.KNOWNMAC ssids = list(set(f[2] for f in ts[m])) t = { 'mac': m, 'known': known, 'vendor': vendor[m], 'ssids': ssids, 'probereq': [{ 'ts': int(f[0] * 1000), 'rssi': f[1], 'ssid': ssids.index(f[2]) } for f in ts[m]] } if len(t['probereq']) > 3: data.append(t) data.sort(key=lambda x: len(x['probereq']), reverse=True) # LAA if 'LAA' in ts.keys(): ssids = list(set(f[2] for f in ts['LAA'])) t = { 'mac': 'LAA', 'vendor': u'UNKNOWN', 'ssids': ssids, 'probereq': [{ 'ts': int(f[0] * 1000), 'rssi': f[1], 'ssid': ssids.index(f[2]) } for f in ts['LAA']] } data.append(t) # MERGED for m in config.MERGED: mm = [ma for ma in ts.keys() if ma.startswith(m)] p = [] for n in mm: p.extend(ts[n]) ssids = list(set(f[2] for f in p)) if len(p) == 0: continue p.sort(key=lambda x: x[0]) t = { 'mac': m, 'vendor': u'UNKNOWN', 'ssids': ssids, 'probereq': [{ 'ts': int(f[0] * 1000), 'rssi': f[1], 'ssid': ssids.index(f[2]) } for f in p] } data.append(t) resp = make_response(jsonify(data)) if not today: resp.headers['Cache-Control'] = 'max-age=21600' return resp @app.errorhandler(InvalidUsage) def handle_invalid_usage(error): response = jsonify(error.to_dict()) response.status_code = error.status_code return response