2016-06-10 03:59:27 +08:00
|
|
|
|
//
|
|
|
|
|
// main.m
|
|
|
|
|
// shadowsocks_sysconf
|
|
|
|
|
//
|
|
|
|
|
// Created by clowwindy on 14-3-15.
|
|
|
|
|
// Copyright (c) 2014年 clowwindy. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
// Changed by QiuYuzhou
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
|
#import <SystemConfiguration/SystemConfiguration.h>
|
|
|
|
|
#import "../ShadowsocksX-NG/proxy_conf_helper_version.h"
|
|
|
|
|
|
|
|
|
|
// A library for parsing command line.
|
|
|
|
|
// https://github.com/stephencelis/BRLOptionParser
|
|
|
|
|
#import <BRLOptionParser/BRLOptionParser.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, const char * argv[])
|
|
|
|
|
{
|
|
|
|
|
NSString* mode;
|
|
|
|
|
NSString* pacURL;
|
|
|
|
|
NSString* portString;
|
2019-06-06 17:39:17 +08:00
|
|
|
|
NSString* socks5ListenAddress;
|
2016-10-09 14:31:13 +08:00
|
|
|
|
NSString* privoxyPortString;
|
2019-06-06 17:39:17 +08:00
|
|
|
|
NSString* privoxyListenAddress;
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
|
|
|
|
BRLOptionParser *options = [BRLOptionParser new];
|
2019-06-06 17:39:17 +08:00
|
|
|
|
[options setBanner:@"Usage: %s [-v] [-m auto|global|off] [-u <url>] [-p <port>] [-l <socks5-listen-address>] [-r <port>] [-p <privoxy-listen-address>] [-x <exception>]", argv[0]];
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
|
|
|
|
// Version
|
|
|
|
|
[options addOption:"version" flag:'v' description:@"Print the version number." block:^{
|
|
|
|
|
printf("%s", [kProxyConfHelperVersion UTF8String]);
|
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
// Help
|
|
|
|
|
__weak typeof(options) weakOptions = options;
|
|
|
|
|
[options addOption:"help" flag:'h' description:@"Show this message" block:^{
|
|
|
|
|
printf("%s", [[weakOptions description] UTF8String]);
|
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
// Mode
|
2016-10-09 14:31:13 +08:00
|
|
|
|
[options addOption:"mode" flag:'m' description:@"Proxy mode, may be: auto,global,off" argument:&mode];
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
|
|
|
|
[options addOption:"pac-url" flag:'u' description:@"PAC file url for auto mode." argument:&pacURL];
|
|
|
|
|
[options addOption:"port" flag:'p' description:@"Listen port for global mode." argument:&portString];
|
2019-06-06 17:39:17 +08:00
|
|
|
|
[options addOption:"socks-listen-address" flag:'l' description:@"Listen socks5 address for global mode." argument:&socks5ListenAddress];
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
2016-10-09 14:31:13 +08:00
|
|
|
|
[options addOption:"privoxy-port" flag:'r' description:@"Privoxy Port for global mode." argument:&privoxyPortString];
|
2019-06-06 17:39:17 +08:00
|
|
|
|
[options addOption:"privoxy-listen-address" flag:'s' description:@"Privoxy Listen Address for global mode." argument:&privoxyListenAddress];
|
2016-10-09 14:31:13 +08:00
|
|
|
|
|
2016-06-30 02:33:37 +08:00
|
|
|
|
NSMutableSet* networkServiceKeys = [NSMutableSet set];
|
|
|
|
|
[options addOption:"network-service" flag:'n' description:@"Manual specify the network profile need to set proxy." blockWithArgument:^(NSString* value){
|
|
|
|
|
[networkServiceKeys addObject:value];
|
|
|
|
|
}];
|
2017-10-30 15:03:02 +08:00
|
|
|
|
|
|
|
|
|
NSMutableSet* proxyExceptions = [NSMutableSet set];
|
|
|
|
|
[options addOption:"proxy-exception" flag:'x' description:@"Bypass proxy settings for this Host / Domain" blockWithArgument:^(NSString *value) {
|
|
|
|
|
[proxyExceptions addObject:value];
|
|
|
|
|
}];
|
2016-06-30 02:33:37 +08:00
|
|
|
|
|
2016-06-10 03:59:27 +08:00
|
|
|
|
NSError *error = nil;
|
|
|
|
|
if (![options parseArgc:argc argv:argv error:&error]) {
|
|
|
|
|
const char * message = error.localizedDescription.UTF8String;
|
|
|
|
|
fprintf(stderr, "%s: %s\n", argv[0], message);
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mode) {
|
|
|
|
|
if ([@"auto" isEqualToString:mode]) {
|
|
|
|
|
if (!pacURL) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
} else if ([@"global" isEqualToString:mode]) {
|
|
|
|
|
if (!portString) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
} else if (![@"off" isEqualToString:mode]) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
printf("%s", [kProxyConfHelperVersion UTF8String]);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-09 14:31:13 +08:00
|
|
|
|
NSInteger port = 0;
|
2016-08-04 00:41:00 +08:00
|
|
|
|
if (portString) {
|
|
|
|
|
port = [portString integerValue];
|
|
|
|
|
if (0 == port) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
2016-10-09 14:31:13 +08:00
|
|
|
|
NSInteger privoxyPort = 0;
|
|
|
|
|
if (privoxyPortString) {
|
|
|
|
|
privoxyPort = [privoxyPortString integerValue];
|
|
|
|
|
if (0 == privoxyPort) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-10 03:59:27 +08:00
|
|
|
|
static AuthorizationRef authRef;
|
|
|
|
|
static AuthorizationFlags authFlags;
|
|
|
|
|
authFlags = kAuthorizationFlagDefaults
|
|
|
|
|
| kAuthorizationFlagExtendRights
|
|
|
|
|
| kAuthorizationFlagInteractionAllowed
|
|
|
|
|
| kAuthorizationFlagPreAuthorize;
|
|
|
|
|
OSStatus authErr = AuthorizationCreate(nil, kAuthorizationEmptyEnvironment, authFlags, &authRef);
|
|
|
|
|
if (authErr != noErr) {
|
|
|
|
|
authRef = nil;
|
|
|
|
|
NSLog(@"Error when create authorization");
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
if (authRef == NULL) {
|
|
|
|
|
NSLog(@"No authorization has been granted to modify network configuration");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCPreferencesRef prefRef = SCPreferencesCreateWithAuthorization(nil, CFSTR("Shadowsocks"), nil, authRef);
|
|
|
|
|
|
|
|
|
|
NSDictionary *sets = (__bridge NSDictionary *)SCPreferencesGetValue(prefRef, kSCPrefNetworkServices);
|
|
|
|
|
|
|
|
|
|
NSMutableDictionary *proxies = [[NSMutableDictionary alloc] init];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCFNetworkProxiesHTTPEnable];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCFNetworkProxiesHTTPSEnable];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCFNetworkProxiesProxyAutoConfigEnable];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:0] forKey:(NSString *)kCFNetworkProxiesSOCKSEnable];
|
2016-06-12 02:06:25 +08:00
|
|
|
|
[proxies setObject:@[] forKey:(NSString *)kCFNetworkProxiesExceptionsList];
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
|
|
|
|
// 遍历系统中的网络设备列表,设置 AirPort 和 Ethernet 的代理
|
|
|
|
|
for (NSString *key in [sets allKeys]) {
|
|
|
|
|
NSMutableDictionary *dict = [sets objectForKey:key];
|
|
|
|
|
NSString *hardware = [dict valueForKeyPath:@"Interface.Hardware"];
|
|
|
|
|
// NSLog(@"%@", hardware);
|
2016-06-30 02:33:37 +08:00
|
|
|
|
BOOL modify = NO;
|
|
|
|
|
if ([networkServiceKeys count] > 0) {
|
|
|
|
|
if ([networkServiceKeys containsObject:key]) {
|
|
|
|
|
modify = YES;
|
|
|
|
|
}
|
|
|
|
|
} else if ([hardware isEqualToString:@"AirPort"]
|
|
|
|
|
|| [hardware isEqualToString:@"Wi-Fi"]
|
|
|
|
|
|| [hardware isEqualToString:@"Ethernet"]) {
|
|
|
|
|
modify = YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (modify) {
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
2016-08-04 00:41:00 +08:00
|
|
|
|
NSString* prefPath = [NSString stringWithFormat:@"/%@/%@/%@", kSCPrefNetworkServices
|
|
|
|
|
, key, kSCEntNetProxies];
|
|
|
|
|
|
2016-06-10 03:59:27 +08:00
|
|
|
|
if ([mode isEqualToString:@"auto"]) {
|
|
|
|
|
|
|
|
|
|
[proxies setObject:pacURL forKey:(NSString *)kCFNetworkProxiesProxyAutoConfigURLString];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:1] forKey:(NSString *)kCFNetworkProxiesProxyAutoConfigEnable];
|
|
|
|
|
|
2016-08-04 00:41:00 +08:00
|
|
|
|
SCPreferencesPathSetValue(prefRef, (__bridge CFStringRef)prefPath
|
|
|
|
|
, (__bridge CFDictionaryRef)proxies);
|
2016-06-10 03:59:27 +08:00
|
|
|
|
} else if ([mode isEqualToString:@"global"]) {
|
|
|
|
|
|
|
|
|
|
|
2019-06-06 17:39:17 +08:00
|
|
|
|
[proxies setObject:socks5ListenAddress forKey:(NSString *)
|
2016-06-10 03:59:27 +08:00
|
|
|
|
kCFNetworkProxiesSOCKSProxy];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInteger:port] forKey:(NSString*)
|
|
|
|
|
kCFNetworkProxiesSOCKSPort];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:1] forKey:(NSString*)
|
|
|
|
|
kCFNetworkProxiesSOCKSEnable];
|
2017-10-30 15:03:02 +08:00
|
|
|
|
[proxies setObject:[proxyExceptions allObjects] forKey:(NSString *)kCFNetworkProxiesExceptionsList];
|
2016-06-10 03:59:27 +08:00
|
|
|
|
|
2016-10-09 14:31:13 +08:00
|
|
|
|
if (privoxyPort != 0) {
|
2019-06-06 17:42:30 +08:00
|
|
|
|
[proxies setObject:privoxyListenAddress forKey:(NSString *)
|
2016-10-09 14:31:13 +08:00
|
|
|
|
kCFNetworkProxiesHTTPProxy];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInteger:privoxyPort] forKey:(NSString*)
|
|
|
|
|
kCFNetworkProxiesHTTPPort];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:1] forKey:(NSString*)
|
|
|
|
|
kCFNetworkProxiesHTTPEnable];
|
|
|
|
|
|
2019-06-06 17:42:30 +08:00
|
|
|
|
[proxies setObject:privoxyListenAddress forKey:(NSString *)
|
2016-10-09 14:31:13 +08:00
|
|
|
|
kCFNetworkProxiesHTTPSProxy];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInteger:privoxyPort] forKey:(NSString*)
|
|
|
|
|
kCFNetworkProxiesHTTPSPort];
|
|
|
|
|
[proxies setObject:[NSNumber numberWithInt:1] forKey:(NSString*)
|
|
|
|
|
kCFNetworkProxiesHTTPSEnable];
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-04 00:41:00 +08:00
|
|
|
|
SCPreferencesPathSetValue(prefRef, (__bridge CFStringRef)prefPath
|
|
|
|
|
, (__bridge CFDictionaryRef)proxies);
|
|
|
|
|
} else if ([mode isEqualToString:@"off"]) {
|
2019-09-15 19:26:07 +08:00
|
|
|
|
if (pacURL != nil && portString != nil && socks5ListenAddress != nil) {
|
2016-08-04 00:41:00 +08:00
|
|
|
|
// 取原来的配置,判断是否为shadowsocksX-NG设置的
|
|
|
|
|
NSDictionary* oldProxies
|
|
|
|
|
= (__bridge NSDictionary*)SCPreferencesPathGetValue(prefRef
|
|
|
|
|
, (__bridge CFStringRef)prefPath);
|
|
|
|
|
|
|
|
|
|
if (([oldProxies[(NSString *)kCFNetworkProxiesProxyAutoConfigURLString] isEqualToString:pacURL]
|
|
|
|
|
&&[oldProxies[(NSString *)kCFNetworkProxiesProxyAutoConfigEnable] isEqual:[NSNumber numberWithInt:1]])
|
2019-09-15 19:26:07 +08:00
|
|
|
|
||([oldProxies[(NSString*)kCFNetworkProxiesSOCKSProxy] isEqualToString:socks5ListenAddress]
|
2016-08-04 00:41:00 +08:00
|
|
|
|
&&[oldProxies[(NSString*)kCFNetworkProxiesSOCKSPort] isEqualTo:[NSNumber numberWithInteger:port]]
|
|
|
|
|
&&[oldProxies[(NSString*)kCFNetworkProxiesSOCKSEnable] isEqual:[NSNumber numberWithInt:1]])
|
|
|
|
|
) {
|
|
|
|
|
SCPreferencesPathSetValue(prefRef, (__bridge CFStringRef)prefPath
|
|
|
|
|
, (__bridge CFDictionaryRef)proxies);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
SCPreferencesPathSetValue(prefRef, (__bridge CFStringRef)prefPath
|
|
|
|
|
, (__bridge CFDictionaryRef)proxies);
|
|
|
|
|
}
|
2016-06-10 03:59:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCPreferencesCommitChanges(prefRef);
|
|
|
|
|
SCPreferencesApplyChanges(prefRef);
|
|
|
|
|
SCPreferencesSynchronize(prefRef);
|
|
|
|
|
|
|
|
|
|
AuthorizationFree(authRef, kAuthorizationFlagDefaults);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("pac proxy set to %s", [mode UTF8String]);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|