From c25ec56f1d79ee72de41323635db63816a51fd98 Mon Sep 17 00:00:00 2001 From: Alessandro Astone Date: Wed, 9 Oct 2024 16:49:31 +0200 Subject: [PATCH 1/2] feat: Add socket-activated systemd service for discovery Introduce a system-wide daemon listening on /run/wsdd.socket, which is managed by systemd. When a client first connects to the socket the daemon is started. Multiple clients can connect and safely use the API simultaneously. The service runs in discovery-only mode. Uses multicast source-port 37020. --- etc/systemd/wsdd-discovery.service | 17 +++++++++++++++++ etc/systemd/wsdd-discovery.socket | 9 +++++++++ etc/systemd/wsdd.defaults | 1 + src/wsdd.py | 19 ++++++++++++++++++- 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 etc/systemd/wsdd-discovery.service create mode 100644 etc/systemd/wsdd-discovery.socket diff --git a/etc/systemd/wsdd-discovery.service b/etc/systemd/wsdd-discovery.service new file mode 100644 index 0000000..7f13202 --- /dev/null +++ b/etc/systemd/wsdd-discovery.service @@ -0,0 +1,17 @@ +[Unit] +Description=Web Services Dynamic Discovery service +Documentation=man:wsdd(8) +Requires=wsdd-discovery.socket + +[Service] +Type=simple +; Use /etc/default/wsdd for defaults, if it exists +EnvironmentFile=-/etc/default/wsdd +; The service is put into an empty runtime directory chroot, +; i.e. the runtime directory which usually resides under /run +ExecStart=/usr/bin/wsdd --shortlog --chroot=/run/wsdd-discovery --source-port=37020 --no-host --discovery $WSDD_DISCOVERY_PARAMS +DynamicUser=yes +User=wsdd-discovery +Group=wsdd-discovery +RuntimeDirectory=wsdd-discovery +AmbientCapabilities=CAP_SYS_CHROOT diff --git a/etc/systemd/wsdd-discovery.socket b/etc/systemd/wsdd-discovery.socket new file mode 100644 index 0000000..dce8ea8 --- /dev/null +++ b/etc/systemd/wsdd-discovery.socket @@ -0,0 +1,9 @@ +[Unit] +Description=Web Services Dynamic Discovery API socket +Documentation=man:wsdd(8) + +[Socket] +ListenStream=%t/wsdd.socket + +[Install] +WantedBy=sockets.target diff --git a/etc/systemd/wsdd.defaults b/etc/systemd/wsdd.defaults index 3c8373e..d717257 100644 --- a/etc/systemd/wsdd.defaults +++ b/etc/systemd/wsdd.defaults @@ -3,3 +3,4 @@ # Refer to the wsdd(8) man page for details WSDD_PARAMS="" +WSDD_DISCOVERY_PARAMS="" diff --git a/src/wsdd.py b/src/wsdd.py index e102422..efba0a3 100755 --- a/src/wsdd.py +++ b/src/wsdd.py @@ -42,6 +42,11 @@ except ModuleNotFoundError: from xml.etree.ElementTree import fromstring as ETfromString +try: + import systemd.daemon +except ModuleNotFoundError: + # Non-systemd host + pass WSDD_VERSION: str = '0.8' @@ -1137,7 +1142,10 @@ async def create_server(self, aio_loop: asyncio.AbstractEventLoop, listen_addres # It appears mypy is not able to check the argument to create_task and the return value of start_server # correctly. The docs say start_server returns a coroutine and the create_task takes a coro. And: It works. # Thus, we ignore type errors here. - if isinstance(listen_address, int) or listen_address.isnumeric(): + if isinstance(listen_address, socket.SocketType): + self.server = await aio_loop.create_task(asyncio.start_unix_server( # type: ignore + self.on_connect, sock=listen_address)) + elif isinstance(listen_address, int) or listen_address.isnumeric(): self.server = await aio_loop.create_task(asyncio.start_server( # type: ignore self.on_connect, host='localhost', port=int(listen_address), reuse_address=True, reuse_port=True)) @@ -2010,6 +2018,15 @@ def main() -> int: api_server = None if args.listen: api_server = ApiServer(aio_loop, args.listen, nm) + else: + fds = [] + try: + fds = systemd.daemon.listen_fds() + except NameError: + # Non-systemd host + pass + if fds: + api_server = ApiServer(aio_loop, socket.socket(fileno=fds[0]), nm) # get uid:gid before potential chroot'ing if args.user is not None: From 6fa319fa940c7953da793c3c963ebf40ded24f54 Mon Sep 17 00:00:00 2001 From: Alessandro Astone Date: Mon, 14 Oct 2024 09:15:22 +0200 Subject: [PATCH 2/2] feat(etc): Allow port 37020 in firewall profiles Used by the socket-activated discovery daemon --- etc/firewalld/services/wsdd.xml | 1 + etc/ufw/applications.d/wsdd | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/firewalld/services/wsdd.xml b/etc/firewalld/services/wsdd.xml index 82729fc..2ae8c20 100644 --- a/etc/firewalld/services/wsdd.xml +++ b/etc/firewalld/services/wsdd.xml @@ -3,6 +3,7 @@ Web Services Dynamic Discovery host daemon wsdd implements a Web Service Discovery host daemon. This enables (Samba) hosts, like your local NAS device, to be found by Web Service Discovery Clients like Windows. + diff --git a/etc/ufw/applications.d/wsdd b/etc/ufw/applications.d/wsdd index 6412fc7..8c62da6 100644 --- a/etc/ufw/applications.d/wsdd +++ b/etc/ufw/applications.d/wsdd @@ -1,4 +1,4 @@ [Wsdd] title=Wsdd description=Web Service Discovery host daemon implementation -ports=3702/udp|5357/tcp +ports=3702/udp|37020/udp|5357/tcp