Skip to content

Commit 5d8af15

Browse files
committed
Improve system proxy API
1 parent 69499a5 commit 5d8af15

File tree

7 files changed

+268
-135
lines changed

7 files changed

+268
-135
lines changed

common/settings/proxy_android.go

+47-17
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,73 @@
11
package settings
22

33
import (
4+
"context"
45
"os"
56
"strings"
67

7-
"github.com/sagernet/sing-box/adapter"
88
C "github.com/sagernet/sing-box/constant"
9+
E "github.com/sagernet/sing/common/exceptions"
910
F "github.com/sagernet/sing/common/format"
11+
M "github.com/sagernet/sing/common/metadata"
1012
"github.com/sagernet/sing/common/shell"
1113
)
1214

13-
var (
14-
useRish bool
15-
rishPath string
16-
)
15+
type AndroidSystemProxy struct {
16+
useRish bool
17+
rishPath string
18+
serverAddr M.Socksaddr
19+
supportSOCKS bool
20+
isEnabled bool
21+
}
1722

18-
func init() {
23+
func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*AndroidSystemProxy, error) {
1924
userId := os.Getuid()
25+
var (
26+
useRish bool
27+
rishPath string
28+
)
2029
if userId == 0 || userId == 1000 || userId == 2000 {
2130
useRish = false
2231
} else {
2332
rishPath, useRish = C.FindPath("rish")
33+
if !useRish {
34+
return nil, E.Cause(os.ErrPermission, "root or system (adb) permission is required for set system proxy")
35+
}
2436
}
37+
return &AndroidSystemProxy{
38+
useRish: useRish,
39+
rishPath: rishPath,
40+
serverAddr: serverAddr,
41+
supportSOCKS: supportSOCKS,
42+
}, nil
2543
}
2644

27-
func runAndroidShell(name string, args ...string) error {
28-
if !useRish {
29-
return shell.Exec(name, args...).Attach().Run()
30-
} else {
31-
return shell.Exec("sh", rishPath, "-c", F.ToString(name, " ", strings.Join(args, " "))).Attach().Run()
45+
func (p *AndroidSystemProxy) IsEnabled() bool {
46+
return p.isEnabled
47+
}
48+
49+
func (p *AndroidSystemProxy) Enable() error {
50+
err := p.runAndroidShell("settings", "put", "global", "http_proxy", p.serverAddr.String())
51+
if err != nil {
52+
return err
3253
}
54+
p.isEnabled = true
55+
return nil
3356
}
3457

35-
func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() error, error) {
36-
err := runAndroidShell("settings", "put", "global", "http_proxy", F.ToString("127.0.0.1:", port))
58+
func (p *AndroidSystemProxy) Disable() error {
59+
err := p.runAndroidShell("settings", "put", "global", "http_proxy", ":0")
3760
if err != nil {
38-
return nil, err
61+
return err
62+
}
63+
p.isEnabled = false
64+
return nil
65+
}
66+
67+
func (p *AndroidSystemProxy) runAndroidShell(name string, args ...string) error {
68+
if !p.useRish {
69+
return shell.Exec(name, args...).Attach().Run()
70+
} else {
71+
return shell.Exec("sh", p.rishPath, "-c", F.ToString(name, " ", strings.Join(args, " "))).Attach().Run()
3972
}
40-
return func() error {
41-
return runAndroidShell("settings", "put", "global", "http_proxy", ":0")
42-
}, nil
4373
}

common/settings/proxy_darwin.go

+69-43
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,109 @@
11
package settings
22

33
import (
4+
"context"
45
"net/netip"
6+
"strconv"
57
"strings"
68

79
"github.com/sagernet/sing-box/adapter"
810
"github.com/sagernet/sing-tun"
911
E "github.com/sagernet/sing/common/exceptions"
10-
F "github.com/sagernet/sing/common/format"
12+
M "github.com/sagernet/sing/common/metadata"
1113
"github.com/sagernet/sing/common/shell"
1214
"github.com/sagernet/sing/common/x/list"
1315
)
1416

15-
type systemProxy struct {
17+
type DarwinSystemProxy struct {
1618
monitor tun.DefaultInterfaceMonitor
1719
interfaceName string
1820
element *list.Element[tun.DefaultInterfaceUpdateCallback]
19-
port uint16
20-
isMixed bool
21+
serverAddr M.Socksaddr
22+
supportSOCKS bool
23+
isEnabled bool
2124
}
2225

23-
func (p *systemProxy) update(event int) {
24-
newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified())
25-
if p.interfaceName == newInterfaceName {
26-
return
26+
func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*DarwinSystemProxy, error) {
27+
interfaceMonitor := adapter.RouterFromContext(ctx).InterfaceMonitor()
28+
if interfaceMonitor == nil {
29+
return nil, E.New("missing interface monitor")
2730
}
28-
if p.interfaceName != "" {
29-
_ = p.unset()
31+
proxy := &DarwinSystemProxy{
32+
monitor: interfaceMonitor,
33+
serverAddr: serverAddr,
34+
supportSOCKS: supportSOCKS,
3035
}
31-
p.interfaceName = newInterfaceName
36+
proxy.element = interfaceMonitor.RegisterCallback(proxy.update)
37+
return proxy, nil
38+
}
39+
40+
func (p *DarwinSystemProxy) IsEnabled() bool {
41+
return p.isEnabled
42+
}
43+
44+
func (p *DarwinSystemProxy) Enable() error {
45+
return p.update0()
46+
}
47+
48+
func (p *DarwinSystemProxy) Disable() error {
3249
interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
3350
if err != nil {
34-
return
51+
return err
3552
}
36-
if p.isMixed {
37-
err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run()
53+
if p.supportSOCKS {
54+
err = shell.Exec("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off").Attach().Run()
3855
}
3956
if err == nil {
40-
err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run()
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()
4161
}
4262
if err == nil {
43-
_ = shell.Exec("networksetup", "-setsecurewebproxy", interfaceDisplayName, "127.0.0.1", F.ToString(p.port)).Attach().Run()
63+
p.isEnabled = false
64+
}
65+
return err
66+
}
67+
68+
func (p *DarwinSystemProxy) update(event int) {
69+
if event&tun.EventInterfaceUpdate == 0 {
70+
return
71+
}
72+
if !p.isEnabled {
73+
return
4474
}
45-
return
75+
_ = p.update0()
4676
}
4777

48-
func (p *systemProxy) unset() error {
78+
func (p *DarwinSystemProxy) update0() error {
79+
newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified())
80+
if p.interfaceName == newInterfaceName {
81+
return nil
82+
}
83+
if p.interfaceName != "" {
84+
_ = p.Disable()
85+
}
86+
p.interfaceName = newInterfaceName
4987
interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
5088
if err != nil {
5189
return err
5290
}
53-
if p.isMixed {
54-
err = shell.Exec("networksetup", "-setsocksfirewallproxystate", interfaceDisplayName, "off").Attach().Run()
91+
if p.supportSOCKS {
92+
err = shell.Exec("networksetup", "-setsocksfirewallproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
5593
}
56-
if err == nil {
57-
err = shell.Exec("networksetup", "-setwebproxystate", interfaceDisplayName, "off").Attach().Run()
94+
if err != nil {
95+
return err
5896
}
59-
if err == nil {
60-
err = shell.Exec("networksetup", "-setsecurewebproxystate", interfaceDisplayName, "off").Attach().Run()
97+
err = shell.Exec("networksetup", "-setwebproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
98+
if err != nil {
99+
return err
61100
}
62-
return err
101+
err = shell.Exec("networksetup", "-setsecurewebproxy", interfaceDisplayName, p.serverAddr.AddrString(), strconv.Itoa(int(p.serverAddr.Port))).Attach().Run()
102+
if err != nil {
103+
return err
104+
}
105+
p.isEnabled = true
106+
return nil
63107
}
64108

65109
func getInterfaceDisplayName(name string) (string, error) {
@@ -77,21 +121,3 @@ func getInterfaceDisplayName(name string) (string, error) {
77121
}
78122
return "", E.New(name, " not found in networksetup -listallhardwareports")
79123
}
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-
proxy.update(tun.EventInterfaceUpdate)
92-
proxy.element = interfaceMonitor.RegisterCallback(proxy.update)
93-
return func() error {
94-
interfaceMonitor.UnregisterCallback(proxy.element)
95-
return proxy.unset()
96-
}, nil
97-
}

0 commit comments

Comments
 (0)