summaryrefslogtreecommitdiff
path: root/internal/namespace/pinning.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/namespace/pinning.go')
-rw-r--r--internal/namespace/pinning.go30
1 files changed, 22 insertions, 8 deletions
diff --git a/internal/namespace/pinning.go b/internal/namespace/pinning.go
index a522f17..e257187 100644
--- a/internal/namespace/pinning.go
+++ b/internal/namespace/pinning.go
@@ -9,9 +9,11 @@ import (
"strconv"
"git.theodohertyfamily.com/tools/wg-wrap/internal/paths"
+ "golang.org/x/sys/unix"
)
-// PinNamespace touches the namespace path to indicate it is pinned/active.
+// PinNamespace binds the current network namespace to the profile's namespace path.
+// This prevents the kernel from destroying the namespace when all processes exit.
func PinNamespace(pm *paths.PathManager, profile string) error {
nsPath := GetProfileNamespacePath(pm, profile)
profilesDir := filepath.Dir(nsPath)
@@ -19,15 +21,21 @@ func PinNamespace(pm *paths.PathManager, profile string) error {
return fmt.Errorf("failed to create profiles directory: %w", err)
}
- // We write a placeholder file to indicate the profile namespace is pinned.
- if err := os.WriteFile(nsPath, []byte("active"), 0644); err != nil {
+ // 1. Create an empty file to serve as the mount point
+ if err := os.WriteFile(nsPath, []byte(""), 0644); err != nil {
return fmt.Errorf("failed to create namespace pin file: %w", err)
}
+
+ // 2. Bind-mount the current network namespace to the file.
+ // This increments the kernel's reference count for the namespace.
+ if err := unix.Mount("/proc/self/ns/net", nsPath, "", unix.MS_BIND, ""); err != nil {
+ return fmt.Errorf("failed to bind-mount network namespace: %w", err)
+ }
+
return nil
}
-// UnpinNamespace removes the pinned namespace file from the filesystem.
-// This allows the namespace to be destroyed once the last process exits.
+// UnpinNamespace unmounts and removes the pinned namespace file.
func UnpinNamespace(pm *paths.PathManager, profile string) error {
nsPath := GetProfileNamespacePath(pm, profile)
@@ -35,13 +43,19 @@ func UnpinNamespace(pm *paths.PathManager, profile string) error {
return nil
}
- pidsDir := GetPidsDirPath(pm, profile)
+ // 1. Unmount the namespace first.
+ // If this is the last reference to the namespace, the kernel will destroy it.
+ if err := unix.Unmount(nsPath, 0); err != nil {
+ return fmt.Errorf("failed to unmount namespace %s: %w", nsPath, err)
+ }
- // Unlink the namespace file
+ // 2. Remove the mount point file.
if err := os.Remove(nsPath); err != nil {
- return fmt.Errorf("failed to unpin namespace %s: %w", nsPath, err)
+ return fmt.Errorf("failed to remove pin file %s: %w", nsPath, err)
}
+ pidsDir := GetPidsDirPath(pm, profile)
+
// Try to remove pids directory and empty parent directories
_ = os.Remove(pidsDir)
_ = os.Remove(filepath.Dir(pidsDir))