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.
This commit is contained in:
@@ -117,11 +117,15 @@ class MacManager(BaseModule):
|
|||||||
if not self._running:
|
if not self._running:
|
||||||
return
|
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:
|
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)
|
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)
|
set_mac(self._wifi_iface, self._original_wifi_mac)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("Failed to restore original MAC: %s", exc)
|
logger.warning("Failed to restore original MAC: %s", exc)
|
||||||
@@ -258,16 +262,27 @@ class MacManager(BaseModule):
|
|||||||
new_mac = f"{oui}:{suffix}"
|
new_mac = f"{oui}:{suffix}"
|
||||||
profile["applied_mac"] = new_mac
|
profile["applied_mac"] = new_mac
|
||||||
|
|
||||||
# Set MAC on Ethernet
|
wifi_ifaces = set(get_wifi_interfaces())
|
||||||
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)
|
|
||||||
|
|
||||||
# Set MAC on WiFi (different suffix for uniqueness)
|
# Set MAC on Ethernet — skip if it's also a WiFi interface (changing MAC
|
||||||
if self._wifi_iface:
|
# 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_suffix = ":".join(f"{random.randint(0, 255):02x}" for _ in range(3))
|
||||||
wifi_mac = f"{oui}:{wifi_suffix}"
|
wifi_mac = f"{oui}:{wifi_suffix}"
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user