Marcio Cunha

Como bloquear tráfego malicioso na borda com eBPF e XDP

Descubra como implementar filtros de pacotes de alta performance diretamente no kernel do Linux usando eBPF e XDP para bloquear ataques na borda.

Marcio Cunha•4 min
Também disponível em:EnglishEspañol
Resumo
  • O XDP executa código no driver de rede antes mesmo de alocar estruturas complexas no kernel.
  • O uso combinado de eBPF e XDP reduz drasticamente a latência e o consumo de CPU sob ataques volumétricos.
  • Mapas eBPF permitem atualizar regras de bloqueio em tempo de execução sem reiniciar a interface.
  • A validação correta do checksum e do offset de pacotes evita falhas graves de estabilidade no sistema.
  • Filtros na borda complementam ferramentas tradicionais como o iptables e fail2ban em cenários de alta carga.

O desafio de proteger a borda contra ataques volumétricos

Quando um servidor enfrenta um ataque de negação de serviço, conhecido como DDoS, o volume de tráfego malicioso pode esgotar os recursos de processamento antes mesmo que as regras tradicionais de firewall consigam agir. Historicamente, ferramentas baseadas em espaço de usuário sofrem com a sobrecarga de contexto entre o kernel e a aplicação, gerando gargalos severos de CPU e latência elevada. Na prática, isso significa que a máquina gasta mais tempo alternando contextos de execução do que processando tráfego legítimo. Para superar essa barreira, engenheiros de redes e infraestrutura buscam alternativas capazes de inspecionar e descartar pacotes indesejados no exato momento em que chegam à placa de rede, muito antes de o sistema operacional precisar alocar memória para eles.

O que é o eBPF e como ele revoluciona o kernel do Linux

O eBPF, ou Extended Berkeley Packet Filter, é uma tecnologia que permite executar programas seguros e sandboxizados diretamente dentro do espaço do kernel do Linux, sem a necessidade de compilar módulos customizados ou reiniciar a máquina. Pense nele como uma máquina virtual leve integrada ao núcleo do sistema operacional, capaz de rodar código otimizado em resposta a eventos de rede, chamadas de sistema e pontos de rastreamento. Quando combinamos essa tecnologia com ferramentas clássicas de filtragem, como o iptables e fail2ban, ganhamos uma camada extra de inteligência que opera em velocidade de hardware. Esse modelo elimina a complexidade de gerenciar regras estáticas e abre espaço para tomadas de decisão dinâmicas baseadas no comportamento real do tráfego.

Entendendo o XDP e a execução na camada de driver

O XDP, sigla para eXpress Data Path, representa o estágio mais profundo e rápido de processamento de pacotes disponível no Linux moderno. Ele injeta o código eBPF diretamente no driver da placa de rede, executando a lógica de filtragem no exato instante em que o driver recebe o pacote físico da interface. Se o pacote for considerado malicioso, o programa XDP pode emitir uma instrução de descarte imediata, conhecida como XDP_DROP, encerrando o ciclo de vida daquele pacote sem gastar ciclos de CPU adicionais. Essa abordagem difere radicalmente de métodos convencionais que exigem a passagem do pacote por toda a pilha TCP/IP do kernel, garantindo vazão máxima mesmo sob ataques pesados.

Decidindo as ações de retorno no fluxo de pacotes

Ao programar um filtro XDP, precisamos definir com precisão cirúrgica qual será o destino de cada pacote analisado através de códigos de retorno específicos. O retorno XDP_TX, por exemplo, devolve o pacote pela mesma interface de rede por onde entrou, útil em cenários de redirecionamento ou testes de loopback. Já o XDP_REDIRECT encaminha o pacote para outra interface ou para um socket AF_XDP no espaço do usuário para análises profundas. Quando lidamos com ameaças óbvias, como IPs listados em bases de inteligência de ameaças, o XDP_DROP é a escolha definitiva para estancar o sangramento e evitar que o tráfego chegue ao servidor web ou banco de dados.

Implementando um filtro prático de pacotes em C e eBPF

Para colocar a teoria em prática, precisamos escrever um programa em C restrito que será compilado para bytecode BPF e carregado no kernel. O código abaixo demonstra uma estrutura básica de um programa XDP que inspeciona o cabeçalho Ethernet e descarta pacotes IPv4 direcionados a uma porta específica sob suspeita. É fundamental garantir que a verificação de limites do pacote seja rigorosa para evitar falhas de leitura no kernel.

#define KBUILD_MODNAME "xdp_filter"
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <bpf/bpf_helpers.h>

SEC("xdp")
int xdp_drop_malicious(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;

struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end)
return XDP_PASS;

if (eth->h_proto != bpf_htons(ETH_P_IP))
return XDP_PASS;

struct iphdr *ip = data + sizeof(*eth);
if ((void *)(ip + 1) > data_end)
return XDP_PASS;

// Exemplo: Bloqueia trafego vindo de uma subrede especifica ou IP de teste
if (ip->saddr == 0x0100007F) { // 127.0.0.1 em exemplo didatico
return XDP_DROP;
}

return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

Carregando e gerenciando mapas eBPF em tempo de execução

Escrever o código é apenas a primeira etapa; o próximo desafio envolve compilar o programa usando o Clang/LLVM e carregá-lo na interface de rede correta com o auxílio da ferramenta iproute2 ou libbpf. Para atualizar listas de bloqueio sem precisar recompilar ou descarregar o programa do kernel, utilizamos estruturas de dados chamadas mapas eBPF. Esses mapas funcionam como tabelas hash compartilhadas entre o espaço do usuário e o kernel, permitindo que scripts externos injetem novos IPs maliciosos instantaneamente. Essa flexibilidade operacional garante que a segurança da borda evolua em tempo real conforme novos padrões de ataque são identificados na infraestrutura. Para aprofundar esses conceitos na prática em produção, confira também nossa análise técnica sobre Como testar o conector NVMe da placa-mãe com multímetro.

Considerações finais sobre resiliência e manutenção na borda

Adotar eBPF e XDP na borda da rede transforma radicalmente a postura defensiva de qualquer infraestrutura moderna, oferecendo uma barreira quase intransponível contra saturações de banda. No entanto, essa potência vem acompanhada de responsabilidade operacional: um programa mal escrito no kernel pode causar travamentos graves no sistema operacional ou corrupção de pacotes legítimos. Testar rigorosamente cada regra em ambientes de homologação e monitorar constantemente o comportamento das interfaces de rede são práticas indispensáveis para manter sistemas resilientes e seguros a longo prazo.