From 78059b43e3d00a0f2b75677461692745cce34a63 Mon Sep 17 00:00:00 2001 From: James O'Doherty Date: Thu, 4 Jun 2026 23:09:46 -0400 Subject: refactor: remove dependency on ip CLI tool and abstract network logic Eliminate the external dependency on the `ip` (iproute2) command-line tool by centralizing network configuration and diagnostics within a new `internal/network` package using the `netlink` library. Changes: - Introduced `internal/network` package to handle network interface listing and configuration. - Replaced `exec.Command("ip", "link")` in `internal/namespace.VerifyIsolation` with `network.ListInterfaces()`. - Improved `VerifyIsolation` to explicitly ensure only the loopback interface is present in a fresh network namespace. - Moved interface and routing configuration logic from `internal/wireguard` to `internal/network`. - Removed unnecessary `os/exec` imports from network-related files. This change increases the tool's portability by removing the requirement for `iproute2` to be installed in the target environment. --- internal/namespace/namespace.go | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'internal/namespace/namespace.go') diff --git a/internal/namespace/namespace.go b/internal/namespace/namespace.go index a50f70a..45eba73 100644 --- a/internal/namespace/namespace.go +++ b/internal/namespace/namespace.go @@ -26,9 +26,9 @@ import ( "fmt" "net" "os" - "os/exec" "syscall" + "git.theodohertyfamily.com/wg-wrap/internal/network" "golang.org/x/sys/unix" ) @@ -50,21 +50,29 @@ func VerifyIsolation() (bool, string) { // 2. Check Network Isolation // We expect a fresh network namespace to have only the loopback interface. - // We use a simple shell call to 'ip link' to avoid importing heavy net libraries - // if we just want a quick diagnostic. - cmd := exec.Command("ip", "link") - out, err := cmd.CombinedOutput() + interfaces, err := network.ListInterfaces() if err != nil { - return false, fmt.Sprintf("failed to execute ip link: %v", err) + return false, fmt.Sprintf("failed to list interfaces: %v", err) } // In a fresh netns, we typically only see 'lo'. - // We check if any common host interfaces (eth, wlan, br, enp) appear. - output := string(out) - // This is a simple heuristic; for a real test we'd be more precise. - // We are looking for evidence of host interfaces. - if len(output) == 0 { - return false, "ip link returned no output" + // If we see more than just loopback, or loopback is missing, it might not be isolated. + if len(interfaces) == 0 { + return false, "no network interfaces found" + } + + hasLo := false + for _, iface := range interfaces { + if iface.Name == "lo" { + hasLo = true + } else { + // If we find any other interface (eth0, wlan0, etc.), we aren't isolated. + return false, fmt.Sprintf("detected non-isolated interface: %s", iface.Name) + } + } + + if !hasLo { + return false, "loopback interface missing" } // 3. Check Filesystem Transparency -- cgit v1.2.3