Files
ShadowsocksX-NG-R/ShadowsocksX-NG/ProxyConfHelper.m
T
秦宇航 c1b37d4482 更新白名单模式
更新白名单模式,现在基于全局模式下使用ACL文件分流
TODO 基于ACL的自动和回国模式
2017-05-07 12:58:18 +08:00

226 lines
8.7 KiB
Objective-C

//
// 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;
+ (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 \"bash %@\" with administrator privileges", helperPath];
NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
if ([appleScript executeAndReturnError:&error]) {
NSLog(@"installation success");
} else {
NSLog(@"installation failure");
}
}
}
+ (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)enablePACProxy:(NSString*) PACFilePath {
//start server here and then using the string next line
//next two lines can open gcdwebserver and work around pac file
NSString *PACURLString = [self startPACServer: PACFilePath];//hi 可以切换成定制pac文件路径来达成使用定制文件路径
NSURL* url = [NSURL URLWithString: PACURLString];
// NSString* urlString = [NSString stringWithFormat:@"%@/.ShadowsocksX-NG/gfwlist.js", NSHomeDirectory()];
// NSURL* url = [NSURL fileURLWithPath:urlString];
NSMutableArray* args = [@[@"--mode", @"auto", @"--pac-url", [url absoluteString]]mutableCopy];
[self addArguments4ManualSpecifyNetworkServices:args];
[self callHelper:args];
}
+ (void)enableGlobalProxy {
NSUInteger port = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalSocks5.ListenPort"];
NSMutableArray* args = [@[@"--mode", @"global", @"--port"
, [NSString stringWithFormat:@"%lu", (unsigned long)port]]mutableCopy];
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTPOn"] && [[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTP.FollowGlobal"]) {
NSUInteger privoxyPort = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalHTTP.ListenPort"];
[args addObject:@"--privoxy-port"];
[args addObject:[NSString stringWithFormat:@"%lu", (unsigned long)privoxyPort]];
}
[self addArguments4ManualSpecifyNetworkServices:args];
[self callHelper:args];
[self stopPACServer];
}
+ (void)enableWhiteListProxy {
// 基于全局socks5代理下使用ACL文件来进行白名单代理 不需要使用pac文件
NSUInteger port = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalSocks5.ListenPort"];
NSMutableArray* args = [@[@"--mode", @"global", @"--port"
, [NSString stringWithFormat:@"%lu", (unsigned long)port]]mutableCopy];
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTPOn"] && [[NSUserDefaults standardUserDefaults] boolForKey:@"LocalHTTP.FollowGlobal"]) {
NSUInteger privoxyPort = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalHTTP.ListenPort"];
[args addObject:@"--privoxy-port"];
[args addObject:[NSString stringWithFormat:@"%lu", (unsigned long)privoxyPort]];
}
[self addArguments4ManualSpecifyNetworkServices:args];
[self callHelper:args];
[self stopPACServer];
}
+ (void)disableProxy:(NSString*) PACFilePath {
// 带上所有参数是为了判断是否原有代理设置是否由ssx-ng设置的。如果是用户手工设置的其他配置,则不进行清空。
// NSString* urlString = [NSString stringWithFormat:@"%@/.ShadowsocksX-NG/gfwlist.js", NSHomeDirectory()];
// NSURL* url = [NSURL fileURLWithPath:urlString];
// NSString *PACURLString = [self startPACServer: PACFilePath];//hi 可以切换成定制pac文件路径来达成使用定制文件路径
// NSURL* url = [NSURL URLWithString: PACURLString];
// NSUInteger port = [[NSUserDefaults standardUserDefaults]integerForKey:@"LocalSocks5.ListenPort"];
//
// NSMutableArray* args = [@[@"--mode", @"off"
// , @"--port", [NSString stringWithFormat:@"%lu", (unsigned long)port]
// , @"--pac-url", [url absoluteString]
// ]mutableCopy];
NSMutableArray* args = [@[@"--mode", @"off"]mutableCopy];
[self addArguments4ManualSpecifyNetworkServices:args];
[self callHelper:args];
[self stopPACServer];
}
+ (NSString*)startPACServer:(NSString*) PACFilePath {
//接受参数为以后使用定制PAC文件
NSData * originalPACData;
NSString * routerPath = @"/proxy.pac";
if ([PACFilePath isEqual: @"hi"]) {//用默认路径来代替
PACFilePath = [NSString stringWithFormat:@"%@/%@", NSHomeDirectory(), @".ShadowsocksX-NG/gfwlist.js"];
originalPACData = [NSData dataWithContentsOfFile: [NSString stringWithFormat:@"%@/%@", NSHomeDirectory(), @".ShadowsocksX-NG/gfwlist.js"]];
}else{//用定制路径来代替
originalPACData = [NSData dataWithContentsOfFile: [NSString stringWithFormat:@"%@/%@/%@", NSHomeDirectory(), @".ShadowsocksX-NG", PACFilePath]];
routerPath = [NSString stringWithFormat:@"/%@",PACFilePath];
}
[self stopPACServer];
webServer = [[GCDWebServer alloc] init];
[webServer addHandlerForMethod:@"GET" path: routerPath requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest *request) {
return [GCDWebServerDataResponse responseWithData: originalPACData contentType:@"application/x-ns-proxy-autoconfig"];
}
];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString * address = [defaults stringForKey:@"PacServer.ListenAddress"];
int port = (short)[defaults integerForKey:@"PacServer.ListenPort"];
// NSMutableDictionary* options = [NSMutableDictionary dictionary];
// [options setObject:[NSNumber numberWithInteger:port] forKey:GCDWebServerOption_Port];
// [options setObject:@YES forKey:@"BindToLocalhost"];
//
// [webServer startWithOptions:options error:NULL];
[webServer startWithOptions:@{@"BindToLocalhost":@YES, @"Port":@(port)} error:nil];
return [NSString stringWithFormat:@"%@%@:%d%@",@"http://",address,port,routerPath];
}
+ (void)stopPACServer {
if ([webServer isRunning]) {
[webServer stop];
}
}
@end