Pergunte a um desenvolvedor o que é WireGuard e você quase certamente ouvirá: “É uma VPN”. Isso é exato, mas é apenas metade da resposta – e a metade menos interessante.
WireGuard é na verdade duas coisas:
- Um aplicativo VPN – o
wgferramenta, módulo de kernel e ecossistema associado que cria túneis de rede criptografados entre máquinas. Isso é o que a maioria das pessoas usa e o que a maioria dos artigos descreve. - Um protocolo criptográfico — uma especificação limpa e moderna baseada no Noise Protocol Framework e no ChaCha20-Poly1305, projetada para criptografar datagramas UDP. Esta parte é totalmente independente de VPNs, tunelamento IP e tabelas de roteamento.
O protocolo é onde mora a engenharia interessante. E acontece que você pode usá-lo como uma biblioteca – como uma camada de criptografia integrada para qualquer aplicativo que mova dados por UDP – sem precisar executar uma VPN. Acabamos de abrir o código-fonte de uma biblioteca .NET que faz exatamente isso.
Por que isso é importante: problemas com TCP
Antes de entrar no que a biblioteca faz, vale a pena ser honesto sobre por que precisamos de opções melhores aqui. A resposta padrão para “Preciso de transporte criptografado” é TLS sobre TCP e funciona bem para uma grande classe de problemas. Mas o TCP tem custos estruturais que aparecem como problemas reais enfrentados pelo usuário sempre que estão envolvidos latência, mobilidade ou links com perdas. Três em particular continuam aparecendo nas filas de suporte.
Bloqueio direto
TCP garante a entrega solicitada. Quando um único pacote é perdido em trânsito, cada pacote subsequente espera em uma fila até que o pacote perdido seja retransmitido – mesmo que os pacotes posteriores já tenham chegado. Para um fluxo de telemetria, atualização do estado do jogo ou leitura do sensor, é quase certo que você não se importa com o pedido. Você quer o valor mais recente. O TCP fornece dados obsoletos entregues em sequência estrita.
O sintoma é familiar: um fluxo que ocasionalmente “trava” brevemente antes de ser alcançado, instabilidade no áudio ou vídeo ou um pico de latência que parece vir do nada, um “travamento” no aplicativo quando ele é bloqueado aguardando um pacote. Ele vem de um único pacote, forçando a pausa de todo o pipeline. A rede subjacente recuperou-se rapidamente; A garantia de pedido do TCP foi o que o tornou visível.
O estado da conexão é redefinido
As conexões TCP estão vinculadas a uma tupla de 4: IP de origem, porta de origem, IP de destino, porta de destino. Quando um cliente móvel faz roaming de Wi-Fi para celular, seu endereço IP muda, cada conexão TCP aberta é interrompida e a sessão TLS com ela. Seu aplicativo absorve o custo de reconexão, renegociação do TLS e restabelecimento do estado no nível do aplicativo.
Para dispositivos móveis – telefones, veículos, equipamentos de campo – este não é um caso extremo. É rotina. O RST chega, o erro se propaga pela pilha e em algum lugar um loop de nova tentativa começa a contar. Se você já se perguntou por que um aplicativo móvel ocasionalmente leva alguns segundos extras para ser retomado após a troca de rede, geralmente é esse o motivo.
Controle de congestionamento em links com perdas
O controle de congestionamento do TCP trata a perda de pacotes como um sinal de que a rede está congestionada e recua de acordo – reduzindo a taxa de envio. Em um link genuinamente com perdas (IoT celular, uplink de satélite, RF industrial), isso cria um ciclo de feedback prejudicial: o link descarta um pacote devido à interferência, a pilha recua como se a rede estivesse saturada e a taxa de transferência entra em colapso, mesmo que o único problema tenha sido uma explosão momentânea de ruído.
Os usuários do outro lado do painel de IoT veem leituras obsoletas – não porque o dispositivo parou de enviar, mas porque o controle de congestionamento acelerou a entrega em resposta à interferência.
Estes não são modos de falha exóticos. Eles são a fonte de uma classe significativa de reclamações em jogos, voz, videoconferência, monitoramento de IoT e qualquer aplicativo executado em infraestrutura móvel. Os desenvolvedores que embarcaram nesses domínios reconhecem todos os três imediatamente.
Segurança: TCP tem TLS, UDP tem VPN
A resposta convencional para “Preciso de criptografia para meu tráfego UDP” tem sido historicamente “colocá-lo em uma VPN”. Isso funciona, mas é operacionalmente pesado. Uma VPN é uma abstração completa de rede – seu próprio roteamento, seu próprio espaço de endereço, sua própria superfície operacional para gerenciar. Ele reúne duas preocupações distintas: quais pacotes rotear e como criptografá-los. Para a maioria dos casos de uso, você só precisa do segundo.
O DTLS (TLS-over-UDP) existe e é uma opção legítima, mas herda a complexidade do TLS: cadeias de certificados, infraestrutura PKI, negociação de conjunto de criptografia e um handshake multi-round-trip. Essa é uma carga operacional significativa a ser imposta a um dispositivo incorporado com 256 KB de RAM ou a uma equipe que deseja apenas criptografar um canal de dados sem precisar de uma autoridade de certificação.
O protocolo do WireGuard é um ponto de design fundamentalmente diferente. Não tem estado – não há conexão para estabelecer antecipadamente, nenhuma sessão para rastrear e nenhuma autoridade de certificação na imagem. Duas chaves, um aperto de mão compacto e você está criptografando. E, diferentemente do TLS, as opções criptográficas do WireGuard são fixas: Noise_IKpsk2 para troca de chaves, ChaCha20-Poly1305 para criptografia autenticada. Não há nada para configurar incorretamente.
A Biblioteca: WireGuardClient
A biblioteca wg-client é compatível com API com os recursos integrados do .NET
UdpClient. Os padrões de envio/recebimento são os mesmos, e adicionar criptografia a um loop de envio UDP simples é uma pequena mudança:
// Before: plain UDP
using var udp = new UdpClient();
var endpoint = IPEndPoint.Parse("gateway.example.com:51820");
var payload = Encoding.UTF8.GetBytes("temp=23.4,hum=61");
await udp.SendAsync(payload, payload.Length, endpoint);// After: WireGuard-encrypted UDP
var endpoint = IPEndPoint.Parse("gateway.example.com:51820");
var serverKey = Convert.FromBase64String("");
var clientKey = Convert.FromBase64String("");
await using var wg = new WireGuardClient(endpoint, serverKey, clientKey);
var payload = Encoding.UTF8.GetBytes("temp=23.4,hum=61");
await wg.SendAsync(payload, CancellationToken.None); // encrypted on the wire A biblioteca lida com o handshake WireGuard, rotação de chaves e enquadramento de mensagens. O código de chamada não muda. O formato wire é o WireGuard padrão, portanto é compatível com qualquer back-end compatível – um Linux
wg interface, um Proxyility WireGuard Listener ou qualquer outra implementação que siga as especificações.
A implementação gira em torno de 800 linhas de C# – pequenas o suficiente para serem lidas de uma só vez e auditadas de forma significativa. A única dependência externa é o NSec, um pacote NuGet gerenciado que fornece um wrapper .NET em torno do libsodium. O handshake Noise e o transporte ChaCha20-Poly1305 são implementados sobre essa base, sem nenhum outro código de terceiros envolvido.
O que “apátrida” realmente significa na prática
A palavra “stateless” aparece frequentemente na documentação de design do WireGuard e vale a pena ser preciso sobre o que isso significa para os desenvolvedores de aplicativos.
No TLS, uma sessão tem um ciclo de vida: o handshake cria um estado compartilhado – chaves de sessão, números de sequência, um contexto de cifra – que deve ser mantido durante a conexão. Se a conexão cair (devido a uma alteração na rede, reinicialização do servidor ou tempo limite), esse estado desaparecerá. Ambos os lados devem negociar do zero antes que a comunicação criptografada seja retomada.
WireGuard lida com isso de maneira diferente. As sessões existem e as chaves são alternadas, mas se os pacotes pararem de fluir e uma sessão expirar, a próxima mensagem de saída acionará silenciosamente um novo handshake. Não há erros para tratar, nem reconexão para orquestrar, nem lógica de repetição no nível do aplicativo para gravar. A biblioteca envia dados; quando a sessão precisa ser atualizada, isso acontece por baixo. Do ponto de vista do aplicativo, isso nunca desapareceu.
Isto é especialmente importante para dispositivos que dormem entre transmissões, se movem entre redes ou operam em ambientes onde a conectividade é intermitente. As mesmas propriedades que tornam o WireGuard resiliente em um contexto VPN o tornam resiliente aqui também – e elas se aplicam independentemente de a carga útil ser um IP encapsulado ou algo totalmente diferente.
Além do IP em túnel
WireGuard, a VPN, usa o protocolo para encapsular pacotes IP. A carga útil interna é um datagrama IP – um pacote no sentido normal da Internet. Esse é o caso de uso da VPN.
WireGuard, o protocolo apenas criptografa uma matriz de bytes. Não inspeciona, valida ou interpreta o conteúdo. A carga útil interna pode ser um IP encapsulado ou pode ser um texto UTF-8, uma leitura de sensor binário, um protocolo de controle proprietário, syslog, NTP ou qualquer outra coisa. Depois de separar o protocolo do aplicativo VPN, cargas arbitrárias deixam de parecer incomuns e passam a parecer a maneira óbvia de usar a coisa.
Isso significa que você pode proteger um canal de dados com o WireGuard exatamente da mesma forma que usaria o TLS – sem nenhum mecanismo VPN envolvido. HTTP sobre WireGuard funciona. Nossos exemplos de syslog-over-WireGuard funcionam. Qualquer protocolo que você proteja atualmente com TLS pode, em princípio, ser protegido com WireGuard, com um modelo operacional mais simples e sem PKI para gerenciar.
O lado da proximidade da história
O Proxyility UDP Gateway oferece suporte a ouvintes WireGuard desde o início do produto. O gateway encerra túneis WireGuard, desencapsula pacotes e roteia a carga interna para Lambda, SQS, Kinesis, CloudWatch Logs e outros destinos. No início deste ano, adicionamos Decapsulated Delivery, que move a etapa de descompactação para o Gateway para que os destinos recebam uma carga interna limpa sem escrever nenhum código.
A biblioteca wg-client é o complemento natural do lado do cliente para essa imagem. Um dispositivo IoT, processo de trabalho ou nó de borda usando WireGuardClient pode enviar datagramas criptografados pelo WireGuard diretamente para um ProxyWireGuard Listener, e a carga chega ao destino limpa e descriptografada, pronta para ser processada. Sem infraestrutura VPN. Nenhuma rede de sobreposição. Nenhum serviço de gerenciamento de chaves separado.
A combinação abrange um caso de uso que é genuinamente comum, mas surpreendentemente mal atendido: software incorporado ou de ponta que precisa de criptografia de transporte e tem UDP disponível, mas onde o TLS é muito pesado para o ambiente, uma VPN completa é uma infraestrutura demais para ser justificada e o DTLS é muito complexo para ser configurado corretamente sob pressão operacional.
A biblioteca é de código aberto sob a licença MIT e está disponível em github.com/proxylity/wg-client. Instale via NuGet:
dotnet add package Proxylity.WireGuardClient. São cerca de 800 linhas com um pouco de trabalho ainda pela frente. Contribuições, relatórios de problemas e feedback são bem-vindos.
Fonte: theverge

