mirror of
https://github.com/fosrl/newt.git
synced 2026-02-07 21:46:39 +00:00
Check permissions
This commit is contained in:
12
clients.go
12
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 {
|
||||
|
||||
18
clients/permissions/permissions_darwin.go
Normal file
18
clients/permissions/permissions_darwin.go
Normal file
@@ -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")
|
||||
}
|
||||
96
clients/permissions/permissions_linux.go
Normal file
96
clients/permissions/permissions_linux.go
Normal file
@@ -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<<CAP_NET_ADMIN) != 0 {
|
||||
logger.Debug("Process has CAP_NET_ADMIN capability, sufficient permissions for native TUN interface")
|
||||
return nil
|
||||
}
|
||||
logger.Debug("Process does not have CAP_NET_ADMIN capability in effective set")
|
||||
}
|
||||
|
||||
// Actually try to create a TUN interface to verify permissions
|
||||
// This is the most reliable check as it tests the actual operation
|
||||
return tryCreateTestTun()
|
||||
}
|
||||
|
||||
// tryCreateTestTun attempts to create a temporary TUN interface to verify
|
||||
// we have the necessary permissions. This tests the actual ioctl call that
|
||||
// will be used when creating the real interface.
|
||||
func tryCreateTestTun() error {
|
||||
f, err := os.OpenFile(tunDevice, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot open %s: %v (need root or CAP_NET_ADMIN capability)", tunDevice, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Try to create a TUN interface with a test name
|
||||
// Using a random-ish name to avoid conflicts
|
||||
var req ifReq
|
||||
copy(req.Name[:], "tuntest0")
|
||||
req.Flags = iffTun | iffNoPi
|
||||
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
f.Fd(),
|
||||
uintptr(tunSetIff),
|
||||
uintptr(unsafe.Pointer(&req)),
|
||||
)
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("cannot create TUN interface (ioctl TUNSETIFF failed): %v (need root or CAP_NET_ADMIN capability)", errno)
|
||||
}
|
||||
|
||||
// Success - the interface will be automatically destroyed when we close the fd
|
||||
logger.Debug("Successfully created test TUN interface, sufficient permissions for native TUN interface")
|
||||
return nil
|
||||
}
|
||||
38
clients/permissions/permissions_windows.go
Normal file
38
clients/permissions/permissions_windows.go
Normal file
@@ -0,0 +1,38 @@
|
||||
//go:build windows
|
||||
|
||||
package permissions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// CheckNativeInterfacePermissions checks if the process has sufficient
|
||||
// permissions to create a native TUN interface on Windows.
|
||||
// This requires Administrator privileges.
|
||||
func CheckNativeInterfacePermissions() error {
|
||||
var sid *windows.SID
|
||||
err := windows.AllocateAndInitializeSid(
|
||||
&windows.SECURITY_NT_AUTHORITY,
|
||||
2,
|
||||
windows.SECURITY_BUILTIN_DOMAIN_RID,
|
||||
windows.DOMAIN_ALIAS_RID_ADMINS,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
&sid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize SID: %v", err)
|
||||
}
|
||||
defer windows.FreeSid(sid)
|
||||
|
||||
token := windows.Token(0)
|
||||
member, err := token.IsMember(sid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check admin group membership: %v", err)
|
||||
}
|
||||
|
||||
if !member {
|
||||
return fmt.Errorf("insufficient permissions: need Administrator to create TUN interface on Windows")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
2
main.go
2
main.go
@@ -236,7 +236,7 @@ func main() {
|
||||
flag.StringVar(&interfaceName, "interface", "newt", "Name of the WireGuard interface")
|
||||
}
|
||||
if useNativeInterfaceEnv == "" {
|
||||
flag.BoolVar(&useNativeInterface, "native", false, "Use native WireGuard interface (requires WireGuard kernel module) and linux")
|
||||
flag.BoolVar(&useNativeInterface, "native", false, "Use native WireGuard interface")
|
||||
}
|
||||
if disableClientsEnv == "" {
|
||||
flag.BoolVar(&disableClients, "disable-clients", false, "Disable clients on the WireGuard interface")
|
||||
|
||||
Reference in New Issue
Block a user