saturnusringar
saturnusringar

Reputation: 169

Create VPN connection

I'm completely new to macos-development and swift so please bear with me...

I'm trying to create a VPN connection in a Cocoa app. I've based the code on macosvpn: https://github.com/halo/macosvpn/blob/master/macosvpn/Classes/VPNServiceCreator.swift

This is what I have so far:

    func createVPNService() {
        let options = ["" : ""]
        let prefs = SCPreferencesCreate(nil, "TheVPN" as CFString, nil)

        // These variables will hold references to our new interfaces
        let initialTopInterface: SCNetworkInterface!
        let initialBottomInterface: SCNetworkInterface!

        // L2TP on top of IPv4
        initialBottomInterface = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, kSCNetworkInterfaceTypeL2TP)
        // PPP on top of L2TP
        initialTopInterface = SCNetworkInterfaceCreateWithInterface(initialBottomInterface!, kSCNetworkInterfaceTypePPP)

        let service = SCNetworkServiceCreate(prefs!, initialTopInterface!)
        SCNetworkServiceSetName(service!, ("Service Name" as CFString))
        // Because, if we would like to modify the interface, we first need to freshly fetch it from the service
        // See https://lists.apple.com/archives/macnetworkprog/2013/Apr/msg00016.html
        let topInterface = SCNetworkServiceGetInterface(service!)

        SCNetworkInterfaceSetConfiguration(topInterface!, options as CFDictionary)
        // Now let's apply the shared secret to the IPSec part of the L2TP/IPSec Interface
        let thingy:CFString = "IPSec" as CFString
        SCNetworkInterfaceSetExtendedConfiguration(topInterface!, thingy, options as CFDictionary)
        SCNetworkServiceEstablishDefaultConfiguration(service!)
        let networkSet = SCNetworkSetCopyCurrent(prefs!)

        let serviceProtocol = SCNetworkServiceCopyProtocol(service!, kSCNetworkProtocolTypeIPv4)
        SCNetworkProtocolSetConfiguration(serviceProtocol!, options as CFDictionary)
        SCNetworkSetAddService(networkSet!, service!)

        if !SCPreferencesCommitChanges(prefs!) {
            print("Error: Could not commit preferences. (Code \(SCError()))")
        }
        if !SCPreferencesApplyChanges(prefs!) {
            print("Error: Could not apply changes. (Code \(SCError()))")
        }
    }

No network service is created when I'm running this.

I have no idea what options and prefs should be really? They are, more or less, empty now.

Also, SCPreferencesCommitChanges and SCPreferencesApplyChanges fails with a 1003-code. I suppose they need root-privileges to work and I haven't been able to figure out how to get root-privileges.

Thanks for any help!

Upvotes: 2

Views: 838

Answers (1)

saturnusringar
saturnusringar

Reputation: 169

I finally figured out how to create the VPN connection/service. But I still have to figure out how options and prefs should be used.

SCPreferencesCreate was replaced with SCPreferencesCreateWithAuthorization and some Authorization code before. This is the updated code.

    func createVPNConnection() {
        let flags : AuthorizationFlags = [.interactionAllowed, .extendRights, .preAuthorize]
        var authRef: AuthorizationRef?
        AuthorizationCreate(nil, nil, flags, &authRef)

        let options = ["" : ""]
        let prefs = SCPreferencesCreateWithAuthorization(nil, "TheVPN" as CFString, nil, authRef)
        // These variables will hold references to our new interfaces
        let initialTopInterface: SCNetworkInterface!
        let initialBottomInterface: SCNetworkInterface!

        // L2TP on top of IPv4
        initialBottomInterface = SCNetworkInterfaceCreateWithInterface(kSCNetworkInterfaceIPv4, kSCNetworkInterfaceTypeL2TP)
        // PPP on top of L2TP
        initialTopInterface = SCNetworkInterfaceCreateWithInterface(initialBottomInterface!, kSCNetworkInterfaceTypePPP)

        let service = SCNetworkServiceCreate(prefs!, initialTopInterface!)
        SCNetworkServiceSetName(service!, ("Test Service Name" as CFString))
        // Because, if we would like to modify the interface, we first need to freshly fetch it from the service
        // See https://lists.apple.com/archives/macnetworkprog/2013/Apr/msg00016.html
        let topInterface = SCNetworkServiceGetInterface(service!)

        // Let's apply all configuration to the PPP interface
        // Specifically, the servername, account username and password
        SCNetworkInterfaceSetConfiguration(topInterface!, options as CFDictionary)

        // Now let's apply the shared secret to the IPSec part of the L2TP/IPSec Interface
        let thingy:CFString = "IPSec" as CFString
        SCNetworkInterfaceSetExtendedConfiguration(topInterface!, thingy, options as CFDictionary)
        SCNetworkServiceEstablishDefaultConfiguration(service!)
        let networkSet = SCNetworkSetCopyCurrent(prefs!)
        let serviceProtocol = SCNetworkServiceCopyProtocol(service!, kSCNetworkProtocolTypeIPv4)
        SCNetworkProtocolSetConfiguration(serviceProtocol!, options as CFDictionary)
        SCNetworkSetAddService(networkSet!, service!)

        if !SCPreferencesCommitChanges(prefs!) {
             print("Error: Could not commit preferences. (Code \(SCError()))")
        }
        if !SCPreferencesApplyChanges(prefs!) {
             print("Error: Could not apply changes. (Code \(SCError()))")
        }
    }

Upvotes: 3

Related Questions