Guia completo para implementar Netfilter e Suricata no Linux

Última atualização: 1 de março de 2026
  • O NFQUEUE permite que o Netfilter delegue as decisões de filtragem e marcação a processos do espaço do usuário, possibilitando firewalls e roteadores IP dinâmicos.
  • O Suricata fornece um mecanismo IDS/IPS multiprocesso com suporte para NFQUEUE, AF_PACKET e regras compatíveis com Snort e Ameaças Emergentes.
  • A integração do NFQUEUE com Suricata, bancos de dados, Memcached ou Pfsense permite criar soluções avançadas de segurança e roteamento com software livre.
  • O desempenho depende em grande parte do design das threads e da lógica do espaço do usuário, tornando essencial a otimização e a seleção cuidadosa do tráfego a ser inspecionado.

Implementação de Netfilter e Suricata

Se você trabalha com redes em GNU/Linux ( melhores distribuições Linux para segurança e privacidade ) e tem interesse em ir além do firewall estático típico, provavelmente está curioso para saber como combinar Netfilter, NFQUEUE e Suricata para construir um IDS/IPS verdadeiramente flexível sem gastar uma fortuna em hardware proprietário. É exatamente essa área que exploraremos neste artigo, combinando elementos de baixo nível (kernel, filas, C) com ferramentas de alto nível (Suricata, regras, MySQL, Memcached, pfSense).

A ideia subjacente é muito poderosa: aproveitar o fato de que o kernel (veja como otimizar o kernel do Linux ) pode enfileirar pacotes no espaço do usuário e deixar que um programa personalizado decida o que fazer com eles. Isso pode ser usado para filtragem de tráfego (firewall avançado, IPS), roteamento dinâmico ou integração de lógica de negócios (bancos de dados, caches, detecção de ataques a aplicações web, VoIP, etc.). E se adicionarmos o Suricata como um mecanismo IDS/IPS multiprocesso, teremos uma combinação muito robusta para ambientes que vão desde laboratórios até data centers de alto tráfego.

NFQUEUE e Netfilter: elevando o firewall ao espaço do usuário.

Em um sistema GNU/Linux típico, as regras do Netfilter/iptables (ou nftables) geralmente são usadas como políticas estáticas que residem inteiramente no espaço do kernel . Interfaces e dispositivos (incluindo muitas soluções baseadas no Netfilter ou no Packet Filter do BSD) armazenam a configuração em arquivos de texto, XML ou SQLite e, quando algo muda, regeneram e recarregam as regras. Isso é flexível, mas a lógica permanece uma espécie de instantâneo do firewall com pequenos ajustes dinâmicos (limites de conexões por segundo, rastreamento de conexões, correspondência de países, camada 7, se disponível, etc.).

O que o NFQUEUE propõe é revolucionário: em vez de o kernel sempre tomar a decisão final, podemos delegar essa decisão a um processo do usuário . O kernel enfileira o pacote em uma fila numerada, e um aplicativo que utiliza a biblioteca libnetfilter_queue o recupera, analisa e retorna um veredito: aceitar, descartar ou até mesmo marcá-lo para roteamento baseado em políticas. É como ter um "juiz" programável escrito em C, Python ou Perl sobre o firewall.

A beleza disso reside no fato de que nosso programa pode literalmente fazer o que quisermos: consultar /dev/urandom, um banco de dados, um serviço web, um cache distribuído ou um algoritmo sofisticado antes de responder ao kernel. Em termos arquitetônicos, o firewall deixa de ser um simples conjunto de regras estáticas e se torna um pipeline onde o Netfilter, as filas e os aplicativos do usuário se encaixam como peças de um quebra-cabeça.

O NFQUEUE consiste em duas partes: o alvo NFQUEUE no iptables , que envia pacotes para uma fila específica, e a biblioteca de usuário libnetfilter_queue , que permite ler esses pacotes e emitir um veredito. Não é um simples analisador de pacotes como o tcpdump: aqui temos a capacidade de decidir diretamente o caminho que o pacote percorre.

monitor de sistema avançado para linux
Artigo relacionado:
Monitoramento Avançado do Sistema para Linux: Um Guia Completo

Configuração básica do iptables com NFQUEUE

Do ponto de vista do iptables, usar o NFQUEUE é bastante simples: você adiciona uma regra à cadeia de protocolos de seu interesse para enviar à fila os pacotes que atendem a determinados critérios (IP de origem/destino, portas, estados, módulos extras como GeoIP ou layer7, se disponíveis, etc.).

Por exemplo, se quisermos enviar para a NFQUEUE todos os pings que chegam ao próprio host:

iptables -I INPUT -p icmp -j NFQUEUE

Isso envia os pacotes ICMP recebidos para a fila 0 (a menos que especificado de outra forma). Podemos especificar outra fila com algo como `--queue-num 3` . Ao listar as regras com contadores (`iptables -L -n -v -x`), veremos os contadores aumentarem, indicando que os pacotes estão sendo enfileirados . Um detalhe importante: se houver pacotes na fila e nenhum processo de usuário os recuperar e processar, o comportamento padrão é negá-los; portanto, uma falha de aplicativo, por definição, resulta no bloqueio do tráfego.

Programação com libnetfilter_queue: o “olá mundo” em C

Para entrar na fila a partir do espaço do usuário, utiliza-se a biblioteca libnetfilter_queue (que, por sua vez, depende da libnfnetlink). Em distribuições como o Debian, basta instalar os pacotes de desenvolvimento:

apt-get install libnfnetlink-dev libnetfilter-queue-dev gcc

A estrutura básica de um programa minimalista que sempre aceita pacotes consiste em alguns passos bem claros: abrir a biblioteca, desvincular quaisquer manipuladores existentes, vincular ao protocolo AF_INET, criar a fila com uma função de retorno de chamada (callback), definir o modo de cópia e entrar em um loop de recebimento . A função de retorno de chamada é executada para cada pacote enfileirado, extraindo o ID e retornando o veredito.

Na prática, o fluxo é algo como: `nfq_open` para obter o identificador, `nfq_unbind_pf` para limpá-lo, `nfq_bind_pf` para associá-lo ao AF_INET, `nfq_create_queue` para registrar o retorno de chamada na fila 0, `nfq_set_mode` para indicar se queremos os metadados ou o pacote inteiro, um loop com `recv()` sobre o descritor e `nfq_handle_packet` para processar cada pacote . Ao final, a fila é destruída com `nfq_destroy_queue` e o identificador é fechado com `nfq_close`.

Esse tipo de "olá mundo" permite uma medição precisa do impacto do NFQUEUE. Se compilarmos o exemplo com algo como:

gcc -o nftest code.c -lnfnetlink -lnetfilter_queue

E se enfileirarmos o tráfego de um iperf (por exemplo, a porta TCP 5001 em INPUT e OUTPUT), veremos que o código que simplesmente aceita pacotes praticamente não afeta o desempenho em uma rede gigabit . No entanto, há um detalhe crucial: imprimir informações no callback (printf, fflush, etc.) penaliza significativamente a taxa de transferência, como pode ser observado ao comparar o iperf com e sem depuração na tela.

Opções avançadas do NFQUEUE: bypass, balanceamento e fail-open

O NFQUEUE incorpora diversas opções interessantes do iptables que modificam o comportamento padrão das filas e que devem ser conhecidas antes de entrar em um ambiente de produção ou de alto desempenho, pois afetam a forma como a falha do aplicativo do usuário ou o preenchimento da fila são tratados.

O comando `--queue-bypass` permite garantir que, se nenhum processo estiver escutando a fila, os pacotes não sejam descartados, mas sim encaminhados para o próximo salto na cadeia do iptables. Isso pode ser útil se você quiser que o sistema "falhe aberto" quando o serviço do usuário estiver indisponível, embora, do ponto de vista da segurança, seja uma faca de dois gumes.

A opção `--queue-balance` permite distribuir pacotes por uma variedade de filas (por exemplo, de 0 a 3) e, em seguida, ter vários processos ou threads independentes consumindo de cada fila . O código do Netfilter garante que os pacotes do mesmo fluxo sempre terminem na mesma fila, o que simplifica bastante a manutenção da consistência na lógica de decisão.

Existe também o modo `--fail-open` , que controla o que acontece quando a fila se enche porque o processo do usuário está muito lento. Habilitá-lo faz com que o kernel aceite pacotes diretamente em vez de descartá-los, evitando grandes interrupções no tráfego. Novamente, isso pode ser um problema de segurança, pois se quisermos tomar decisões caso a caso, perder pacotes de decisão significa não atingir esse objetivo.

Para monitorar o que está acontecendo com as filas, o Netfilter expõe informações no pseudo-sistema de arquivos /proc/net/netfilter/nfnetlink_queue , que pode ser facilmente consultado por scripts ou ferramentas de monitoramento.

Integração da lógica de negócios: testes com Memcached e MySQL

Uma vez que o processo "hello world" esteja sob controle, o próximo passo natural é enriquecer o callback com chamadas a sistemas externos . Um experimento típico envolve decidir se um pacote deve ser aceito ou rejeitado com base na presença do endereço IP de origem em algum backend, como um banco de dados MySQL ou um cache Memcached.

  LD_LIBRARY_PATH no Linux: uso correto, riscos e alternativas

No caso do Memcached, o daemon é instalado (apt-get install memcached) e uma chave, por exemplo, authorized , é carregada com o endereço IP que nos interessa. Podemos fazer isso com um simples echo e netcat, e então verificar com um comando get se o valor está armazenado corretamente. A partir daí, o programa NFQUEUE, além de obter o ID do pacote, recebe o pacote inteiro usando NFQNL_COPY_PACKET , extrai o cabeçalho IP (struct iphdr) e converte o endereço de origem em uma string com inet_ntop.

Para evitar a perda de tempo abrindo conexões a cada pacote, a conexão com o Memcached é inicializada apenas uma vez no método principal (memcached_create, memcached_server_list_append, memcached_server_push), e o manipulador é armazenado em variáveis ​​globais. No retorno de chamada, memcached_get é chamado com a chave desejada, o endereço IP de origem é comparado ao valor recuperado e, se coincidirem, NF_ACCEPT é retornado; caso contrário, NF_DROP é retornado. Se a chave não existir ou ocorrer um erro, o pacote é descartado como medida de segurança.

Usando o iperf, essa estratégia reduz a taxa de transferência para aproximadamente 140 Mbit/s em uma rede gigabit , e observa-se que a fila começa a sofrer perdas (indicadas, por exemplo, por símbolos dentro do próprio código). Em outras palavras, simplesmente chamar um serviço de cache por pacote já acarreta um custo significativo, embora permaneça viável para volumes de tráfego médios se otimizado.

Com o MySQL, a abordagem é semelhante, mas mais complexa: as bibliotecas do servidor e do cliente são instaladas, um banco de dados (por exemplo, nfqueue) é criado com uma tabela simples chamada authorized(ip varchar(50)), e o endereço IP permitido é inserido. No programa, `mysql_init` e `mysql_real_connect` são executados na inicialização e, no retorno de chamada, uma consulta como `select * from authorized where ip like 'xxxx'` é construída. Se a consulta for executada com sucesso e uma linha for encontrada, o pacote é aceito; caso contrário, é descartado.

Com o cache de consultas MySQL ativado, os testes resultaram em cerca de 188 Mbit/s , valor que cai para 103 Mbit/s quando o cache de consultas é desativado. Esses números, embora longe de gigabits, demonstram que mesmo com a abordagem menos elegante (monothread, sem otimização) , volumes de tráfego consideráveis ​​podem ser gerenciados usando decisões baseadas em banco de dados ou em cache.

Desempenho, multithreading e uso da CPU

Testes com iperf, Memcached e MySQL mostram claramente que o limite de desempenho não é imposto tanto pelo NFQUEUE em si, mas sim pela lógica que adicionamos no espaço do usuário e como a implementamos. Um executável que retorna apenas NF_ACCEPT atinge quase um gigabit sem esforço; assim que introduzimos E/S ou chamadas de rede, a taxa de transferência cai e a CPU da máquina NFQUEUE, do daemon Memcached ou do MySQL é levada ao seu limite.

Do ponto de vista arquitetônico, isso tem duas implicações. Por um lado, confirma que delegar decisões de firewall para aplicativos de usuário em volumes de tráfego significativos é perfeitamente viável , desde que os custos reais de cada chamada sejam levados em consideração. Por outro lado, demonstra que, para atingir o potencial máximo da plataforma, é necessário considerar o uso de multithreading ou multiprocessamento . O NFQUEUE permite que o tráfego seja distribuído entre várias filas; poderíamos executar diversas cópias do nosso aplicativo, cada uma escutando uma fila diferente, e aproveitar vários núcleos sem a necessidade de pthreads ou forks em larga escala.

Outra otimização óbvia seria limitar o tráfego que passa pelo NFQUEUE . Nos testes, todo o fluxo do iperf estava sendo enfileirado, mas em um cenário real, poderíamos enfileirar apenas pacotes com estado NEW, permitir a passagem de pacotes ESTABLISHED/RELATED e reservar a lógica mais complexa para logins ou padrões suspeitos.

Em última análise, o uso da CPU e o design das threads são cruciais: se o processo do usuário não for suficiente, a fila se enche e temos que recorrer a soluções como fail-open ou accept-drops, perdendo parte do controle preciso que essa abordagem busca.

Roteamento dinâmico com a marca Netfilter

NFQUEUE não se limita a simplesmente dizer "aceitar" ou "rejeitar". Também pode ser usado para aplicar flags do Netfilter (fwmark) a pacotes e combiná-las com ip rule e iproute2 para criar esquemas de roteamento político altamente flexíveis e quase leves, no estilo VRF.

Em linhas gerais, o procedimento seria: definir várias tabelas de roteamento em /etc/iproute2/rt_tables , por exemplo, lenta e rápida; atribuir a cada tabela uma rota padrão diferente (uma via fibra e outra via um link mais limitado); usar a regra ip para especificar que os pacotes com fwmark 1 vão para a tabela rápida, aqueles com fwmark 2 para a lenta, etc.; e, finalmente, usar o NFQUEUE para marcar os pacotes adequadamente antes de retornar o veredicto.

Para definir um veredicto a partir do callback, usa-se `nfq_set_verdict2` , que é semelhante a `nfq_set_verdict`, mas permite definir um valor de veredicto que `ip rule` irá então ver. Combinando tudo isso, você pode construir um roteador IP que decide para onde rotear com base em critérios arbitrários: desde coisas absurdas como tamanho de pacote par/ímpar até entradas externas como algoritmos de previsão de tráfego, eventos de mídias sociais ou sinais de sistemas de monitoramento.

O resultado é um sistema no qual o kernel continua a encaminhar pacotes na taxa normal, mas o caminho exato que cada fluxo percorre é delegado a um software externo que pode mudar de ideia em tempo real sem alterar regras estáticas.

NFQUEUE e Suricata: IPS de alto nível em GNU/Linux

Tudo isso pode ser programado manualmente em C, mas quando se trata de detecção de intrusões e inspeção profunda de pacotes, a opção mais sensata geralmente é confiar em um mecanismo IDS/IPS consolidado . É aí que entra o Suricata, que nasceu justamente como uma alternativa multiprocesso ao Snort, com recursos IPS desde o início e um foco intenso no aproveitamento dos diversos núcleos de CPU disponíveis atualmente.

O Suricata foi escrito do zero e distribuído sob a licença GPLv2 ; a Open Information Security Foundation (OISF) mantém tanto o mecanismo quanto um ecossistema bastante abrangente de regras e documentação. Ao contrário do Snort 2.x, que herdou um núcleo de thread única e foi adaptado a ele, o Suricata foi projetado para dividir a carga de trabalho entre várias threads: captura, decodificação, detecção e saída, com diferentes estratégias de compartilhamento de carga.

Em termos funcionais, o Suricata oferece suporte nativo para IPv6, inspeção da camada 7 (HTTP muito avançado via biblioteca HTP), reconhecimento de protocolo independente de portas , reconstrução de fluxo e um sistema muito poderoso de variáveis ​​de sessão (flowbits) para correlacionar diferentes estágios de um ataque propagado por várias conexões TCP.

Um ponto forte adicional é a sua compatibilidade com as regras do Snort e a capacidade de usar os conjuntos de assinaturas Sourcefire VRT e Emerging Threats (as versões gratuita ET Open e comercial ET Pro). Além disso, exporta eventos em formatos muito úteis (fast.log, JSON em eve.json) para integração com SIEMs, ELK, Splunk e outros sistemas.

Suricata como um IPS no Linux: modos de captura e NFQUEUE

No GNU/Linux, o Suricata pode operar em diferentes modos, dependendo de como o tráfego é interceptado: NFQUEUE, AF_PACKET, PF_RING, libpcap, NFLOG, IPFW, DAG, Napatech … Cada um tem suas vantagens e requisitos. No nível puro de IPS, os dois mais importantes são NFQUEUE e AF_PACKET.

No modo NFQ (NFQUEUE) , o fluxo é semelhante ao descrito anteriormente: um conjunto de regras do iptables envia pacotes para uma fila; o Suricata, executado no espaço do usuário, lê dessa fila, inspeciona o conteúdo de acordo com suas regras e retorna um veredicto para o kernel: NF_ACCEPT, NF_DROP ou NF_REPEAT. O terceiro pode ser usado para reinjetar o pacote na mesma tabela do iptables após a aplicação de marcas ou modificações adicionais.

Este modo é muito flexível e fácil de implementar em infraestruturas existentes , pois requer apenas a modificação das regras em pontos específicos (por exemplo, FORWARD, INPUT, OUTPUT), mantendo todo o resto inalterado. O custo é a sobrecarga adicional de encaminhar pacotes de e para cima através do NFQUEUE, com o impacto já mencionado caso o volume seja muito alto ou as regras exijam muitos recursos.

No modo AF_PACKET , o Suricata opera mais próximo da interface de rede, copiando pacotes através de sockets AF_PACKET. Essa é uma abordagem de cópia zero muito mais rápida , mas exige que o sistema funcione como um gateway com duas interfaces e que o bloqueio de tráfego seja realizado no nível de encaminhamento entre as NICs: o pacote a ser bloqueado simplesmente não é passado da interface de entrada para a interface de saída.

  GNOME 50 Tokyo: VRR estável, Wayland puro e área de trabalho remota aprimorada.

Em ambos os modos, o Suricata pode ser combinado com o Netfilter, mas o NFQUEUE se encaixa especialmente bem em cenários onde queremos reutilizar toda a lógica do iptables (políticas, intervalos, regras anteriores) e enviar para o Suricata apenas o tráfego que nos interessa inspecionar em detalhes.

Instalação básica do Suricata a partir do código-fonte.

Para aqueles que preferem compilar o Suricata em vez de usar pacotes, o processo em distribuições do tipo Debian/Ubuntu envolve primeiro instalar as dependências de compilação (build-essential, libpcre, libpcap-dev, libnet-dev, libyaml-dev, zlib, libcap-ng-dev, libjansson-dev, etc.), baixar o arquivo tarball do site oficial e executar o clássico ./configure, make, make install.

Durante a fase de configuração, o script indicará quais recursos de suporte foram habilitados: AF_PACKET sim/não, PF_RING, NFQUEUE sim/não, NFLOG, IPFW, suporte para libnss, libjansson, Prelude, PCRE JIT, Lua, GeoIP, etc. É importante verificar se o NFQUEUE está habilitado caso desejemos trabalhar nesse modo , e se a biblioteca de captura desejada foi localizada.

Após instalar o binário, você pode executar `make install-conf` para implantar uma configuração padrão em `/etc/suricata` e `make install-rules` para baixar e colocar um conjunto de regras de Ameaças Emergentes em `/etc/suricata/rules`. Esses conjuntos podem ser atualizados usando ferramentas como `suricata-update`.

Em sistemas Red Hat/CentOS, a lógica é semelhante, utilizando yum ou dnf para dependências (libpcap-devel, pcre-devel, libnet-devel, libyaml-devel, jansson-devel, etc.) e compilando com os mesmos passos. Por motivos de desempenho, também é recomendável desabilitar LRO/GRO na interface de captura usando o ethtool, pois essas funções de descarregamento podem afetar a visibilidade dos pacotes no nível do IDS.

Configuração do Suricata: YAML, variáveis ​​e threads

A configuração principal do Suricata reside em /etc/suricata/suricata.yaml . Trata-se de um arquivo YAML bastante legível e ricamente comentado, onde tudo, desde caminhos de logs e conjuntos de regras até políticas do sistema operacional de destino e parâmetros de threading, é definido.

Um dos campos básicos é `default-log-dir` , que especifica onde os arquivos de log serão armazenados (por padrão, `/var/log/suricata`). Na seção `vars`, encontram-se variáveis ​​como `HOME_NET`, `EXTERNAL_NET`, `HTTP_PORTS`, `SHELLCODE_PORTS` e `SSH_PORTS`, que servem como abreviações nas regras. `HOME_NET` geralmente é configurado com o intervalo de rede local que desejamos proteger, enquanto `EXTERNAL_NET` normalmente é definido como `!HOME_NET`.

Outra parte importante é a política de sistema operacional do host (host-os-policy) , que informa ao Suricata qual sistema operacional deve executar determinados intervalos de IP. Isso permite que ele ajuste a forma como reconstrói o TCP ou interpreta certos comportamentos da pilha de rede , dificultando a evasão de protocolos com base em diferenças entre pilhas (Windows vs. Linux, etc.). Intervalos específicos podem ser atribuídos a categorias como Windows, Linux, BSD, Vista, Windows 2003, etc.

Em relação ao gerenciamento de threads, a seção de threads permite ajustar a afinidade da CPU e o número de threads de detecção. Por padrão, `set-cpu-affinity` geralmente está desativado, o que permite que o agendador do sistema distribua as threads entre os núcleos. O parâmetro `detect-thread-ratio` indica quantas threads de detecção são criadas por núcleo disponível; com `detect-thread-ratio: 1.5` em uma máquina de 8 núcleos, o Suricata gerará 12 threads de detecção, além das threads de captura e gerenciamento.

Todo esse modelo é então refletido na saída quando o daemon é iniciado: uma thread de captura (por exemplo, pcap) e várias threads de detecção ficam visíveis, além de gerenciadores de fluxo e gerenciadores de estatísticas. Essa arquitetura multiprocesso é o que permite que o Suricata escale muito melhor do que mecanismos de thread única quando confrontado com links de 10/40 Gbit/s.

Atualizações de regras e assinaturas no Suricata

O Suricata utiliza conjuntos de regras para detectar padrões de ataque, comportamentos anômalos e uso indevido de protocolos. Além de aceitar regras no formato Snort , o ecossistema mais comum é o de Ameaças Emergentes: ET Open (gratuito) e ET Pro (comercial), com regras voltadas para ameaças atuais.

Muitas distribuições modernas incluem a ferramenta `suricata-update` , que simplifica o gerenciamento de regras: ela atualiza as fontes, habilita ou desabilita provedores específicos e baixa as versões mais recentes dos conjuntos de assinaturas. Um fluxo de trabalho típico seria instalar o `suricata-update` (por exemplo, via pip), executar o primeiro `suricata-update` para baixar o ET Open, listar as fontes com `suricata-update list-sources`, habilitar fontes adicionais como `ptresearch/attackdetection`, `oisf/trafficid` ou `sslbl/ssl-fp-blacklist` e executar o `suricata-update` novamente para regenerar o arquivo de regras.

O arquivo suricata.yaml é ajustado para apontar para o caminho correto das regras e, a partir daí, o Suricata começará a gerar eventos de alerta que serão registrados em fast.log (texto rápido e legível) e eve.json (JSON estruturado com informações muito completas) . Este último formato é especialmente útil para alimentar painéis de controle, sistemas de correlação ou scripts personalizados.

Além das assinaturas, o Suricata incorpora decodificadores e analisadores para múltiplos protocolos , permitindo que ele seja menos dependente de portas: ele pode identificar tráfego HTTP mesmo que passe por portas não padrão, detectar SSH, TLS, DNS, etc. em diferentes portas e níveis de encapsulamento (incluindo túneis mistos IPv4/IPv6).

Uso prático: da detecção de vulnerabilidades na web ao bloqueio automático.

Um dos casos de uso mais desejados em ambientes de hospedagem ou centros de dados é a detecção em tempo real de tentativas de exploração de vulnerabilidades em aplicações web (por exemplo, WordPress e seus plugins) e a reação automática, geralmente bloqueando ou adicionando o endereço IP de origem à lista negra no firewall.

O Suricata, com suas regras atualizadas, é capaz de reconhecer padrões de ataque específicos contra URLs, parâmetros, payloads HTTP e até mesmo sequências de requisições que correspondem a exploits conhecidos. O IDS pode operar em modo passivo, recebendo tráfego via espelhamento de uma porta de switch (SPAN), mas para atuar como um IPS e bloquear ataques, precisa ser integrado ao plano de encaminhamento.

Existem duas abordagens comuns: configurar o IDS como uma ponte online, de forma que o tráfego passe fisicamente pela máquina (usando iptables, AF_PACKET ou PF, dependendo da plataforma), ou manter a topologia como está, mas combinar o espelhamento com ações no firewall central via API, scripts ou NFQUEUE . A primeira abordagem minimiza a latência entre a detecção e o bloqueio, ao custo de adicionar outro elemento "no meio" da rede; a segunda oferece maior flexibilidade e resiliência, mas introduz mais complexidade à orquestração.

É perfeitamente viável que um Sistema de Detecção de Intrusão (IDS) detecte uma tentativa de explorar uma vulnerabilidade em um plugin do WordPress e, em seguida, seja diretamente ou por meio de um componente associado, adicione o endereço IP do atacante a uma lista negra do iptables. Isso pode ser feito através da saída JSON do Suricata e de scripts que chamam o iptables/nftables , ou delegando parte da lógica ao NFQUEUE, onde o próprio mecanismo ou um processo associado toma a decisão em tempo real, sem esperar que uma lista externa seja atualizada.

Isso permite que você se concentre nas ameaças que realmente importam (explorações, tentativas de escalonamento, varreduras muito agressivas), ignorando ou simplesmente registrando ruídos de fundo, como varreduras básicas de portas que, em muitos contextos, não são preocupantes por si só.

Suricata no Pfsense: firewall de código aberto com IDS/IPS integrado.

Nem todos podem ou querem arcar com o custo de um firewall proprietário de ponta como o Palo Alto. Em muitos ambientes, é mais atraente configurar uma solução de código aberto com pfSense e Suricata , que abrange tanto as necessidades avançadas de firewall (multi-WAN, VLAN, VPN, NAT, etc.) quanto as de IDS/IPS.

O pfSense, baseado em FreeBSD e Packet Filter, funciona particularmente bem com ambientes virtualizados (Proxmox, KVM, etc.), com a exceção de que é recomendável usar placas E1000 em vez de Virtio em máquinas KVM se você quiser evitar problemas de desempenho e travamentos sob carga, a menos que você siga as recomendações da Netgate (desativar o descarregamento de checksum de hardware em Sistema > Avançado > Rede e reiniciar, sabendo que isso pode não ser suficiente com cargas muito altas).

Os requisitos mínimos de hardware para um laboratório com Suricata no PfSense podem ser modestos (1 CPU de 500 MHz, 1 GB de RAM, 4 GB de disco), mas para uso sério, recomenda-se pelo menos 2 CPUs, 4 GB de RAM e 16 GB de armazenamento , sem esquecer de ter várias interfaces de rede (uma para WAN, outra para LAN, e mais se você quiser várias WANs ou VLANs complexas).

  Guia completo para fluxos de trabalho de agentes de IA e segurança de aplicativos

A instalação do pfSense em si é muito rápida: você inicializa a partir da ISO, aceita a licença, escolhe instalar, seleciona o idioma e o layout do teclado, deixa o particionamento em automático (Auto UFS se você for usar o disco inteiro) e, em poucos minutos, o sistema está pronto para a primeira inicialização. O console oferece um menu para atribuir interfaces, reiniciar, iniciar o shell, etc.

Em um laboratório, por exemplo, no VirtualBox, é comum desativar temporariamente o firewall do Pfsense a partir do console com o comando `pfctl -d` para acessar a interface web via WAN (nome de usuário admin, senha pfsense) e concluir o assistente inicial: dados gerais, servidores NTP, configuração da WAN (DHCP geralmente é suficiente em laboratório), LAN, alteração da senha de administrador e aplicação da configuração.

Assim que o acesso estiver estabilizado, você pode criar uma regra no firewall da WAN que permita HTTPS de qualquer origem para o endereço IP do pfSense, adicionando separadores descritivos para organizar visualmente as regras (por exemplo, "Acesso ao Firewall"). Também é recomendável desativar a opção de bloquear redes privadas na WAN se você estiver em um ambiente de teste com endereços RFC1918, para evitar ter que usar constantemente o comando `pfctl -d`.

Instalação e visão geral do Suricata no pfSense

Com o pfSense instalado e funcionando, instalar o Suricata é tão simples quanto acessar Sistema > Gerenciador de Pacotes > Pacotes Disponíveis , procurar por Suricata e instalar o pacote. O processo baixa vários arquivos e pode demorar um pouco dependendo do seu hardware, mas é totalmente assistido pela interface web.

Após a instalação, uma entrada do Suricata aparece na aba Serviços, onde você pode configurar instâncias por interface (WAN, LAN, VLANs, etc.), escolher quais conjuntos de regras usar, ativar o modo IDS ou IPS e ajustar os parâmetros de desempenho e registro. A gama de opções é extensa (suficiente para artigos inteiros apenas sobre configuração), mas a vantagem é que muitas tarefas que no Linux exigem edição manual de YAML são realizadas aqui com formulários e caixas de seleção.

Nota importante: Embora possa ser tentador expor a administração do pfSense diretamente à internet em um ambiente de laboratório, em produção é crucial restringir o acesso a endereços IP estáticos, usar VPNs para gerenciamento remoto e evitar a todo custo deixar o console web exposto . O pfSense é muito flexível, mas também deve ser tratado como o elemento crítico que é.

Com o Suricata habilitado no pfSense, você obtém um ambiente onde o tráfego passa pelo pfSense para firewall e NAT, e o Suricata o inspeciona de acordo com suas regras e pode bloqueá-lo no modo IPS . Essa combinação, gerenciada a partir de uma única interface web, simplifica bastante a implementação da proteção DPI em redes de pequeno e médio porte.

Em muitas implementações, isso é complementado por uma conexão do Pfsense/Suricata a um SIEM ou plataforma de logs centralizada, aproveitando os formatos de saída estruturados para correlacionar eventos e detectar campanhas mais amplas.

Monitoramento de eventos e exemplos de logs no Suricata

Após o Suricata estar em execução, os eventos são registrados no caminho definido por default-log-dir, geralmente /var/log/suricata . O arquivo fast.log usa um formato de texto compacto com registros de data e hora, IDs de regras, classificações e prioridade, adequado para inspeção rápida a partir do terminal (tail -f).

Por exemplo, ao encontrar tráfego com checksums TCP incorretos, podemos ver linhas como estas: carimbos de data/hora com data e hora, seguidos pelo identificador da regra (por exemplo, 1:2200074:1), a mensagem "SURICATA TCPv4 checksum inválido", classificação, prioridade e o par IP/porta de origem-destino. Esses tipos de alertas permitem a rápida identificação de problemas de integridade de pacotes ou tentativas de evasão.

O arquivo eve.json contém os mesmos eventos em formato JSON, com campos como timestamp, event_type, src_ip, dest_ip, src_port, dest_port, proto e um subarquivo de alertas com action, gid, signature_id, rev, signature, category e severity. Esse formato pode ser facilmente integrado ao Logstash, Fluentd, Filebeat ou qualquer outro agente de log , permitindo análises muito mais ricas do que simplesmente usar texto sem formatação.

Ao implantar o Suricata em um servidor com múltiplos núcleos (por exemplo, 8 núcleos), a compressão de threads fica evidente em ferramentas como o htop no modo de threads, mostrando uma ou mais threads de captura (pcap, AF_PACKET ou NFQ) e um grande número de threads de detecção distribuídas entre os núcleos. Ajustar a proporção de threads de detecção e a afinidade da CPU pode impactar significativamente a taxa de transferência e a latência quando o volume de tráfego se aproxima dos limites da plataforma.

Antes de implantá-lo em produção, é recomendável dedicar algum tempo ao ajuste fino dos conjuntos de regras ativados para evitar uma enxurrada de falsos positivos que possam bloquear tráfego legítimo ou poluir os logs. O Suricata-update permite desativar categorias inteiras ou regras individuais para encontrar um equilíbrio razoável entre sensibilidade e usabilidade.

Aplicações especiais: VoIP, análise de áudio e NFQUEUE criativo

Além dos usos clássicos (proteção de serviços web, detecção de malware, análise de DDoS), a dupla Netfilter+NFQUEUE permite soluções bastante criativas em áreas como VoIP. Por exemplo, é possível configurar um filtro anti-SPIT (spam sobre telefonia IP) ou um sistema para censurar palavrões em fluxos RTP.

A ideia seria: identificar o tráfego RTP por portas ou por reconhecimento de protocolo e enviá-lo para o NFQUEUE; a partir da aplicação do usuário, reconstruir o fluxo RTP usando uma biblioteca como a librtp , extrair o áudio em formato WAV e passá-lo para um mecanismo de reconhecimento de palavras-chave (wordspotting), como uma biblioteca de síntese ou reconhecimento oferecida por terceiros.

Com base nas palavras detectadas, o processo NFQUEUE poderia decidir permitir, bloquear ou até mesmo alterar a reprodução inserindo um bipe no fluxo, embora esta última opção exija um controle muito preciso do RTCP, das sequências de pacotes e dos tempos — quase uma abordagem de ataque do tipo "homem no meio". Não é trivial, mas teoricamente é perfeitamente viável utilizando o mesmo sistema de filas e veredictos.

É verdade que parte disso poderia ser feito com um simples analisador de pacotes enviando dados para um processador externo e, em seguida, atuando na sinalização SIP ou por meio de um SBC (Asterisk, Kamailio etc.). A diferença ao usar o NFQUEUE é que a ação no fluxo RTP pode ser imediata e direta , sem a necessidade de coordenar vários componentes ou esperar que a camada de sinalização complete a chamada.

Esses cenários ilustram claramente o potencial da combinação GNU/Linux + Netfilter + Suricata + bibliotecas de terceiros: não se trata apenas de bloquear portas e endereços IP, mas de orquestrar decisões complexas de tráfego em tempo real usando um ecossistema de software 100% livre.

Ao analisar toda a jornada, desde o pequeno programa em C que sempre aceita pacotes até uma implementação Suricata multiprocesso integrada com NFQUEUE, Pfsense, bancos de dados e caches, é possível perceber a flexibilidade que essa pilha de tecnologia oferece para construir desde firewalls dinâmicos simples até arquiteturas IDS/IPS em escala de data center, com recursos reais de inspeção profunda e resposta automatizada a ataques cada vez mais complexos.