From a1d5892b6b3bb7d30bda847aa80531243100b9ed Mon Sep 17 00:00:00 2001 From: Cobra Date: Tue, 14 Apr 2026 22:45:15 -0400 Subject: [PATCH] Prevent churn suppression from silencing labeled personal devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phone (c6:37:b0:b2:07:30) was cycling through arrivals/departures faster than the 30-min churn window threshold, causing _check_churn to add its IP to infrastructure_ips. All subsequent on_arrival calls were silently dropped by the infrastructure IP check, so no ARRIVED alerts fired. Two fixes: - _check_churn: skip churn suppression entirely for MACs in device_labels or personal_devices — labeled devices are never infrastructure - on_arrival already-known path: upgrade ip from '0.0.0.0'/'unknown' (ARP probe placeholder) to real IP when netlink delivers the actual address --- net_alerter/net_alerter.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net_alerter/net_alerter.py b/net_alerter/net_alerter.py index f92eb43..a1222c2 100644 --- a/net_alerter/net_alerter.py +++ b/net_alerter/net_alerter.py @@ -412,6 +412,10 @@ def _clear_recovery(): def _check_churn(mac: str, ip: str) -> bool: """Return True and suppress if this device churns too frequently.""" + # Explicitly labeled personal devices are never churn-suppressed into infrastructure + with personal_lock: + if mac in device_labels or mac in personal_devices: + return False now = time.time() with _churn_lock: events = _churn_tracker.get(mac, []) @@ -1050,6 +1054,10 @@ def on_arrival(mac: str, ip: str, hostname: str = "") -> None: # Device is already known dev = known_devices[mac] dev['last_seen'] = now + # Upgrade from ARP-probe placeholder to real IP + if dev.get('ip') in ('0.0.0.0', 'unknown') and ip not in ('0.0.0.0', 'unknown'): + dev['ip'] = ip + logging.debug(f"Updated {mac} IP from placeholder to {ip}") # DHCP renewal dedup: if last_seen < 30 min, skip alert if now - dev['first_seen'] < 1800: # 30 min