From e5da98fd7fc9f1c426dd4da108b188f8aa24aca7 Mon Sep 17 00:00:00 2001 From: 5aaee9 <7685264+5aaee9@users.noreply.github.com> Date: Sun, 21 Apr 2024 00:27:19 +0800 Subject: [PATCH] fix: darwin system proxy in user mode --- pkgs/proxy/sysproxy/sysproxy_darwin.go | 269 ++++--------------------- pkgs/proxy/sysproxy/sysproxy_test.go | 13 ++ 2 files changed, 52 insertions(+), 230 deletions(-) diff --git a/pkgs/proxy/sysproxy/sysproxy_darwin.go b/pkgs/proxy/sysproxy/sysproxy_darwin.go index 5ce1e42..2ebfc87 100644 --- a/pkgs/proxy/sysproxy/sysproxy_darwin.go +++ b/pkgs/proxy/sysproxy/sysproxy_darwin.go @@ -1,226 +1,35 @@ package sysproxy -/* -#cgo CFLAGS: -x objective-c -fmodules -#cgo LDFLAGS: -framework Foundation -framework SystemConfiguration -#import -#import -#import -#import - -#include -#include -#include - -enum RET_ERRORS { - RET_NO_ERROR = 0, - INVALID_FORMAT = 1, - NO_PERMISSION = 2, - SYSCALL_FAILED = 3, - NO_MEMORY = 4 -}; - -typedef Boolean (*visitor) (SCNetworkProtocolRef proxyProtocolRef, NSDictionary* oldPreferences, NSDictionary* args); - -Boolean showAction(SCNetworkProtocolRef proxyProtocolRef, NSDictionary* oldPreferences, NSDictionary* args) -{ - NSNumber* on = [oldPreferences valueForKey:(NSString*)kSCPropNetProxiesHTTPEnable]; - NSString* nsOldProxyHost = [oldPreferences valueForKey:(NSString*)kSCPropNetProxiesHTTPProxy]; - NSNumber* nsOldProxyPort = [oldPreferences valueForKey:(NSString*)kSCPropNetProxiesHTTPPort]; - if ([on intValue] == 1) { - printf("%s:%d\n", [nsOldProxyHost UTF8String], [nsOldProxyPort intValue]); - } - - return TRUE; -} - -Boolean turnOnAction(SCNetworkProtocolRef proxyProtocolRef, NSDictionary* oldPreferences, NSDictionary* args) { - NSString* nsProxyHost = [args objectForKey:@"host"]; - NSNumber* nsProxyPort = [args objectForKey:@"port"]; - - NSMutableDictionary *newPreferences = [NSMutableDictionary dictionaryWithDictionary: oldPreferences]; - Boolean success; - - [newPreferences setValue: nsProxyHost forKey:(NSString*)kSCPropNetProxiesHTTPProxy]; - [newPreferences setValue: nsProxyHost forKey:(NSString*)kSCPropNetProxiesHTTPSProxy]; - [newPreferences setValue: nsProxyPort forKey:(NSString*)kSCPropNetProxiesHTTPPort]; - [newPreferences setValue: nsProxyPort forKey:(NSString*)kSCPropNetProxiesHTTPSPort]; - [newPreferences setValue:[NSNumber numberWithInt:1] forKey:(NSString*)kSCPropNetProxiesHTTPEnable]; - [newPreferences setValue:[NSNumber numberWithInt:1] forKey:(NSString*)kSCPropNetProxiesHTTPSEnable]; - - success = SCNetworkProtocolSetConfiguration(proxyProtocolRef, (__bridge CFDictionaryRef)newPreferences); - if(!success) { - NSLog(@"Failed to set Protocol Configuration"); - } - return success; -} - -Boolean turnOffAction(SCNetworkProtocolRef proxyProtocolRef, NSDictionary* oldPreferences, NSDictionary* args) { - NSMutableDictionary *newPreferences = [NSMutableDictionary dictionaryWithDictionary: oldPreferences]; - Boolean success; - - [newPreferences setValue:[NSNumber numberWithInt:0] forKey:(NSString*)kSCPropNetProxiesHTTPEnable]; - [newPreferences setValue: @"" forKey:(NSString*)kSCPropNetProxiesHTTPProxy]; - [newPreferences setValue: @"" forKey:(NSString*)kSCPropNetProxiesHTTPPort]; - [newPreferences setValue:[NSNumber numberWithInt:0] forKey:(NSString*)kSCPropNetProxiesHTTPSEnable]; - [newPreferences setValue: @"" forKey:(NSString*)kSCPropNetProxiesHTTPSProxy]; - [newPreferences setValue: @"" forKey:(NSString*)kSCPropNetProxiesHTTPSPort]; - - success = SCNetworkProtocolSetConfiguration(proxyProtocolRef, (__bridge CFDictionaryRef)newPreferences); - if(!success) { - NSLog(@"Failed to set Protocol Configuration"); - } - return success; -} - -NSDictionary* visit(visitor v, bool persist, NSDictionary* args) -{ - NSMutableDictionary *ret = [NSMutableDictionary new]; - Boolean success; - - SCNetworkSetRef networkSetRef; - CFArrayRef networkServicesArrayRef; - SCNetworkServiceRef networkServiceRef; - SCNetworkProtocolRef proxyProtocolRef; - NSDictionary *oldPreferences; - - // Get System Preferences Lock - SCPreferencesRef prefsRef = SCPreferencesCreate(NULL, CFSTR("org.getlantern.lantern"), NULL); - - if (prefsRef == NULL) { - [ret setObject:@"Fail to obtain Preferences Ref" forKey:@"error"]; - [ret setObject:[[NSNumber alloc] initWithInt:NO_PERMISSION] forKey:@"code"]; - goto freePrefsRef; - } - - success = SCPreferencesLock(prefsRef, true); - if (!success) { - [ret setObject:@"Fail to obtain PreferencesLock" forKey:@"error"]; - [ret setObject:[[NSNumber alloc] initWithInt:NO_PERMISSION] forKey:@"code"]; - goto freePrefsRef; - } - - // Get available network services - networkSetRef = SCNetworkSetCopyCurrent(prefsRef); - if(networkSetRef == NULL) { - [ret setObject:@"Fail to get available network services" forKey:@"error"]; - [ret setObject:[[NSNumber alloc] initWithInt:SYSCALL_FAILED] forKey:@"code"]; - goto freeNetworkSetRef; - } - - //Look up interface entry - networkServicesArrayRef = SCNetworkSetCopyServices(networkSetRef); - networkServiceRef = NULL; - for (long i = 0; i < CFArrayGetCount(networkServicesArrayRef); i++) { - networkServiceRef = CFArrayGetValueAtIndex(networkServicesArrayRef, i); - - // Get proxy protocol - proxyProtocolRef = SCNetworkServiceCopyProtocol(networkServiceRef, kSCNetworkProtocolTypeProxies); - if(proxyProtocolRef == NULL) { - [ret setObject:@"Couldn't acquire copy of proxyProtocol" forKey:@"error"]; - [ret setObject:[[NSNumber alloc] initWithInt:SYSCALL_FAILED] forKey:@"code"]; - goto freeProxyProtocolRef; - } - - oldPreferences = (__bridge NSDictionary*)SCNetworkProtocolGetConfiguration(proxyProtocolRef); - if (!v(proxyProtocolRef, oldPreferences, args)) { - [ret setObject:[[NSNumber alloc] initWithInt:SYSCALL_FAILED] forKey:@"code"]; - } - - freeProxyProtocolRef: - CFRelease(proxyProtocolRef); - } - - if (persist) { - success = SCPreferencesCommitChanges(prefsRef); - if(!success) { - [ret setObject:@"Failed to Commit Changes" forKey:@"error"]; - [ret setObject:[[NSNumber alloc] initWithInt:SYSCALL_FAILED] forKey:@"code"]; - goto freeNetworkServicesArrayRef; - } - - success = SCPreferencesApplyChanges(prefsRef); - if(!success) { - [ret setObject:@"Failed to Apply Changes" forKey:@"error"]; - [ret setObject:[[NSNumber alloc] initWithInt:SYSCALL_FAILED] forKey:@"code"]; - goto freeNetworkServicesArrayRef; - } - } - - //Free Resources - freeNetworkServicesArrayRef: - CFRelease(networkServicesArrayRef); - freeNetworkSetRef: - CFRelease(networkSetRef); - freePrefsRef: - SCPreferencesUnlock(prefsRef); - CFRelease(prefsRef); - - return ret; -} - -const char* nsstring2cstring(NSString *s) { - if (s == NULL) { return NULL; } - - const char *cstr = [s UTF8String]; - return cstr; -} - -const char* dictionaryToString(NSDictionary *dict) { - NSError *error; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error]; - NSString *data; - if (! jsonData) { - data = @"{}"; - } else { - data = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - } - - return nsstring2cstring(data); -} - -//int show(void) -//{ -// return visit(&showAction, false, @{}); -//} - - -const char* turnOn(const char *host, const char *port) -{ - NSLog(@"%s:%s", host, port); - NSString* nsProxyHost = [[NSString alloc] initWithCString: host encoding:NSUTF8StringEncoding]; - NSNumber* nsProxyPort = [[NSNumber alloc] initWithLong: [[[NSString alloc] initWithCString: port encoding:NSUTF8StringEncoding] integerValue]]; - - NSLog(@"%@:%@", nsProxyHost, nsProxyPort); - //NSDictionary* dict = @{ - // @"host": @(nsProxyHost), - // @"port": @(nsProxyPort), - //}; - NSMutableDictionary *args = [NSMutableDictionary new]; - [args setObject:nsProxyHost forKey:@"host"]; - [args setObject:nsProxyPort forKey:@"port"]; - - return dictionaryToString(visit(&turnOnAction, true, args)); -} - -const char* turnOff() { - return dictionaryToString(visit(&turnOffAction, true, @{})); -} -*/ -import "C" - import ( - "encoding/json" "errors" + "fmt" "net" "os/exec" "strings" - "unsafe" ) +var firmwareType = []string{ + "webproxy", + "securewebproxy", + "socksfirewallproxy", +} + type DarwinSystemProxy struct { } +func RunBashCmd(cmd string) (string, error) { + c := exec.Command("sh", "-c", cmd) + out, err := c.CombinedOutput() + if err != nil { + return "", errors.New(string(out) + err.Error()) + } + return strings.TrimSpace(string(out)), nil +} + +func GetNetworkInterface() (string, error) { + return RunBashCmd("networksetup -listnetworkserviceorder | grep -B 1 $(route -n get default | grep interface | awk '{print $2}') | head -n 1 | sed 's/.*) //'") +} + var _ SystemProxy = (*DarwinSystemProxy)(nil) type RequestResponse struct { @@ -229,17 +38,17 @@ type RequestResponse struct { } func (p *DarwinSystemProxy) TurnOff() error { - ret := C.turnOff() - data := C.GoString(ret) - - var r RequestResponse - if err := json.Unmarshal([]byte(data), &r); err != nil { + s, err := GetNetworkInterface() + if err != nil { return err } - if r.Code != 0 { - return errors.New(r.Error) + for _, t := range firmwareType { + if _, err := RunBashCmd(fmt.Sprintf("networksetup -set%sstate %s off", t, s)); err != nil { + return err + } } + return nil } @@ -264,23 +73,23 @@ func (p *DarwinSystemProxy) TurnOn(addrport string) error { return err } - chost := C.CString(host) - cport := C.CString(port) - - ret := C.turnOn(chost, cport) - C.free(unsafe.Pointer(chost)) - C.free(unsafe.Pointer(cport)) + netInterface, err := GetNetworkInterface() + if err != nil { + return err + } - data := C.GoString(ret) + for _, t := range firmwareType { + cmd := fmt.Sprintf(`networksetup -set%s "%s" "%s" %s && networksetup -set%sstate "%s" on`, t, netInterface, host, port, t, netInterface) + if _, err := RunBashCmd(cmd); err != nil { + return err + } + } - var r RequestResponse - if err := json.Unmarshal([]byte(data), &r); err != nil { + cmd := fmt.Sprintf(`networksetup -setproxybypassdomains "%s" "192.168.0.0/16" "10.0.0.0/8" "172.16.0.0/12" "127.0.0.1" "localhost" "*.local" "timestamp.apple.com"`, netInterface) + if _, err := RunBashCmd(cmd); err != nil { return err } - if r.Code != 0 { - return errors.New(r.Error) - } return nil } diff --git a/pkgs/proxy/sysproxy/sysproxy_test.go b/pkgs/proxy/sysproxy/sysproxy_test.go index df35185..e9c89d5 100644 --- a/pkgs/proxy/sysproxy/sysproxy_test.go +++ b/pkgs/proxy/sysproxy/sysproxy_test.go @@ -13,3 +13,16 @@ func Test_SystemProxyStatus(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, status) } + +// func Test_CloseSystemProxy(t *testing.T) { +// proxy := NewSystemProxy() +// err := proxy.TurnOff() +// assert.NoError(t, err) +// } + +// func Test_OpenSystemProxy(t *testing.T) { +// proxy := NewSystemProxy() +// err := proxy.TurnOn("127.0.0.1:9090") + +// assert.NoError(t, err) +// }