谈谈 iOS的 Network Extension

由于工作原因,对 iOS 的 VPN 方面比较关心,基本上在第一时间就发现并研究了 Network Extension(以下简称 NE),在这篇文章里做个入门指南。
另外,做了一个完整的 IKEv2 版 Demo(Github),服务端配置可以参考用 strongSwan 搭建免证书的 IKEv2 VPN

介绍
NE 向应用开放了 VPN(Personal VPN)的权限,开发者可以创建、修改、删除 VPN 配置,启动、停止 VPN,以及获取 VPN 状态等。目前只支持 Cisco IPSec 和 IKEv2。
可能是 NE 的受众太小,只有我们这样的厂商才会关心,所以 Apple 连个官方文档头没提供,目前所能掌握的东西只有头文件里的注释。
推荐读者在看这篇文章之前先阅读一篇外国友人写的教程,他把步骤描述的很详细,基本上照着一步步做就行了。我当时也是看了这篇文章,然后根据自己摸索才弄明白的。这里只点出需要注意的重点。
准备工作
你需要 Enable App ID 中的 “VPN Configuration & Control”,然后在应用的 “Capabilities” 中打开 “Personal VPN”,这时候 Xcode 会完成一些初始化工作。
最后,链接上 “NetworkExtension.framework”,然后在代码里#import <NetworkExtension/NetworkExtension.h>
就 OK 了。
工作流程
NE 的工作流程基本上分为以下几步:
加载系统配置
这步很重要,初次操作 NE 时一定别忘了先加载,否则将会出现一些莫名其妙的问题。
// init VPN managerself.vpnManager = [NEVPNManager sharedManager]; // load config from perference [_vpnManager loadFromPreferencesWithCompletionHandler:^(NSError *error) { // Do something}];

这里需要说明一下,NE 需要给系统安装一个配置文件(类似于 mobileconfig)才能工作,应用在退出后可以在系统设置的 VPN 选项中手动开启 VPN。这个配置文件和 NEVPNManager 是不会自动同步的,也就是说每次操作 NEVPNManager,都必须先从配置文件加载内容,如果做了修改,一定要记得保存。
而且,如果手动在系统设置里面把配置文件删除,NEVPNManager 的内容还是会存在的。所以,每次启动 VPN 之前都应该加载一下配置,确保配置文件存在。
'添加或修改 IPSec 或 IKEv2 配置信息(以 IPSec 为例)
// config IPSec protocolNEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init]; p.username = @"[Your username]"; p.serverAddress = @"[Your server address]"; // get password persistent reference from keychain p.passwordReference = [self searchKeychainCopyMatching:@"VPN_PASSWORD"];// PSK p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret; p.sharedSecretReference = [self searchKeychainCopyMatching:@"PSK"]; // certificate p.identityData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle]]; pathForResource:@"client" ofType:@"p12"]]; p.identityDataPassword = @"[Your certificate import password]"; p.localIdentifier = @"[VPN local identifier]"; p.remoteIdentifier = @"[VPN remote identifier]"; p.useExtendedAuthentication = YES; p.disconnectOnSleep = NO;

上面的代码应该放到loadFromPreferencesWithCompletionHandler
的 block 中执行,这样可以确保系统配置已经加载完成。
IPSec 协议里的密码以及预共享密钥都需要是一个 KeyChain 中密码的永久引用(persistent reference)。
如果用证书来作为 IKE 的认证方式,而且 Server 端用的是自签发证书,则需要手工将 CA 导入到 iOS 设备。目前 Apple 还没提供添加授信证书的方法。
保存配置
[_vpnManager saveToPreferencesWithCompletionHandler:^(NSError *error) { NSLog(@"Save config failed [%@]", error.localizedDescription);}];

启动 VPN
NSError *startError; [_vpnManager.connection startVPNTunnelAndReturnError:&startError];if (startError) { NSLog("Start VPN failed: [%@]", startError.localizedDescription);}

根据目前的测试结果来看,startVPNTunnelAndReturnError
只会在配置有误的时候才会返回 Error。其他时候,比如协议协商失败、连接超时等系统都会直接弹出对话框。

由于没有官方文档说明,不知道是调用方式不对还是 NE 本身不稳定,开发过程中遇到了很多大坑:
上面提到的,系统配置文件和 NEVPNManager 内容不同步,需要监听 “NEVPNConfigurationChangeNotification” 消息。
NEVPNManager 的操作基本上都是异步的,改配置时必须确保 load 完成,启动 VPN 时必须确保 save 完成。
有时候创建、保存配置一切正常,但是启动时就会提示 “未知错误”。这时候需要在系统设置里面手动启动一次 VPN,然后程序就可以正常启动了……有时候手动启动也不成,那就得把配置文件删除,然后重新安装……

更新解决方法:
在调用 NEVPNManager 的 saveToPreferencesWithCompletionHandler
方法前,应将它的 enabled
属性置成 “YES”。

配置 IPSec 协议时,密码相关的(证书密码除外)必须得是 KeyChain 的永久引用,即kSecReturnPersistentRef
需要是 YES。

获取 VPN 状态时,NEVPNConnection 的 status 属性是不支持 KVO 的,需要监听 “NEVPNStatusDidChangeNotification” 事件。这点应该是 By-design 的,但是这个问题当时困扰我很久……

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 开发者账号 iOS Developer Program 目前有三种: 个人版,公司版和企业版。点击详情. •$ 9...
    2c8c24bf4556阅读 764评论 0 1
  • 扯淡的事,干了不少。 没有高效输入,也没有多渠道输出,更离谱的是没有建立反馈机制。搞得一副干大事的样子,口号喊得山...
    池恩琛阅读 457评论 0 1
  • 今天读了《财务自由之路II》,总结出几个对自己有用的赚钱游戏规则。 【游戏规则一:并非一次,而是多次(自用省钱,分...
    南茜_Nancy阅读 661评论 0 0