feat: associate recon clients with confirmed networks
This commit is contained in:
@@ -1341,17 +1341,79 @@ def recon_scan_data(scan_id, _timeout=20, _limit=None, db=None):
|
||||
'encryption': decode_encryption(r.get('encryption')),
|
||||
'band': band_of(r.get('freq')),
|
||||
'vendor': oui_vendor(fmt_mac(r.get('bssid'))),
|
||||
'device_identity': oui_identity(fmt_mac(r.get('bssid'))),
|
||||
'first_seen': lo,
|
||||
'last_seen': hi})
|
||||
aps.sort(key=lambda row: row['signal'] if row['signal'] is not None else 0)
|
||||
devices = [r for r in rows if r.get('kind') == 'device']
|
||||
mac_of = {r['row_id']: fmt_mac(r.get('mac')) for r in devices}
|
||||
ssid_of = {}
|
||||
for r in (row for row in rows if row.get('kind') == 'ap'):
|
||||
bssid = _norm_mac(r.get('bssid'))
|
||||
if bssid and bssid not in ssid_of:
|
||||
ssid_of[bssid] = decode_ssid(r.get('ssid'))
|
||||
|
||||
evidence = {}
|
||||
def add_association(client_mac, ssid, bssid=None, source=None, **timestamps):
|
||||
client_mac = _norm_mac(client_mac)
|
||||
bssid = _norm_mac(bssid) if bssid else None
|
||||
ssid = decode_ssid(ssid)
|
||||
if not client_mac or not ssid or not source:
|
||||
return
|
||||
key = (client_mac, bssid, ssid)
|
||||
association = evidence.get(key)
|
||||
if association is None:
|
||||
association = {'ssid': ssid, 'sources': []}
|
||||
if bssid:
|
||||
association['bssid'] = bssid
|
||||
evidence[key] = association
|
||||
if source not in association['sources']:
|
||||
association['sources'].append(source)
|
||||
for name, value in timestamps.items():
|
||||
if value is not None:
|
||||
association[name] = value
|
||||
|
||||
for r in (row for row in rows if row.get('kind') == 'handshake'):
|
||||
client = mac_of.get(r.get('stahash'))
|
||||
bssid = mac_of.get(r.get('aphash'))
|
||||
add_association(client, ssid_of.get(_norm_mac(bssid)), bssid, 'handshake')
|
||||
try:
|
||||
hostap_rows = _db_rows(
|
||||
db, 'SELECT mac, ssid, connected_time, disconnected_time '
|
||||
'FROM hostap_client WHERE scan = %d ORDER BY connected_time, id' % scan_id,
|
||||
timeout=_timeout)
|
||||
except Exception:
|
||||
hostap_rows = []
|
||||
for r in hostap_rows:
|
||||
add_association(r.get('mac'), r.get('ssid'), source='hostap_client',
|
||||
connected_time=r.get('connected_time'),
|
||||
disconnected_time=r.get('disconnected_time'))
|
||||
|
||||
associations_by_client = {}
|
||||
for key, association in evidence.items():
|
||||
associations_by_client.setdefault(key[0], []).append(association)
|
||||
for ap in aps:
|
||||
ap['clients'] = []
|
||||
ap['client_count'] = 0
|
||||
ap_by_bssid = {_norm_mac(ap['bssid']): ap for ap in aps}
|
||||
clients = []
|
||||
for r in sorted(devices, key=lambda row: row.get('time') or 0):
|
||||
if (r.get('mac') or '').strip().upper() in ap_macs:
|
||||
continue
|
||||
clients.append({'mac': fmt_mac(r.get('mac')), 'signal': r.get('signal'),
|
||||
'freq': r.get('freq'), 'packets': r.get('packets')})
|
||||
mac_of = {r['row_id']: fmt_mac(r.get('mac')) for r in devices}
|
||||
mac = _norm_mac(r.get('mac'))
|
||||
client_associations = associations_by_client.get(mac, [])
|
||||
client = {'mac': fmt_mac(r.get('mac')), 'signal': r.get('signal'),
|
||||
'freq': r.get('freq'), 'packets': r.get('packets'),
|
||||
'vendor': oui_identity(fmt_mac(r.get('mac'))),
|
||||
'associations': client_associations}
|
||||
clients.append(client)
|
||||
for association in client_associations:
|
||||
ap = ap_by_bssid.get(_norm_mac(association.get('bssid')))
|
||||
if ap is None:
|
||||
continue
|
||||
if not any(item['mac'] == client['mac'] for item in ap['clients']):
|
||||
ap['clients'].append(client)
|
||||
ap['client_count'] += 1
|
||||
handshakes = []
|
||||
for r in (row for row in rows if row.get('kind') == 'handshake'):
|
||||
handshakes.append({'ap': mac_of.get(r.get('aphash'), '--'),
|
||||
|
||||
Reference in New Issue
Block a user