Desde el lanzamiento de iOS 8 beta, he encontrado una Extensión de la Red en su bundle, que va a permitir que los desarrolladores de configurar y conectarse a los servidores de VPN mediante programación y sin ningún tipo de perfil de instalación.

El marco contiene una clase principal llamada NEVPNManager. Esta clase también tiene 3 métodos principales que me deja guardar, cargar o quitar VPN preferencias. He escrito una pieza 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 he colocado un botón en mi punto de vista y establecer su TouchUpInside de acción para el siguiente método:

- (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, el siguiente error se emite: Guardar error: Error de Dominio=NEVPNErrorDomain Código=4 «La operación no pudo ser completado. (NEVPNErrorDomain de error 4.)» ¿Qué es este error? ¿Cómo puedo solucionar este problema?

2) [[NEVPNManager sharedManager].conexión startVPNTunnelAndReturnError:&startError]; el método no devuelve ningún error cuando me llaman, pero la conexión de los cambios de estado de Desconectado a Conectar sólo por un momento y luego se vuelve a estado Desconectado.

Cualquier ayuda será apreciada 🙂

  • extraño, cuando estoy ejecutando una copia de su código en un dispositivo con la beta 4 me estoy poniendo un nil devuelve desde [NEVPNManager sharedManager];
  • Ah, no me había añadido el «VPN» derecho a mi ID de la Aplicación o de los derechos archivo. Para ello, vaya a «Capacidades» en el marco del proyecto
  • ¿Cómo está la recuperación de la contraseña del llavero? He almacena la contraseña de mi cuenta en el llavero, y he tratado de recuperar la referencia persistente (que la documentación implica que sean necesarias en el protocolo.passwordReference campo, pero todavía me pide una contraseña cuando voy a conectar a la VPN de servicio (una vez que entrar en ella, me conecto, así que todo lo demás parece bueno).
  • El uso de la NEVPNManager clase requiere la com.apple.developer.networking.vpn.api derecho. Usted puede obtener este derecho para su aplicación mediante la activación de la «VPN» la capacidad para su aplicación en Xcode.
  • ¿por qué no conectar dirección ip vpn gratuita objective c

2 Comentarios

  1. 27

    El problema es el error que se produce al ahorro:
    Save error: Error Domain=NEVPNErrorDomain Code=4

    Si usted mira en el NEVPNManager.h archivo de encabezado, usted verá que el código de error 4 es «NEVPNErrorConfigurationStale». La configuración está obsoleto y necesita ser cargado.
    Usted debe llamar a loadFromPreferencesWithCompletionHandler: y en el controlador de finalización modificar los valores que desea modificar, y luego llamada saveToPreferencesWithCompletionHandler:. En el ejemplo de la pregunta es la modificación de la configuración antes de que la carga se ha completado, que es la razón por la que usted está recibiendo este error.

    Más parecido a esto:

    [manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
         //do config stuff
         [manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
         }];
    }];
    • Funciona OK! Una cosa más es que, esta funcionalidad sólo funciona y dispositivos reales no simulador.
    • Por cierto: me voy de blog sobre esta noche y voy a hablar de que el hombre 😉
    • pimpmyradar.com 😉
    • Has probado esto en beta5? Tengo un código similar que funciona hasta la beta 4, y en la beta 5 tengo un error: Dominio=NEConfigurationErrorDomain Código=2 «Falta el nombre de» UserInfo=0x170078940 {NSLocalizedDescription=nombre que Faltan}
    • ¿Tiene usted alguna idea acerca de la «Falta de error» nombre?
    • mismo Nombre que Faltan error en xcode 6 beta 6 ! Alguna solución?
    • La falta de la cuestión del nombre mostró a mí, cuando en realidad me olvidó poner un nombre de usuario.
    • Puedo obtener una «Falta de identidad» error al intentar guardar la configuración en preferencias. Alguna solución? (trabajando con iOS 8.2)
    • Cuando se utiliza el modo de autenticación de Certificado que necesita este certificado establecido en el protocolo como un NSData objeto prot.authenticationMethod = NEVPNIKEAuthenticationMethod.Certificate; prot.identityData = certificate; prot.identityDataPassword = self._PKCS12CertificatePassword (código swift)
    • entonces, si yo lo hice como dijiste en tu respuesta ahora recibiendo este error : stackoverflow.com/questions/47550706/… ¿puedes ayudarme por favor ?

  2. 9

    Esta respuesta será útil para aquellos que están buscando la solución por medio de la Red de Extensión de marco.

    Mi, era requisito para conectar/desconectar servidor VPN con IKEv2 Protocolo (por supuesto, usted puede utilizar esta solución para IPSec también por el cambio de vpnManager protocolConfiguration)

    NOTA : Si usted está buscando para el Protocolo L2TP, Usando la Red de extensión que no es posible la conexión de servidor VPN. Referencia : https://forums.developer.apple.com/thread/29909

    Aquí está mi trabajo fragmento de código :

    Declarar VPNManager de Objetos y otras cosas útiles

    var vpnManager = NEVPNManager.shared()
    var isConnected = false
    
    @IBOutlet weak var switchConntectionStatus: UISwitch!    
    @IBOutlet weak var labelConntectionStatus: UILabel!

    Agregar observador en viewDidLoad para llegar VPN Staus y almacenar vpnPassword en el Llavero, puede almacenar sharedSecret demasiado para lo que se necesita del 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 fue tener UISwitch para conectar/desconectar del 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 de iniciar el túnel VPN utilizando a continuación el 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..")
    }
    }
    })
    }
    })
    }
    }
    }

    VPN una vez iniciado 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://stackoverflow.com/a/47569982/3931796

    https://forums.developer.apple.com/thread/25928

    http://blog.moatazthenervous.com/create-a-vpn-connection-with-apple-swift/

    Gracias 🙂

    • he seguido tus pasos , pero me estoy poniendo «Error Inesperado» estado de alerta durante la conexión a la vpn, mi ikev2 server utiliza .crt y ya tengo instalado en mi dispositivo , agregar manualmente la configuración de las buenas obras , sólo personal de vpn con la misma configuración recibiendo el error
    • Instalado .crt puede trabajar con ambos añadido y configuración de vpn Personal ? o tenemos que hacer algo más para vpn Personal para el certificado de uso?
    • KeychainSwift no funciona aquí acabo de volver de la Cadena con los Datos que necesita un llavero ref blog.moatazthenervous.com/create-a-key-chain-for-apples-vpn
    • me estoy enfrentando el mismo problema de utilizar esta clase es conseguir estrelló mientras que el ahorro de las preferencias .
    • Genial!

Dejar respuesta

Please enter your comment!
Please enter your name here