proxy_darwin.go 2.9 KB

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