'I am working on a VPN app which used Open VPN and I am not sure how to call the tunnel
I don't understand how does packet tunnel work and also don't understand where use packet tunnel in view controller. My .ovpn file is working fine but not connecting only show the details of my server address.
Can any one explain whole process how does implement OpenVPN and vpn on demand.
import NetworkExtension
import UIKit
class ViewController: UIViewController {
var providerManager: NETunnelProviderManager!
override func viewDidLoad() {
super.viewDidLoad()
self.loadProviderManager {
self.configureVPN(serverAddress: "s_id", username: "uid", password: "password")
}
}
func loadProviderManager(completion:@escaping () -> Void) {
NETunnelProviderManager.loadAllFromPreferences { (managers, error) in
if error == nil {
self.providerManager = managers?.first ?? NETunnelProviderManager()
completion()
}
}
}
func configureVPN(serverAddress: String, username: String, password: String) {
guard
let configurationFileURL = Bundle.main.url(forResource: "ios", withExtension: ".ovpn"),
let configData = try? Data(contentsOf: configurationFileURL)
else {
fatalError()
}
self.providerManager?.loadFromPreferences { error in
if error == nil {
let tunnelProtocol = NETunnelProviderProtocol()
tunnelProtocol.username = username
tunnelProtocol.serverAddress = serverAddress
tunnelProtocol.providerBundleIdentifier = "com.pushNotifications.tunnel" // bundle id of the network extension target
tunnelProtocol.providerConfiguration = ["ovpn": configData, "username": username, "password": password]
tunnelProtocol.disconnectOnSleep = false
self.providerManager.protocolConfiguration = tunnelProtocol
self.providerManager.localizedDescription = "OpenVPN" // the title of the VPN profile which will appear on Settings
self.providerManager.isEnabled = true
self.providerManager.saveToPreferences(completionHandler: { (error) in
if error == nil {
self.providerManager.loadFromPreferences(completionHandler: { (error) in
do {
try self.providerManager.connection.startVPNTunnel()
print("Starting")// starts the VPN tunnel.
} catch let error {
print(error.localizedDescription)
}
})
}
})
}
}
}
This is my packet tunnel code.
import NetworkExtension
import OpenVPNAdapter
import UIKit
class PacketTunnelProvider: NEPacketTunnelProvider {
var startHandler: ((Error?) -> Void)?
var stopHandler: (() -> Void)?
var vpnReachability = OpenVPNReachability()
var configuration: OpenVPNConfiguration!
var properties: OpenVPNConfigurationEvaluation!
var UDPSession: NWUDPSession!
var TCPConnection: NWTCPConnection!
lazy var vpnAdapter: OpenVPNAdapter = {
let adapter = OpenVPNAdapter()
adapter.delegate = self
return adapter
}()
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
guard
let protocolConfiguration = protocolConfiguration as? NETunnelProviderProtocol,
let providerConfiguration = protocolConfiguration.providerConfiguration
else {
fatalError()
}
guard let ovpnFileContent: Data = providerConfiguration["ovpn"] as? Data else { return }
let configuration = OpenVPNConfiguration()
configuration.fileContent = ovpnFileContent
do {
properties = try vpnAdapter.apply(configuration: configuration)
} catch {
completionHandler(error)
return
}
configuration.tunPersist = true
if !properties.autologin {
if let username: String = providerConfiguration["username"] as? String, let password: String = providerConfiguration["password"] as? String {
let credentials = OpenVPNCredentials()
credentials.username = username
credentials.password = password
do {
try vpnAdapter.provide(credentials: credentials)
print("vpnAdapter")
} catch {
completionHandler(error)
return
}
}
}
vpnReachability.startTracking { [weak self] status in
guard status != .notReachable else { return }
self?.vpnAdapter.reconnect(afterTimeInterval: 5)
}
startHandler = completionHandler
vpnAdapter.connect(using: packetFlow)
}
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
stopHandler = completionHandler
if vpnReachability.isTracking {
vpnReachability.stopTracking()
}
vpnAdapter.disconnect()
}
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
if let handler = completionHandler {
handler(messageData)
}
}
override func sleep(completionHandler: @escaping () -> Void) {
completionHandler()
}
override func wake() {
}
}
extension PacketTunnelProvider: OpenVPNAdapterDelegate {
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (Error?) -> Void) {
networkSettings?.dnsSettings?.matchDomains = [""]
// Set the network settings for the current tunneling session.
setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)
}
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (OpenVPNAdapterPacketFlow?) -> Void) {
setTunnelNetworkSettings(networkSettings) { (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
}
NSLog("Error: \(error.localizedDescription)")
NSLog("Connection Info: \(vpnAdapter.connectionInformation.debugDescription)")
if vpnReachability.isTracking {
vpnReachability.stopTracking()
}
if let startHandler = startHandler {
startHandler(error)
self.startHandler = nil
} else {
cancelTunnelWithError(error)
}
}
func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleLogMessage logMessage: String) {
NSLog("Log: \(logMessage)")
}
}
extension PacketTunnelProvider: OpenVPNAdapterPacketFlow {
func readPackets(completionHandler: @escaping ([Data], [NSNumber]) -> Void) {
packetFlow.readPackets(completionHandler: completionHandler)
}
func writePackets(_ packets: [Data], withProtocols protocols: [NSNumber]) -> Bool {
return packetFlow.writePackets(packets, withProtocols: protocols)
}
}
extension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|