diff --git a/cmd/tun2socks/main.go b/cmd/tun2socks/main.go index 12d29782..645180ef 100644 --- a/cmd/tun2socks/main.go +++ b/cmd/tun2socks/main.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "flag" "fmt" "io" @@ -75,7 +76,7 @@ func (a *CmdArgs) addFlag(f cmdFlag) { if fn, found := flagCreaters[f]; found && fn != nil { fn() } else { - log.Fatalf("unsupported flag") + fatal("unsupported flag") } } @@ -85,6 +86,22 @@ const ( maxMTU = 65535 ) +func fatal(err interface{}) { + if runtime.GOOS == "windows" { + // Escalated privileges in windows opens a new terminal, and if there is an + // error, it is impossible to see it. Thus we wait for user to press a button. + log.Errorf("%s, press enter to exit", err) + bufio.NewReader(os.Stdin).ReadBytes('\n') + os.Exit(1) + } + switch err := err.(type) { + case error: + log.Fatalf(err.Error()) + case string: + log.Fatalf(err) + } +} + func main() { // linux and darwin pick up the tun index automatically // windows requires the exact tun name @@ -116,6 +133,10 @@ func main() { os.Exit(0) } + if err := checkPermissions(); err != nil { + fatal(err) + } + if *args.TunMTU > maxMTU { fmt.Printf("MTU exceeds %d\n", maxMTU) os.Exit(1) @@ -146,7 +167,7 @@ func main() { err := run() if err != nil { - log.Fatalf("%v", err) + fatal(err) } } diff --git a/cmd/tun2socks/root_others.go b/cmd/tun2socks/root_others.go new file mode 100644 index 00000000..881c37f3 --- /dev/null +++ b/cmd/tun2socks/root_others.go @@ -0,0 +1,15 @@ +// +build !windows + +package main + +import ( + "fmt" + "os" +) + +func checkPermissions() error { + if uid := os.Getuid(); uid != 0 { + return fmt.Errorf("tun2socks needs to run as root") + } + return nil +} diff --git a/cmd/tun2socks/root_windows.go b/cmd/tun2socks/root_windows.go new file mode 100644 index 00000000..9da0022d --- /dev/null +++ b/cmd/tun2socks/root_windows.go @@ -0,0 +1,56 @@ +// +build windows + +package main + +import ( + "fmt" + "os" + "path/filepath" + + "golang.org/x/sys/windows" +) + +const ( + winTun = "wintun.dll" + winTunSite = "https://www.wintun.net/" +) + +func checkPermissions() error { + // https://github.com/golang/go/issues/28804#issuecomment-505326268 + var sid *windows.SID + + // https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-checktokenmembership + 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("error while checking for elevated permissions: %s", err) + } + + // We must free the sid to prevent security token leaks + defer windows.FreeSid(sid) + token := windows.Token(0) + + member, err := token.IsMember(sid) + if err != nil { + return fmt.Errorf("error while checking for elevated permissions: %s", err) + } + if !member { + return fmt.Errorf("tun2socks needs to run with administrator permissions") + } + + err = windows.NewLazyDLL(winTun).Load() + if err != nil { + dir, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + dir = "tun2socks" + } + return fmt.Errorf("the %s was not found, you can download it from %s and place it into the %q directory", winTun, winTunSite, dir) + } + + return nil +} diff --git a/cmd/tun2socks/tun2socks.manifest b/cmd/tun2socks/tun2socks.manifest new file mode 100644 index 00000000..20f793a6 --- /dev/null +++ b/cmd/tun2socks/tun2socks.manifest @@ -0,0 +1,16 @@ + + + +tun2socks requires Administrator privileges + + + + + + + + diff --git a/cmd/tun2socks/tun2socks_windows.syso b/cmd/tun2socks/tun2socks_windows.syso new file mode 100644 index 00000000..f310342d Binary files /dev/null and b/cmd/tun2socks/tun2socks_windows.syso differ