以编程方式在 Mac OS X 上创建 PPTP ***
Posted
技术标签:
【中文标题】以编程方式在 Mac OS X 上创建 PPTP ***【英文标题】:Creating PPTP *** on Mac OS X Programatically 【发布时间】:2015-03-22 01:09:01 【问题描述】:我正在尝试创建一个以编程方式在 Mac 上设置 *** 的应用。不幸的是,网络领域的 Apple 文档对设置和连接 *** 不是很具体。
所以我在网上找到了一些用于设置 L2TP 和 IPsec 的示例代码,但我找不到 PPTP 的任何内容。下面是我正在使用的通用代码,但 PPTP 不适用于我。当我运行它时,它肯定会崩溃。
所以下面是一些我无法弄清楚的问题。
-我在设置 PPTP *** 时缺少什么?
-如何连接到设置 ***?
-如何找到已经添加的***并删除它们?
- (AuthorizationRef) getAuth
AuthorizationRef auth = NULL;
OSStatus status;
status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, [self flags], &auth);
if (status == errAuthorizationSuccess)
//NSLog(@"Successfully obtained Authorization reference");
else
NSLog(@"Could not obtain Authorization reference");
exit(101);
return auth;
- (AuthorizationFlags) flags
return kAuthorizationFlagDefaults |
kAuthorizationFlagExtendRights |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize;
- (void)setup***:(***Config *)***Config
// Obtaining permission to modify network settings
AuthorizationRef auth = [self getAuth];
SCPreferencesRef prefs = SCPreferencesCreateWithAuthorization(NULL, CFSTR("mac***"), NULL, auth);
// Making sure other process cannot make configuration modifications
// by obtaining a system-wide lock over the system preferences.
if (SCPreferencesLock(prefs, TRUE))
NSLog(@"Gained superhuman rights.");
else
NSLog(@"Sorry, without superuser privileges I won't be able to add any *** interfaces.");
return;
// If everything will work out fin
[self createService:***Config usingPreferencesRef:prefs];
// We're done, other processes may modify the system configuration again
SCPreferencesUnlock(prefs);
return;
#pragma mark - Create *** Service
// This method creates one *** interface according to the desired configuration
- (void) createService:(***Config*)config usingPreferencesRef:(SCPreferencesRef)prefs
NSLog(@"Creating new %@ Service using %@", config.humanType, config);
// These variables will hold references to our new interfaces
SCNetworkInterfaceRef bottomInterface = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4,kSCNetworkInterfaceTypePPTP);
SCNetworkInterfaceRef topInterface = SCNetworkInterfaceCreateWithInterface(bottomInterface, kSCNetworkInterfaceTypePPP);
// Creating a new, fresh *** service in memory using the interface we already created
SCNetworkServiceRef service = SCNetworkServiceCreate(prefs, topInterface);
// That service is to have a name
SCNetworkServiceSetName(service, (__bridge CFStringRef)config.name);
// And we also woould like to know the internal ID of this service
NSString *serviceID = (__bridge NSString *)(SCNetworkServiceGetServiceID(service));
// It will be used to find the correct passwords in the system keychain
config.serviceID = serviceID;
// Interestingly enough, the interface variables in itself are now worthless
// We used them to create the service and that's it, we cannot modify them any more.
CFRelease(topInterface);
CFRelease(bottomInterface);
topInterface = NULL;
bottomInterface = NULL;
topInterface = SCNetworkServiceGetInterface(service);
// Let's apply all configuration to the PPTP interface
// Specifically, the servername, account username and password
if (SCNetworkInterfaceSetConfiguration(topInterface, config.PPTPConfig))
NSLog(@"Successfully configured PPP interface of service %@", config.name);
else
NSLog(@"Error: Could not configure PPP interface for service %@", config.name);
return;
if (SCNetworkInterfaceSetExtendedConfiguration(topInterface, NULL, config.PPTPConfig))
NSLog(@"Successfully configured IPSec on PPP interface for service %@", config.name);
else
NSLog(@"Error: Could not configure PPTP on PPP interface for service %@. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
NSLog(@"Adding default protocols (DNS, etc.) to service %@...", config.name);
if (!SCNetworkServiceEstablishDefaultConfiguration(service))
NSLog(@"Error: Could not establish a default service configuration for %@. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
NSLog(@"Fetching set of all available network services...");
SCNetworkSetRef networkSet = SCNetworkSetCopyCurrent(prefs);
if (!networkSet)
NSLog(@"Error: Could not fetch current network set when creating %@. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
if (!SCNetworkSetAddService (networkSet, service))
if (SCError() == 1005)
NSLog(@"Skipping *** Service %@ because it already exists.", config.humanType);
return;
else
NSLog(@"Error: Could not add new *** service %@ to current network set. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
NSLog(@"Fetching IPv4 protocol of service %@...", config.name);
SCNetworkProtocolRef protocol = SCNetworkServiceCopyProtocol(service, kSCNetworkProtocolTypeIPv4);
if (!protocol)
NSLog(@"Error: Could not fetch IPv4 protocol of %@. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
NSLog(@"Configuring IPv4 protocol of service %@...", config.name);
if (!SCNetworkProtocolSetConfiguration(protocol, config.L2TPIPv4Config))
NSLog(@"Error: Could not configure IPv4 protocol of %@. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
NSLog(@"Commiting all changes including service %@...", config.name);
if (!SCPreferencesCommitChanges(prefs))
NSLog(@"Error: Could not commit preferences with service %@. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
NSLog(@"Preparing to add Keychain items for service %@...", config.name);
// The password and the shared secret are not stored directly in the System Preferences .plist file
// Instead we put them into the KeyChain. I know we're creating new items each time you run this application
// But this actually is the same behaviour you get using the official System Preferences Network Pane
[***Keychain createPasswordKeyChainItem:config.name forService:serviceID withAccount:config.username andPassword:config.password];
[***Keychain createSharedSecretKeyChainItem:config.name forService:serviceID withPassword:config.sharedSecret];
if (!SCPreferencesApplyChanges(prefs))
NSLog(@"Error: Could not apply changes with service %@. %s (Code %i)", config.name, SCErrorString(SCError()), SCError());
return;
NSLog(@"Successfully created %@ *** %@ with ID %@", config.humanType, config.name, serviceID);
return;
这是我的 ***Config 文件:
// ***Config.h
@interface ***Config : NSObject
@property (atomic) NSUInteger type;
@property (strong) NSString *serviceID;
@property (strong) NSString *name;
@property (strong) NSString *endpointPrefix;
@property (nonatomic) NSString *endpoint;
@property (strong) NSString *endpointSuffix;
@property (strong) NSString *username;
@property (strong) NSString *password;
@property (strong) NSString *sharedSecret;
@property (readonly) NSString *humanType;
@property (readonly) CFDictionaryRef PPTPConfig;
@property (readonly) CFDictionaryRef L2TPPPPConfig;
@property (readonly) CFDictionaryRef L2TPIPSecConfig;
@property (readonly) CFDictionaryRef L2TPIPv4Config;
@end
// ***Config.m
typedef NS_ENUM(NSInteger, ***ServiceType)
***ServicePPTP ,
***ServiceL2TPOverIPSec,
***ServiceCiscoIPSec
;
@implementation ***Config
@synthesize type, name, endpointPrefix, endpointSuffix, username, password, sharedSecret;
@synthesize endpoint = _endpoint;
- (void) setEndpoint:(NSString *)newEndpoint
_endpoint = newEndpoint;
- (NSString*) endpoint
if (_endpoint) return _endpoint;
if ((!endpointPrefix && !endpointSuffix) || ([endpointPrefix isEqualToString:@""] && [endpointSuffix isEqualToString:@""])) return NULL;
return [NSString stringWithFormat:@"%@%@", endpointPrefix, endpointSuffix];
- (BOOL) is:(NSUInteger)aType
return self.type == aType;
- (NSString*) humanType
switch(self.type)
case ***ServicePPTP : return @"PPTP"; break;
case ***ServiceL2TPOverIPSec : return @"L2TP over IPSec"; break;
case ***ServiceCiscoIPSec : return @"Cisco IPSec"; break;
default : return @"Unknown"; break;
- (NSString*) description
return [NSString stringWithFormat:@"<[%@] name=%@ endpointPrefix=%@ endpoint=%@ endpointSuffix=%@ username=%@ password=%@ sharedSecret=%@>", self.humanType, self.name, self.endpointPrefix, self.endpoint, self.endpointSuffix, self.username, self.password, self.sharedSecret];
- (CFDictionaryRef) PPTPConfig
CFStringRef keys[4] = NULL, NULL, NULL, NULL ;
CFStringRef vals[4] = NULL, NULL, NULL, NULL ;
CFIndex count = 0;
keys[count] = kSCPropNetPPPAuthName;
vals[count++] = (__bridge CFStringRef)self.username;
keys[count] = kSCPropNetPPPAuthPassword;
vals[count++] = (__bridge CFStringRef)self.serviceID;
keys[count] = kSCPropNetPPPCommRemoteAddress;
vals[count++] = (__bridge CFStringRef)self.endpoint;
keys[count] = kSCPropUserDefinedName;
vals[count++] = (__bridge CFStringRef)C_***_NAME;
return CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&vals, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- (CFDictionaryRef) L2TPIPSecConfig
CFStringRef keys[3] = NULL, NULL, NULL ;
CFStringRef vals[3] = NULL, NULL, NULL ;
CFIndex count = 0;
keys[count] = kSCPropNetIPSecAuthenticationMethod;
vals[count++] = kSCValNetIPSecAuthenticationMethodSharedSecret;
keys[count] = kSCPropNetIPSecSharedSecretEncryption;
vals[count++] = kSCValNetIPSecSharedSecretEncryptionKeychain;
keys[count] = kSCPropNetIPSecSharedSecret;
vals[count++] = (__bridge CFStringRef)[NSString stringWithFormat:@"%@.SS", self.serviceID];
return CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&vals, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- (CFDictionaryRef) L2TPIPv4Config
CFStringRef keys[5] = NULL, NULL, NULL, NULL, NULL ;
CFStringRef vals[5] = NULL, NULL, NULL, NULL, NULL ;
CFIndex count = 0;
keys[count] = kSCPropNetIPv4ConfigMethod;
vals[count++] = kSCValNetIPv4ConfigMethodPPP;
int one = 1;
keys[count] = kSCPropNetOverridePrimary;
vals[count++] = CFNumberCreate(NULL, kCFNumberIntType, &one);
return CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&vals, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
【问题讨论】:
你还遇到这个问题吗? @MalavSoni 在我的情况下服务器地址和帐户名称在界面中显示为空,我正在使用 macos***-0.1.0 请帮助我,我将非常感激 @soheil B.marvasti 你有解决方案吗?我也想PPTP。请帮助我,我将非常感激 @MalavSoni 当我将 EditScheme->Run->Info->Debug Process 设置为 (Me) 时,此代码不会将密码数据存储在系统钥匙串中。它只能以(root)身份工作。我已经安装了 Helpertool 仍然是同样的问题 【参考方案1】:您可以查看以下链接以了解 ***/pptp 连接
http://lists.apple.com/archives/macnetworkprog/2011/Jul/msg00001.html
希望这可以解决您的问题。
【讨论】:
以上是关于以编程方式在 Mac OS X 上创建 PPTP ***的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式在 macOS Sierra/High Sierra 上创建 PPTP *** 连接?
在 Mac OS X 上以编程方式为 Matplotlib 选择正确的后端