Add set system proxy support for macOS

This commit is contained in:
世界
2022-08-04 22:01:20 +08:00
parent 64dbac8138
commit f691bd5ce1
21 changed files with 225 additions and 174 deletions

View File

@@ -13,3 +13,9 @@ func runCommand(name string, args ...string) error {
command.Stderr = os.Stderr
return command.Run()
}
func readCommand(name string, args ...string) ([]byte, error) {
command := exec.Command(name, args...)
command.Env = os.Environ()
return command.CombinedOutput()
}

View File

@@ -4,6 +4,7 @@ import (
"os"
"strings"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
F "github.com/sagernet/sing/common/format"
)
@@ -30,10 +31,12 @@ func runAndroidShell(name string, args ...string) error {
}
}
func ClearSystemProxy() error {
return runAndroidShell("settings", "put", "global", "http_proxy", ":0")
}
func SetSystemProxy(port uint16, mixed bool) error {
return runAndroidShell("settings", "put", "global", "http_proxy", F.ToString("127.0.0.1:", port))
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))
if err != nil {
return nil, err
}
return func() error {
return runAndroidShell("settings", "put", "global", "http_proxy", ":0")
}, nil
}

View File

@@ -0,0 +1,98 @@
package settings
import (
"strings"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-tun"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/x/list"
)
type systemProxy struct {
monitor tun.DefaultInterfaceMonitor
interfaceName string
element *list.Element[tun.DefaultInterfaceUpdateCallback]
port uint16
isMixed bool
}
func (p *systemProxy) update() error {
newInterfaceName := p.monitor.DefaultInterfaceName()
if p.interfaceName == newInterfaceName {
return nil
}
if p.interfaceName != "" {
_ = p.unset()
}
p.interfaceName = newInterfaceName
interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
if err != nil {
return err
}
if p.isMixed {
err = runCommand("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port))
}
if err == nil {
err = runCommand("networksetup", "-setwebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port))
}
if err == nil {
err = runCommand("networksetup", "-setsecurewebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port))
}
return err
}
func (p *systemProxy) unset() error {
interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
if err != nil {
return err
}
if p.isMixed {
err = runCommand("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off")
}
if err == nil {
err = runCommand("networksetup", "-setwebproxystate", interfaceDisplayName, "off")
}
if err == nil {
err = runCommand("networksetup", "-setsecurewebproxystate", interfaceDisplayName, "off")
}
return err
}
func getInterfaceDisplayName(name string) (string, error) {
content, err := readCommand("networksetup", "-listallhardwareports")
if err != nil {
return "", err
}
for _, deviceSpan := range strings.Split(string(content), "Ethernet Address") {
if strings.Contains(deviceSpan, "Device: "+name) {
substr := "Hardware Port: "
deviceSpan = deviceSpan[strings.Index(deviceSpan, substr)+len(substr):]
deviceSpan = deviceSpan[:strings.Index(deviceSpan, "\n")]
return deviceSpan, nil
}
}
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,
}
err := proxy.update()
if err != nil {
return nil, err
}
proxy.element = interfaceMonitor.RegisterCallback(proxy.update)
return func() error {
interfaceMonitor.UnregisterCallback(proxy.element)
return proxy.unset()
}, nil
}

View File

@@ -7,7 +7,7 @@ import (
"os/exec"
"strings"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
@@ -35,42 +35,33 @@ func runAsUser(name string, args ...string) error {
}
}
func ClearSystemProxy() error {
if hasGSettings {
return runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "none")
func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
if !hasGSettings {
return nil, E.New("unsupported desktop environment")
}
return nil
}
func SetSystemProxy(port uint16, mixed bool) error {
if hasGSettings {
err := runAsUser("gsettings", "set", "org.gnome.system.proxy.http", "enabled", "true")
if err != nil {
return err
}
if mixed {
err = setGnomeProxy(port, "ftp", "http", "https", "socks")
if err != nil {
return err
}
} else {
err = setGnomeProxy(port, "http", "https")
if err != nil {
return err
}
}
err = runAsUser("gsettings", "set", "org.gnome.system.proxy", "use-same-proxy", F.ToString(mixed))
if err != nil {
return err
}
err = runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "manual")
if err != nil {
return err
}
err := runAsUser("gsettings", "set", "org.gnome.system.proxy.http", "enabled", "true")
if err != nil {
return nil, err
}
if isMixed {
err = setGnomeProxy(port, "ftp", "http", "https", "socks")
} else {
log.Warn("set system proxy: unsupported desktop environment")
err = setGnomeProxy(port, "http", "https")
}
return nil
if err != nil {
return nil, err
}
err = runAsUser("gsettings", "set", "org.gnome.system.proxy", "use-same-proxy", F.ToString(isMixed))
if err != nil {
return nil, err
}
err = runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "manual")
if err != nil {
return nil, err
}
return func() error {
return runAsUser("gsettings", "set", "org.gnome.system.proxy", "mode", "none")
}, nil
}
func setGnomeProxy(port uint16, proxyTypes ...string) error {

View File

@@ -1,14 +1,13 @@
//go:build !windows && !linux
//go:build !(windows || linux || darwin)
package settings
import "github.com/sagernet/sing-box/log"
import (
"os"
func ClearSystemProxy() error {
return nil
}
"github.com/sagernet/sing-box/adapter"
)
func SetSystemProxy(port uint16, mixed bool) error {
log.Warn("set system proxy: unsupported operating system")
return nil
func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
return nil, os.ErrInvalid
}

View File

@@ -1,14 +1,17 @@
package settings
import (
"github.com/sagernet/sing-box/adapter"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/wininet"
)
func ClearSystemProxy() error {
return wininet.ClearSystemProxy()
}
func SetSystemProxy(port uint16, mixed bool) error {
return wininet.SetSystemProxy(F.ToString("http://127.0.0.1:", port), "local")
func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
err := wininet.SetSystemProxy(F.ToString("http://127.0.0.1:", port), "local")
if err != nil {
return nil, err
}
return func() error {
return wininet.ClearSystemProxy()
}, nil
}