TunnelKit
这个库为 VPN 开发提供了一个通用的框架,并在 Apple 平台上提供了一个针对 OpenVPN® 协议的简化 Swift/Obj-C 实现。加密层建立在 OpenSSL 1.1.1 的基础上,从而支持一定范围的加密和摘要算法。
入门指南
客户端已知与 OpenVPN® 2.3+ 服务器兼容。
- 通过 UDP 或 TCP 进行握手和隧道传输
- 加密
- AES-CBC (128/192/256 位)
- AES-GCM (128/192/256 位,2.4)
- HMAC 摘要
- SHA-1
- SHA-2 (224/256/384/512 位)
- NCP (可协商加密参数,2.4)
- 服务器端
- TLS 握手
- 服务器验证(CA,EKU)
- 客户端证书
- TLS 包装
- 身份验证(
--tls-auth
) - 加密(
--tls-crypt
)
- 身份验证(
- 压缩帧
- 通过
--comp-lzo
(2.4 中已弃用) - 通过
--compress
- 通过
- 压缩算法
- LZO(通过
--comp-lzo
或--compress lzo
)
- LZO(通过
- 密钥协商
- 重放保护(硬编码的窗口)
因此,此库支持压缩帧,但不支持新的压缩算法。请确保与服务器端匹配压缩和帧类型,否则客户端将以错误终止。例如,如果服务器具有 comp-lzo no
,则客户端必须使用 compressionFraming = .compLZO
。
支持 .ovpn 配置
TunnelKit 能够解析 .ovpn 配置文件。以下是一些值得关注的细节。
非标准配置
- 单字节 XOR 掩码
- 通过
--scramble xormask <字符>
- 使用字符参数的 ASCII 值进行 XOR 所有传入和传出的字节
- 有关更多详细信息,请参阅 Tunnelblick 网站
- 通过
不支持
- UDP 分片,即
--fragment
- 通过
--compress
压缩(除空或lzo
外的所有内容) - 通过代理连接
- 外部文件引用(仅内联
<block>
) - 静态密钥加密(非 TLS)
<connection>
块- 路由中的
vpn_gateway
和net_gateway
语句
忽略
- 一些 MTU 覆盖
--link-mtu
及其变体--mssfix
- 带有不同
host
值的多个--remote
(第一个优先) - 静态客户端路由
许多其他标志也被忽略,但通常不会造成问题。
安装
要求
- iOS 12.0+ / macOS 10.15+
- Xcode 11+ (Swift 5)
- Git(Xcode 命令行工具预装)
- Ruby(macOS 预装)
- CocoaPods 1.6.0
- jazzy(可选,用于文档,为文档)
- 禁用 Bitcode
强烈建议使用由 Homebrew 提供的 Git 和 Ruby 软件包。
CocoaPods
要配合CocoaPods使用,只需添加以下内容到您的Podfile中:
pod 'TunnelKit'
测试
在本地下载库代码库
$ git clone https://github.com/passepartoutvpn/tunnelkit.git
假设您已经有一个工作正常的CocoaPods环境,设置库工作空间只需安装pod依赖项
$ pod install
然后,在Xcode中打开TunnelKit.xcworkspace
,运行TunnelKitTests
文件夹中的单元测试。只需在TunnelKit-(iOS|macOS)
上按CMD+U即可。
示例
有示例目标包含一个用于测试隧道的基本应用,称为BasicTunnel
。
为了使VPN正常工作,BasicTunnel
示例需要
- 应用组和密钥链共享功能
- 具有数据包隧道权限的应用ID
这两种功能都在主应用和隧道扩展目标中。
要测试您自己环境中的连接性,请修改文件TunnelKit/Demo/Configuration.swift
以匹配您的VPN服务器参数。
示例
private let ca = CryptoContainer(pem: """
-----BEGIN CERTIFICATE-----
MIIFJDCC...
-----END CERTIFICATE-----
""")
请确保也更新以下文件中的以下常量,根据您的开发账户和目标包标识符
public static let appGroup
public static let tunnelIdentifier
请记住,macOS上的App Group需要团队ID前缀。
文档
该库分为几个模块,以将底层协议实现与特定平台的桥接解耦,即NetworkExtension VPN框架。
公共接口的完整文档可用,并可以使用jazzy生成。在安装jazzy Ruby gem后,进入存储库的根目录并运行
$ gem install jazzy
然后
$ jazzy
生成的输出存储在HTML格式的docs
目录中。
核心
包含VPN协议的基本构建块。最终,消费者将实现会话
接口,预期用来启动和控制VPN会话。会话可以与通用网络接口一起工作。
LinkInterface
(例如,一个套接字)TunnelInterface
(例如,一个utun
接口)
此模块中没有物理网络实现(例如UDP或TCP)。
应用扩展
在NetworkExtension框架之上提供了一个层。最重要的是,它将原生NWUDPSession和NWTCPConnection桥梁连接到一个抽象的GenericSocket
接口,从而使多协议VPN的管理变得容易很多。
管理器
此子规范包括方便的类来控制VPN隧道,而无需NetworkExtension的烦恼。查看VPNProvider
实现
MockVPNProvider
(默认,用于仿真器上的测试)NetworkExtensionVPNProvider
(用于IPSec/IKEv2)
协议/原生
在这里您可以找到NativeProvider
,它是一种基于原生的IPSec/IKEv2协议管理VPN配置的通用方式。只需将一个NEVPNProtocolIPSec
或NEVPNProtocolIKEv2
对象包装在NetworkExtensionVPNConfiguration
中,然后用于安装或连接VPN。
协议/OpenVPN
这里是在其上建立 OpenVPN 连接的低级别实体。代码混合了 Swift 和 Obj-C,大部分并未对消费者暴露。此模块依赖于 OpenSSL。
入口点是 OpenVPNSession
类。网络层完全抽象,并使用不透明的 IOInterface
(LinkInterface
和 TunnelInterface
)以及 OpenVPNSessionDelegate
协议外部委派。
本模块的另一个目标是打包一个黑盒实现的 NEPacketTunnelProvider,它是 Packet Tunnel Provider 应用程序扩展的核心部分。您将在 OpenVPNTunnelProvider
类中找到主要实现。在客户端,您可以使用 OpenVPNProvider
类管理 VPN 个人资料,它是 NetworkExtensionVPNProvider
的具体实现。
可选地维护并共享调试日志快照,以便通过 App Group 容器托管宿主应用程序。
额外/LZO
由于限制性的许可(GPLv2),LZO 支持作为一个可选子规范提供。
许可
版权 (c) 2020 Davide De Rosa。保留所有权利。
第I部分
此项目遵循 GPLv3 许可。
第II部分
如 libsignal-protocol-c 所见
提交到苹果应用商店的额外权限:在您遵守每个被覆盖作品(包括但不限于根据 GPL 第 6 条提供相应用户源代码)的 GPLv3 的前提下,作者还授予您额外的许可,通过苹果应用商店传达程序的非源执行版本,这些版本作为应用程序中每个相关的被覆盖作品的可执行版本仅根据 Mozilla 公共许可证版本 2.0 (MPL 2.0) 进行传达 https://www.mozilla.org/en-US/MPL/2.0/ )。
第三部分
第一部分和第二部分不适用于LZO库,它仍按GPLv2+条款授权。
贡献
通过贡献本项目,您同意在《贡献者许可协议(CLA)》中声明的条款。
更多详细信息请参阅CONTRIBUTING。
致谢
- lzo - 版权所有 (c) 1996-2017 Markus F.X.J. Oberhumer
- PIATunnel - 版权所有 (c) 2018-Present Private Internet Access
- SURFnet
- SwifyBeaver - 版权所有 (c) 2015 Sebastian Kreutzberger
- XMB5 的 XOR 补丁 - 版权所有 (c) 2020 Sam Foxman
本产品包含由OpenSSL项目为OpenSSL工具包开发的开源软件。(https://www.openssl.org/)
版权所有 (c) 2002-2018 OpenVPN Inc. - OpenVPN 是 OpenVPN Inc. 的注册商标。
联系信息
Twitter: @keeshux