OpenVPN Adapter now can be compiled for both macOS and iOS

This commit is contained in:
Sergey Abramchuk
2017-03-11 13:48:47 +03:00
parent fd528d6274
commit 146ea30114
30 changed files with 705 additions and 172 deletions
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>OpenVPN iOS Tunnel Provider</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.networkextension.packet-tunnel</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
</dict>
</dict>
</plist>
@@ -0,0 +1,45 @@
//
// KeychainAccess+Reference.swift
// OpenVPN iOS Client
//
// Created by Sergey Abramchuk on 07.03.17.
//
//
import Foundation
import KeychainAccess
extension Keychain {
public func get(ref: Data) throws -> String? {
guard let data = try getData(ref: ref) else {
return nil
}
return String(data: data, encoding: .utf8)
}
public func getData(ref: Data) throws -> Data? {
let query: [String: Any] = [
String(kSecClass): itemClass.rawValue,
String(kSecReturnData): kCFBooleanTrue,
String(kSecValuePersistentRef): ref as CFData
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
switch status {
case errSecSuccess:
guard let data = result as? Data else {
throw Status.unexpectedError
}
return data
case errSecItemNotFound:
return nil
default:
throw Status(status: status)
}
}
}
@@ -0,0 +1,13 @@
//
// NEPacketTunnelFlow+OpenVPN.swift
// OpenVPN iOS Client
//
// Created by Sergey Abramchuk on 09.03.17.
//
//
import Foundation
import NetworkExtension
import OpenVPNAdapter
extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow { }
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.me.ss-abramchuk.openvpn-ios-client</string>
</array>
</dict>
</plist>
@@ -0,0 +1,87 @@
//
// PacketTunnelProvider.swift
// OpenVPN Tunnel Provider
//
// Created by Sergey Abramchuk on 05.02.17.
//
//
import NetworkExtension
import KeychainAccess
import OpenVPNAdapter
enum PacketTunnelProviderError: Error {
case fatalError(message: String)
}
class PacketTunnelProvider: NEPacketTunnelProvider {
let keychain = Keychain(service: "me.ss-abramchuk.openvpn-ios-client", accessGroup: "2TWXCGG7R3.keychain-shared")
lazy var vpnAdapter: OpenVPNAdapter = {
return OpenVPNAdapter().then { $0.delegate = self }
}()
var startHandler: ((Error?) -> Void)?
var stopHandler: (() -> Void)?
override func startTunnel(options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void) {
guard let settings = options?["Settings"] as? Data else {
let error = PacketTunnelProviderError.fatalError(message: "Failed to retrieve OpenVPN settings from options")
completionHandler(error)
return
}
if let username = protocolConfiguration.username {
vpnAdapter.username = username
}
if let reference = protocolConfiguration.passwordReference {
do {
guard let password = try keychain.get(ref: reference) else {
throw PacketTunnelProviderError.fatalError(message: "Failed to retrieve password from keychain")
}
vpnAdapter.password = password
} catch {
completionHandler(error)
return
}
}
do {
try vpnAdapter.configure(using: settings)
} catch {
completionHandler(error)
return
}
startHandler = completionHandler
vpnAdapter.connect()
}
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
stopHandler = completionHandler
vpnAdapter.disconnect()
}
}
extension PacketTunnelProvider: OpenVPNAdapterDelegate {
func configureTunnel(settings: NEPacketTunnelNetworkSettings, callback: @escaping (OpenVPNAdapterPacketFlow?) -> Void) {
setTunnelNetworkSettings(settings) { (error) in
callback(error == nil ? self.packetFlow : nil)
}
}
func handle(event: OpenVPNEvent, message: String?) {
}
func handle(error: Error) {
}
}
+62
View File
@@ -0,0 +1,62 @@
//
// Then.swift
// MCPEBot
//
// Created by Sergey Abramchuk on 27.01.17.
// Copyright © 2017 ss-abramchuk. All rights reserved.
//
import Foundation
import CoreGraphics
public protocol Then {}
extension Then where Self: Any {
/// Makes it available to set properties with closures just after initializing and copying the value types.
///
/// let frame = CGRect().with {
/// $0.origin.x = 10
/// $0.size.width = 100
/// }
public func with(_ block: (inout Self) -> Void) -> Self {
var copy = self
block(&copy)
return copy
}
/// Makes it available to execute something with closures.
///
/// UserDefaults.standard.do {
/// $0.set("devxoul", forKey: "username")
/// $0.set("devxoul@gmail.com", forKey: "email")
/// $0.synchronize()
/// }
public func `do`(_ block: (Self) -> Void) {
block(self)
}
}
extension Then where Self: AnyObject {
/// Makes it available to set properties with closures just after initializing.
///
/// let label = UILabel().then {
/// $0.textAlignment = .Center
/// $0.textColor = UIColor.blackColor()
/// $0.text = "Hello, World!"
/// }
public func then(_ block: (Self) -> Void) -> Self {
block(self)
return self
}
}
extension NSObject: Then {}
extension CGPoint: Then {}
extension CGRect: Then {}
extension CGSize: Then {}
extension CGVector: Then {}