Pergunte a uma app iOS se o telefone está numa VPN e a resposta honesta é que não o pode saber no sentido que tem em mente. O SDK não expõe qualquer indicador de «o dispositivo está num túnel», e as interfaces privadas que se poderiam aproximar disso estão fechadas às apps publicadas. Pode observar a configuração da sua própria app, o estado associado a ela e um ou dois indícios indiretos da pilha de rede. Cada um responde a uma pergunta diferente, e a maioria das verificações avariadas vem de tomar um deles como a resposta completa.

O mito do indicador único de VPN

A crença é que existe algures no SDK uma propriedade que indica se o dispositivo está num túnel, tal como um indicador de alcançabilidade indica se um anfitrião responde. Essa propriedade pública não existe. E mesmo que existisse, «existe um túnel» e «o meu tráfego usa-o» são afirmações diferentes, e só a segunda importa à maioria das apps.

É precisamente esta lacuna que faz com que as bibliotecas que anunciam um detetor de VPN numa linha leiam normalmente algo frágil, como um nome de interface ou uma chave de proxy, e o apresentem como veredicto.

Carregue as preferências antes de confiar num nil

A instância partilhada do gestor existe assim que a pede, mas a sua propriedade de protocolo continua nil até a chamada de carregamento terminar. Portanto, um protocolo nil significa «ainda não carregado» pelo menos com a mesma frequência com que significa «não instalado». Faça a leitura dentro do bloco de conclusão e só depois decida: um objeto de protocolo que existe, com o indicador de ativação ligado, é o aspeto de «instalado».

Um segundo sinal está no objeto de ligação: o estado inválido, que o sistema comunica quando esta app não tem nenhuma configuração instalada. Um estado inválido juntamente com um protocolo nil após um carregamento concluído é uma ausência real, não uma corrida de tempos.

As mudanças de ligação chegam como notificações

Os manipuladores passados a load e save comunicam o que aconteceu à configuração, não o que o túnel está a fazer. Esperar que um deles dispare ao ligar é uma corrida que nunca se resolve. Observe antes a notificação de mudança de estado e leia o valor atual do objeto de ligação quando ela chegar.

Depois de uma configuração estar instalada, o estado da ligação percorre uma sequência curta: desligado, a ligar, ligado, a reafirmar, a desligar. «Ligado» descreve o túnel e não o servidor por trás dele, pelo que não é prova de que o tráfego flua. O On-demand também pode levantar um túnel enquanto a app está suspensa, e então a notificação chega antes de ter algo para atualizar.

O instantâneo de proxy de âmbito limitado é um indício, não um veredicto

O CFNetwork pode dar à app as definições de proxy atuais do sistema, e dentro desse resultado há um dicionário de âmbito limitado com chave por nome de interface. Ver um nome que começa por tun, utun, ppp, ipsec ou tap é um indício de que existe um túnel. Continua a ser um instantâneo do que esta app consegue ver, não uma afirmação sobre por onde viajam os pacotes.

Os fornecedores não concordam quanto aos nomes, pelo que um prefixo ausente não prova nada, e uma interface presente pode existir sem transportar tráfego. A alcançabilidade é ainda mais fraca: um pedido bem-sucedido para um endereço privado mostra que o caminho funcionou para esse pedido naquele momento, não que exista uma VPN instalada.

O simulador pede emprestado o Mac, e as outras apps ficam invisíveis

O simulador não tem pilha de rede própria; cada ligação que faz é a do Mac. Uma VPN a correr no Mac anfitrião já está, portanto, em vigor para a app simulada, e as definições do próprio simulador não mostram nada. Se o túnel subiu depois de o simulador arrancar, reiniciá-lo costuma ser mais rápido do que depurar a app. Um anfitrião numa porta não padrão precisa dessa porta no URL, ou de um encaminhamento local como socat TCP-LISTEN:12345,fork TCP:host:12345.

As API públicas não enumeram perfis de VPN que pertencem a outras apps ou a perfis de configuração. Para uma app conhecida, a sonda de esquema de URL através de canOpenURL é o truque portátil, e desde o iOS 9 o esquema consultado tem de ser declarado no seu Info.plist; se o omitir, a chamada devolve false. O OpenVPN Connect responde em openvpn://, o que faz dele um bom exemplo e um mau detetor geral.

Combine três observações e diga o que significam

Na prática empilhe três resultados: uma configuração que foi carregada e está ativada, um estado de ligação que não é inválido e um pedido para um endereço só alcançável pelo túnel. Cada um engana sozinho; juntos dizem o que a app pode saber em vez do que o utilizador assume.

Escreva o resultado como três linhas nos seus diagnósticos, não como um único booleano. Quando um utilizador diz que a VPN está desligada e a sua app discorda, as três linhas mostram qual observação divergiu, e essa é a diferença entre um pedido de suporte sobre o qual pode agir e um que termina em «comigo funciona».

Artigos relacionados