mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-24 09:36:31 +00:00
Support custom DNS configuration on auto
So far, when the network setting is set to auto, we don't allow a custom DNS configuration. However, it is a perfectly valid use case to provide custom DNS configuration while using automatic IP configuration (e.g. DHCP). Especially when the DHCP server doesn't provide a DNS server. In this case, systemd-resolved (at least on Home Assistant OS) falls back to Cloudflare. This might not what the user wants. Customze the DNS setting allows to set a custom fallback DNS server or override a potential non-working DHCP provided one.
This commit is contained in:
parent
8ab396d77c
commit
1e9a3d7d0f
@ -29,6 +29,7 @@ from ..const import (
|
||||
ATTR_METHOD,
|
||||
ATTR_MODE,
|
||||
ATTR_NAMESERVERS,
|
||||
ATTR_NAMESERVERS_AUTO,
|
||||
ATTR_PARENT,
|
||||
ATTR_PRIMARY,
|
||||
ATTR_PSK,
|
||||
@ -90,6 +91,7 @@ def ipconfig_struct(config: IpConfig) -> dict[str, Any]:
|
||||
return {
|
||||
ATTR_METHOD: config.method,
|
||||
ATTR_ADDRESS: [address.with_prefixlen for address in config.address],
|
||||
ATTR_NAMESERVERS_AUTO: config.nameservers_auto,
|
||||
ATTR_NAMESERVERS: [str(address) for address in config.nameservers],
|
||||
ATTR_GATEWAY: str(config.gateway) if config.gateway else None,
|
||||
ATTR_READY: config.ready,
|
||||
@ -200,15 +202,19 @@ class APINetwork(CoreSysAttributes):
|
||||
if key == ATTR_IPV4:
|
||||
interface.ipv4 = replace(
|
||||
interface.ipv4
|
||||
or IpConfig(InterfaceMethod.STATIC, [], None, [], None),
|
||||
or IpConfig(InterfaceMethod.STATIC, [], None, False, [], None),
|
||||
**config,
|
||||
)
|
||||
if interface.ipv4.method == InterfaceMethod.AUTO:
|
||||
interface.ipv4.nameservers_auto = ATTR_NAMESERVERS not in config
|
||||
elif key == ATTR_IPV6:
|
||||
interface.ipv6 = replace(
|
||||
interface.ipv6
|
||||
or IpConfig(InterfaceMethod.STATIC, [], None, [], None),
|
||||
or IpConfig(InterfaceMethod.STATIC, [], None, False, [], None),
|
||||
**config,
|
||||
)
|
||||
if interface.ipv6.method == InterfaceMethod.AUTO:
|
||||
interface.ipv6.nameservers_auto = ATTR_NAMESERVERS not in config
|
||||
elif key == ATTR_WIFI:
|
||||
interface.wifi = replace(
|
||||
interface.wifi
|
||||
|
@ -244,6 +244,7 @@ ATTR_MODE = "mode"
|
||||
ATTR_MULTICAST = "multicast"
|
||||
ATTR_NAME = "name"
|
||||
ATTR_NAMESERVERS = "nameservers"
|
||||
ATTR_NAMESERVERS_AUTO = "nameservers_auto"
|
||||
ATTR_NETWORK = "network"
|
||||
ATTR_NETWORK_DESCRIPTION = "network_description"
|
||||
ATTR_NETWORK_RX = "network_rx"
|
||||
|
@ -64,6 +64,7 @@ class IpProperties:
|
||||
"""IP properties object for Network Manager."""
|
||||
|
||||
method: str | None
|
||||
dns: list[str] | None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
|
@ -6,7 +6,7 @@ from typing import Any
|
||||
from dbus_fast import Variant
|
||||
from dbus_fast.aio.message_bus import MessageBus
|
||||
|
||||
from ....const import ATTR_METHOD, ATTR_MODE, ATTR_PSK, ATTR_SSID
|
||||
from ....const import ATTR_DNS, ATTR_METHOD, ATTR_MODE, ATTR_PSK, ATTR_SSID
|
||||
from ...const import DBUS_NAME_NM
|
||||
from ...interface import DBusInterface
|
||||
from ...utils import dbus_connected
|
||||
@ -75,7 +75,7 @@ def _merge_settings_attribute(
|
||||
class NetworkSetting(DBusInterface):
|
||||
"""Network connection setting object for Network Manager.
|
||||
|
||||
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html
|
||||
https://networkmanager.dev/docs/api/1.48.0/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html
|
||||
"""
|
||||
|
||||
bus_name: str = DBUS_NAME_NM
|
||||
@ -229,11 +229,13 @@ class NetworkSetting(DBusInterface):
|
||||
if CONF_ATTR_IPV4 in data:
|
||||
self._ipv4 = IpProperties(
|
||||
data[CONF_ATTR_IPV4].get(ATTR_METHOD),
|
||||
data[CONF_ATTR_IPV4].get(ATTR_DNS),
|
||||
)
|
||||
|
||||
if CONF_ATTR_IPV6 in data:
|
||||
self._ipv6 = IpProperties(
|
||||
data[CONF_ATTR_IPV6].get(ATTR_METHOD),
|
||||
data[CONF_ATTR_IPV6].get(ATTR_DNS),
|
||||
)
|
||||
|
||||
if CONF_ATTR_MATCH in data:
|
||||
|
@ -76,13 +76,6 @@ def get_connection_from_interface(
|
||||
ipv4["method"] = Variant("s", "disabled")
|
||||
else:
|
||||
ipv4["method"] = Variant("s", "manual")
|
||||
ipv4["dns"] = Variant(
|
||||
"au",
|
||||
[
|
||||
socket.htonl(int(ip_address))
|
||||
for ip_address in interface.ipv4.nameservers
|
||||
],
|
||||
)
|
||||
|
||||
adressdata = []
|
||||
for address in interface.ipv4.address:
|
||||
@ -96,6 +89,18 @@ def get_connection_from_interface(
|
||||
ipv4["address-data"] = Variant("aa{sv}", adressdata)
|
||||
ipv4["gateway"] = Variant("s", str(interface.ipv4.gateway))
|
||||
|
||||
if (
|
||||
interface.ipv4.method == InterfaceMethod.AUTO
|
||||
and not interface.ipv4.nameservers_auto
|
||||
) or interface.ipv4.method == InterfaceMethod.STATIC:
|
||||
ipv4["dns"] = Variant(
|
||||
"au",
|
||||
[
|
||||
socket.htonl(int(ip_address))
|
||||
for ip_address in interface.ipv4.nameservers
|
||||
],
|
||||
)
|
||||
|
||||
conn[CONF_ATTR_IPV4] = ipv4
|
||||
|
||||
ipv6 = {}
|
||||
@ -105,9 +110,6 @@ def get_connection_from_interface(
|
||||
ipv6["method"] = Variant("s", "link-local")
|
||||
else:
|
||||
ipv6["method"] = Variant("s", "manual")
|
||||
ipv6["dns"] = Variant(
|
||||
"aay", [ip_address.packed for ip_address in interface.ipv6.nameservers]
|
||||
)
|
||||
|
||||
adressdata = []
|
||||
for address in interface.ipv6.address:
|
||||
@ -121,6 +123,14 @@ def get_connection_from_interface(
|
||||
ipv6["address-data"] = Variant("aa{sv}", adressdata)
|
||||
ipv6["gateway"] = Variant("s", str(interface.ipv6.gateway))
|
||||
|
||||
if (
|
||||
interface.ipv6.method == InterfaceMethod.AUTO
|
||||
and not interface.ipv6.nameservers_auto
|
||||
) or interface.ipv6.method == InterfaceMethod.STATIC:
|
||||
ipv6["dns"] = Variant(
|
||||
"aay", [ip_address.packed for ip_address in interface.ipv6.nameservers]
|
||||
)
|
||||
|
||||
conn[CONF_ATTR_IPV6] = ipv6
|
||||
|
||||
if interface.type == InterfaceType.ETHERNET:
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from dataclasses import dataclass
|
||||
from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface
|
||||
import socket
|
||||
|
||||
from ..dbus.const import (
|
||||
ConnectionStateFlags,
|
||||
@ -32,6 +33,7 @@ class IpConfig:
|
||||
method: InterfaceMethod
|
||||
address: list[IPv4Interface | IPv6Interface]
|
||||
gateway: IPv4Address | IPv6Address | None
|
||||
nameservers_auto: bool
|
||||
nameservers: list[IPv4Address | IPv6Address]
|
||||
ready: bool | None
|
||||
|
||||
@ -102,6 +104,30 @@ class Interface:
|
||||
bool(inet.connection)
|
||||
and ConnectionStateFlags.IP6_READY in inet.connection.state_flags
|
||||
)
|
||||
|
||||
# Use Nameserver from configuration if present (means manual DNS override)
|
||||
if inet.settings.ipv4.dns:
|
||||
ipv4_nameservers_auto = False
|
||||
ipv4_nameservers = [
|
||||
IPv4Address(socket.ntohl(ip)) for ip in inet.settings.ipv4.dns
|
||||
]
|
||||
elif inet.connection.ipv4.nameservers:
|
||||
ipv4_nameservers_auto = True
|
||||
ipv4_nameservers = inet.connection.ipv4.nameservers
|
||||
else:
|
||||
ipv4_nameservers_auto = True
|
||||
ipv4_nameservers = []
|
||||
|
||||
if inet.settings.ipv6.dns:
|
||||
ipv6_nameservers_auto = False
|
||||
ipv6_nameservers = [IPv6Address(bytes(ip)) for ip in inet.settings.ipv6.dns]
|
||||
elif inet.connection.ipv6.nameservers:
|
||||
ipv6_nameservers_auto = True
|
||||
ipv6_nameservers = inet.connection.ipv6.nameservers
|
||||
else:
|
||||
ipv6_nameservers_auto = True
|
||||
ipv6_nameservers = []
|
||||
|
||||
return Interface(
|
||||
inet.name,
|
||||
inet.hw_address,
|
||||
@ -111,27 +137,29 @@ class Interface:
|
||||
inet.primary,
|
||||
Interface._map_nm_type(inet.type),
|
||||
IpConfig(
|
||||
ipv4_method,
|
||||
inet.connection.ipv4.address if inet.connection.ipv4.address else [],
|
||||
inet.connection.ipv4.gateway,
|
||||
inet.connection.ipv4.nameservers
|
||||
if inet.connection.ipv4.nameservers
|
||||
method=ipv4_method,
|
||||
address=inet.connection.ipv4.address
|
||||
if inet.connection.ipv4.address
|
||||
else [],
|
||||
ipv4_ready,
|
||||
gateway=inet.connection.ipv4.gateway,
|
||||
nameservers_auto=ipv4_nameservers_auto,
|
||||
nameservers=ipv4_nameservers,
|
||||
ready=ipv4_ready,
|
||||
)
|
||||
if inet.connection and inet.connection.ipv4
|
||||
else IpConfig(ipv4_method, [], None, [], ipv4_ready),
|
||||
else IpConfig(ipv4_method, [], None, True, [], ipv4_ready),
|
||||
IpConfig(
|
||||
ipv6_method,
|
||||
inet.connection.ipv6.address if inet.connection.ipv6.address else [],
|
||||
inet.connection.ipv6.gateway,
|
||||
inet.connection.ipv6.nameservers
|
||||
if inet.connection.ipv6.nameservers
|
||||
method=ipv6_method,
|
||||
address=inet.connection.ipv6.address
|
||||
if inet.connection.ipv6.address
|
||||
else [],
|
||||
ipv6_ready,
|
||||
gateway=inet.connection.ipv6.gateway,
|
||||
nameservers_auto=ipv6_nameservers_auto,
|
||||
nameservers=ipv6_nameservers,
|
||||
ready=ipv6_ready,
|
||||
)
|
||||
if inet.connection and inet.connection.ipv6
|
||||
else IpConfig(ipv6_method, [], None, [], ipv6_ready),
|
||||
else IpConfig(ipv6_method, [], None, True, [], ipv6_ready),
|
||||
Interface._map_nm_wifi(inet),
|
||||
Interface._map_nm_vlan(inet),
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user