Files
ShadowsocksX-NG/ShadowsocksX-NG/ProxyConfHelper.m

266 lines
10 KiB
Mathematica
Raw Normal View History

2016-06-10 03:59:27 +08:00
//
// ProxyConfHelper.m
// ShadowsocksX-NG
//
// Created by on 16/6/10.
// Copyright © 2016 qiuyuzhou. All rights reserved.
//
#import "ProxyConfHelper.h"
#import "proxy_conf_helper_version.h"
#define kShadowsocksHelper @"/Library/Application Support/ShadowsocksX-NG/proxy_conf_helper"
@implementation ProxyConfHelper
GCDWebServer *webServer =nil;
2016-06-10 03:59:27 +08:00
+ (BOOL)isVersionOk {
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath:kShadowsocksHelper];
NSArray *args;
args = [NSArray arrayWithObjects:@"-v", nil];
[task setArguments: args];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *fd;
fd = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [fd readDataToEndOfFile];
NSString *str;
str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (![str isEqualToString:kProxyConfHelperVersion]) {
return NO;
}
return YES;
}
+ (void)install {
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:kShadowsocksHelper] || ![self isVersionOk]) {
NSString *helperPath = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] resourcePath], @"install_helper.sh"];
NSLog(@"run install script: %@", helperPath);
NSDictionary *error;
NSString *script = [NSString stringWithFormat:@"do shell script \"/bin/bash \\\"%@\\\"\" with administrator privileges", helperPath];
2016-06-10 03:59:27 +08:00
NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
if ([appleScript executeAndReturnError:&error]) {
NSLog(@"installation success");
} else {
NSLog(@"installation failure: %@", error);
2016-06-10 03:59:27 +08:00
}
}
}
+ (void)callHelper:(NSArray*) arguments {
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath:kShadowsocksHelper];
// this log is very important
NSLog(@"run shadowsocks helper: %@", kShadowsocksHelper);
[task setArguments:arguments];
NSPipe *stdoutpipe;
stdoutpipe = [NSPipe pipe];
[task setStandardOutput:stdoutpipe];
NSPipe *stderrpipe;
stderrpipe = [NSPipe pipe];
[task setStandardError:stderrpipe];
NSFileHandle *file;
file = [stdoutpipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (string.length > 0) {
NSLog(@"%@", string);
}
file = [stderrpipe fileHandleForReading];
data = [file readDataToEndOfFile];
string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (string.length > 0) {
NSLog(@"%@", string);
}
}
+ (void)addArguments4ManualSpecifyNetworkServices:(NSMutableArray*) args {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if (![defaults boolForKey:@"AutoConfigureNetworkServices"]) {
NSArray* serviceKeys = [defaults arrayForKey:@"Proxy4NetworkServices"];
if (serviceKeys) {
for (NSString* key in serviceKeys) {
[args addObject:@"--network-service"];
[args addObject:key];
}
}
}
}
+ (void)addArguments4ManualSpecifyProxyExceptions:(NSMutableArray*) args {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSString* rawExceptions = [defaults stringForKey:@"ProxyExceptions"];
if (rawExceptions) {
NSCharacterSet* whites = [NSCharacterSet whitespaceAndNewlineCharacterSet];
2017-11-26 12:46:00 +08:00
NSMutableCharacterSet* seps = [NSMutableCharacterSet characterSetWithCharactersInString:@",、"];
[seps formUnionWithCharacterSet:whites];
NSArray* exceptions = [rawExceptions componentsSeparatedByCharactersInSet:seps];
2017-11-26 12:46:00 +08:00
for (NSString* domainOrHost in exceptions) {
if ([domainOrHost length] > 0) {
[args addObject:@"-x"];
[args addObject:domainOrHost];
}
}
}
}
+ (NSString*)getPACFilePath {
return [NSString stringWithFormat:@"%@/%@", NSHomeDirectory(), @".ShadowsocksX-NG/gfwlist.js"];
}
2016-10-18 23:35:17 +08:00
+ (void)enablePACProxy {
//start server here and then using the string next line
//next two lines can open gcdwebserver and work around pac file
NSString* PACFilePath = [self getPACFilePath];
2016-10-18 23:35:17 +08:00
[self startPACServer: PACFilePath];
NSURL* url = [NSURL URLWithString: [self getHttpPACUrl]];
NSMutableArray* args = [@[@"--mode", @"auto", @"--pac-url", [url absoluteString]]mutableCopy];
[self addArguments4ManualSpecifyNetworkServices:args];
[self addArguments4ManualSpecifyProxyExceptions:args];
[self callHelper:args];
2016-06-10 03:59:27 +08:00
}
+ (void)enableGlobalProxy {
NSUInteger port = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalSocks5.ListenPort"];
NSMutableArray* args = [@[@"--mode", @"global", @"--port"
, [NSString stringWithFormat:@"%lu", (unsigned long)port]]mutableCopy];
2016-10-21 23:36:05 +08:00
// Because issue #106 https://github.com/shadowsocks/ShadowsocksX-NG/issues/106
// Comment below out.
2016-10-26 19:25:35 +08:00
// if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTPOn"] && [[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTP.FollowGlobal"]) {
2016-10-21 23:36:05 +08:00
// NSUInteger privoxyPort = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalHTTP.ListenPort"];
//
// [args addObject:@"--privoxy-port"];
// [args addObject:[NSString stringWithFormat:@"%lu", (unsigned long)privoxyPort]];
// }
2016-10-09 14:31:13 +08:00
[self addArguments4ManualSpecifyNetworkServices:args];
[self addArguments4ManualSpecifyProxyExceptions:args];
[self callHelper:args];
[self stopPACServer];
2016-06-10 03:59:27 +08:00
}
2016-10-18 23:35:17 +08:00
+ (void)disableProxy {
// ssx-ng
NSURL* url = [NSURL URLWithString: [self getHttpPACUrl]];
NSUInteger port = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalSocks5.ListenPort"];
NSMutableArray* args = [@[@"--mode", @"off"
, @"--port", [NSString stringWithFormat:@"%lu", (unsigned long)port]
, @"--pac-url", [url absoluteString]
]mutableCopy];
[self addArguments4ManualSpecifyNetworkServices:args];
[self addArguments4ManualSpecifyProxyExceptions:args];
[self callHelper:args];
[self stopPACServer];
2016-06-10 03:59:27 +08:00
}
2016-10-18 23:35:17 +08:00
+ (NSString*)getHttpPACUrl {
NSString * routerPath = @"/proxy.pac";
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString * address = @"127.0.0.1";
int port = (short)[defaults integerForKey:@"PacServer.ListenPort"];
return [NSString stringWithFormat:@"%@%@:%d%@",@"http://",address,port,routerPath];
}
+ (void)startPACServer:(NSString*) PACFilePath {
[self stopPACServer];
2016-10-18 23:35:17 +08:00
NSString * routerPath = @"/proxy.pac";
2016-10-18 23:35:17 +08:00
NSData* originalPACData = [NSData dataWithContentsOfFile:PACFilePath];
webServer = [[GCDWebServer alloc] init];
2016-10-18 23:35:17 +08:00
[webServer addHandlerForMethod:@"GET"
path:routerPath
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest *request)
{
GCDWebServerDataResponse* resp = [GCDWebServerDataResponse responseWithData:originalPACData
contentType:@"application/x-ns-proxy-autoconfig"];
return resp;
}
];
2016-10-18 23:35:17 +08:00
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
2016-10-18 23:35:17 +08:00
int port = (short)[defaults integerForKey:@"PacServer.ListenPort"];
2016-10-18 23:35:17 +08:00
[webServer startWithOptions:@{@"BindToLocalhost":@YES, @"Port":@(port)} error:nil];
}
+ (void)stopPACServer {
//webserver
if ([webServer isRunning]) {
[webServer stop];
}
}
+ (void)startMonitorPAC {
NSString* PACFilePath = [self getPACFilePath];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
int fileId = open([PACFilePath UTF8String], O_EVTONLY);
__block dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fileId,
DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE,
queue);
dispatch_source_set_event_handler(source, ^
{
unsigned long flags = dispatch_source_get_data(source);
if(flags & DISPATCH_VNODE_DELETE)
{
dispatch_source_cancel(source);
} else {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:@"ShadowsocksOn"]) {
if ([[defaults stringForKey:@"ShadowsocksRunningMode"] isEqualToString:@"auto"]) {
[ProxyConfHelper disableProxy];
[ProxyConfHelper enablePACProxy];
}
}
}
});
dispatch_source_set_cancel_handler(source, ^(void)
{
close(fileId);
});
dispatch_resume(source);
}
2016-06-10 03:59:27 +08:00
@end