Expose async_get_source_ip in the network integration (#52901)
* Expose async_get_source_ip in the network integration * Handle source ip on disabled interface * add coverage
This commit is contained in:
parent
d09035db2a
commit
a021d7d628
2 changed files with 78 additions and 0 deletions
|
@ -11,6 +11,7 @@ from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
|
|
||||||
|
from . import util
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_ADAPTERS,
|
ATTR_ADAPTERS,
|
||||||
ATTR_CONFIGURED_ADAPTERS,
|
ATTR_CONFIGURED_ADAPTERS,
|
||||||
|
@ -31,6 +32,19 @@ async def async_get_adapters(hass: HomeAssistant) -> list[Adapter]:
|
||||||
return network.adapters
|
return network.adapters
|
||||||
|
|
||||||
|
|
||||||
|
@bind_hass
|
||||||
|
async def async_get_source_ip(hass: HomeAssistant, target_ip: str) -> str | None:
|
||||||
|
"""Get the source ip for a target ip."""
|
||||||
|
adapters = await async_get_adapters(hass)
|
||||||
|
all_ipv4s = []
|
||||||
|
for adapter in adapters:
|
||||||
|
if adapter["enabled"] and (ipv4s := adapter["ipv4"]):
|
||||||
|
all_ipv4s.extend([ipv4["address"] for ipv4 in ipv4s])
|
||||||
|
|
||||||
|
source_ip = util.async_get_source_ip(target_ip)
|
||||||
|
return source_ip if source_ip in all_ipv4s else all_ipv4s[0]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
"""Set up network for Home Assistant."""
|
"""Set up network for Home Assistant."""
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from homeassistant.components import network
|
||||||
from homeassistant.components.network.const import (
|
from homeassistant.components.network.const import (
|
||||||
ATTR_ADAPTERS,
|
ATTR_ADAPTERS,
|
||||||
ATTR_CONFIGURED_ADAPTERS,
|
ATTR_CONFIGURED_ADAPTERS,
|
||||||
|
MDNS_TARGET_IP,
|
||||||
STORAGE_KEY,
|
STORAGE_KEY,
|
||||||
STORAGE_VERSION,
|
STORAGE_VERSION,
|
||||||
)
|
)
|
||||||
|
@ -444,3 +445,66 @@ async def test_interfaces_configured_from_storage_websocket_update(
|
||||||
"name": "vtun0",
|
"name": "vtun0",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_get_source_ip_matching_interface(hass, hass_storage):
|
||||||
|
"""Test getting the source ip address with interface matching."""
|
||||||
|
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=_generate_mock_adapters(),
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.network.util.socket.socket.getsockname",
|
||||||
|
return_value=["192.168.1.5"],
|
||||||
|
):
|
||||||
|
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "192.168.1.5"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_get_source_ip_interface_not_match(hass, hass_storage):
|
||||||
|
"""Test getting the source ip address with interface does not match."""
|
||||||
|
hass_storage[STORAGE_KEY] = {
|
||||||
|
"version": STORAGE_VERSION,
|
||||||
|
"key": STORAGE_KEY,
|
||||||
|
"data": {ATTR_CONFIGURED_ADAPTERS: ["vtun0"]},
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.network.util.ifaddr.get_adapters",
|
||||||
|
return_value=_generate_mock_adapters(),
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.network.util.socket.socket.getsockname",
|
||||||
|
return_value=["192.168.1.5"],
|
||||||
|
):
|
||||||
|
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "169.254.3.2"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_get_source_ip_cannot_determine_target(hass, hass_storage):
|
||||||
|
"""Test getting the source ip address when getsockname 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=_generate_mock_adapters(),
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.network.util.socket.socket.getsockname",
|
||||||
|
return_value=[None],
|
||||||
|
):
|
||||||
|
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "192.168.1.5"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue