From e15e077be8f4b4057b2cda11e850b9bd10f3c769 Mon Sep 17 00:00:00 2001 From: Cobra Date: Tue, 7 Apr 2026 12:48:56 -0400 Subject: [PATCH] Skip MAC rotation on active WiFi interfaces to prevent ENETDOWN When wlan0 is the primary data interface (WiFi-only deployment), changing its MAC via SIOCSIFHWADDR drops the AP association and puts all AF_PACKET sockets into ENETDOWN permanently until wpa_supplicant re-associates. - _apply_profile: skip set_mac if _eth_iface is a WiFi interface - _apply_profile: skip WiFi set_mac if _wifi_iface == _eth_iface (same card) - stop: mirror the same skip logic for MAC restoration DHCP hostname + TCP stack tuning still applied for blending on WiFi-only nodes. --- modules/stealth/mac_manager.py | 39 +++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/modules/stealth/mac_manager.py b/modules/stealth/mac_manager.py index dd61ada..8a2240a 100644 --- a/modules/stealth/mac_manager.py +++ b/modules/stealth/mac_manager.py @@ -117,11 +117,15 @@ class MacManager(BaseModule): if not self._running: return - # Restore original MACs on clean exit + # Restore original MACs on clean exit — skip WiFi interfaces to avoid + # dropping the active association. + wifi_ifaces = set(get_wifi_interfaces()) try: - if self._eth_iface and self._original_eth_mac: + if self._eth_iface and self._original_eth_mac and self._eth_iface not in wifi_ifaces: set_mac(self._eth_iface, self._original_eth_mac) - if self._wifi_iface and self._original_wifi_mac: + if (self._wifi_iface and self._original_wifi_mac + and self._wifi_iface != self._eth_iface + and self._wifi_iface not in wifi_ifaces): set_mac(self._wifi_iface, self._original_wifi_mac) except Exception as exc: logger.warning("Failed to restore original MAC: %s", exc) @@ -258,16 +262,27 @@ class MacManager(BaseModule): new_mac = f"{oui}:{suffix}" profile["applied_mac"] = new_mac - # Set MAC on Ethernet - if self._eth_iface: - try: - set_mac(self._eth_iface, new_mac) - logger.debug("Set %s MAC to %s", self._eth_iface, new_mac) - except Exception as exc: - logger.error("Failed to set MAC on %s: %s", self._eth_iface, exc) + wifi_ifaces = set(get_wifi_interfaces()) - # Set MAC on WiFi (different suffix for uniqueness) - if self._wifi_iface: + # Set MAC on Ethernet — skip if it's also a WiFi interface (changing MAC + # on an associated WiFi interface drops the connection and causes ENETDOWN + # on all AF_PACKET sockets bound to it). + if self._eth_iface: + if self._eth_iface in wifi_ifaces: + logger.info( + "Skipping MAC change on %s — active WiFi interface, would break association", + self._eth_iface, + ) + else: + try: + set_mac(self._eth_iface, new_mac) + logger.debug("Set %s MAC to %s", self._eth_iface, new_mac) + except Exception as exc: + logger.error("Failed to set MAC on %s: %s", self._eth_iface, exc) + + # Set MAC on WiFi only if it's a separate interface from the primary eth + # (e.g., a dedicated monitor card). Same interface = already handled above. + if self._wifi_iface and self._wifi_iface != self._eth_iface: wifi_suffix = ":".join(f"{random.randint(0, 255):02x}" for _ in range(3)) wifi_mac = f"{oui}:{wifi_suffix}" try: