浏览代码

WireGuard kernelTun: Check Capabilities instead of checking UID (#3871)

https://github.com/XTLS/Xray-core/pull/3871#issuecomment-2412820323

---------

Co-authored-by: RPRX <[email protected]>
チセ 1 年之前
父节点
当前提交
19f3f709b2
共有 3 个文件被更改,包括 27 次插入11 次删除
  1. 15 4
      infra/conf/wireguard.go
  2. 2 2
      proxy/wireguard/tun_default.go
  3. 10 5
      proxy/wireguard/tun_linux.go

+ 15 - 4
infra/conf/wireguard.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/base64"
 	"encoding/hex"
+	"fmt"
 	"strings"
 
 	"github.com/xtls/xray-core/common/errors"
@@ -52,6 +53,7 @@ func (c *WireGuardPeerConfig) Build() (proto.Message, error) {
 type WireGuardConfig struct {
 	IsClient bool `json:""`
 
+	KernelTun      *bool                  `json:"kernelTun"`
 	KernelMode     *bool                  `json:"kernelMode"`
 	SecretKey      string                 `json:"secretKey"`
 	Address        []string               `json:"address"`
@@ -119,15 +121,24 @@ func (c *WireGuardConfig) Build() (proto.Message, error) {
 	}
 
 	config.IsClient = c.IsClient
+	kernelTunSupported, err := wireguard.KernelTunSupported()
+	if err != nil {
+		errors.LogWarning(context.Background(), fmt.Sprintf("Failed to check kernel TUN support: %v. This may indicate that your OS doesn't support kernel TUN or you lack the necessary permissions. Please ensure you have the required privileges.", err))
+		config.KernelMode = false
+		return config, nil
+	}
+	if c.KernelMode == nil {
+		c.KernelMode = c.KernelTun
+	}
 	if c.KernelMode != nil {
 		config.KernelMode = *c.KernelMode
-		if config.KernelMode && !wireguard.KernelTunSupported() {
-			errors.LogWarning(context.Background(), "kernel mode is not supported on your OS or permission is insufficient")
+		if config.KernelMode && !kernelTunSupported {
+			errors.LogWarning(context.Background(), "kernel TUN is not supported on your OS or permission is insufficient")
 		}
 	} else {
-		config.KernelMode = wireguard.KernelTunSupported()
+		config.KernelMode = kernelTunSupported
 		if config.KernelMode {
-			errors.LogDebug(context.Background(), "kernel mode is enabled as it's supported and permission is sufficient")
+			errors.LogDebug(context.Background(), "kernel TUN is enabled as it's supported and permission is sufficient")
 		}
 	}
 

+ 2 - 2
proxy/wireguard/tun_default.go

@@ -11,6 +11,6 @@ func createKernelTun(localAddresses []netip.Addr, mtu int, handler promiscuousMo
 	return nil, errors.New("not implemented")
 }
 
-func KernelTunSupported() bool {
-	return false
+func KernelTunSupported() (bool, error) {
+	return false, nil
 }

+ 10 - 5
proxy/wireguard/tun_linux.go

@@ -231,10 +231,15 @@ func createKernelTun(localAddresses []netip.Addr, mtu int, handler promiscuousMo
 	return out, nil
 }
 
-func KernelTunSupported() bool {
-	// run a superuser permission check to check
-	// if the current user has the sufficient permission
-	// to create a tun device.
+func KernelTunSupported() (bool, error) {
+	var hdr unix.CapUserHeader
+	hdr.Version = unix.LINUX_CAPABILITY_VERSION_3
+	hdr.Pid = 0 // 0 means current process
 
-	return unix.Geteuid() == 0 // 0 means root
+	var data unix.CapUserData
+	if err := unix.Capget(&hdr, &data); err != nil {
+		return false, fmt.Errorf("failed to get capabilities: %v", err)
+	}
+
+	return (data.Effective & (1 << unix.CAP_NET_ADMIN)) != 0, nil
 }