Hand NetworkExtension: 1 create L2TP/IPSec VPN connection

Since Apple announced in WWDC 2015 NetworkExtension, there have been a lot of excellent based on this app, such as Surge, Sh**Rocket, etc., and there are a lot of tutorials on the network (laugh) how to use NetworkExtensions.

Unfortunately, in 2017, with Xcode 8.3 and macOS 10.12, you will definitely be taken into the pit (laughs) along with those tutorials

Let me take you along with the network tutorial configuration encountered in the pit.
(Note: this series of tutorials, if no special instructions, the development environment is macOS 10.12.4 + Xcode 8.3 + Swift +)


0 pits

0 official document is too simple, the tutorial flying, can not be used

Cry… On the search for documentation and tutorials thing, really want to die. Either tutorial is a copy of the code excerpt put all sorts of things together, or illogical or unintelligible, the code is too old, completely run up, confused

The official tutorial is not to write API documents, really slag… Seen people say slag… Don’t believe you can do…

There is, whether it is Google or StackOverflow, really can not find the available tutorials, had to step out of step by step

0.1 go to the developer center for entitlement?

In fact, from 2016 to October, apple developers no longer need to apply separately for the authority of NetworkExtension. In the app ID Developer Center is set inside, can be added in the figure NetworkExtension permissions:

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 0.1.1

Of course, if you want to apply for Hotspot Helper permissions, or to go to the official website to apply for –&gt

In this regard, the official description:

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 0.1.2

0.2 NEProviderTargetTemplates.pkg?

Apple does not know what the reason, from the beginning of the macOS 10.12 to remove the expansion of the package and the official forum is given in the recommendation, extracted from the 10.11

The burning goose, you will find that after installation in the App Extensions list and ugly, and all the template code installation can not compile, is the old method, the old enumeration name, so crazy. So the installation of the how to do?

Very simple, to delete the corresponding $dir file:

  • If the current user is installed: $dir = ~/Library/Developer/Xcode/Templates/Project Templates/
  • If all users: $dir = /Library/Developer/Xcode/Templates/Project Templates/

To the $dir directory, delete the iOS and Mac under the relevant documents in the Application Extension

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 0.2.1

So, in the end how to create the corresponding Extensions extensions do not worry, this article will be mentioned

0.3 other pits and so on I think to add

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection

Well, get to the point where you can teach you how to develop a VPN that can be connected to L2TP/IPSec demo

1 configuration

First, create a new project, the language selected swift, the package name is called com.lucifer.proxydump bar

According to the contents of the pit 0.1, configured entitlement and provision, open the NetworkExtensions in the project Capabilities, PersonalVPN and KeychainSharing (because of the establishment of the VPN when the password is to get KeyChain from the details will be discussed later), and the addition of com.apple.managed.vpn.shared in KeychainSharing

Well, start developing

2 start

2.1 new Package Tunnel Protocol target

The problem is not related to Extension in the Xcode App Target
there? In fact, Apple Developer Forum in February 14, 2017, the official added the following reference (yes, is this post, recommended to use 10.11 of the PKG template):

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.1.1
  • New Spotlight Index Extension target (called PacketTunnelProvider)
Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.1.2
  • Delete IndexRequestHandler.{swift, h, m}
Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.1.3

In fact, there is also a step away, that is, in the PacketTunnelProvider Target Capabilities also open PersonalVPN and NetworkExtensions these two switches, or the introduction of the relevant library does not come in

  • Create a subclass of NEPacketTunnelProvider, called PacketTunnelProvider well (remember that the new finished, the introduction of NetworkExtension in the class)
  • Modify the Info.plist file under the Extension NSExtension: NSExtensionPointIdentifier is set to com.apple.networkextension.packet-tunnel to replace NSExtensionPrincipalClass in IndexRequestHandler is just our new class effect figure:
Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.1.4

2.2 configuration PacketTunnelProvider

The logic of PacketTunnelProvider is the core of network communication protocol sh**cks protocol processing. For example, the famous the custom processing, if you have their own communication protocol, can also be customized here. Put the startTunnel and stopTunnel to rewrite

Import UIKit import NetworkExtension class PacketTunnelProvider: NEPacketTunnelProvider override func startTunnel (options: {[String: NSObject] = nil, completionHandler:? @escaping (Error?) -> Void) {completionHandler} (NIL) override func stopTunnel (with reason: NEProviderStopReason), completionHandler: @escaping (-> Void) {}}

After all, just in order to establish an ordinary VPN, so do not need to configure the PacketTunnelProvider too, leaving the default value is good, this section does not detail the contents of the following articles in the exhibition to talk about

2.3 add main logic

Add a SwitchButton to the ViewController center as the VPN switch

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.3.1

The core logic to add a
NEVpnManager, used to control the VPN. But we are using IPSec authentication, and NetworkExtension password must be read from the KeyChain, so as to establish a method for accessing KeyChain data. Some relevant KeyChain instructions please search.

Here’s a quote from other blogs (because you’re lazy, just copy it)

The IPSec code and the pre shared key are required to be a permanent reference to the password in the KeyChain (persistent reference).
if the certificate is used as a IKE authentication method, and the Server side is used to issue a certificate, you need to manually import CA to iOS devices. At present, Apple has not provided a method to add credit certificate.

The related code is as follows

Let serviceName = "let.us.try.vpn.in.ipsec" / / casual custom let = "vpnPassword" vpnPwdIdentifier //keychain key let vpnPrivateKeyIdentifier access password = "sharedKey" //keychain key func createManager to access the shared key () {/ / first shared key and password in keychain, will use createKeychainValue (behind the "VPN code", vpnPwdIdentifier / createKeychainValue) password ("IPSec key", vpnPrivateKeyIdentifier / let) = NEVPNManager.shared (manager key) / / the first use shared to obtain the single case of loading VPN information manager.loadFromPreferences {/ / (error) in var conf: NEVPNProtocolIPSec? As NEVPNProtocolIPSec if conf = manager.protocolConfiguration? = = {conf = NEVPNProtocolIPSec (NIL) } conf!.serverAddress = "10.200.11.108" //vpn server address conf!.username = "Zach" //vpn conf.AuthenticationMethod.SharedSecret account! = / / select shared key conf!.sharedSecretReference = self.searchKeychainCopyMatching (self.vpnPrivateKeyIdentifier / CONF) to get the shared key from the keychain!.passwordReference = self.searchKeychainCopyMatching (self.vpnPwdIdentifier) / manager.protocolConfiguration password = conf from keychain;! Manager.localizedDescription = "you VPN"; automatically selected the current VPN {manager.isEnabled = manager.saveToPreferences true //allow (error) in dialog box ("done: / print (error.debugDescription)" if error = = Nil) {self.vpnManager}}}} = Manager / * * * * func dictionary used to access the keychain newSearchDictionary (identifier _: String -> NSMutableDictionary) {let searchDictionary = NSMutableDictionary (let) encodedIdentifier: Data = identifier.data (using:.Utf8) searchDictionary.addEntries from: kSecClass as! ([NSString: kSecClassGenericPassword as NSString kSecAttrGeneric as, NSString: encodedIdentifier, kSecAttrAccount as NSString: encodedIdentifier kSecAttrService, as NSString: serviceName return searchDictionary)]} / * * * * func searchKeychainCopyMatching search Keychain data corresponding to the (_ identifier: String -> Data{let search); Dictionary = newSearchDictionary (identifier) searchDictionary.addEntries (from: kSecMatchLimit as NSString: kSecMatchLimitOne as NSString [kSecReturnPersistentRef as true], NSString:) var result: CFTypeRef? SecItemCopyMatching (searchDictionary = nil as CFMutableDictionary, & return result; result) as Keychain func createKeychainValue Data data! * /} / * * * create the corresponding (_ password: String, identifier: String _) -> Bool{let dictionary = newSearchDictionary (identifier) var status: OSStatus = SecItemDelete (Dictionary as CFMutableDictionary) let passwordData: Data (using:.Utf8) = password.data (passwordData, forKey: dictionary.setObject! KSecValueData as status = NSString) SecItemAdd (Dictionary as CFDictionary, Nil) return status = = errSecSuccess}

The content is very simple, after obtaining NEVPNManager cases, call the manager.loadFromPreferences method to load the configuration information once it is simple, in order to write here, every time to directly modify the configuration information. Note: NEVPNManager can not be directly initialized, it calls the shared () method to obtain single cases.

It should be noted that conf!.authenticationMethod has three values:

Public enum NEVPNIKEAuthenticationMethod: Int @const NEVPNIKEAuthenticationMethodNone {/ *! Do not authenticate with the IPSec server / case none / / @const NEVPNIKEAuthenticationMethodCertificate / * do authentication! Use a certificate and private key as the authentication credential / case certificate / NEVPNIKEAuthenticationMethodSharedSecret Use / @const certification! A shared secret as the authentication credential case sharedSecret * /} / / shared key authentication

And we use the shared key authentication. If you want to use certificate authentication, call the method as follows:

Conf!.authenticationMethod =.Certificate try!.identityData = Data (contentsOf: Bundle.main.url (forResource: "client", withExtension: "p12")! Conf!.identityDataPassword = "p12 file password"

Other content mainly look at the code on the list

Finally, in the viewDidLoad method calls the createManager method, so that when you open the software that prompted the installation of VPN dialog box

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.3.2

Click allow, after the certification can be seen below the personal VPN which will be added to a just set to go you VPN”

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.3.3

(in fact, after the completion of the verification, the switch has been closed in, here is the screenshot, so do not care about these details)

And then back to the main interface. We want to open VPN, click on the middle of the switch to add, you can happily connect to the VPN (laughs)

Of course, even not, because we haven’t given the middle UISwitch add logic section

@IBAction func switchChangeAction (_ sender: UISwitch) {if vpnManager.connection.status = =.Disconnected {do {try} catch {NSLog (vpnManager.connection.startVPNTunnel) ("start / error: (error.localizedDescription)} {else}")}} (vpnManager.connection.stopVPNTunnel)

Well, it’s done, turn on the switch and connect to our server

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.3.4

Pictured above is the connection of the state, to determine how we really connected to it, a visit IP website after viewing the current public ip. because I am in the VPN test set up within the network, so the network IP is the same, so simply check the login server connection users know
figure, login before vpn:

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.3.5

After connecting vpn:

Hand NetworkExtension: 1 create L2TP/IPSec VPN connection
figure 2.3.6

Well, it’s done!!!

Finally, you have to spit Tucao, NetworkExtension related tutorials, the network can not be found on the whole letter, a lot of either can not be used, or is too old, really can not be normal use

This article describes the PersonalVPN function is actually very relevant to NetworkExtension, such as learning to develop such as Surge or Sh****Rocket, etc. these excellent tools, this part of the knowledge is the first step

Well, the first step towards Surge or Sh****Rocket’s one hundred step (laughter) is a good step forward, and the next few days will continue to talk about this development

Than heart

P.S. 10.12.4 Chrome57.0.2987.133 (64-bit) version is really really collapse and the collapse of the
P.S. core browser actually careful people have found that the creation of L2TP/IPSec no less than PacketProtocolProvider, even if it does not add also never mind. No! After all with the NEVPNManager, instead of NETunnelProtocolManager. in NETunnelProtocolManager is a subclass of NEVPNManager in subsequent articles, we will use this, don’t worry, I’m not rich old Kennedy (after all, nobody’s talent), will not stop more
P.S. second has been updated to –> the hand analysis of NetworkExtension: 2 official Demo source NEPacketTunnelProvider part

Please tell me, and indicate the source, thank you