VPN vista por dentro, do software

Se você perguntar a dez pessoas o que é uma VPN, provavelmente vai ouvir sobre privacidade, catálogo de streaming e trabalho remoto. Tudo válido, mas pouco diz sobre o que acontece por trás da tela Conectar. Este texto é para quem gosta de software. Vamos abrir o cliente, olhar as interfaces virtuais e acompanhar um pacote IP cruzando o túnel.

Começa com uma interface que não existe de verdade

Toda VPN de uso geral cria uma interface virtual. No Linux ela costuma se chamar tun0, no Windows aparece via Wintun, no macOS e iOS vive dentro das Network Extensions. É uma porta falsa onde você entrega pacotes IP já prontos. O driver captura esses pacotes, cifra, coloca no envelope do protocolo escolhido e os lança na rede real usando um socket normal.

No caminho inverso, o cliente recebe datagramas, retira o envelope, confere a integridade, decripta e injeta o IP original de volta na interface virtual. Do ponto de vista do seu aplicativo nada mudou. Do ponto de vista do kernel, a rota preferida passou a apontar para o dispositivo virtual.

Protocolos não são todos iguais

WireGuard ficou famoso por ter pouco código, chaves simples e performance sólida com ChaCha20-Poly1305. Funciona sobre UDP de forma direta. OpenVPN carrega mais história e roda sobre TLS, o que facilita no ambiente corporativo e complica no de latência. IPsec fica mais perto do kernel e brilha em gateways, mas dói um pouco para portar entre plataformas de aplicativo.

Quem escreve cliente aprende cedo que UDP facilita atravessar NAT. Ainda assim, alguns ambientes só deixam passar tráfego que parece HTTPS. Aí entram QUIC e MASQUE, que usam HTTP/3 para camuflar o túnel em algo que proxies e firewalls já aceitam. Dá trabalho, mas evita a armadilha do TCP sobre TCP, aquela situação em que duas camadas tentam retransmitir e o throughput despenca.

Também tem a novela do MTU. O pacote cifrado cresce e os fragmentos começam a surgir. Resolver isso passa por descobrir o tamanho ideal em cada rota e ajustar o MSS no caminho, senão seu túnel fica parecendo um carro potente preso em primeira marcha.

Vida real do cliente: reconectar, hibernar, acordar

O usuário fecha o notebook, troca de Wi-Fi, liga o tethering do celular, entra num hotel com portal cativo. O cliente precisa detectar que o mundo mudou e refazer o handshake sem drama. Mantém timers de keepalive, percebe quando a NIC sumiu, aguarda DNS voltar, tenta caminhos alternativos. Em dispositivos móveis entra o fator bateria. Rechaves mais espaçadas ajudam, mas não podem arriar a segurança. É um equilíbrio fino.

Em plataformas Apple, o caminho passa por NEPacketTunnelProvider. No Android, o VpnService fornece o file descriptor da interface. No Windows, a família Win32 e o WFP ajudam a implementar o bloqueio total quando a VPN cai. No Linux, ip route e nftables dão conta do recado com precisão cirúrgica.

Desempenho é detalhe acumulado

Criptografia moderna não é o gargalo quando a implementação respeita o hardware. AES-GCM voa em máquinas com AES-NI, ChaCha20 vai melhor em CPUs sem aceleração. Paralelizar a cifragem em lotes, reduzir cópias de buffer e manter a fila curta de pacotes evita jitter. Logs mostram a diferença entre um túnel que parece fibra e outro que soa como rádio antigo.

Se houver apenas TCP dentro do túnel, vale considerar congestion control que lide bem com perda. BBR costuma se sair melhor que CUBIC em links de alta latência. Com QUIC, parte disso já vem no pacote. Ainda assim, medir conta mais do que opinar.

Segurança que aparece quando algo dá errado

Vazamento de DNS acontece quando o resolvedor do sistema ignora a rota. Resolver isso exige controlar o DNS no nível do túnel e, em alguns sistemas, registrar o resolvedor com prioridade alta. IPv6 esquecido é um clássico. O aplicativo testa IPv4 bonitinho enquanto páginas e WebRTC anunciam endereços v6 por fora. Feche a torneira de IPv6 quando não for suportado ou transporte v6 no túnel como gente grande.

Kill switch não é um botão no UI. É regra de firewall que bloqueia qualquer tráfego fora da interface virtual, exceto o handshake com o servidor. Sem isso, a desconexão vira um curto período de tráfego em claro. Split tunneling por aplicativo é outra fonte de surpresas. No Windows e no macOS ele depende de filtros de socket. No Linux, políticas de roteamento por marcação de pacote funcionam bem. Mais uma vez, testes reais são menos gentis do que diagramas.

Observabilidade sem bisbilhotar

Telemetria de VPN deve contar o que interessa para a saúde do software e nada sobre a vida do usuário. Handshake time, perda de pacotes, latência, rekey, falhas de DNS, renegociação por troca de rede. Um pequeno conjunto de métricas e logs estruturados já ajuda a priorizar correções. eBPF facilita medir no Linux sem encher o caminho de hooks. E quando algo quebra na casa do cliente, ter um botão que gera um relatório com dados não sensíveis salva o suporte.

falhas de dns

Um microexemplo para tirar a teoria da página

A seguir um esqueleto do lado cliente em Go que abre uma TUN, lê pacotes e os despeja cifrados em um UDP. Não é produção, serve apenas para visualizar o fluxo.

package main

import (
	"log"
	"net"
	"os"
	"golang.org/x/net/ipv4"

	"github.com/songgao/water"       // cria TUN
	"golang.org/x/crypto/chacha20poly1305"
)

func main() {
	iface, err := water.New(water.Config{DeviceType: water.TUN})
	if err != nil { log.Fatal(err) }
	log.Println("TUN:", iface.Name())

	conn, err := net.Dial("udp", "203.0.113.10:51820")
	if err != nil { log.Fatal(err) }

	key := make([]byte, chacha20poly1305.KeySize)
	if _, err := os.ReadFull(randReader{}, key); err != nil { log.Fatal(err) }
	aead, _ := chacha20poly1305.NewX(key)

	buf := make([]byte, 1<<16)
	for {
		n, err := iface.Read(buf)
		if err != nil { log.Fatal(err) }

		pkt := buf[:n]
		hdr, _ := ipv4.ParseHeader(pkt)
		_ = hdr // aqui você poderia aplicar políticas ou contadores

		nonce := make([]byte, aead.NonceSize())
		ct := aead.Seal(nil, nonce, pkt, nil)
		if _, err := conn.Write(append(nonce, ct...)); err != nil { log.Fatal(err) }
	}
}

// gerador de bytes simples para exemplo
type randReader struct{}
func (randReader) Read(p []byte) (int, error) { return len(p), nil }

Um cliente real precisa negociar chaves, rotear tráfego, lidar com MTU, implementar rekey, autenticar o servidor, registrar DNS, aplicar kill switch e muito mais. Mesmo assim, esse esqueleto já mostra o coração da coisa. Você escreve e lê de um arquivo especial que, na verdade, é um dispositivo virtual. O resto é protocolo.

UI de VPN também é engenharia

Botões grandes ajudam, mas os detalhes sutis é que evitam frustração. Detectar portal cativo antes de tentar o handshake economiza tempo. Explicar por que a conexão falhou evita a sequência fechar e abrir de novo que não muda nada. Trocar de servidor automaticamente quando a latência sobe permite que o usuário nem perceba. E nada disso precisa coletar a vida da pessoa. Dá para construir um cliente útil e respeitoso.

O que vem por aí

Túneis sobre HTTP/3 devem se tornar comuns em ambientes empresariais. Handshakes híbridos que misturam curvas elípticas com esquemas pós-quânticos começam a aparecer nas bibliotecas. Para uso pessoal, WireGuard tende a continuar simples e rápido. No back-end, provedores investem em endereçamento IPv6 pleno e balanceamento com anycast para reduzir pulos até o servidor. Se você escreve software nessa área, o futuro é menos sobre truques para burlar firewalls e mais sobre adotar padrões que a internet já fala bem.

Fechando o túnel

VPN não é um feitiço. É software, com socket, buffer, fila, temporizador, criptografia e um bocado de decisões chatas porém decisivas. Quando o cliente é bem escrito, a experiência fica silenciosa. O pacote sai, viaja cifrado e volta como se nada especial tivesse acontecido. Do lado de cá, alguém escreveu um programa paciente o bastante para lidar com a internet como ela é. E é isso que faz a mágica parecer simples.

Melhores VPNs

A imagem abaixo mostra as top 6 VPNs da américa latina (em termos de provedores) segundo nossa avaliação:

mejores vpns

Leave a Reply

Your email address will not be published. Required fields are marked *