O Berkeley Packet Filter (BPF) é uma tecnologia de filtragem de pacotes de rede que captura e filtra pacotes no nível do sistema operacional e executa programas no espaço do usuário, o que aumenta a latência pela transferência de dados entre o espaço do usuário e o kernel.
Utiliza uma “interface direta” (pseudo-dispositivo) vinculada às interfaces de rede, capturando os dados que trafegam nas camadas de enlace, sem a necessidade de processamento adicional.
Com isso, programas no espaço do usuário lêem os pacotes recebidos e os injetem diretamente na interface, facilitando a análise e manipulação do tráfego de rede. Um exemplo de pseudo-dispositivo criado pelo BPF, que pode ser vinculado a uma interface de rede, é o /dev/bpf.
O uso destes pseudo-dispositivos é fundamental para ferramentas de análise de tráfego capturarem e filtrarem pacotes de dados, como tcpdump e wireshark, a partir de expressões que definem critérios de filtragem determinados pelos usuários (por ex.: endereços IP, portas e protocolos). No caso do tcpdump:
# tcpdump tcp port 80
Popularmente denominado de modo promíscuo, onde o adjetivo “promíscuo” refere-se à capacidade da interface de aceitar todos os pacotes que trafegam na rede, não se limitando apenas aos pacotes endereçados a ela. Isso é similar ao conceito de “promiscuidade” em outros contextos, onde há uma falta de restrições ou limites.
Essa característica é essencial para ferramentas de monitoramento e análise de tráfego, permitindo aos administradores detectar falhas de segurança na rede.
O espaço do usuário
A expressão “espaço do usuário” refere-se à parte da memória onde os processos de um sistema operacional são executados fora do kernel, em contraste com o espaço do kernel, reservado para o sistema operacional e suas operações críticas. Distinção é importante para entender como o BPF melhora a eficiência da captura de pacotes em ferramentas como tcpdump e wireshark.
Essa separação entre os dois espaços é uma medida de segurança e estabilidade, evitando que processos do usuário interfiram diretamente nas operações do kernel.
Como já visto, isso melhora o desempenho e diminui a carga no sistema, já que menos dados precisam ser processados e armazenados temporariamente.
O espaço do kernel… a fronteira final
A expressão “espaço do kernel” refere-se à parte da memória onde o núcleo do sistema operacional opera. Essa área é crítica para a execução de funções essenciais e gerenciamento de recursos do sistema, e é onde os processos do sistema têm acesso direto a hardware e recursos de baixo nível.
O espaço do kernel é responsável por executar o código que gerencia a interação entre o hardware e o software, incluindo drivers de dispositivos e gerenciamento de memória.
O acesso ao espaço do kernel é restrito a processos com privilégios elevados (como o próprio kernel e módulos de kernel), o que ajuda a proteger o sistema contra falhas e vulnerabilidades que poderiam comprometer sua integridade.
O BPF permite que programas sejam executados diretamente no espaço do kernel, oferecendo uma interface para capturar e filtrar pacotes de rede sem a necessidade de transferir dados para o espaço do usuário.
BPF tradicional e o eBPF
O Berkeley Packet Filter (BPF) e o Extended Berkeley Packet Filter (eBPF) são tecnologias de filtragem de pacotes com diferenças significativas em termos de funcionalidade e aplicação.
O eBPF é uma evolução do BPF tradicional, oferecendo um ambiente mais seguro e eficiente para execução de programas no kernel, permitindo aplicações mais complexas e um desempenho superior na filtragem e monitoramento de pacotes.
Expande suas capacidades para incluir uma variedade de funções no kernel, como monitoramento de desempenho, segurança, e rastreamento de chamadas de sistema.
Permite a execução de programas diretamente no kernel, proporcionando acesso em tempo real a dados do sistema com impacto mínimo sobre o desempenho.
O eBPF inclui um verificador que garante que os programas não realizem operações prejudiciais antes de serem executados no espaço do kernel. Isso assegura que o código seja seguro para rodar em um ambiente crítico:
- loops infinitos - que poderiam travar o sistema.
- instruções ilegais - que não são permitidas no contexto do kernel.
- acesso à memória fora dos limites - que poderia corromper dados ou causar falhas.
Suporta uma ampla gama de operações complexas, permitindo que desenvolvedores criem programas personalizados para diferentes casos de uso. Utiliza compilação Just-In-Time (JIT) para otimizar a execução dos programas, tornando-os quase tão rápidos quanto código nativo.
Uma comunidade ativa desenvolve SDKs e ferramentas que facilitam a criação de programas eBPF, ampliando suas aplicações.