Mac OS VPN连接以编程方式

时间:2015-03-09 10:30:33

标签: objective-c xcode macos vpn system-configuration

我想创建将与L2TP协议建立新连接的代码。

下面是我的代码。

我没有发现任何错误,但代码运行成功并创建新网络,但它没有显示我传递的数据,例如用户名。

- (IBAction)connectVPN_Cliced:(NSButton *)sender{

VPNServiceConfig *config = [[VPNServiceConfig alloc]init];
config.username = @"username";
config.password = @"password";
config.endpointPrefix = @"Server IP end prefix";
config.endpointSuffix = @"Server IP end endpointSuffix";
config.sharedSecret = @"sharedkey";
config.name = @"L2TP By Mac Application";
config.endpoint = @"Server IP";
config.type = 1;

[self setupVPN:config];
}


- (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)setupVPN:(VPNServiceConfig *)vpnConfig {
        // Obtaining permission to modify network settings
        AuthorizationRef auth = [self getAuth];
        SCPreferencesRef prefs =     SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, CFSTR("macVPN"), NULL, auth);

        SCPreferencesUnlock(prefs);
    //-------- This is i tried by me to add data but it's not working ------ Start //
        SCPreferencesSetValue(prefs, CFSTR("Type"), CFSTR("PPP"));
        SCPreferencesSetValue(prefs, CFSTR("SubType"), CFSTR("L2TP"));
        SCPreferencesSetValue(prefs, CFSTR("AuthName"), CFSTR("username"));
        SCPreferencesSetValue(prefs, CFSTR("AuthPassword"), CFSTR("password"));
        SCPreferencesSetValue(prefs, CFSTR("CommRemoteAddress"), CFSTR("server ip"));

        NSData *pppData = [@"0000" dataUsingEncoding:NSUTF8StringEncoding];


    CFDataRef ref = CFDataCreate(kCFAllocatorDefault, pppData.bytes, pppData.length);

    // CFPropertyListFormat

    CFPropertyListRef propertyRef = CFPropertyListCreateWithData(kCFAllocatorDefault, ref, kCFPropertyListMutableContainers, nil,nil);

    Boolean isValidData = CFPropertyListIsValid(propertyRef, kCFPropertyListXMLFormat_v1_0);

    SCPreferencesSetValue(prefs, CFSTR("AuthPassword"), propertyRef);

    //-------- This is i tried by me to add data but it's not working ------ End //

    // 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 VPN interfaces.");
        return;
    }
    // If everything will work out fin
    [self createService:vpnConfig usingPreferencesRef:prefs];

    // We're done, other processes may modify the system configuration again

    return;
}


- (void) createService:(VPNServiceConfig *)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,kSCNetworkInterfaceTypeL2TP);

    SCNetworkInterfaceRef topInterface = SCNetworkInterfaceCreateWithInterface(bottomInterface, kSCNetworkInterfaceTypePPP);
        // Creating a new, fresh VPN 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;
        [config setServiceID: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.L2TPIPSecConfig)) {
            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, kSCEntNetIPSec, config.L2TPIPSecConfig)) {
            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 VPN Service %@ because it already exists.", config.humanType);
            return;
        } else {
            NSLog(@"Error: Could not add new VPN 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.L2TPIPSecConfig)) {

        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

    [VPNKeychain createPasswordKeyChainItem:config.name forService:serviceID withAccount:config.username andPassword:config.password];

    [VPNKeychain 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 %@ VPN %@ with ID %@", config.humanType, config.name, serviceID);



    return;
}

我试过这个: how to set up a vpn connection programmatically in MAC?

更新: 代码我曾经自动连接到vpn服务器

SCNetworkConnectionRef  connetionRef =  SCNetworkConnectionCreateWithServiceID(kCFAllocatorDefault, (__bridge CFStringRef)(newServiceId), myCallBack, &callBackContext);
SCNetworkConnectionStart(connetionRef, config.L2TPPPPConfig, FALSE);

0 个答案:

没有答案