Tesseras

Fase 4: Furando NATs

2026-02-15

A maioria dos dispositivos das pessoas ficam atras de um NAT — um tradutor de enderecos de rede que permite acessar a internet mas impede conexoes de entrada. Para uma rede P2P, isso e um problema existencial: se dois nos atras de NATs nao conseguem se comunicar, a rede se fragmenta. A Fase 4 continua com uma pilha completa de travessia de NAT: descoberta via STUN, hole punching coordenado e fallback por relay.

A abordagem segue o mesmo padrao da maioria dos sistemas P2P consolidados (WebRTC, BitTorrent, IPFS): tente a opcao mais barata primeiro, escale apenas quando necessario. Conectividade direta nao custa nada. Hole punching custa alguns pacotes coordenados. Relay custa largura de banda sustentada de um terceiro. Tesseras tenta nessa ordem.

O que foi construido

Classificacao NatType (tesseras-core/src/network.rs) — Um novo enum NatType (Public, Cone, Symmetric, Unknown) adicionado a camada de dominio core. Esse tipo e compartilhado por toda a pilha: o cliente STUN o escreve, o DHT o divulga em mensagens Pong, e o coordenador de punch o le para decidir se hole punching vale a pena tentar (Cone-para-Cone funciona ~80% das vezes; Symmetric-para-Symmetric quase nunca funciona).

Cliente STUN (tesseras-net/src/stun.rs) — Uma implementacao STUN minima (RFC 5389 Binding Request/Response) que descobre o endereco externo de um no. O codec codifica requisicoes de 20 bytes com um ID de transacao aleatorio e decodifica respostas XOR-MAPPED-ADDRESS. A funcao discover_nat() consulta multiplos servidores STUN em paralelo (Google, Cloudflare por padrao), compara os enderecos mapeados e classifica o tipo de NAT:

Retentativas com backoff exponencial e timeouts configuraveis. 12 testes cobrindo roundtrips de codec, todos os caminhos de classificacao e consultas async em loopback.

Coordenacao de punch assinada (tesseras-net/src/punch.rs) — Assinatura e verificacao Ed25519 para mensagens PunchIntro, RelayRequest e RelayMigrate. Cada introducao e assinada pelo iniciador com uma janela de timestamp de 30 segundos, prevenindo ataques de reflexao (onde um atacante reproduz uma introducao antiga para redirecionar trafego). O formato do payload e target || external_addr || timestamp — alterar qualquer campo invalida a assinatura. 6 testes unitarios mais 3 testes baseados em propriedades com proptest (IDs de no, portas e tokens de sessao arbitrarios).

Gerenciador de sessoes de relay (tesseras-net/src/relay.rs) — Gerencia sessoes de relay UDP transparente entre nos com NAT. Cada sessao tem um token aleatorio de 16 bytes; os nos prefixam seus pacotes com o token, o relay remove e encaminha. Funcionalidades:

Extensoes de mensagens DHT (tesseras-dht/src/message.rs) — Sete novas variantes de mensagem adicionadas ao protocolo DHT:

MensagemProposito
PunchIntro"Quero conectar ao no X, aqui esta meu endereco externo assinado"
PunchRequestO introdutor encaminha a requisicao ao destino
PunchReadyO destino confirma prontidao, envia seu endereco externo
RelayRequest"Crie uma sessao de relay para o no X"
RelayOfferO relay responde com seu endereco e token de sessao
RelayCloseEncerrar uma sessao de relay
RelayMigrateAtualizar sessao apos mudanca de rede

A mensagem Pong foi estendida com metadados NAT: nat_type, relay_slots_available e relay_bandwidth_used_kbps. Todos os novos campos usam #[serde(default)] para compatibilidade retroativa — nos antigos ignoram o que nao reconhecem, nos novos usam defaults. 9 novos testes de roundtrip de serializacao.

Trait NatHandler e dispatch (tesseras-dht/src/engine.rs) — Uma nova trait async NatHandler (5 metodos) injetada no engine DHT, seguindo o mesmo padrao de injecao de dependencia do ReplicationHandler existente. O loop de dispatch de mensagens do engine agora roteia todas as mensagens punch/relay para o handler. Isso mantem o engine DHT agnóstico ao protocolo enquanto permite que a logica de travessia de NAT viva em tesseras-net.

Tipos de reconexao mobile (tesseras-embedded/src/reconnect.rs) — Uma maquina de estados de reconexao em tres fases para dispositivos moveis:

  1. QuicMigration (0-2s) — tenta migracao de conexao QUIC para todos os peers ativos
  2. ReStun (2-5s) — redescobre endereco externo via STUN
  3. ReEstablish (5-10s) — reconecta peers que a migracao nao conseguiu salvar

Peers sao reconectados em ordem de prioridade: nos bootstrap primeiro, depois nos que guardam nossos fragmentos, depois nos cujos fragmentos guardamos, depois vizinhos DHT gerais. Uma nova variante de evento NetworkChanged foi adicionada ao stream de eventos FFI para que o app Flutter possa mostrar progresso de reconexao.

Configuracao NAT do daemon (tesd/src/config.rs) — Uma nova secao [nat] na configuracao TOML com lista de servidores STUN, toggle de relay, maximo de sessoes relay, limites de largura de banda (reciproco vs bootstrap) e timeout de inatividade. Todos os campos tem defaults sensiveis; relay e desabilitado por padrao.

Metricas Prometheus (tesseras-net/src/metrics.rs) — 16 metricas em quatro subsistemas:

6 testes verificando registro, incremento, cardinalidade de labels e deteccao de registro duplo.

Testes de integracao — Dois testes end-to-end usando MemTransport (rede simulada em memoria):

Testes de propriedade — 7 testes baseados em proptest cobrindo: roundtrips de assinatura para todos os tres tipos de mensagem assinada (IDs de no, portas e tokens arbitrarios), determinismo de classificacao NAT (mesmas entradas sempre produzem mesma saida), validade de binding request STUN, unicidade de tokens de sessao, e rejeicao de pacotes curtos pelo relay.

Alvos Justfilejust test-nat executa todos os testes de travessia NAT em tesseras-net e tesseras-dht. just test-chaos e um placeholder para futuros testes de caos com Docker Compose e tc netem.

Decisoes de arquitetura

O que vem a seguir

Com travessia de NAT, Tesseras pode conectar nos independentemente de sua topologia de rede. Nos publicos conversam diretamente. Nos com NAT Cone furam com ajuda de um introdutor. Nos com NAT Symmetric ou firewalled usam relay atraves de peers voluntarios. A rede se adapta ao mundo real, onde a maioria dos dispositivos esta atras de um NAT e as condicoes de rede mudam constantemente.