From e6e200f3c1232c00f9c246b0b9acda05ff5c838d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 4 Jan 2022 19:22:28 -1000 Subject: [PATCH] Handle no enabled ipv4 addresses in the network integration (#63416) --- homeassistant/components/network/__init__.py | 14 ++++++ tests/components/network/test_init.py | 48 ++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/homeassistant/components/network/__init__.py b/homeassistant/components/network/__init__.py index 7cc864727d7..b3ef88e7ab2 100644 --- a/homeassistant/components/network/__init__.py +++ b/homeassistant/components/network/__init__.py @@ -2,8 +2,10 @@ from __future__ import annotations from ipaddress import IPv4Address, IPv6Address, ip_interface +import logging from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.typing import ConfigType from homeassistant.loader import bind_hass @@ -12,6 +14,8 @@ from .const import IPV4_BROADCAST_ADDR, PUBLIC_TARGET_IP from .models import Adapter from .network import Network, async_get_network +_LOGGER = logging.getLogger(__name__) + @bind_hass async def async_get_adapters(hass: HomeAssistant) -> list[Adapter]: @@ -32,6 +36,16 @@ async def async_get_source_ip( all_ipv4s.extend([ipv4["address"] for ipv4 in ipv4s]) source_ip = util.async_get_source_ip(target_ip) + if not all_ipv4s: + _LOGGER.warning( + "Because the system does not have any enabled IPv4 addresses, source address detection may be inaccurate" + ) + if source_ip is None: + raise HomeAssistantError( + "Could not determine source ip because the system does not have any enabled IPv4 addresses and creating a socket failed" + ) + return source_ip + return source_ip if source_ip in all_ipv4s else all_ipv4s[0] diff --git a/tests/components/network/test_init.py b/tests/components/network/test_init.py index 5a6802a14fb..1103c6fa850 100644 --- a/tests/components/network/test_init.py +++ b/tests/components/network/test_init.py @@ -3,6 +3,7 @@ from ipaddress import IPv4Address from unittest.mock import MagicMock, Mock, patch import ifaddr +import pytest from homeassistant.components import network from homeassistant.components.network.const import ( @@ -13,6 +14,7 @@ from homeassistant.components.network.const import ( STORAGE_KEY, STORAGE_VERSION, ) +from homeassistant.exceptions import HomeAssistantError from homeassistant.setup import async_setup_component _NO_LOOPBACK_IPADDR = "192.168.1.5" @@ -602,3 +604,49 @@ async def test_async_get_ipv4_broadcast_addresses_multiple(hass, hass_storage): IPv4Address("192.168.1.255"), IPv4Address("169.254.255.255"), } + + +async def test_async_get_source_ip_no_enabled_addresses(hass, hass_storage, caplog): + """Test getting the source ip address when all adapters are disabled.""" + hass_storage[STORAGE_KEY] = { + "version": STORAGE_VERSION, + "key": STORAGE_KEY, + "data": {ATTR_CONFIGURED_ADAPTERS: ["eth1"]}, + } + + with patch( + "homeassistant.components.network.util.ifaddr.get_adapters", + return_value=[], + ), patch( + "homeassistant.components.network.util.socket.socket", + return_value=_mock_socket(["192.168.1.5"]), + ): + assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) + await hass.async_block_till_done() + + assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "192.168.1.5" + + assert "source address detection may be inaccurate" in caplog.text + + +async def test_async_get_source_ip_cannot_be_determined_and_no_enabled_addresses( + hass, hass_storage, caplog +): + """Test getting the source ip address when all adapters are disabled and getting it fails.""" + hass_storage[STORAGE_KEY] = { + "version": STORAGE_VERSION, + "key": STORAGE_KEY, + "data": {ATTR_CONFIGURED_ADAPTERS: ["eth1"]}, + } + + with patch( + "homeassistant.components.network.util.ifaddr.get_adapters", + return_value=[], + ), patch( + "homeassistant.components.network.util.socket.socket", + return_value=_mock_socket([None]), + ): + assert not await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) + await hass.async_block_till_done() + with pytest.raises(HomeAssistantError): + await network.async_get_source_ip(hass, MDNS_TARGET_IP)