From 15070233d1f7317c16f28579d029c137937599ca Mon Sep 17 00:00:00 2001 From: Mika Joenpera Date: Wed, 23 Oct 2024 11:42:34 +0300 Subject: [PATCH] Fix "IPv6 connection unreliable from external PC" Avahi workaround Jira-Id: SECO-7551 Signed-off-by: Mika Joenpera --- .../src/nats/conf/default_ms_config.yaml | 3 + .../src/nats/src/cbma_adaptation.py | 35 ++++++++++++ .../src/nats/src/comms_service_refresh.py | 56 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 modules/sc-mesh-secure-deployment/src/nats/src/comms_service_refresh.py diff --git a/modules/sc-mesh-secure-deployment/src/nats/conf/default_ms_config.yaml b/modules/sc-mesh-secure-deployment/src/nats/conf/default_ms_config.yaml index 4710d932..004bd78a 100644 --- a/modules/sc-mesh-secure-deployment/src/nats/conf/default_ms_config.yaml +++ b/modules/sc-mesh-secure-deployment/src/nats/conf/default_ms_config.yaml @@ -2,6 +2,9 @@ # Mesh Shield config file # ########################### +# hostname of the device +hostname: nixos + # All the interfaces are black by default. # Excluded interfaces or interfaces without macsec certificates are not added to lower CBMA. # White interfaces are added to upper CBMA and are excluded automatically from lower CBMA. diff --git a/modules/sc-mesh-secure-deployment/src/nats/src/cbma_adaptation.py b/modules/sc-mesh-secure-deployment/src/nats/src/cbma_adaptation.py index 782f6e94..05b9cd64 100644 --- a/modules/sc-mesh-secure-deployment/src/nats/src/cbma_adaptation.py +++ b/modules/sc-mesh-secure-deployment/src/nats/src/cbma_adaptation.py @@ -22,6 +22,7 @@ from src.interface import Interface from src import comms_config_store from src.bat_ctrl_utils import BatCtrlUtils +from src.comms_service_refresh import CommsServiceRefresh from controller import CBMAController from models.certificates import CBMACertificates @@ -85,6 +86,7 @@ def __init__( if self.__config is not None: self.__cbma_config = self.__config.read("CBMA") self.__vlan_config = self.__config.read("VLAN") + self.__hostname = self.__config.read("hostname") # Create VLAN interfaces if configured self.__create_vlan_interfaces() @@ -106,6 +108,9 @@ def __init__( self.__red_interfaces.extend(red_interfaces) self.__na_cbma_interfaces.extend(exclude_interfaces) + self.__service_refresh = CommsServiceRefresh(self.__hostname, logger) + self.__service_thread = None + def __validate_cbma_config( self, exclude_interfaces: List[str], @@ -277,6 +282,24 @@ def __delete_vlan_interfaces(self) -> bool: success = False return success + def __set_hostname(self) -> None: + """ + Set hostname for device configured in ms_config.yaml. + """ + try: + subprocess.run(["hostname", self.__hostname], check=True) + except subprocess.CalledProcessError as e: + self.logger.error(f"Error setting hostname {self.__hostname}: {e}") + + def __update_avahi_hostname(self) -> None: + """ + Update avahi hostname for device configured in ms_config.yaml. + """ + try: + subprocess.run(["avahi-set-host-name", self.__hostname], check=True) + except subprocess.CalledProcessError as e: + self.logger.error(f"Error updating avahi hostname {self.__hostname}: {e}") + def __get_interfaces(self) -> None: interfaces = [] ip = IPRoute() @@ -731,6 +754,10 @@ def setup_cbma(self) -> bool: :return: True if both lower and upper CBMA was setup successfully. Returns False otherwise. """ + # hostname updates + self.__set_hostname() + self.__update_avahi_hostname() + self.__init_batman_and_bridge() self.__update_cbma_interface_lists() @@ -762,6 +789,10 @@ def setup_cbma(self) -> bool: # Set batman hop penalty self.__batman.set_hop_penalty() + # Start the service publisher thread + self.__service_thread = threading.Thread(target=self.__service_refresh.dns_service_refresh) + self.__service_thread.start() + return True def __is_valid_ipv6_local(self, address: tuple[str, int]) -> bool: @@ -1007,4 +1038,8 @@ def stop_cbma(self) -> bool: self.__cleanup_cbma() self.stop_radios() + self.__service_refresh.shutdown_service() + if self.__service_thread is not None: + self.__service_thread.join() + return lower_stopped and upper_stopped diff --git a/modules/sc-mesh-secure-deployment/src/nats/src/comms_service_refresh.py b/modules/sc-mesh-secure-deployment/src/nats/src/comms_service_refresh.py new file mode 100644 index 00000000..3ae4ec1a --- /dev/null +++ b/modules/sc-mesh-secure-deployment/src/nats/src/comms_service_refresh.py @@ -0,0 +1,56 @@ +""" +Refresher class for the comms service registration +""" +import logging +import threading +import time +import subprocess + +class CommsServiceRefresh: + """ + Comms service publisher class + """ + DNS_SERVICE_EVENT_LOOP_TIMEOUT: int = 5 + + def __init__(self, __hostname, __logger: logging.Logger) -> None: + + self.logger: logging.Logger = __logger.getChild("CommsServicePublisher") + self.logger.setLevel(logging.INFO) + self.__event: threading.Event = threading.Event() + self.__hostname: str = __hostname + + + def __refresh_hostname(self) -> None: + """ + Refresh the hostname with avahi-resolve-host-name + """ + try: + subprocess.run(["avahi-resolve-host-name", self.__hostname + ".local"], check=True) + except subprocess.CalledProcessError: + self.logger.exception("Error refreshing hostname") + + def dns_service_refresh(self) -> None: + """ + Register and re-announce service periodically + """ + self.logger.info("Refresh start") + while not self.__event.is_set(): + time.sleep(self.DNS_SERVICE_EVENT_LOOP_TIMEOUT) + self.__refresh_hostname() + self.logger.info("Refresh stopped") + + + def shutdown_service(self) -> None: + """ + Shutdown the service + """ + self.__event.set() + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + logger = logging.getLogger("CommsServiceRefresh") + comms_service_refresh = CommsServiceRefresh("mika-battlestation", logger) + comms_service_refresh.dns_service_refresh() + time.sleep(100) + # Wait for the service to be registered + comms_service_refresh.shutdown_service()