diff --git a/infra/conf/wireguard.go b/infra/conf/wireguard.go index bba258516c6c..4a189b54e93d 100644 --- a/infra/conf/wireguard.go +++ b/infra/conf/wireguard.go @@ -118,13 +118,13 @@ func (c *WireGuardConfig) Build() (proto.Message, error) { // check device exist for wireguard setup // module "golang.zx2c4.com/wireguard" only support linux and require /dev/net/tun - if !wireguard.CheckWireGuardDeviceRequire() { + if wireguard.IsLinux() && !wireguard.CheckUnixKernelTunDeviceEnabled() { return nil, newError("wireguard module require device /dev/net/tun") } config.IsClient = c.IsClient if c.IsClient { - if support := wireguard.KernelTunSupported(); c.KernelMode == nil { + if support := wireguard.CheckUnixKernelTunSupported(); c.KernelMode == nil { config.KernelMode = support } else if *c.KernelMode && support { config.KernelMode = true diff --git a/proxy/wireguard/check_tun_linux_only.go b/proxy/wireguard/check_tun_linux_only.go deleted file mode 100644 index 5af304becd15..000000000000 --- a/proxy/wireguard/check_tun_linux_only.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build linux && !android - -package wireguard - -import "os" - -func CheckWireGuardDeviceRequire() bool { - if _, err := os.Stat("/dev/net/tun"); err != nil { - return false - } - return true -} diff --git a/proxy/wireguard/check_tun_other.go b/proxy/wireguard/check_tun_other.go deleted file mode 100644 index abeab837b165..000000000000 --- a/proxy/wireguard/check_tun_other.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !linux || android - -package wireguard - -func CheckWireGuardDeviceRequire() bool { - return true -} diff --git a/proxy/wireguard/config.go b/proxy/wireguard/config.go index 2a316cdd7df8..9ddf36e55a7a 100644 --- a/proxy/wireguard/config.go +++ b/proxy/wireguard/config.go @@ -25,7 +25,7 @@ func (c *DeviceConfig) fallbackIP6() bool { } func (c *DeviceConfig) createTun() tunCreator { - if c.KernelMode { + if c.IsClient && c.KernelMode { return createKernelTun } return createGVisorTun diff --git a/proxy/wireguard/tun_default.go b/proxy/wireguard/tun_default.go index 4d0567af0029..61836ebd371f 100644 --- a/proxy/wireguard/tun_default.go +++ b/proxy/wireguard/tun_default.go @@ -1,4 +1,4 @@ -//go:build !linux || android +//go:build !linux package wireguard @@ -8,9 +8,5 @@ import ( ) func createKernelTun(localAddresses []netip.Addr, mtu int, handler promiscuousModeHandler) (t Tunnel, err error) { - return nil, errors.New("not implemented") -} - -func KernelTunSupported() bool { - return false + return nil, errors.New("not implemented kernel tunnel for non-linux system") } diff --git a/proxy/wireguard/tun_linux.go b/proxy/wireguard/tun_linux.go index a3987d4c1928..c03ac2848675 100644 --- a/proxy/wireguard/tun_linux.go +++ b/proxy/wireguard/tun_linux.go @@ -1,4 +1,4 @@ -//go:build linux && !android +//go:build linux package wireguard @@ -8,19 +8,14 @@ import ( "fmt" "net" "net/netip" - "os" - "os/exec" - "strings" "golang.org/x/sys/unix" "github.com/sagernet/sing/common/control" "github.com/vishvananda/netlink" - wgtun "golang.zx2c4.com/wireguard/tun" - "kernel.org/pub/linux/libs/security/libcap/cap" - "github.com/xtls/xray-core/proxy/wireguard/iptables" iptexec "github.com/xtls/xray-core/proxy/wireguard/iptables/exec" + wgtun "golang.zx2c4.com/wireguard/tun" ) type deviceNet struct { @@ -92,7 +87,7 @@ func createKernelTun(localAddresses []netip.Addr, mtu int, handler promiscuousMo x := prefixes v4 = &x } - if v6 == nil && prefixes.Is6() { + if v6 == nil && prefixes.Is6() && CheckUnixKernelIPv6IsEnabled() { x := prefixes v6 = &x } @@ -244,33 +239,3 @@ func createKernelTun(localAddresses []netip.Addr, mtu int, handler promiscuousMo out.tun = wgt return out, nil } - -// KernelTunSupported returns true if kernel tun is supported. -// 1. check if the current process has CAP_NET_ADMIN capability -// 2. check if /proc/sys/net/ipv4/conf/all/src_valid_mark exists and is set to 1 -// 3. check if iptables is available -func KernelTunSupported() bool { - orig := cap.GetProc() - c, err := orig.Dup() - if err != nil { - return false - } - on, _ := c.GetFlag(cap.Effective, cap.NET_ADMIN) - if !on { - return false - } - - buf, _ := os.ReadFile("/proc/sys/net/ipv4/conf/all/src_valid_mark") - value := strings.TrimSpace(string(buf)) - if value != "1" { - return false - } - - outCmd := exec.Command("sh", "-c", "command -v iptables") - outBuffer, err := outCmd.CombinedOutput() - if err != nil { - return false - } - iptablesPath := strings.TrimSpace(string(outBuffer)) - return iptablesPath != "" -} diff --git a/proxy/wireguard/wireguard_linux.go b/proxy/wireguard/wireguard_linux.go new file mode 100644 index 000000000000..2d84b0f1d5b5 --- /dev/null +++ b/proxy/wireguard/wireguard_linux.go @@ -0,0 +1,61 @@ +//go:build linux + +package wireguard + +import ( + "os" + "os/exec" + "strings" + + "kernel.org/pub/linux/libs/security/libcap/cap" +) + +func IsLinux() bool { + return true +} + +func CheckUnixKernelTunDeviceEnabled() bool { + if _, err := os.Stat("/dev/net/tun"); err != nil { + return false + } + return true +} + +func CheckUnixKernelNetAdminCapEnabled() bool { + orig := cap.GetProc() + c, err := orig.Dup() + if err != nil { + return false + } + on, _ := c.GetFlag(cap.Effective, cap.NET_ADMIN) + return on +} + +func CheckUnixKernelIPv4SrcValidMarkEnabled() bool { + buf, _ := os.ReadFile("/proc/sys/net/ipv4/conf/all/src_valid_mark") + value := strings.TrimSpace(string(buf)) + return value == "1" +} + +func CheckUnixKernelIPv6IsEnabled() bool { + buf, _ := os.ReadFile("/proc/sys/net/ipv6/conf/all/disable_ipv6") + value := strings.TrimSpace(string(buf)) + return value == "0" +} + +// CheckUnixKernelTunSupported returns true if kernel tun is supported. +// 1. check if the current process has CAP_NET_ADMIN capability +// 2. check if /proc/sys/net/ipv4/conf/all/src_valid_mark exists and is set to 1 +// 3. check if iptables is available +func CheckUnixKernelTunSupported() bool { + if !CheckUnixKernelTunDeviceEnabled() || !CheckUnixKernelNetAdminCapEnabled() { + return false + } + outCmd := exec.Command("sh", "-c", "command -v iptables") + outBuffer, err := outCmd.CombinedOutput() + if err != nil { + return false + } + iptablesPath := strings.TrimSpace(string(outBuffer)) + return iptablesPath != "" +} diff --git a/proxy/wireguard/wireguard_others.go b/proxy/wireguard/wireguard_others.go new file mode 100644 index 000000000000..9dd8bef1890e --- /dev/null +++ b/proxy/wireguard/wireguard_others.go @@ -0,0 +1,27 @@ +//go:build !linux + +package wireguard + +func IsLinux() bool { + return false +} + +func CheckUnixKernelTunDeviceEnabled() bool { + return true +} + +func CheckUnixKernelNetAdminCapEnabled() bool { + return false +} + +func CheckUnixKernelIPv6IsEnabled() bool { + return false +} + +func CheckUnixKernelIPv4SrcValidMarkEnabled() bool { + return false +} + +func CheckUnixKernelTunSupported() bool { + return false +}