From 74a30af79ba491197d3f48c7b07e2e2217249de7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 9 Aug 2021 14:13:55 -0500 Subject: [PATCH] Always set interfaces explicitly when IPv6 is present (#54268) --- homeassistant/components/zeroconf/__init__.py | 17 +++---- tests/components/zeroconf/test_init.py | 47 +++++++++++++++++-- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/zeroconf/__init__.py b/homeassistant/components/zeroconf/__init__.py index cdb46318578..e7132f56b55 100644 --- a/homeassistant/components/zeroconf/__init__.py +++ b/homeassistant/components/zeroconf/__init__.py @@ -142,7 +142,15 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool: zc_args: dict = {} adapters = await network.async_get_adapters(hass) - if _async_use_default_interface(adapters): + + ipv6 = True + if not any(adapter["enabled"] and adapter["ipv6"] for adapter in adapters): + ipv6 = False + zc_args["ip_version"] = IPVersion.V4Only + else: + zc_args["ip_version"] = IPVersion.All + + if not ipv6 and _async_use_default_interface(adapters): zc_args["interfaces"] = InterfaceChoice.Default else: interfaces = zc_args["interfaces"] = [] @@ -158,13 +166,6 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool: if adapter["ipv6"] and adapter["index"] not in interfaces: interfaces.append(adapter["index"]) - ipv6 = True - if not any(adapter["enabled"] and adapter["ipv6"] for adapter in adapters): - ipv6 = False - zc_args["ip_version"] = IPVersion.V4Only - else: - zc_args["ip_version"] = IPVersion.All - aio_zc = await _async_get_instance(hass, **zc_args) zeroconf = cast(HaZeroconf, aio_zc.zeroconf) zeroconf_types, homekit_models = await asyncio.gather( diff --git a/tests/components/zeroconf/test_init.py b/tests/components/zeroconf/test_init.py index e1e346621fe..0db8f0f5227 100644 --- a/tests/components/zeroconf/test_init.py +++ b/tests/components/zeroconf/test_init.py @@ -794,11 +794,6 @@ async def test_async_detect_interfaces_setting_empty_route(hass, mock_async_zero ), patch( "homeassistant.components.zeroconf.AsyncServiceInfo", side_effect=get_service_info_mock, - ), patch( - "socket.if_nametoindex", - side_effect=lambda iface: {"eth0": 1, "eth1": 2, "eth2": 3, "vtun0": 4}.get( - iface, 0 - ), ): assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}}) hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) @@ -827,3 +822,45 @@ async def test_get_announced_addresses(hass, mock_async_zeroconf): first_ip = ip_address("192.168.1.5").packed actual = _get_announced_addresses(_ADAPTERS_WITH_MANUAL_CONFIG, first_ip) assert actual[0] == first_ip and set(actual) == expected + + +_ADAPTER_WITH_DEFAULT_ENABLED_AND_IPV6 = [ + { + "auto": True, + "default": True, + "enabled": True, + "index": 1, + "ipv4": [{"address": "192.168.1.5", "network_prefix": 23}], + "ipv6": [ + { + "address": "fe80::dead:beef:dead:beef", + "network_prefix": 64, + "flowinfo": 1, + "scope_id": 3, + } + ], + "name": "eth1", + } +] + + +async def test_async_detect_interfaces_explicitly_set_ipv6(hass, mock_async_zeroconf): + """Test interfaces are explicitly set when IPv6 is present.""" + with patch("homeassistant.components.zeroconf.HaZeroconf") as mock_zc, patch.object( + hass.config_entries.flow, "async_init" + ), patch.object( + zeroconf, "HaAsyncServiceBrowser", side_effect=service_update_mock + ), patch( + "homeassistant.components.zeroconf.network.async_get_adapters", + return_value=_ADAPTER_WITH_DEFAULT_ENABLED_AND_IPV6, + ), patch( + "homeassistant.components.zeroconf.AsyncServiceInfo", + side_effect=get_service_info_mock, + ): + assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}}) + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() + + assert mock_zc.mock_calls[0] == call( + interfaces=["192.168.1.5", 1], ip_version=IPVersion.All + )