Skip to content

Commit

Permalink
fix: darwin system proxy in user mode
Browse files Browse the repository at this point in the history
  • Loading branch information
5aaee9 committed Apr 20, 2024
1 parent 17c52b8 commit e5da98f
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 230 deletions.
269 changes: 39 additions & 230 deletions pkgs/proxy/sysproxy/sysproxy_darwin.go
Original file line number Diff line number Diff line change
@@ -1,226 +1,35 @@
package sysproxy

/*
#cgo CFLAGS: -x objective-c -fmodules
#cgo LDFLAGS: -framework Foundation -framework SystemConfiguration
#import <Foundation/NSArray.h>
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SCPreferences.h>
#import <SystemConfiguration/SCNetworkConfiguration.h>
#include <sys/syslimits.h>
#include <sys/stat.h>
#include <mach-o/dyld.h>
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 {
Expand All @@ -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
}

Expand All @@ -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
}

Expand Down
13 changes: 13 additions & 0 deletions pkgs/proxy/sysproxy/sysproxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
// }

0 comments on commit e5da98f

Please sign in to comment.