github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/common/settings/proxy_darwin.go (about) 1 package settings 2 3 import ( 4 "context" 5 "net/netip" 6 "strings" 7 8 "github.com/inazumav/sing-box/adapter" 9 "github.com/sagernet/sing-tun" 10 E "github.com/sagernet/sing/common/exceptions" 11 M "github.com/sagernet/sing/common/metadata" 12 "github.com/sagernet/sing/common/shell" 13 "github.com/sagernet/sing/common/x/list" 14 ) 15 16 type DarwinSystemProxy struct { 17 monitor tun.DefaultInterfaceMonitor 18 interfaceName string 19 element *list.Element[tun.DefaultInterfaceUpdateCallback] 20 serverAddr M.Socksaddr 21 supportSOCKS bool 22 isEnabled bool 23 } 24 25 func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*DarwinSystemProxy, error) { 26 interfaceMonitor := adapter.RouterFromContext(ctx).InterfaceMonitor() 27 if interfaceMonitor == nil { 28 return nil, E.New("missing interface monitor") 29 } 30 proxy := &DarwinSystemProxy{ 31 monitor: interfaceMonitor, 32 serverAddr: serverAddr, 33 supportSOCKS: supportSOCKS, 34 } 35 proxy.element = interfaceMonitor.RegisterCallback(proxy.update) 36 return proxy, nil 37 } 38 39 func (p *DarwinSystemProxy) IsEnabled() bool { 40 return p.isEnabled 41 } 42 43 func (p *DarwinSystemProxy) Enable() error { 44 return p.update0() 45 } 46 47 func (p *DarwinSystemProxy) Disable() error { 48 interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName) 49 if err != nil { 50 return err 51 } 52 if p.supportSOCKS { 53 err = shell.Exec("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off").Attach().Run() 54 } 55 if err == nil { 56 err = shell.Exec("networksetup", "-setwebproxystate", interfaceDisplayName, "off").Attach().Run() 57 } 58 if err == nil { 59 err = shell.Exec("networksetup", "-setsecurewebproxystate", interfaceDisplayName, "off").Attach().Run() 60 } 61 if err == nil { 62 p.isEnabled = false 63 } 64 return err 65 } 66 67 func (p *DarwinSystemProxy) update(event int) { 68 if event&tun.EventInterfaceUpdate == 0 { 69 return 70 } 71 if !p.isEnabled { 72 return 73 } 74 _ = p.update0() 75 } 76 77 func (p *DarwinSystemProxy) update0() error { 78 newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified()) 79 if p.interfaceName == newInterfaceName { 80 return nil 81 } 82 if p.interfaceName != "" { 83 _ = p.Disable() 84 } 85 p.interfaceName = newInterfaceName 86 interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName) 87 if err != nil { 88 return err 89 } 90 if p.supportSOCKS { 91 err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, p.serverAddr.String()).Attach().Run() 92 } 93 if err != nil { 94 return err 95 } 96 err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, p.serverAddr.String()).Attach().Run() 97 if err != nil { 98 return err 99 } 100 err = shell.Exec("networksetup", "-setsecurewebproxy", interfaceDisplayName, p.serverAddr.String()).Attach().Run() 101 if err != nil { 102 return err 103 } 104 p.isEnabled = true 105 return nil 106 } 107 108 func getInterfaceDisplayName(name string) (string, error) { 109 content, err := shell.Exec("networksetup", "-listallhardwareports").ReadOutput() 110 if err != nil { 111 return "", err 112 } 113 for _, deviceSpan := range strings.Split(string(content), "Ethernet Address") { 114 if strings.Contains(deviceSpan, "Device: "+name) { 115 substr := "Hardware Port: " 116 deviceSpan = deviceSpan[strings.Index(deviceSpan, substr)+len(substr):] 117 deviceSpan = deviceSpan[:strings.Index(deviceSpan, "\n")] 118 return deviceSpan, nil 119 } 120 } 121 return "", E.New(name, " not found in networksetup -listallhardwareports") 122 }