瀏覽代碼

Improve system proxy API

世界 2 年之前
父節點
當前提交
5d8af150a7

+ 47 - 17
common/settings/proxy_android.go

@@ -1,43 +1,73 @@
 package settings
 package settings
 
 
 import (
 import (
+	"context"
 	"os"
 	"os"
 	"strings"
 	"strings"
 
 
-	"github.com/sagernet/sing-box/adapter"
 	C "github.com/sagernet/sing-box/constant"
 	C "github.com/sagernet/sing-box/constant"
+	E "github.com/sagernet/sing/common/exceptions"
 	F "github.com/sagernet/sing/common/format"
 	F "github.com/sagernet/sing/common/format"
+	M "github.com/sagernet/sing/common/metadata"
 	"github.com/sagernet/sing/common/shell"
 	"github.com/sagernet/sing/common/shell"
 )
 )
 
 
-var (
-	useRish  bool
-	rishPath string
-)
+type AndroidSystemProxy struct {
+	useRish      bool
+	rishPath     string
+	serverAddr   M.Socksaddr
+	supportSOCKS bool
+	isEnabled    bool
+}
 
 
-func init() {
+func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*AndroidSystemProxy, error) {
 	userId := os.Getuid()
 	userId := os.Getuid()
+	var (
+		useRish  bool
+		rishPath string
+	)
 	if userId == 0 || userId == 1000 || userId == 2000 {
 	if userId == 0 || userId == 1000 || userId == 2000 {
 		useRish = false
 		useRish = false
 	} else {
 	} else {
 		rishPath, useRish = C.FindPath("rish")
 		rishPath, useRish = C.FindPath("rish")
+		if !useRish {
+			return nil, E.Cause(os.ErrPermission, "root or system (adb) permission is required for set system proxy")
+		}
 	}
 	}
+	return &AndroidSystemProxy{
+		useRish:      useRish,
+		rishPath:     rishPath,
+		serverAddr:   serverAddr,
+		supportSOCKS: supportSOCKS,
+	}, nil
 }
 }
 
 
-func runAndroidShell(name string, args ...string) error {
-	if !useRish {
-		return shell.Exec(name, args...).Attach().Run()
-	} else {
-		return shell.Exec("sh", rishPath, "-c", F.ToString(name, " ", strings.Join(args, " "))).Attach().Run()
+func (p *AndroidSystemProxy) IsEnabled() bool {
+	return p.isEnabled
+}
+
+func (p *AndroidSystemProxy) Enable() error {
+	err := p.runAndroidShell("settings", "put", "global", "http_proxy", p.serverAddr.String())
+	if err != nil {
+		return err
 	}
 	}
+	p.isEnabled = true
+	return nil
 }
 }
 
 
-func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
-	err := runAndroidShell("settings", "put", "global", "http_proxy", F.ToString("127.0.0.1:", port))
+func (p *AndroidSystemProxy) Disable() error {
+	err := p.runAndroidShell("settings", "put", "global", "http_proxy", ":0")
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return err
+	}
+	p.isEnabled = false
+	return nil
+}
+
+func (p *AndroidSystemProxy) runAndroidShell(name string, args ...string) error {
+	if !p.useRish {
+		return shell.Exec(name, args...).Attach().Run()
+	} else {
+		return shell.Exec("sh", p.rishPath, "-c", F.ToString(name, " ", strings.Join(args, " "))).Attach().Run()
 	}
 	}
-	return func() error {
-		return runAndroidShell("settings", "put", "global", "http_proxy", ":0")
-	}, nil
 }
 }

+ 69 - 43
common/settings/proxy_darwin.go

@@ -1,65 +1,109 @@
 package settings
 package settings
 
 
 import (
 import (
+	"context"
 	"net/netip"
 	"net/netip"
+	"strconv"
 	"strings"
 	"strings"
 
 
 	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing-tun"
 	"github.com/sagernet/sing-tun"
 	E "github.com/sagernet/sing/common/exceptions"
 	E "github.com/sagernet/sing/common/exceptions"
-	F "github.com/sagernet/sing/common/format"
+	M "github.com/sagernet/sing/common/metadata"
 	"github.com/sagernet/sing/common/shell"
 	"github.com/sagernet/sing/common/shell"
 	"github.com/sagernet/sing/common/x/list"
 	"github.com/sagernet/sing/common/x/list"
 )
 )
 
 
-type systemProxy struct {
+type DarwinSystemProxy struct {
 	monitor       tun.DefaultInterfaceMonitor
 	monitor       tun.DefaultInterfaceMonitor
 	interfaceName string
 	interfaceName string
 	element       *list.Element[tun.DefaultInterfaceUpdateCallback]
 	element       *list.Element[tun.DefaultInterfaceUpdateCallback]
-	port          uint16
-	isMixed       bool
+	serverAddr    M.Socksaddr
+	supportSOCKS  bool
+	isEnabled     bool
 }
 }
 
 
-func (p *systemProxy) update(event int) {
-	newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified())
-	if p.interfaceName == newInterfaceName {
-		return
+func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*DarwinSystemProxy, error) {
+	interfaceMonitor := adapter.RouterFromContext(ctx).InterfaceMonitor()
+	if interfaceMonitor == nil {
+		return nil, E.New("missing interface monitor")
 	}
 	}
-	if p.interfaceName != "" {
-		_ = p.unset()
+	proxy := &DarwinSystemProxy{
+		monitor:      interfaceMonitor,
+		serverAddr:   serverAddr,
+		supportSOCKS: supportSOCKS,
 	}
 	}
-	p.interfaceName = newInterfaceName
+	proxy.element = interfaceMonitor.RegisterCallback(proxy.update)
+	return proxy, nil
+}
+
+func (p *DarwinSystemProxy) IsEnabled() bool {
+	return p.isEnabled
+}
+
+func (p *DarwinSystemProxy) Enable() error {
+	return p.update0()
+}
+
+func (p *DarwinSystemProxy) Disable() error {
 	interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
 	interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
 	if err != nil {
 	if err != nil {
-		return
+		return err
 	}
 	}
-	if p.isMixed {
-		err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run()
+	if p.supportSOCKS {
+		err = shell.Exec("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off").Attach().Run()
 	}
 	}
 	if err == nil {
 	if err == nil {
-		err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run()
+		err = shell.Exec("networksetup", "-setwebproxystate", interfaceDisplayName, "off").Attach().Run()
+	}
+	if err == nil {
+		err = shell.Exec("networksetup", "-setsecurewebproxystate", interfaceDisplayName, "off").Attach().Run()
 	}
 	}
 	if err == nil {
 	if err == nil {
-		_ = shell.Exec("networksetup", "-setsecurewebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run()
+		p.isEnabled = false
+	}
+	return err
+}
+
+func (p *DarwinSystemProxy) update(event int) {
+	if event&tun.EventInterfaceUpdate == 0 {
+		return
+	}
+	if !p.isEnabled {
+		return
 	}
 	}
-	return
+	_ = p.update0()
 }
 }
 
 
-func (p *systemProxy) unset() error {
+func (p *DarwinSystemProxy) update0() error {
+	newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified())
+	if p.interfaceName == newInterfaceName {
+		return nil
+	}
+	if p.interfaceName != "" {
+		_ = p.Disable()
+	}
+	p.interfaceName = newInterfaceName
 	interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
 	interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	if p.isMixed {
-		err = shell.Exec("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off").Attach().Run()
+	if p.supportSOCKS {
+		err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
 	}
 	}
-	if err == nil {
-		err = shell.Exec("networksetup", "-setwebproxystate", interfaceDisplayName, "off").Attach().Run()
+	if err != nil {
+		return err
 	}
 	}
-	if err == nil {
-		err = shell.Exec("networksetup", "-setsecurewebproxystate", interfaceDisplayName, "off").Attach().Run()
+	err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
+	if err != nil {
+		return err
 	}
 	}
-	return err
+	err = shell.Exec("networksetup", "-setsecurewebproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
+	if err != nil {
+		return err
+	}
+	p.isEnabled = true
+	return nil
 }
 }
 
 
 func getInterfaceDisplayName(name string) (string, error) {
 func getInterfaceDisplayName(name string) (string, error) {
@@ -77,21 +121,3 @@ func getInterfaceDisplayName(name string) (string, error) {
 	}
 	}
 	return "", E.New(name, " not found in networksetup -listallhardwareports")
 	return "", E.New(name, " not found in networksetup -listallhardwareports")
 }
 }
-
-func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
-	interfaceMonitor := router.InterfaceMonitor()
-	if interfaceMonitor == nil {
-		return nil, E.New("missing interface monitor")
-	}
-	proxy := &systemProxy{
-		monitor: interfaceMonitor,
-		port:    port,
-		isMixed: isMixed,
-	}
-	proxy.update(tun.EventInterfaceUpdate)
-	proxy.element = interfaceMonitor.RegisterCallback(proxy.update)
-	return func() error {
-		interfaceMonitor.UnregisterCallback(proxy.element)
-		return proxy.unset()
-	}, nil
-}

+ 91 - 60
common/settings/proxy_linux.go

@@ -3,106 +3,137 @@
 package settings
 package settings
 
 
 import (
 import (
+	"context"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
 
 
-	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing/common"
 	"github.com/sagernet/sing/common"
 	E "github.com/sagernet/sing/common/exceptions"
 	E "github.com/sagernet/sing/common/exceptions"
 	F "github.com/sagernet/sing/common/format"
 	F "github.com/sagernet/sing/common/format"
+	M "github.com/sagernet/sing/common/metadata"
 	"github.com/sagernet/sing/common/shell"
 	"github.com/sagernet/sing/common/shell"
 )
 )
 
 
-var (
-	hasGSettings bool
-	isKDE5       bool
-	sudoUser     string
-)
+type LinuxSystemProxy struct {
+	hasGSettings     bool
+	hasKWriteConfig5 bool
+	sudoUser         string
+	serverAddr       M.Socksaddr
+	supportSOCKS     bool
+	isEnabled        bool
+}
 
 
-func init() {
-	isKDE5 = common.Error(exec.LookPath("kwriteconfig5")) == nil
-	hasGSettings = common.Error(exec.LookPath("gsettings")) == nil
+func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*LinuxSystemProxy, error) {
+	hasGSettings := common.Error(exec.LookPath("gsettings")) == nil
+	hasKWriteConfig5 := common.Error(exec.LookPath("kwriteconfig5")) == nil
+	var sudoUser string
 	if os.Getuid() == 0 {
 	if os.Getuid() == 0 {
 		sudoUser = os.Getenv("SUDO_USER")
 		sudoUser = os.Getenv("SUDO_USER")
 	}
 	}
+	if !hasGSettings && !hasKWriteConfig5 {
+		return nil, E.New("unsupported desktop environment")
+	}
+	return &LinuxSystemProxy{
+		hasGSettings:     hasGSettings,
+		hasKWriteConfig5: hasKWriteConfig5,
+		sudoUser:         sudoUser,
+		serverAddr:       serverAddr,
+		supportSOCKS:     supportSOCKS,
+	}, nil
 }
 }
 
 
-func runAsUser(name string, args ...string) error {
-	if os.Getuid() != 0 {
-		return shell.Exec(name, args...).Attach().Run()
-	} else if sudoUser != "" {
-		return shell.Exec("su", "-", sudoUser, "-c", F.ToString(name, " ", strings.Join(args, " "))).Attach().Run()
-	} else {
-		return E.New("set system proxy: unable to set as root")
-	}
+func (p *LinuxSystemProxy) IsEnabled() bool {
+	return p.isEnabled
 }
 }
 
 
-func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
-	if hasGSettings {
-		err := runAsUser("gsettings", "set", "org.gnome.system.proxy.http", "enabled", "true")
+func (p *LinuxSystemProxy) Enable() error {
+	if p.hasGSettings {
+		err := p.runAsUser("gsettings", "set", "org.gnome.system.proxy.http", "enabled", "true")
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
-		if isMixed {
-			err = setGnomeProxy(port, "ftp", "http", "https", "socks")
+		if p.supportSOCKS {
+			err = p.setGnomeProxy("ftp", "http", "https", "socks")
 		} else {
 		} else {
-			err = setGnomeProxy(port, "http", "https")
+			err = p.setGnomeProxy("http", "https")
 		}
 		}
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
-		err = runAsUser("gsettings", "set", "org.gnome.system.proxy", "use-same-proxy", F.ToString(isMixed))
+		err = p.runAsUser("gsettings", "set", "org.gnome.system.proxy", "use-same-proxy", F.ToString(p.supportSOCKS))
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
-		err = runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "manual")
+		err = p.runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "manual")
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
-		return func() error {
-			return runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "none")
-		}, nil
 	}
 	}
-	if isKDE5 {
-		err := runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "'Proxy Settings'", "--key", "ProxyType", "1")
+	if p.hasKWriteConfig5 {
+		err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "'Proxy Settings'", "--key", "ProxyType", "1")
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
-		if isMixed {
-			err = setKDEProxy(port, "ftp", "http", "https", "socks")
+		if p.supportSOCKS {
+			err = p.setKDEProxy("ftp", "http", "https", "socks")
 		} else {
 		} else {
-			err = setKDEProxy(port, "http", "https")
+			err = p.setKDEProxy("http", "https")
 		}
 		}
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
-		err = runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "'Proxy Settings'", "--key", "Authmode", "0")
+		err = p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "'Proxy Settings'", "--key", "Authmode", "0")
 		if err != nil {
 		if err != nil {
-			return nil, err
+			return err
 		}
 		}
-		err = runAsUser("dbus-send", "--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''")
+		err = p.runAsUser("dbus-send", "--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''")
 		if err != nil {
 		if err != nil {
-			return nil, err
-		}
-		return func() error {
-			err = runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "'Proxy Settings'", "--key", "ProxyType", "0")
-			if err != nil {
-				return err
-			}
-			return runAsUser("dbus-send", "--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''")
-		}, nil
+			return err
+		}
+	}
+	p.isEnabled = true
+	return nil
+}
+
+func (p *LinuxSystemProxy) Disable() error {
+	if p.hasGSettings {
+		err := p.runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "none")
+		if err != nil {
+			return err
+		}
+	}
+	if p.hasKWriteConfig5 {
+		err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "'Proxy Settings'", "--key", "ProxyType", "0")
+		if err != nil {
+			return err
+		}
+		err = p.runAsUser("dbus-send", "--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''")
+		if err != nil {
+			return err
+		}
+	}
+	p.isEnabled = false
+	return nil
+}
+
+func (p *LinuxSystemProxy) runAsUser(name string, args ...string) error {
+	if os.Getuid() != 0 {
+		return shell.Exec(name, args...).Attach().Run()
+	} else if p.sudoUser != "" {
+		return shell.Exec("su", "-", p.sudoUser, "-c", F.ToString(name, " ", strings.Join(args, " "))).Attach().Run()
+	} else {
+		return E.New("set system proxy: unable to set as root")
 	}
 	}
-	return nil, E.New("unsupported desktop environment")
 }
 }
 
 
-func setGnomeProxy(port uint16, proxyTypes ...string) error {
+func (p *LinuxSystemProxy) setGnomeProxy(proxyTypes ...string) error {
 	for _, proxyType := range proxyTypes {
 	for _, proxyType := range proxyTypes {
-		err := runAsUser("gsettings", "set", "org.gnome.system.proxy."+proxyType, "host", "127.0.0.1")
+		err := p.runAsUser("gsettings", "set", "org.gnome.system.proxy."+proxyType, "host", p.serverAddr.AddrString())
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		err = runAsUser("gsettings", "set", "org.gnome.system.proxy."+proxyType, "port", F.ToString(port))
+		err = p.runAsUser("gsettings", "set", "org.gnome.system.proxy."+proxyType, "port", F.ToString(p.serverAddr.Port))
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -110,20 +141,20 @@ func setGnomeProxy(port uint16, proxyTypes ...string) error {
 	return nil
 	return nil
 }
 }
 
 
-func setKDEProxy(port uint16, proxyTypes ...string) error {
+func (p *LinuxSystemProxy) setKDEProxy(proxyTypes ...string) error {
 	for _, proxyType := range proxyTypes {
 	for _, proxyType := range proxyTypes {
 		var proxyUrl string
 		var proxyUrl string
 		if proxyType == "socks" {
 		if proxyType == "socks" {
-			proxyUrl = "socks://127.0.0.1:" + F.ToString(port)
+			proxyUrl = "socks://" + p.serverAddr.String()
 		} else {
 		} else {
-			proxyUrl = "http://127.0.0.1:" + F.ToString(port)
+			proxyUrl = "http://" + p.serverAddr.String()
 		}
 		}
-		err := runAsUser(
+		err := p.runAsUser(
 			"kwriteconfig5",
 			"kwriteconfig5",
 			"--file",
 			"--file",
 			"kioslaverc",
 			"kioslaverc",
 			"--group",
 			"--group",
-			"'Proxy Settings'",
+			"Proxy Settings",
 			"--key", proxyType+"Proxy",
 			"--key", proxyType+"Proxy",
 			proxyUrl,
 			proxyUrl,
 		)
 		)

+ 3 - 2
common/settings/proxy_stub.go

@@ -3,11 +3,12 @@
 package settings
 package settings
 
 
 import (
 import (
+	"context"
 	"os"
 	"os"
 
 
-	"github.com/sagernet/sing-box/adapter"
+	M "github.com/sagernet/sing/common/metadata"
 )
 )
 
 
-func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
+func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (SystemProxy, error) {
 	return nil, os.ErrInvalid
 	return nil, os.ErrInvalid
 }
 }

+ 34 - 8
common/settings/proxy_windows.go

@@ -1,17 +1,43 @@
 package settings
 package settings
 
 
 import (
 import (
-	"github.com/sagernet/sing-box/adapter"
-	F "github.com/sagernet/sing/common/format"
+	"context"
+
+	M "github.com/sagernet/sing/common/metadata"
 	"github.com/sagernet/sing/common/wininet"
 	"github.com/sagernet/sing/common/wininet"
 )
 )
 
 
-func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
-	err := wininet.SetSystemProxy(F.ToString("http://127.0.0.1:", port), "")
+type WindowsSystemProxy struct {
+	serverAddr   M.Socksaddr
+	supportSOCKS bool
+	isEnabled    bool
+}
+
+func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*WindowsSystemProxy, error) {
+	return &WindowsSystemProxy{
+		serverAddr:   serverAddr,
+		supportSOCKS: supportSOCKS,
+	}, nil
+}
+
+func (p *WindowsSystemProxy) IsEnabled() bool {
+	return p.isEnabled
+}
+
+func (p *WindowsSystemProxy) Enable() error {
+	err := wininet.SetSystemProxy("http://"+p.serverAddr.String(), "")
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return err
 	}
 	}
-	return func() error {
-		return wininet.ClearSystemProxy()
-	}, nil
+	p.isEnabled = true
+	return nil
+}
+
+func (p *WindowsSystemProxy) Disable() error {
+	err := wininet.ClearSystemProxy()
+	if err != nil {
+		return err
+	}
+	p.isEnabled = false
+	return nil
 }
 }

+ 7 - 0
common/settings/system_proxy.go

@@ -0,0 +1,7 @@
+package settings
+
+type SystemProxy interface {
+	IsEnabled() bool
+	Enable() error
+	Disable() error
+}

+ 17 - 5
inbound/default.go

@@ -33,8 +33,8 @@ type myInboundAdapter struct {
 
 
 	// http mixed
 	// http mixed
 
 
-	setSystemProxy   bool
-	clearSystemProxy func() error
+	setSystemProxy bool
+	systemProxy    settings.SystemProxy
 
 
 	// internal
 	// internal
 
 
@@ -91,7 +91,19 @@ func (a *myInboundAdapter) Start() error {
 		}
 		}
 	}
 	}
 	if a.setSystemProxy {
 	if a.setSystemProxy {
-		a.clearSystemProxy, err = settings.SetSystemProxy(a.router, M.SocksaddrFromNet(a.tcpListener.Addr()).Port, a.protocol == C.TypeMixed)
+		listenPort := M.SocksaddrFromNet(a.tcpListener.Addr()).Port
+		var listenAddrString string
+		listenAddr := a.listenOptions.Listen.Build()
+		if listenAddr.IsUnspecified() {
+			listenAddrString = "127.0.0.1"
+		} else {
+			listenAddrString = listenAddr.String()
+		}
+		a.systemProxy, err = settings.NewSystemProxy(a.ctx, M.ParseSocksaddrHostPort(listenAddrString, listenPort), a.protocol == C.TypeMixed)
+		if err != nil {
+			return E.Cause(err, "initialize system proxy")
+		}
+		err = a.systemProxy.Enable()
 		if err != nil {
 		if err != nil {
 			return E.Cause(err, "set system proxy")
 			return E.Cause(err, "set system proxy")
 		}
 		}
@@ -102,8 +114,8 @@ func (a *myInboundAdapter) Start() error {
 func (a *myInboundAdapter) Close() error {
 func (a *myInboundAdapter) Close() error {
 	a.inShutdown.Store(true)
 	a.inShutdown.Store(true)
 	var err error
 	var err error
-	if a.clearSystemProxy != nil {
-		err = a.clearSystemProxy()
+	if a.systemProxy != nil && a.systemProxy.IsEnabled() {
+		err = a.systemProxy.Disable()
 	}
 	}
 	return E.Errors(err, common.Close(
 	return E.Errors(err, common.Close(
 		a.tcpListener,
 		a.tcpListener,