IPIP dentro do WireGuard: os 20 bytes extras que ninguém orçou
O IPIP custa 20 bytes a mais dentro do WireGuard. Faça o orçamento na camada certa antes de culpar a fragmentação por uma transferência travada num túnel ativo.
Pings pequenos atravessam o túnel o dia inteiro, o banner SSH chega e então a sessão congela no momento em que começa uma transferência de arquivo. Esse padrão aponta para um orçamento de bytes contado na camada errada, onde o túnel externo foi dimensionado para o seu próprio custo e ninguém subtraiu o interno. Um pacote IPIP aninhado é apenas outro pacote IP para o WireGuard, e é exatamente por isso que consome bytes que você nunca reservou. A correção é aritmética, e cabe em três comandos e uma tabela.
O sintoma que o denuncia
Problemas de fragmentação se anunciam pelo tamanho, nunca pelos endereços. Seu par responde a um ping de 56 bytes por uma hora e depois fica em silêncio nos 1400 bytes enquanto o túnel continua no ar e nenhuma rota mudou. O handshake cabe, a primeira janela TCP completa não, e a transferência trava segundos depois de parecer saudável.
Meça o teto antes de editar qualquer coisa, porque um teto não medido é aquele que você vai perseguir duas vezes. Envie uma sonda abaixo do tamanho suspeito com o bit do-not-fragment ligado, ping -M do -s 1000 10.9.0.2, e repita-a num tamanho que você já sabe ser grande demais. Quando a virada acompanha o tamanho da carga enquanto o destino permanece inalterado, o roteamento está fazendo seu trabalho e falta um cabeçalho no orçamento.
Conte cada cabeçalho uma vez, na camada certa
Comece pelo menor MTU do caminho e não pela interface do túnel, porque a parede fica acima das duas pontas. O WireGuard gasta 60 bytes num transporte externo IPv4: 20 para IP, 8 para UDP e 32 para seu próprio cabeçalho, e 80 bytes quando esse transporte é IPv6. Um wg0 de 1420 bytes mantém 20 bytes de folga sob os 1440 que um caminho de 1500 bytes pode realmente entregar, e por isso a cifra copiada de uma wiki ainda se encaixa aqui. Desenhe a pilha inteira no diagrama, porque quem mudar o MTU depois vai, de outro modo, escolher um novo número redondo e herdar seu bug.
| Layer | Bytes | Remaining |
|---|---|---|
| Path MTU on the wired link | none yet | 1500 |
| WireGuard outer: IP, UDP, WG header | 60 | 1440 |
| Slack kept for safety | 20 | 1420 (wg0) |
| IPIP header inside the tunnel | 20 | 1400 (ipip0) |
| Original IPv4 and TCP headers | 40 | 1360 payload |
A quinta linha é onde os orçamentos dão errado, porque os 1400 bytes que uma interface aninhada carrega já incluem os próprios 40 bytes de cabeçalhos do pacote original. Apenas 1360 desses bytes chegam ao processo que lê o arquivo. Trate 1400 como carga da aplicação, como qualquer diagrama sem essa coluna convida você a fazer, e o dispositivo interno termina 40 bytes generoso demais diante de uma parede que não se moveu.
Defina os dois MTU separadamente
O portador e o dispositivo aninhado são objetos separados, então cada um precisa do seu próprio valor. Aplique-os nesta ordem, porque o dispositivo aninhado não herda nada do portador:
ip link set wg0 mtu 1420
ip tunnel add ipip0 mode ipip remote 203.0.113.9 local 198.51.100.4
ip link set ipip0 mtu 1400
A regra que vale memorizar: MTU interno = MTU externo - 20 quando o pacote que o túnel IPIP carrega é IPv4, e - 40 assim que qualquer lado do pacote interno é IPv6, porque o cabeçalho aninhado cresce de 20 bytes para 40. Nada mais pertence a essa subtração. O custo do WireGuard já foi gasto quando você escolheu 1420, e cobrá-lo duas vezes produz um túnel que funciona perfeitamente e permanece lento enquanto ninguém o mede. Uma implantação em que os dois dispositivos carregam um 1400 redondo é a impressão digital exatamente desse erro.
IPv6 em qualquer lado do pacote aninhado invalida cada cifra acima, então recalcule em vez de copiar um número de um site parecido. Os cabeçalhos subtraídos são de 40 bytes cada assim que IPv6 aparece no caminho externo ou no datagrama original, e a cifra da carga cai exatamente outro tanto.
A regra de firewall que você provavelmente não precisa
Entre dois pares do WireGuard a única coisa no fio é UDP, então uma regra de entrada para o protocolo 4, o número que a RFC 2003 atribui ao encapsulamento IPv4-dentro-de-IPv4, nem cria o caminho aninhado nem o mantém vivo. O cabeçalho IPIP vive dentro da carga cifrada, onde nenhum firewall de borda o vê. Abrir o protocolo 4 de qualquer forma não compra nada além de mais uma via permitida para o host.
A política que menciona as origens e os destinos do pacote original pertence ao pós-desencapsulamento, nas interfaces do túnel e na tabela de roteamento. Coloque-a lá e a regra de borda pode ficar fechada.
O que o WireGuard realmente valida
AllowedIPs julga a origem do pacote que o WireGuard carrega, e o que ele carrega é o pacote encapsulado em IPIP. Uma origem IPIP permitida é aceita mesmo quando o cabeçalho interno nomeia um host que você preferiria não rotear. A origem original, portanto, não é o que o par verificou por você, e esse par interno de endereços precisa da própria aplicação após a desencapsulação.
O invólucro fornece estrutura de roteamento, não uma segunda camada de criptografia. Chamar o IPIP de proteção extra dentro do WireGuard descreve outro projeto.
Verifique com uma escada, não com um único ping
Teste tamanhos que cercam a fronteira que você calculou e depois confirme o que o kernel acredita sobre os dois dispositivos. Com 1360 bytes de carga mais 40 bytes de cabeçalhos formando 1400, o primeiro eco abaixo cabe e o segundo fica um byte além do teto:
ping -M do -s 1372 10.9.0.2
ping -M do -s 1373 10.9.0.2
wg show wg0
ip -d link show ipip0
Uma passagem limpa sob o teto e uma falha no primeiro tamanho acima dele significam que a aritmética se sustenta de ponta a ponta. Depois execute novamente a transferência que travou originalmente, porque uma sonda sintética prova o orçamento e não diz nada sobre os tamanhos de escrita do próprio remetente. Se o caminho aninhado ainda quebra num tamanho que você provou caber, inspecione a desencapsulação e as rotas da ponta distante antes de cortar mais dez bytes do MTU.