MCPcopy Create free account
hub / github.com/PierreGode/Ragnar / do_locate_port

Function do_locate_port

network_diagnostics.py:1334–1378  ·  view source on GitHub ↗

Physically locate which switch port this device is plugged into by flapping the link in a timed pattern (link LED blinks). Managed switches already report the port via LLDP/CDP (Switch Discovery) -- this is the fallback for unmanaged switches. Runs in the background and returns at once.

(interface, count=6, on_ms=800, off_ms=800, force=False)

Source from the content-addressed store, hash-verified

1332 for e in hi_events[-8:]:
1333 reasons.append(f"IP {e['ip']} changed MAC {e['old_mac']} → {e['new_mac']} "
1334 f"({_fmt_ago(now - e['ts'])}) — possible spoof/clone in the past")
1335
1336 # (4) Randomization inventory (aggregate, not per-MAC).
1337 randomized = [c for c in current if c['klass'] == 'randomized']
1338 virtual = [c for c in current if c['klass'] == 'virtual_laa']
1339 with _mac_watch_lock:
1340 macs_store = (_mac_watch_load().get('macs') or {})
1341 ephemeral = 0
1342 for mac, rec in macs_store.items():
1343 if rec.get('klass') != 'randomized':
1344 continue
1345 life = rec.get('last', 0) - rec.get('first', 0)
1346 if 0 <= life < _MAC_EPHEMERAL_S and rec.get('count', 0) >= 1:
1347 ephemeral += 1
1348 randomization = {
1349 'count': len(randomized),
1350 'ephemeral': ephemeral,
1351 'virtual': len(virtual),
1352 'macs': [c['mac'] for c in randomized],
1353 'virtual_macs': [{'mac': c['mac'], 'vendor': c['vendor']} for c in virtual],
1354 }
1355 if randomized:
1356 note = (f"{len(randomized)} randomized (privacy) MAC(s) on the segment"
1357 + (f", {ephemeral} short-lived (active rotation)" if ephemeral else ""))
1358 reasons.append(note)
1359
1360 # (5) Tracking — an IP that cycled through >=2 randomized MACs is one device
1361 # rotating to hide. Group its randomized addresses into a followable track.
1362 tracks = []
1363 with _mac_watch_lock:
1364 ip_hist = (_mac_watch_load().get('ip_history') or {})
1365 for ip, hist in ip_hist.items():
1366 rand_macs, first, last = [], None, None
1367 for h in hist:
1368 if _classify_mac(h['mac'])['klass'] == 'randomized':
1369 rand_macs.append(h['mac'])
1370 first = h['first'] if first is None else min(first, h['first'])
1371 last = h['last'] if last is None else max(last, h['last'])
1372 uniq = sorted(set(rand_macs))
1373 if len(uniq) >= 2 and last and now - last <= _MAC_WATCH_WINDOW_S:
1374 tracks.append({'ip': ip, 'macs': uniq, 'changes': len(uniq) - 1,
1375 'first': first, 'last': last,
1376 'span': _fmt_ago(now - first) if first else None})
1377 tracks.sort(key=lambda t: len(t['macs']), reverse=True)
1378 for t in tracks[:6]:
1379 reasons.append(f"device at {t['ip']} rotated through {len(t['macs'])} "
1380 f"randomized MACs — tracked across its address changes")
1381

Callers 1

net_locate_portFunction · 0.85

Calls 5

do_interfacesFunction · 0.85
_clamp_intFunction · 0.85
_default_route_ifaceFunction · 0.85
getMethod · 0.45
startMethod · 0.45

Tested by

no test coverage detected