mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2024-10-06 17:22:07 +08:00
168 lines
5.4 KiB
Markdown
168 lines
5.4 KiB
Markdown
# OpenVPNAdapter
|
|
|
|
![Platforms](https://img.shields.io/badge/Platforms-iOS%20%7C%20macOS-lightgrey.svg)
|
|
![iOS Versions](https://img.shields.io/badge/iOS-9.0+-yellow.svg)
|
|
![macOS Versions](https://img.shields.io/badge/macOS-10.11+-yellow.svg)
|
|
![Xcode Version](https://img.shields.io/badge/Xcode-9.0+-yellow.svg)
|
|
![Carthage Compatible](https://img.shields.io/badge/Carthage-Compatible-4BC51D.svg?style=flat)
|
|
![License](https://img.shields.io/badge/License-AGPLv3-lightgrey.svg)
|
|
|
|
## Overview
|
|
## Installation
|
|
### Requirements
|
|
- iOS 9.0+ or macOS 10.11+
|
|
- Xcode 9.0+
|
|
|
|
### Carthage
|
|
To install OpenVPNAdapter with Carthage, add the following line to your `Cartfile`.
|
|
|
|
```
|
|
github "ss-abramchuk/OpenVPNAdapter"
|
|
```
|
|
|
|
Then run `carthage update` command. For details of the installation and usage of Carthage, visit [its project page](https://github.com/Carthage/Carthage).
|
|
|
|
## Usage
|
|
OpenVPNAdapter is designed to use in conjunction with [`NetworkExtension`](https://developer.apple.com/documentation/networkextension) framework. So at first, you need to add a Packet Tunnel Provider extension to the project and configure provision profiles for both the container app and the extension. There are official documentation and many tutorials describing how to do it so we won't dwell on this in detail.
|
|
|
|
Packet Tunnel Provider extension uses [`NEPacketTunnelProvider`](https://developer.apple.com/documentation/networkextension/nepackettunnelprovider) subclass to configure and establish VPN connection. Therefore, that class is the right place to configure OpenVPNAdapter. The following example shows how you can setup it:
|
|
|
|
```swift
|
|
import NetworkExtension
|
|
import OpenVPNAdapter
|
|
|
|
class PacketTunnelProvider: NEPacketTunnelProvider {
|
|
|
|
lazy var vpnAdapter: OpenVPNAdapter = {
|
|
let adapter = OpenVPNAdapter()
|
|
adapter.delegate = self
|
|
|
|
return adapter
|
|
}()
|
|
|
|
let vpnReachability = OpenVPNReachability()
|
|
|
|
var startHandler: ((Error?) -> Void)?
|
|
var stopHandler: (() -> Void)?
|
|
|
|
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
|
let ovpnFileContent: NSData = ... // Retrieve content of a ovpn file
|
|
let ovpnSettings: [String : String] = ... // Retrieve settings as key:value pairs
|
|
|
|
let configuration = OpenVPNConfiguration()
|
|
configuration.fileContent = ovpnFileContent
|
|
configuration.settings = ovpnSettings
|
|
|
|
let properties: OpenVPNProperties
|
|
do {
|
|
properties = try vpnAdapter.apply(configuration: configuration)
|
|
} catch {
|
|
completionHandler(error)
|
|
return
|
|
}
|
|
|
|
if !properties.autologin {
|
|
let username: String = ... // Retrieve a username
|
|
let password: String = ... // Retrieve a password
|
|
|
|
let credentials = OpenVPNCredentials()
|
|
credentials.username = username
|
|
credentials.password = password
|
|
|
|
do {
|
|
try vpnAdapter.provide(credentials: credentials)
|
|
} catch {
|
|
completionHandler(error)
|
|
return
|
|
}
|
|
}
|
|
|
|
vpnReachability.startTracking { [weak self] status in
|
|
guard status != .notReachable else { return }
|
|
self?.vpnAdapter.reconnect(interval: 5)
|
|
}
|
|
|
|
startHandler = completionHandler
|
|
vpnAdapter.connect()
|
|
}
|
|
|
|
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
|
stopHandler = completionHandler
|
|
|
|
if vpnReachability.isTracking {
|
|
vpnReachability.stopTracking()
|
|
}
|
|
|
|
vpnAdapter.disconnect()
|
|
}
|
|
|
|
}
|
|
|
|
extension PacketTunnelProvider: OpenVPNAdapterDelegate {
|
|
|
|
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings, completionHandler: @escaping (OpenVPNAdapterPacketFlow?) -> Void) {
|
|
setTunnelNetworkSettings(settings) { (error) in
|
|
completionHandler(error == nil ? self.packetFlow : nil)
|
|
}
|
|
}
|
|
|
|
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleEvent event: OpenVPNAdapterEvent, message: String?) {
|
|
switch event {
|
|
case .connected:
|
|
if reasserting {
|
|
reasserting = false
|
|
}
|
|
|
|
guard let startHandler = startHandler else { return }
|
|
|
|
startHandler(nil)
|
|
self.startHandler = nil
|
|
|
|
case .disconnected:
|
|
guard let stopHandler = stopHandler else { return }
|
|
|
|
if vpnReachability.isTracking {
|
|
vpnReachability.stopTracking()
|
|
}
|
|
|
|
stopHandler()
|
|
self.stopHandler = nil
|
|
|
|
case .reconnecting:
|
|
reasserting = true
|
|
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleError error: Error) {
|
|
guard let fatal = (error as NSError).userInfo[OpenVPNAdapterErrorFatalKey] as? Bool, fatal == true else {
|
|
return
|
|
}
|
|
|
|
if vpnReachability.isTracking {
|
|
vpnReachability.stopTracking()
|
|
}
|
|
|
|
if let startHandler = startHandler {
|
|
startHandler(error)
|
|
self.startHandler = nil
|
|
} else {
|
|
cancelTunnelWithError(error)
|
|
}
|
|
}
|
|
|
|
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleLogMessage logMessage: String) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {}
|
|
```
|
|
|
|
## Contributing
|
|
## Acknowledgments
|
|
## License
|