github.com/sagernet/sing-box@v1.2.7/common/settings/proxy_darwin.go (about) 1 package settings 2 3 import ( 4 "net/netip" 5 "strings" 6 7 "github.com/sagernet/sing-box/adapter" 8 "github.com/sagernet/sing-tun" 9 E "github.com/sagernet/sing/common/exceptions" 10 F "github.com/sagernet/sing/common/format" 11 "github.com/sagernet/sing/common/shell" 12 "github.com/sagernet/sing/common/x/list" 13 ) 14 15 type systemProxy struct { 16 monitor tun.DefaultInterfaceMonitor 17 interfaceName string 18 element *list.Element[tun.DefaultInterfaceUpdateCallback] 19 port uint16 20 isMixed bool 21 } 22 23 func (p *systemProxy) update(event int) error { 24 newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified()) 25 if p.interfaceName == newInterfaceName { 26 return nil 27 } 28 if p.interfaceName != "" { 29 _ = p.unset() 30 } 31 p.interfaceName = newInterfaceName 32 interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName) 33 if err != nil { 34 return err 35 } 36 if p.isMixed { 37 err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run() 38 } 39 if err == nil { 40 err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run() 41 } 42 if err == nil { 43 err = shell.Exec("networksetup", "-setsecurewebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run() 44 } 45 return err 46 } 47 48 func (p *systemProxy) unset() error { 49 interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName) 50 if err != nil { 51 return err 52 } 53 if p.isMixed { 54 err = shell.Exec("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off").Attach().Run() 55 } 56 if err == nil { 57 err = shell.Exec("networksetup", "-setwebproxystate", interfaceDisplayName, "off").Attach().Run() 58 } 59 if err == nil { 60 err = shell.Exec("networksetup", "-setsecurewebproxystate", interfaceDisplayName, "off").Attach().Run() 61 } 62 return err 63 } 64 65 func getInterfaceDisplayName(name string) (string, error) { 66 content, err := shell.Exec("networksetup", "-listallhardwareports").ReadOutput() 67 if err != nil { 68 return "", err 69 } 70 for _, deviceSpan := range strings.Split(string(content), "Ethernet Address") { 71 if strings.Contains(deviceSpan, "Device: "+name) { 72 substr := "Hardware Port: " 73 deviceSpan = deviceSpan[strings.Index(deviceSpan, substr)+len(substr):] 74 deviceSpan = deviceSpan[:strings.Index(deviceSpan, "\n")] 75 return deviceSpan, nil 76 } 77 } 78 return "", E.New(name, " not found in networksetup -listallhardwareports") 79 } 80 81 func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) { 82 interfaceMonitor := router.InterfaceMonitor() 83 if interfaceMonitor == nil { 84 return nil, E.New("missing interface monitor") 85 } 86 proxy := &systemProxy{ 87 monitor: interfaceMonitor, 88 port: port, 89 isMixed: isMixed, 90 } 91 err := proxy.update(tun.EventInterfaceUpdate) 92 if err != nil { 93 return nil, err 94 } 95 proxy.element = interfaceMonitor.RegisterCallback(proxy.update) 96 return func() error { 97 interfaceMonitor.UnregisterCallback(proxy.element) 98 return proxy.unset() 99 }, nil 100 }