Catch dhcp setup permission errors sooner (#47639)

This solves an unexpected thread exception on macs when running as
a user intead of root
This commit is contained in:
J. Nick Koston 2021-03-08 13:15:22 -10:00 committed by GitHub
parent 10eca5b986
commit 1dd35ff059
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 14 additions and 14 deletions

View File

@ -207,8 +207,11 @@ class DHCPWatcher(WatcherBase):
async def async_start(self): async def async_start(self):
"""Start watching for dhcp packets.""" """Start watching for dhcp packets."""
# disable scapy promiscuous mode as we do not need it
conf.sniff_promisc = 0
try: try:
_verify_l2socket_creation_permission() await self.hass.async_add_executor_job(_verify_l2socket_setup, FILTER)
except (Scapy_Exception, OSError) as ex: except (Scapy_Exception, OSError) as ex:
if os.geteuid() == 0: if os.geteuid() == 0:
_LOGGER.error("Cannot watch for dhcp packets: %s", ex) _LOGGER.error("Cannot watch for dhcp packets: %s", ex)
@ -219,7 +222,7 @@ class DHCPWatcher(WatcherBase):
return return
try: try:
await _async_verify_working_pcap(self.hass, FILTER) await self.hass.async_add_executor_job(_verify_working_pcap, FILTER)
except (Scapy_Exception, ImportError) as ex: except (Scapy_Exception, ImportError) as ex:
_LOGGER.error( _LOGGER.error(
"Cannot watch for dhcp packets without a functional packet filter: %s", "Cannot watch for dhcp packets without a functional packet filter: %s",
@ -233,6 +236,7 @@ class DHCPWatcher(WatcherBase):
prn=self.handle_dhcp_packet, prn=self.handle_dhcp_packet,
store=0, store=0,
) )
self._sniffer.start() self._sniffer.start()
def handle_dhcp_packet(self, packet): def handle_dhcp_packet(self, packet):
@ -283,7 +287,7 @@ def _format_mac(mac_address):
return format_mac(mac_address).replace(":", "") return format_mac(mac_address).replace(":", "")
def _verify_l2socket_creation_permission(): def _verify_l2socket_setup(cap_filter):
"""Create a socket using the scapy configured l2socket. """Create a socket using the scapy configured l2socket.
Try to create the socket Try to create the socket
@ -292,15 +296,13 @@ def _verify_l2socket_creation_permission():
thread so we will not be able to capture thread so we will not be able to capture
any permission or bind errors. any permission or bind errors.
""" """
# disable scapy promiscuous mode as we do not need it conf.L2socket(filter=cap_filter)
conf.sniff_promisc = 0
conf.L2socket()
async def _async_verify_working_pcap(hass, cap_filter): def _verify_working_pcap(cap_filter):
"""Verify we can create a packet filter. """Verify we can create a packet filter.
If we cannot create a filter we will be listening for If we cannot create a filter we will be listening for
all traffic which is too intensive. all traffic which is too intensive.
""" """
await hass.async_add_executor_job(compile_filter, cap_filter) compile_filter(cap_filter)

View File

@ -281,7 +281,7 @@ async def test_setup_and_stop(hass):
await hass.async_block_till_done() await hass.async_block_till_done()
with patch("homeassistant.components.dhcp.AsyncSniffer.start") as start_call, patch( with patch("homeassistant.components.dhcp.AsyncSniffer.start") as start_call, patch(
"homeassistant.components.dhcp._verify_l2socket_creation_permission", "homeassistant.components.dhcp._verify_l2socket_setup",
), patch( ), patch(
"homeassistant.components.dhcp.compile_filter", "homeassistant.components.dhcp.compile_filter",
): ):
@ -307,7 +307,7 @@ async def test_setup_fails_as_root(hass, caplog):
wait_event = threading.Event() wait_event = threading.Event()
with patch("os.geteuid", return_value=0), patch( with patch("os.geteuid", return_value=0), patch(
"homeassistant.components.dhcp._verify_l2socket_creation_permission", "homeassistant.components.dhcp._verify_l2socket_setup",
side_effect=Scapy_Exception, side_effect=Scapy_Exception,
): ):
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
@ -330,7 +330,7 @@ async def test_setup_fails_non_root(hass, caplog):
await hass.async_block_till_done() await hass.async_block_till_done()
with patch("os.geteuid", return_value=10), patch( with patch("os.geteuid", return_value=10), patch(
"homeassistant.components.dhcp._verify_l2socket_creation_permission", "homeassistant.components.dhcp._verify_l2socket_setup",
side_effect=Scapy_Exception, side_effect=Scapy_Exception,
): ):
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
@ -351,9 +351,7 @@ async def test_setup_fails_with_broken_libpcap(hass, caplog):
) )
await hass.async_block_till_done() await hass.async_block_till_done()
with patch( with patch("homeassistant.components.dhcp._verify_l2socket_setup",), patch(
"homeassistant.components.dhcp._verify_l2socket_creation_permission",
), patch(
"homeassistant.components.dhcp.compile_filter", "homeassistant.components.dhcp.compile_filter",
side_effect=ImportError, side_effect=ImportError,
) as compile_filter, patch( ) as compile_filter, patch(