Add set system proxy support for macOS
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
98
common/settings/proxy_darwin.go
Normal file
98
common/settings/proxy_darwin.go
Normal 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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user