File yggdrasil-sd_notify.patch of Package yggdrasil-go

From b1bb764ce8cb64c6f1f0c9c5709e124be163e002 Mon Sep 17 00:00:00 2001
From: "Remy D. Farley" <one-d-wide@protonmail.com>
Date: Sat, 15 Jun 2024 14:40:39 +0000
Subject: [PATCH] Add logic to notify service manager when start up is
 completed

---
 cmd/yggdrasil/main.go                    |  4 ++
 cmd/yggdrasil/notify_startup_linux.go    | 50 ++++++++++++++++++++++++
 cmd/yggdrasil/notify_startup_other.go    |  8 ++++
 contrib/systemd/yggdrasil.service        |  4 ++
 contrib/systemd/yggdrasil.service.debian |  1 +
 5 files changed, 67 insertions(+)
 create mode 100644 cmd/yggdrasil/notify_startup_linux.go
 create mode 100644 cmd/yggdrasil/notify_startup_other.go

diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go
index 29afdf5..b28929e 100644
--- a/cmd/yggdrasil/main.go
+++ b/cmd/yggdrasil/main.go
@@ -280,6 +280,10 @@ func main() {
 		<-done
 	})
 
+	if _, err = notifyStartupCompleted(); err != nil {
+		log.Warnln("Error while sending start up notification:", err)
+	}
+
 	// Block until we are told to shut down.
 	<-ctx.Done()
 
diff --git a/cmd/yggdrasil/notify_startup_linux.go b/cmd/yggdrasil/notify_startup_linux.go
new file mode 100644
index 0000000..d5f090d
--- /dev/null
+++ b/cmd/yggdrasil/notify_startup_linux.go
@@ -0,0 +1,50 @@
+//go:build linux
+// +build linux
+
+package main
+
+import (
+	"net"
+	"os"
+)
+
+// Notify systemd daemon when start up is completed.
+// Required to ensure that dependent services are started only after TUN interface is ready.
+//
+// One of the following is returned:
+// (false, nil) - notification not supported (i.e. `notifySocketEnv` is unset)
+// (false, err) - notification supported, but failure happened (e.g. error connecting to `notifySocketEnv` or while sending data)
+// (true, nil) - notification supported, data has been sent
+//
+// Based on `SdNotify` from [`coreos/go-systemd`](https://github.com/coreos/go-systemd/blob/7d375ecc2b092916968b5601f74cca28a8de45dd/daemon/sdnotify.go#L56)
+func notifyStartupCompleted() (bool, error) {
+	const (
+		notifyReady     = "READY=1"
+		notifySocketEnv = "NOTIFY_SOCKET"
+	)
+
+	socketAddr := &net.UnixAddr{
+		Name: os.Getenv(notifySocketEnv),
+		Net:  "unixgram",
+	}
+
+	// `notifySocketEnv` not set
+	if socketAddr.Name == "" {
+		return false, nil
+	}
+
+	os.Unsetenv(notifySocketEnv)
+
+	conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
+	// Error connecting to `notifySocketEnv`
+	if err != nil {
+		return false, err
+	}
+	defer conn.Close()
+
+	if _, err = conn.Write([]byte(notifyReady)); err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
diff --git a/cmd/yggdrasil/notify_startup_other.go b/cmd/yggdrasil/notify_startup_other.go
new file mode 100644
index 0000000..f3107fb
--- /dev/null
+++ b/cmd/yggdrasil/notify_startup_other.go
@@ -0,0 +1,8 @@
+//go:build !linux
+// +build !linux
+
+package main
+
+func notifyStartupCompleted() (bool, error) {
+	return false, nil
+}
diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service
index cdada6c..8dbc811 100644
--- a/contrib/systemd/yggdrasil.service
+++ b/contrib/systemd/yggdrasil.service
@@ -6,6 +6,10 @@ After=network-online.target
 After=yggdrasil-default-config.service
 
 [Service]
+Type=notify
+# Allow forked off processes to send notifications.
+# Uncomment if e.g. yggdrasil is started by a script.
+#NotifyAccess=all
 Group=yggdrasil
 ProtectHome=true
 ProtectSystem=true
diff --git a/contrib/systemd/yggdrasil.service.debian b/contrib/systemd/yggdrasil.service.debian
index 0f3c7a8..fb29882 100644
--- a/contrib/systemd/yggdrasil.service.debian
+++ b/contrib/systemd/yggdrasil.service.debian
@@ -6,6 +6,7 @@ After=network-online.target
 After=yggdrasil-default-config.service
 
 [Service]
+Type=notify
 Group=yggdrasil
 ProtectHome=true
 ProtectSystem=strict
-- 
2.45.2