123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- package settings
- import (
- "context"
- "strconv"
- "strings"
- "github.com/sagernet/sing-box/adapter"
- "github.com/sagernet/sing-tun"
- "github.com/sagernet/sing/common/control"
- E "github.com/sagernet/sing/common/exceptions"
- M "github.com/sagernet/sing/common/metadata"
- "github.com/sagernet/sing/common/shell"
- "github.com/sagernet/sing/common/x/list"
- "github.com/sagernet/sing/service"
- )
- type DarwinSystemProxy struct {
- monitor tun.DefaultInterfaceMonitor
- interfaceName string
- element *list.Element[tun.DefaultInterfaceUpdateCallback]
- serverAddr M.Socksaddr
- supportSOCKS bool
- isEnabled bool
- }
- func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*DarwinSystemProxy, error) {
- interfaceMonitor := service.FromContext[adapter.NetworkManager](ctx).InterfaceMonitor()
- if interfaceMonitor == nil {
- return nil, E.New("missing interface monitor")
- }
- proxy := &DarwinSystemProxy{
- monitor: interfaceMonitor,
- serverAddr: serverAddr,
- supportSOCKS: supportSOCKS,
- }
- proxy.element = interfaceMonitor.RegisterCallback(proxy.routeUpdate)
- 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)
- if err != nil {
- return err
- }
- if p.supportSOCKS {
- err = shell.Exec("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off").Attach().Run()
- }
- if err == nil {
- err = shell.Exec("networksetup", "-setwebproxystate", interfaceDisplayName, "off").Attach().Run()
- }
- if err == nil {
- err = shell.Exec("networksetup", "-setsecurewebproxystate", interfaceDisplayName, "off").Attach().Run()
- }
- if err == nil {
- p.isEnabled = false
- }
- return err
- }
- func (p *DarwinSystemProxy) routeUpdate(defaultInterface *control.Interface, flags int) {
- if !p.isEnabled || defaultInterface == nil {
- return
- }
- _ = p.update0()
- }
- func (p *DarwinSystemProxy) update0() error {
- newInterface := p.monitor.DefaultInterface()
- if p.interfaceName == newInterface.Name {
- return nil
- }
- if p.interfaceName != "" {
- _ = p.Disable()
- }
- p.interfaceName = newInterface.Name
- interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
- if err != nil {
- return err
- }
- if p.supportSOCKS {
- err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
- }
- if err != nil {
- return err
- }
- err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
- if err != nil {
- 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) {
- content, err := shell.Exec("networksetup", "-listallhardwareports").ReadOutput()
- 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")
- }
|