ios - plus - id remoto vpn iphone
Conéctate a la VPN programáticamente en iOS 8 (2)
Desde el lanzamiento de iOS 8 beta, encontré un marco de extensión de red en su paquete que permitirá a los desarrolladores configurar y conectarse a servidores VPN mediante programación y sin ninguna instalación de perfil.
El marco contiene una clase principal llamada NEVPNManager. Esta clase también tiene 3 métodos principales que me permiten guardar, cargar o eliminar preferencias de VPN. He escrito un fragmento de código en el método viewDidLoad de la siguiente manera:
NEVPNManager *manager = [NEVPNManager sharedManager];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vpnConnectionStatusChanged) name:NEVPNStatusDidChangeNotification object:nil];
[manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
if(error) {
NSLog(@"Load error: %@", error);
}}];
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.username = @“[My username]”;
p.passwordReference = [KeyChainAccess loadDataForServiceNamed:@"VIT"];
p.serverAddress = @“[My Server Address]“;
p.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
p.localIdentifier = @“[My Local identifier]”;
p.remoteIdentifier = @“[My Remote identifier]”;
p.useExtendedAuthentication = NO;
p.identityData = [My VPN certification private key];
p.disconnectOnSleep = NO;
[manager setProtocol:p];
[manager setOnDemandEnabled:NO];
[manager setLocalizedDescription:@"VIT VPN"];
NSArray *array = [NSArray new];
[manager setOnDemandRules: array];
NSLog(@"Connection desciption: %@", manager.localizedDescription);
NSLog(@"VPN status: %i", manager.connection.status);
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
if(error) {
NSLog(@"Save error: %@", error);
}
}];
También coloqué un botón en mi vista y configuré su acción TouchUpInside según el método a continuación:
- (IBAction)buttonPressed:(id)sender {
NSError *startError;
[[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];
if(startError) {
NSLog(@"Start error: %@", startError.localizedDescription);
}
}
Hay dos problemas aquí:
1) Cuando intento guardar las preferencias, aparecerá el siguiente error: Guardar error: Dominio de error = NEVPNErrorDomain Code = 4 "No se pudo completar la operación. (Error de NEVPNErrorDomain 4.)" ¿Qué es este error? ¿Cómo puedo hacerlo? ¿Resuelvo este problema?
2) [[NEVPNManager sharedManager] .connection startVPNTunnelAndReturnError: & startError]; El método no devuelve ningún error cuando lo llamo, pero el estado de la conexión cambia de Desconectado a Conectándose por un momento y luego vuelve al estado Desconectado.
Cualquier ayuda será apreciada :)
El problema es el error que está obteniendo al guardar: Save error: Error Domain=NEVPNErrorDomain Code=4
guardado: Save error: Error Domain=NEVPNErrorDomain Code=4
Si busca en el archivo de cabecera NEVPNManager.h, verá que el código de error 4 es "NEVPNErrorConfigurationStale". La configuración es obsoleta y necesita ser cargada. Debe llamar a loadFromPreferencesWithCompletionHandler:
y, en el controlador de finalización, modificar los valores que desea modificar y luego llamar a saveToPreferencesWithCompletionHandler:
El ejemplo de su pregunta es modificar la configuración antes de que se complete la carga, por lo que está recibiendo este error.
Más así:
[manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
// do config stuff
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
}];
}];
Esta respuesta será útil para aquellos que buscan una solución utilizando el marco de Network Extension.
Mi requisito era conectar / desconectar el servidor VPN con el protocolo IKEv2 (por supuesto, también puede usar esta solución para IPSec cambiando la configuración del protocolo vpnManager)
NOTA: Si está buscando el protocolo L2TP, no es posible usar la extensión de red para conectar el servidor VPN. Consulte: https://forums.developer.apple.com/thread/29909
Aquí está mi fragmento de código de trabajo:
Declarar objetos VPNManager y otras cosas útiles
var vpnManager = NEVPNManager.shared()
var isConnected = false
@IBOutlet weak var switchConntectionStatus: UISwitch!
@IBOutlet weak var labelConntectionStatus: UILabel!
Agregue un observador en viewDidLoad para obtener VPN Staus y almacene vpnPassword en Keychain, también puede almacenar SharedSecret, que necesitará el protocolo IPSec.
override func viewDidLoad() {
super.viewDidLoad()
let keychain = KeychainSwift()
keychain.set("*****", forKey: "vpnPassword")
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.VPNStatusDidChange(_:)), name: NSNotification.Name.NEVPNStatusDidChange, object: nil)
}
Ahora en mi aplicación tenía UISwitch para conectar / desconectar el servidor VPN.
func switchClicked() {
switchConntectionStatus.isOn = false
if !isConnected {
initVPNTunnelProviderManager()
}
else{
vpnManager.removeFromPreferences(completionHandler: { (error) in
if((error) != nil) {
print("VPN Remove Preferences error: 1")
}
else {
self.vpnManager.connection.stopVPNTunnel()
self.labelConntectionStatus.text = "Disconnected"
self.switchConntectionStatus.isOn = false
self.isConnected = false
}
})
}
}
Después de hacer clic en el interruptor, inicie el túnel VPN utilizando el siguiente código.
func initVPNTunnelProviderManager(){
self.vpnManager.loadFromPreferences { (error) -> Void in
if((error) != nil) {
print("VPN Preferences error: 1")
}
else {
let p = NEVPNProtocolIKEv2()
// You can change Protocol and credentials as per your protocol i.e IPSec or IKEv2
p.username = "*****"
p.remoteIdentifier = "*****"
p.serverAddress = "*****"
let keychain = KeychainSwift()
let data = keychain.getData("vpnPassword")
p.passwordReference = data
p.authenticationMethod = NEVPNIKEAuthenticationMethod.none
// p.sharedSecretReference = KeychainAccess.getData("sharedSecret")!
// Useful for when you have IPSec Protocol
p.useExtendedAuthentication = true
p.disconnectOnSleep = false
self.vpnManager.protocolConfiguration = p
self.vpnManager.isEnabled = true
self.vpnManager.saveToPreferences(completionHandler: { (error) -> Void in
if((error) != nil) {
print("VPN Preferences error: 2")
}
else {
self.vpnManager.loadFromPreferences(completionHandler: { (error) in
if((error) != nil) {
print("VPN Preferences error: 2")
}
else {
var startError: NSError?
do {
try self.vpnManager.connection.startVPNTunnel()
}
catch let error as NSError {
startError = error
print(startError)
}
catch {
print("Fatal Error")
fatalError()
}
if((startError) != nil) {
print("VPN Preferences error: 3")
let alertController = UIAlertController(title: "Oops..", message:
"Something went wrong while connecting to the VPN. Please try again.", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: nil))
self.present(alertController, animated: true, completion: nil)
print(startError)
}
else {
self.VPNStatusDidChange(nil)
print("VPN started successfully..")
}
}
})
}
})
}
}
}
Una vez que VPN se inició correctamente, puede cambiar el estado en consecuencia, es decir, llamando a VPNStatusDidChange
func VPNStatusDidChange(_ notification: Notification?) {
print("VPN Status changed:")
let status = self.vpnManager.connection.status
switch status {
case .connecting:
print("Connecting...")
self.labelConntectionStatus.text = "Connecting..."
self.switchConntectionStatus.isOn = false
self.isConnected = false
break
case .connected:
print("Connected")
self.labelConntectionStatus.text = "Connected"
self.switchConntectionStatus.isOn = true
self.isConnected = true
break
case .disconnecting:
print("Disconnecting...")
self.labelConntectionStatus.text = "Disconnecting..."
self.switchConntectionStatus.isOn = false
self.isConnected = false
break
case .disconnected:
print("Disconnected")
self.labelConntectionStatus.text = "Disconnected..."
self.switchConntectionStatus.isOn = false
self.isConnected = false
break
case .invalid:
print("Invalid")
self.labelConntectionStatus.text = "Invalid Connection"
self.switchConntectionStatus.isOn = false
self.isConnected = false
break
case .reasserting:
print("Reasserting...")
self.labelConntectionStatus.text = "Reasserting Connection"
self.switchConntectionStatus.isOn = false
self.isConnected = false
break
}
}
Me he referido desde aquí:
https://.com/a/47569982/3931796
https://forums.developer.apple.com/thread/25928
http://blog.moatazthenervous.com/create-a-vpn-connection-with-apple-swift/
Gracias :)