From aebd21d01a5a710c4f6bce53aef470b93197933f Mon Sep 17 00:00:00 2001 From: Igor Yamolov Date: Wed, 1 Jan 2025 12:52:11 +0000 Subject: [PATCH 1/3] Add network interface settings for mDNS/LLMNR --- supervisor/api/network.py | 11 ++++++++ supervisor/const.py | 2 ++ supervisor/dbus/const.py | 8 ++++++ supervisor/dbus/network/configuration.py | 2 ++ supervisor/dbus/network/setting/__init__.py | 2 ++ supervisor/dbus/network/setting/generate.py | 20 +++++++++++--- supervisor/host/configuration.py | 30 ++++++++++++++++++++- supervisor/host/const.py | 8 ++++++ 8 files changed, 79 insertions(+), 4 deletions(-) diff --git a/supervisor/api/network.py b/supervisor/api/network.py index f93749236..dc5cfb0a1 100644 --- a/supervisor/api/network.py +++ b/supervisor/api/network.py @@ -24,7 +24,9 @@ from ..const import ( ATTR_INTERFACES, ATTR_IPV4, ATTR_IPV6, + ATTR_LLMNR, ATTR_MAC, + ATTR_MDNS, ATTR_METHOD, ATTR_MODE, ATTR_NAMESERVERS, @@ -49,6 +51,7 @@ from ..host.configuration import ( InterfaceMethod, IpConfig, IpSetting, + MulticastDnsMode, VlanConfig, WifiConfig, ) @@ -90,6 +93,8 @@ SCHEMA_UPDATE = vol.Schema( vol.Optional(ATTR_IPV6): _SCHEMA_IPV6_CONFIG, vol.Optional(ATTR_WIFI): _SCHEMA_WIFI_CONFIG, vol.Optional(ATTR_ENABLED): vol.Boolean(), + vol.Optional(ATTR_MDNS): vol.Coerce(MulticastDnsMode), + vol.Optional(ATTR_LLMNR): vol.Coerce(MulticastDnsMode), } ) @@ -136,6 +141,8 @@ def interface_struct(interface: Interface) -> dict[str, Any]: ATTR_IPV6: ipconfig_struct(interface.ipv6, interface.ipv6setting), ATTR_WIFI: wifi_struct(interface.wifi) if interface.wifi else None, ATTR_VLAN: vlan_struct(interface.vlan) if interface.vlan else None, + ATTR_MDNS: interface.mdns, + ATTR_LLMNR: interface.lldmp, } @@ -230,6 +237,10 @@ class APINetwork(CoreSysAttributes): ) elif key == ATTR_ENABLED: interface.enabled = config + elif key == ATTR_MDNS: + interface.mdns = config + elif key == ATTR_LLMNR: + interface.llmnr = config await asyncio.shield(self.sys_host.network.apply_changes(interface)) diff --git a/supervisor/const.py b/supervisor/const.py index 1f1fec244..6669905ad 100644 --- a/supervisor/const.py +++ b/supervisor/const.py @@ -228,6 +228,7 @@ ATTR_KERNEL_MODULES = "kernel_modules" ATTR_LABELS = "labels" ATTR_LAST_BOOT = "last_boot" ATTR_LEGACY = "legacy" +ATTR_LLMNR = "llmnr" ATTR_LOCALS = "locals" ATTR_LOCATION = "location" ATTR_LOGGING = "logging" @@ -237,6 +238,7 @@ ATTR_MAC = "mac" ATTR_MACHINE = "machine" ATTR_MAINTAINER = "maintainer" ATTR_MAP = "map" +ATTR_MDNS = "mdns" ATTR_MEMORY_LIMIT = "memory_limit" ATTR_MEMORY_PERCENT = "memory_percent" ATTR_MEMORY_USAGE = "memory_usage" diff --git a/supervisor/dbus/const.py b/supervisor/dbus/const.py index 82c75d8f3..e16f94a65 100644 --- a/supervisor/dbus/const.py +++ b/supervisor/dbus/const.py @@ -296,6 +296,14 @@ class MulticastProtocolEnabled(StrEnum): RESOLVE = "resolve" +class MulticastDnsValue(IntEnum): + """Connection MulticastDNS (mdns/lldmp) values.""" + + OFF = 0 + RESOLVE = 1 + ANNOUNCE = 2 + + class DNSOverTLSEnabled(StrEnum): """DNS over TLS enabled.""" diff --git a/supervisor/dbus/network/configuration.py b/supervisor/dbus/network/configuration.py index b78855f85..6b21811bb 100644 --- a/supervisor/dbus/network/configuration.py +++ b/supervisor/dbus/network/configuration.py @@ -23,6 +23,8 @@ class ConnectionProperties: uuid: str | None type: str | None interface_name: str | None + mdns: int | None + lldmp: int | None @dataclass(slots=True) diff --git a/supervisor/dbus/network/setting/__init__.py b/supervisor/dbus/network/setting/__init__.py index 5bf1dbad2..d002186ae 100644 --- a/supervisor/dbus/network/setting/__init__.py +++ b/supervisor/dbus/network/setting/__init__.py @@ -219,6 +219,8 @@ class NetworkSetting(DBusInterface): data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_UUID), data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_TYPE), data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_INTERFACE_NAME), + data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_MDNS), + data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_LLMNR), ) if CONF_ATTR_802_ETHERNET in data: diff --git a/supervisor/dbus/network/setting/generate.py b/supervisor/dbus/network/setting/generate.py index 554c5b230..9cc6c59c7 100644 --- a/supervisor/dbus/network/setting/generate.py +++ b/supervisor/dbus/network/setting/generate.py @@ -8,7 +8,8 @@ from uuid import uuid4 from dbus_fast import Variant -from ....host.const import InterfaceMethod, InterfaceType +from ....host.const import InterfaceMethod, InterfaceType, MulticastDnsMode +from ...const import MulticastDnsValue from .. import NetworkManager from . import ( CONF_ATTR_802_ETHERNET, @@ -133,6 +134,16 @@ def _get_ipv6_connection_settings(ipv6setting) -> dict: return ipv6 +def _map_mdns_setting(mode: MulticastDnsMode | None) -> int: + mapping = { + MulticastDnsMode.OFF: MulticastDnsValue.OFF, + MulticastDnsMode.RESOLVE: MulticastDnsValue.RESOLVE, + MulticastDnsMode.ANNOUNCE: MulticastDnsValue.ANNOUNCE, + } + + return int(mapping[mode] if mode else MulticastDnsValue.ANNOUNCE) + + def get_connection_from_interface( interface: Interface, network_manager: NetworkManager, @@ -158,13 +169,16 @@ def get_connection_from_interface( if not uuid: uuid = str(uuid4()) + llmnr = _map_mdns_setting(interface.llmnr) + mdns = _map_mdns_setting(interface.mdns) + conn: dict[str, dict[str, Variant]] = { CONF_ATTR_CONNECTION: { CONF_ATTR_CONNECTION_ID: Variant("s", name), CONF_ATTR_CONNECTION_UUID: Variant("s", uuid), CONF_ATTR_CONNECTION_TYPE: Variant("s", iftype), - CONF_ATTR_CONNECTION_LLMNR: Variant("i", 2), - CONF_ATTR_CONNECTION_MDNS: Variant("i", 2), + CONF_ATTR_CONNECTION_LLMNR: Variant("i", llmnr), + CONF_ATTR_CONNECTION_MDNS: Variant("i", mdns), CONF_ATTR_CONNECTION_AUTOCONNECT: Variant("b", True), }, } diff --git a/supervisor/host/configuration.py b/supervisor/host/configuration.py index cfce58831..a0f9deb96 100644 --- a/supervisor/host/configuration.py +++ b/supervisor/host/configuration.py @@ -9,10 +9,17 @@ from ..dbus.const import ( ConnectionStateType, DeviceType, InterfaceMethod as NMInterfaceMethod, + MulticastDnsValue, ) from ..dbus.network.connection import NetworkConnection from ..dbus.network.interface import NetworkInterface -from .const import AuthMethod, InterfaceMethod, InterfaceType, WifiMode +from .const import ( + AuthMethod, + InterfaceMethod, + InterfaceType, + MulticastDnsMode, + WifiMode, +) @dataclass(slots=True) @@ -82,6 +89,8 @@ class Interface: ipv6setting: IpSetting | None wifi: WifiConfig | None vlan: VlanConfig | None + mdns: MulticastDnsMode | None + llmnr: MulticastDnsMode | None def equals_dbus_interface(self, inet: NetworkInterface) -> bool: """Return true if this represents the dbus interface.""" @@ -145,6 +154,13 @@ class Interface: and ConnectionStateFlags.IP6_READY in inet.connection.state_flags ) + if inet.settings and inet.settings.connection: + mdns = inet.settings.connection.mdns + lldmp = inet.settings.connection.lldmp + else: + mdns = None + lldmp = None + return Interface( inet.name, inet.hw_address, @@ -181,6 +197,8 @@ class Interface: ipv6_setting, Interface._map_nm_wifi(inet), Interface._map_nm_vlan(inet), + Interface._map_nm_multicast_dns(mdns), + Interface._map_nm_multicast_dns(lldmp), ) @staticmethod @@ -258,3 +276,13 @@ class Interface: return None return VlanConfig(inet.settings.vlan.id, inet.settings.vlan.parent) + + @staticmethod + def _map_nm_multicast_dns(mode: int | None) -> MulticastDnsMode | None: + mapping = { + MulticastDnsValue.OFF: MulticastDnsMode.OFF, + MulticastDnsValue.RESOLVE: MulticastDnsMode.RESOLVE, + MulticastDnsValue.ANNOUNCE: MulticastDnsMode.ANNOUNCE, + } + + return mapping[mode] diff --git a/supervisor/host/const.py b/supervisor/host/const.py index 9c3a9dc4a..ddd920728 100644 --- a/supervisor/host/const.py +++ b/supervisor/host/const.py @@ -70,3 +70,11 @@ class LogFormatter(StrEnum): PLAIN = "plain" VERBOSE = "verbose" + + +class MulticastDnsMode(StrEnum): + """Multicast DNS (MDNS/LLMNR) mode.""" + + OFF = "off" + RESOLVE = "resolve" + ANNOUNCE = "announce" From 0b7f2b6a156e12ac56bea95c722512983134c753 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 14 Jan 2025 11:43:38 +0100 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- supervisor/api/network.py | 2 +- supervisor/dbus/network/configuration.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/supervisor/api/network.py b/supervisor/api/network.py index dc5cfb0a1..c72ba679c 100644 --- a/supervisor/api/network.py +++ b/supervisor/api/network.py @@ -142,7 +142,7 @@ def interface_struct(interface: Interface) -> dict[str, Any]: ATTR_WIFI: wifi_struct(interface.wifi) if interface.wifi else None, ATTR_VLAN: vlan_struct(interface.vlan) if interface.vlan else None, ATTR_MDNS: interface.mdns, - ATTR_LLMNR: interface.lldmp, + ATTR_LLMNR: interface.llmnr, } diff --git a/supervisor/dbus/network/configuration.py b/supervisor/dbus/network/configuration.py index 6b21811bb..83e610fb1 100644 --- a/supervisor/dbus/network/configuration.py +++ b/supervisor/dbus/network/configuration.py @@ -24,7 +24,7 @@ class ConnectionProperties: type: str | None interface_name: str | None mdns: int | None - lldmp: int | None + llmnr: int | None @dataclass(slots=True) From bbb361fead9cced0c6db3f23353822e995a16047 Mon Sep 17 00:00:00 2001 From: Igor Yamolov Date: Mon, 27 Jan 2025 10:16:53 +0100 Subject: [PATCH 3/3] Fix naming inconsistencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks @sairon for code review Co-authored-by: Jan Čermák --- supervisor/dbus/const.py | 2 +- supervisor/host/configuration.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/supervisor/dbus/const.py b/supervisor/dbus/const.py index e16f94a65..b6c4dd225 100644 --- a/supervisor/dbus/const.py +++ b/supervisor/dbus/const.py @@ -297,7 +297,7 @@ class MulticastProtocolEnabled(StrEnum): class MulticastDnsValue(IntEnum): - """Connection MulticastDNS (mdns/lldmp) values.""" + """Connection MulticastDNS (mdns/llmnr) values.""" OFF = 0 RESOLVE = 1 diff --git a/supervisor/host/configuration.py b/supervisor/host/configuration.py index a0f9deb96..780fa9622 100644 --- a/supervisor/host/configuration.py +++ b/supervisor/host/configuration.py @@ -156,10 +156,10 @@ class Interface: if inet.settings and inet.settings.connection: mdns = inet.settings.connection.mdns - lldmp = inet.settings.connection.lldmp + llmnr = inet.settings.connection.llmnr else: mdns = None - lldmp = None + llmnr = None return Interface( inet.name, @@ -198,7 +198,7 @@ class Interface: Interface._map_nm_wifi(inet), Interface._map_nm_vlan(inet), Interface._map_nm_multicast_dns(mdns), - Interface._map_nm_multicast_dns(lldmp), + Interface._map_nm_multicast_dns(llmnr), ) @staticmethod