diff --git a/clients.go b/clients.go index 13f73fc..e95eadb 100644 --- a/clients.go +++ b/clients.go @@ -5,6 +5,7 @@ import ( "github.com/fosrl/newt/clients" wgnetstack "github.com/fosrl/newt/clients" + "github.com/fosrl/newt/clients/permissions" "github.com/fosrl/newt/logger" "github.com/fosrl/newt/netstack2" "github.com/fosrl/newt/websocket" @@ -28,6 +29,17 @@ func setupClients(client *websocket.Client) { host = strings.TrimSuffix(host, "/") logger.Info("Setting up clients with netstack2...") + + // if useNativeInterface is true make sure we have permission to use native interface + if useNativeInterface { + logger.Debug("Checking permissions for native interface") + err := permissions.CheckNativeInterfacePermissions() + if err != nil { + logger.Fatal("Insufficient permissions to create native TUN interface: %v", err) + return + } + } + // Create WireGuard service wgService, err = wgnetstack.NewWireGuardService(interfaceName, mtuInt, host, id, client, dns, useNativeInterface) if err != nil { diff --git a/clients/permissions/permissions_darwin.go b/clients/permissions/permissions_darwin.go new file mode 100644 index 0000000..d14bef4 --- /dev/null +++ b/clients/permissions/permissions_darwin.go @@ -0,0 +1,18 @@ +//go:build darwin + +package permissions + +import ( + "fmt" + "os" +) + +// CheckNativeInterfacePermissions checks if the process has sufficient +// permissions to create a native TUN interface on macOS. +// This typically requires root privileges. +func CheckNativeInterfacePermissions() error { + if os.Geteuid() == 0 { + return nil + } + return fmt.Errorf("insufficient permissions: need root to create TUN interface on macOS") +} diff --git a/clients/permissions/permissions_linux.go b/clients/permissions/permissions_linux.go new file mode 100644 index 0000000..e97ee6a --- /dev/null +++ b/clients/permissions/permissions_linux.go @@ -0,0 +1,96 @@ +//go:build linux + +package permissions + +import ( + "fmt" + "os" + "unsafe" + + "github.com/fosrl/newt/logger" + "golang.org/x/sys/unix" +) + +const ( + // TUN device constants + tunDevice = "/dev/net/tun" + ifnamsiz = 16 + iffTun = 0x0001 + iffNoPi = 0x1000 + tunSetIff = 0x400454ca +) + +// ifReq is the structure for TUNSETIFF ioctl +type ifReq struct { + Name [ifnamsiz]byte + Flags uint16 + _ [22]byte // padding to match kernel structure +} + +// CheckNativeInterfacePermissions checks if the process has sufficient +// permissions to create a native TUN interface on Linux. +// This requires either root privileges (UID 0) or CAP_NET_ADMIN capability. +func CheckNativeInterfacePermissions() error { + logger.Debug("Checking native interface permissions on Linux") + + // Check if running as root + if os.Geteuid() == 0 { + logger.Debug("Running as root, sufficient permissions for native TUN interface") + return nil + } + + // Check for CAP_NET_ADMIN capability + caps := unix.CapUserHeader{ + Version: unix.LINUX_CAPABILITY_VERSION_3, + Pid: 0, // 0 means current process + } + + var data [2]unix.CapUserData + if err := unix.Capget(&caps, &data[0]); err != nil { + logger.Debug("Failed to get capabilities: %v, will try creating test TUN", err) + } else { + // CAP_NET_ADMIN is capability bit 12 + const CAP_NET_ADMIN = 12 + if data[0].Effective&(1<