Static loop no Mikrotik: rota blackhole para pool e CGNAT

O static loop é um daqueles problemas que não aparecem no dia em que a rede é montada. Tudo funciona, os clientes navegam, o BGP está estabelecido. Meses depois o link de trânsito começa a encher em horário estranho, a CPU da borda sobe e ninguém acha um cliente responsável. Muitas vezes a causa é um pacote para um endereço que ninguém usa, preso entre dois roteadores até o TTL acabar.
Este post mostra como o static loop nasce num provedor com borda e concentrador Mikrotik, como reconhecer os sintomas com traceroute e fping, e como fechar o buraco com rotas blackhole para o bloco anunciado, para os pools PPPoE e para o CGNAT. Os comandos seguem a sintaxe do RouterOS v7 conferida na documentação da MikroTik, com o equivalente em NULL0 para quem tem borda Huawei.
Resposta rápida
Todo bloco que chega até um roteador e que ele não sabe entregar por inteiro precisa de uma rota blackhole. Na prática:
- Na borda, crie uma rota blackhole para cada prefixo que você anuncia ou que o trânsito roteia para você, em IPv4 e IPv6.
- No concentrador, crie blackhole para o pool PPPoE, para o pool público do CGNAT, para a faixa 100.64 dos clientes e para o pool de prefixos delegados.
- Use
distance=254, para que qualquer rota real ganhe da blackhole. - Teste com traceroute para um endereço livre: o caminho deve parar, e não alternar entre dois saltos.
Como o static loop nasce
Pense numa borda com duas coisas na tabela: uma rota default apontando para o trânsito e rotas específicas para as partes do bloco que estão em uso. O trânsito, por sua vez, manda para a borda tudo que é do seu /24, seja por BGP, seja por uma rota estática do lado dele. Agora chega um pacote para 203.0.113.200, um endereço que não está em pool nenhum.
- O trânsito entrega o pacote para a borda, porque o /24 é seu.
- A borda procura uma rota para 203.0.113.200. Não existe rota específica, então vale a default.
- A default aponta para o trânsito. O pacote volta pelo mesmo link.
- O trânsito olha a tabela de novo e devolve para a borda.
- O vai e volta continua até o TTL zerar. Só aí alguém descarta o pacote e responde com ICMP Time Exceeded.
Um pacote que chega ao trânsito com TTL 50 atravessa o link umas 50 vezes antes de morrer; quem ataca pode sair com TTL 255 e passar das 200 voltas. Ou seja, cada pacote que entra para um endereço sem uso vira dezenas de pacotes no seu link de trânsito, nos dois sentidos. Quem descobre isso e manda tráfego para a faixa vazia consegue lotar o link com uma fração da banda que precisaria num ataque comum. É por isso que o static loop é tratado como risco de segurança, e não só como erro de configuração.

Cenário do laboratório
O exemplo usa uma borda Mikrotik ligada ao trânsito e um concentrador PPPoE que também faz CGNAT. É o desenho mais comum em provedor pequeno, montado como nos posts sobre PPPoE server no Mikrotik RouterOS v7 e CGNAT no Mikrotik com netmap.
| Item | Valor | Onde fica |
|---|---|---|
| Bloco próprio | 203.0.113.0/24 e 2001:db8::/32 | Anunciado ao trânsito |
| Link de trânsito | 198.51.100.0/30 (trânsito .1, borda .2) | Default da borda |
| Borda e concentrador | 192.0.2.0/30 (borda .1, concentrador .2) | Default do concentrador |
| Pool PPPoE público | 203.0.113.0/25 | No concentrador |
| Pool público do CGNAT | 203.0.113.128/27 | No concentrador |
| Clientes CGNAT | 100.64.0.0/22 | No concentrador |
| Prefixos delegados | 2001:db8:a000::/40 | No concentrador |
| Sem uso | 203.0.113.160 a 203.0.113.255 | Onde o loop aparece |
A tabela de rotas da borda, antes da correção, tem a default e as rotas para o que está em uso no concentrador:
/ip route add dst-address=0.0.0.0/0 gateway=198.51.100.1 add dst-address=203.0.113.0/25 gateway=192.0.2.2 add dst-address=203.0.113.128/27 gateway=192.0.2.2
E o concentrador só conhece as próprias redes e uma default para a borda:
/ip route add dst-address=0.0.0.0/0 gateway=192.0.2.1
Esse par parece certo e funciona para todo cliente conectado. O problema está no que sobra: o pedaço do /24 que ninguém usa, os IPs do pool PPPoE que estão livres naquele momento e as portas e endereços do CGNAT sem tradução ativa.
Os dois lugares onde o static loop aparece
Entre a borda e o trânsito
É o caso do diagrama. Qualquer endereço do bloco sem rota específica na borda volta pela default. O tráfego de fora chega pelo trânsito, então o loop acontece no link mais caro e mais visível da rede. Em IPv6 o problema é igual e costuma ser maior, porque o bloco é enorme e quase todo vazio.
Entre o concentrador e a borda
A borda manda o /25 do PPPoE para o concentrador. Se o 203.0.113.37 não está com nenhum cliente naquele momento, o concentrador não tem a rota /32 dinâmica que a sessão PPPoE cria. Ele cai na default, devolve para a borda, a borda manda de novo para o concentrador, e assim até o TTL acabar. O mesmo vale para o pool público do CGNAT: pacote para um IP ou porta sem tradução ativa não é traduzido e segue a tabela de rotas comum.
A faixa 100.64.0.0/22 tem um caso parecido no sentido contrário. Um cliente que tenta falar com um 100.64 que não está em uso faz o concentrador mandar o pacote para a borda. Se a borda tiver alguma rota que leve esse destino de volta ao concentrador, o static loop fecha dentro da sua rede; se não tiver, um endereço privado sai pela default rumo ao trânsito, o que também não deveria acontecer.
Sintomas e como detectar o static loop
| Sintoma | O que significa |
|---|---|
| Link de trânsito cheio nos dois sentidos | Entrada e saída sobem juntas, com volumes parecidos |
| Muitos pacotes por segundo sem cliente responsável | O tráfego é para endereços sem uso |
| ICMP Time Exceeded vindo da sua borda ou do trânsito | O TTL acabou no meio do loop |
| Traceroute alternando entre dois saltos | A assinatura clássica do static loop |
| CPU da borda ou do concentrador alta em horário sem pico | Cada pacote é roteado dezenas de vezes |
O teste mais direto é um traceroute para um endereço que você sabe que está livre. Da própria borda:
/tool traceroute 203.0.113.200
Com o loop presente, a saída alterna entre o trânsito e a borda até o fim. A saída abaixo está resumida nas colunas principais:
# ADDRESS LOSS SENT LAST 1 198.51.100.1 0% 3 0.6ms 2 198.51.100.2 0% 3 1.1ms 3 198.51.100.1 0% 3 1.7ms 4 198.51.100.2 0% 3 2.2ms 5 198.51.100.1 0% 3 2.8ms 6 198.51.100.2 0% 3 3.3ms
Para varrer o bloco inteiro, rode o fping de uma máquina fora da sua rede, como um servidor em outro provedor. Ele manda um ping para cada endereço do bloco, e os avisos de Time Exceeded apontam exatamente os endereços presos num static loop:
fping -g 203.0.113.0/24 2>&1 | grep -i exceeded
ICMP Time Exceeded from 198.51.100.1 for ICMP Echo sent to 203.0.113.200 ICMP Time Exceeded from 198.51.100.1 for ICMP Echo sent to 203.0.113.201
Repita a varredura para cada bloco que você anuncia. Um endereço sem uso que não responde nada é o resultado esperado; um que devolve Time Exceeded é um loop esperando para ser explorado.
A correção: rota blackhole no RouterOS v7
A rota blackhole descarta em silêncio tudo que casar com ela. Como o roteador sempre escolhe a rota mais específica, uma blackhole para o bloco inteiro só pega o que não tem rota melhor. No RouterOS v7, a palavra blackhole entra sozinha, sem o type=blackhole do v6.
Na borda: o bloco inteiro
/ip route add dst-address=203.0.113.0/24 blackhole distance=254 /ipv6 route add dst-address=2001:db8::/32 blackhole distance=254
Com isso, 203.0.113.200 casa com o /24 blackhole e é descartado na primeira chegada. As rotas específicas para o /25 e o /27 continuam ganhando, porque são mais longas. O mesmo vale para o /32 de IPv6.
No concentrador: pools, CGNAT e prefixos delegados
/ip route add dst-address=203.0.113.0/25 blackhole distance=254 add dst-address=203.0.113.128/27 blackhole distance=254 add dst-address=100.64.0.0/22 blackhole distance=254 /ipv6 route add dst-address=2001:db8:a000::/40 blackhole distance=254
- Pool PPPoE: cada cliente conectado ganha uma rota /32 dinâmica, mais específica que o /25. Os IPs livres do pool caem na blackhole em vez da default.
- Pool público do CGNAT: o tráfego de volta das traduções ativas é tratado pelo connection tracking antes da decisão de rota. O post sobre CGNAT no Mikrotik com netmap já usa essa mesma rota.
- 100.64.0.0/22: os clientes conectados têm a rota da sessão; endereço sem sessão não sai mais pela default.
- Prefixos delegados: no prefixo delegado no PPPoE, cada sessão instala a rota do prefixo do cliente. O resto do /40 fica na blackhole.
Por que distance=254
A distance só desempata rotas com o mesmo prefixo. Com 254, se o mesmo /24 aparecer por outro caminho, como OSPF ou iBGP vindo de outro roteador, a rota real ganha e a blackhole fica de reserva. Com uma distance baixa, a blackhole poderia vencer uma rota legítima de mesmo tamanho e derrubar tráfego que deveria passar.
Blackhole e anúncio BGP
No RouterOS v7, o que é anunciado ao trânsito sai de uma lista de endereços referenciada pelo output.network do template ou da conexão BGP:
/ip firewall address-list add list=bgp-networks address=203.0.113.0/24
Como mostra o post sobre BGP no Mikrotik RouterOS v7, o prefixo precisa existir na tabela de rotas para ser anunciado de forma estável. A blackhole do /24 faz esse papel de âncora: o anúncio não depende de nenhuma interface estar de pé e, ao mesmo tempo, impede o static loop do bloco. Uma rota resolve os dois problemas.
Há uma consequência que vale ter em mente: se a borda perder o caminho para o concentrador, o /24 continua anunciado, e o tráfego para os clientes é descartado na borda em vez de dar voltas. Para o link de trânsito, é o melhor cenário possível numa falha interna.
Equivalente no Huawei: NULL0
Na borda Huawei VRP, a rota para a interface NULL0 cumpre o mesmo papel da blackhole do Mikrotik:
ip route-static 203.0.113.0 255.255.255.0 NULL0 ipv6 route-static 2001:db8:: 32 NULL0
A rota estática no VRP tem preferência 60 por padrão, e um número menor ganha. Isso quer dizer que, diferente do exemplo com distance 254 no Mikrotik, a NULL0 vence uma rota de mesmo prefixo aprendida por BGP (preferência 255) e perde para uma rota interna do OSPF (10), mas ganha de uma rota externa do OSPF (ASE, 150). Para o agregado que você mesmo origina isso costuma ser o desejado; se o mesmo prefixo também vier de outro roteador por BGP, ajuste a preferência da estática, como em ip route-static 203.0.113.0 255.255.255.0 NULL0 preference 254.
Erros comuns
| Erro | Consequência | Como evitar |
|---|---|---|
| Blackhole com distance baixa no mesmo prefixo de uma rota real | Tráfego legítimo descartado | Usar distance=254 |
| Blackhole só em IPv4 | Static loop continua no IPv6 | Criar a rota também em /ipv6 route |
| Blackhole só na borda | Loop entre concentrador e borda nos pools | Repetir nos concentradores |
| Pool novo sem blackhole | Loop volta quando o pool cresce | Incluir no procedimento de criar pool |
| Copiar type=blackhole de um tutorial do v6 | Sintaxe antiga | No v7 a palavra blackhole vai sozinha |
| Confiar só no firewall | Cada pacote ainda passa pelo filtro | A rota resolve antes e custa menos |
Depois de criar as rotas, confira se elas estão ativas e se a rota específica continua ganhando:
/ip route print where dst-address=203.0.113.0/24 /ip route print where dst-address=203.0.113.0/25 /tool traceroute 203.0.113.200
O traceroute para o endereço livre agora para logo no início, sem alternar saltos. Repita o fping de fora e guarde o resultado como evidência de que o static loop foi fechado.
Perguntas frequentes
O que é static loop em provedor?
É o loop de roteamento que acontece quando um roteador recebe tráfego para um endereço do próprio bloco sem rota específica e devolve pela default. O pacote vai e volta entre dois roteadores até o TTL acabar, multiplicando o tráfego no link.
A rota blackhole derruba os clientes conectados?
Não. As sessões PPPoE e as traduções ativas criam rotas ou entradas mais específicas, que sempre ganham da blackhole do bloco. Ela só pega o que não tem destino.
Preciso de blackhole se eu não uso BGP?
Precisa. Se o trânsito roteia o bloco para você por rota estática e a sua borda tem default para ele, o static loop acontece do mesmo jeito. O BGP só muda a forma como o trânsito aprende o bloco.
Qual a diferença entre essa blackhole e o RTBH?
Esta blackhole é permanente e cuida de endereços sem uso. O RTBH é temporário, marca um IP em uso que está sob ataque e pede ao trânsito que descarte o tráfego antes de chegar à sua rede.
Também preciso fazer isso no IPv6?
Sim, e com mais motivo. O bloco IPv6 é muito maior e quase todo vazio, então quase todo endereço cai no loop se faltar a blackhole do prefixo inteiro e dos pools de prefixo delegado.
Conclusão
O static loop custa pouco para evitar e caro para descobrir no meio de uma madrugada. A regra é curta: todo bloco que chega a um roteador ganha uma rota blackhole com distance alta, na borda e em cada concentrador, em IPv4 e IPv6. As rotas específicas continuam funcionando e o que sobra morre na primeira chegada.
Coloque a criação da blackhole no mesmo procedimento que cria um pool ou anuncia um prefixo, e rode a varredura com fping de tempos em tempos. Assim o static loop não volta quando a rede cresce.
Leitura recomendada: Static Loop, um erro que pode matar seu ISP/ITP, na wiki do Brasil Peering Forum (conteúdo sob licença CC BY-NC 4.0).
