Como montar um SIEM doméstico no Linux e vigiar sua rede
Descubra como construir um micro-SIEM caseiro no Linux para monitorar intrusos e novos dispositivos na rede local com varredura ARP sem pesar na CPU.
Se você administra um servidor em casa, mantém um homelab ou simplesmente possui dezenas de aparelhos conectados na sua residência, com certeza já viveu esta cena: abrir a interface web do roteador da operadora e se deparar com uma lista de vinte endereços MAC misteriosos.
A tela do roteador raramente ajuda. Metade dos itens aparece com o nome "Desconhecido", "Wireless-Device" ou com um campo em branco. Você fica na dúvida se aquele endereço pertence à lâmpada inteligente da sala, ao leitor de e-book da sua família ou a um vizinho que conseguiu a senha do seu Wi-Fi.
Os firmwares padrão de roteadores domésticos são lentos para atualizar concessões de DHCP, não avisam quando um aparelho se conecta e não identificam o fabricante do hardware. Por outro lado, ferramentas corporativas de monitoramento como Wazuh ou Splunk exigem servidores pesados, muita memória RAM e configurações complexas demais para quem só quer saber o que acontece na sala de estar.
Neste artigo, você vai aprender a montar um sentinela de rede doméstico (um micro-SIEM) extremamente enxuto no Linux. A solução foi inspirada em uma implementação compartilhada pelo desenvolvedor Evandro Carvalho na comunidade técnica e utiliza recursos nativos do próprio sistema operacional para vigiar a rede local gastando quase zero de processamento.
O que é um SIEM e por que ter uma versão caseira?
A sigla SIEM significa Security Information and Event Management (Gerenciamento de Eventos e Informações de Segurança). No mundo corporativo, é a central que coleta registros de todos os servidores, firewalls e computadores para alertar quando algo suspeito acontece.
Em casa ou em um homelab modesto, você não precisa de uma central gigantesca. O seu objetivo principal é muito mais direto:
- Saber exatamente quem está conectado na sua rede local.
- Identificar qual empresa fabricou a placa de rede daquele aparelho.
- Receber um alerta imediato no instante em que um dispositivo desconhecido aparecer.
Se você já acompanhou nosso artigo sobre o que é self-host e por que você deveria se importar, sabe que ter controle sobre seus próprios dados e infraestrutura começa dentro da sua própria casa. Da mesma forma que mostramos os riscos de aparelhos inteligentes em sua Smart TV está vendendo sua internet: como se proteger, manter os olhos abertos na camada de rede é essencial.
O erro comum: por que rodar Nmap em loop é uma má ideia
A primeira reação de muitos administradores quando pensam em varrer a rede local é criar um script em shell com o Nmap rodando a cada dois minutos:
# Evite fazer isso em loop contínuo
nmap -sn 192.168.1.0/24
Embora o Nmap seja fantástico para auditorias pontuais, usá-lo como monitor contínuo em redes domésticas traz dois problemas sérios:
- Ruído e consumo de recursos: Disparar varreduras completas a cada minuto gera tráfego contínuo desnecessário e eleva o uso de CPU em servidores modestos (como Raspberry Pi ou mini PCs).
- Instabilidade em aparelhos de IoT: Lâmpadas inteligentes, interruptores e tomadas conectados via chips ESP8266 ou ESP32 possuem pilhas de rede muito frágeis. Uma chuva constante de pacotes SYN e probes ARP pode sobrecarregar a memória desses microcontroladores, fazendo com que eles reiniciem ou percam a conexão com o Home Assistant.
A sacada inteligente: aproveitando o kernel do Linux e o ARP
Em redes locais Ethernet e Wi-Fi, toda comunicação entre máquinas utiliza o protocolo ARP (Address Resolution Protocol) para traduzir um endereço IP (como 192.168.1.50) em um endereço físico MAC (como DC:A6:32:11:22:33).
O próprio kernel do Linux mantém uma tabela com todas essas correspondências na memória RAM. Essa tabela pode ser consultada a qualquer momento lendo um arquivo virtual do sistema:
cat /proc/net/arp
A saída desse comando mostra os endereços IP ativos, os respectivos endereços MAC e a interface de rede:
IP address HW type Flags HW address Mask Device
192.168.1.1 0x1 0x2 e4:ca:12:34:56:78 * eth0
192.168.1.105 0x1 0x2 dc:a6:32:88:99:aa * eth0
192.168.1.142 0x1 0x2 ec:fa:bc:12:77:88 * eth0
Ler o arquivo /proc/net/arp consome 0% de CPU porque o arquivo não está no disco, mas diretamente na memória gerenciada pelo kernel.
Para garantir que a tabela esteja sempre atualizada mesmo para dispositivos em modo de economia de energia, basta disparar um ping sweep assíncrono e suave a cada três ou cinco minutos. Disparar uma rajada de pings simultâneos usando asyncio em Python leva menos de dois segundos na sub-rede inteira e não sobrecarrega os dispositivos menores.
Como identificar o fabricante: o padrão IEEE OUI
Todo endereço MAC é composto por seis pares de caracteres hexadecimais (octetos). Os três primeiros pares (por exemplo, DC:A6:32) formam o chamado OUI (Organizationally Unique Identifier).
Essa sequência é registrada oficialmente no comitê internacional IEEE por cada fabricante de hardware:
DC:A6:32pertence à Raspberry Pi Foundation.EC:FA:BCe30:AE:A4pertencem à Espressif Systems (os famosos chips de lâmpadas Tuya, Sonoff e projetos DIY).AC:D1:B8pertence à Apple.24:4C:E3pertence à Samsung.18:66:DApertence à Intel.
Ao cruzar os primeiros caracteres do endereço MAC com um dicionário local, o nosso script descobre na hora se o novo hóspede da rede é um iPhone, um notebook de trabalho ou um dispositivo IoT recém-instalado, sem precisar fazer nenhuma consulta em APIs lentas na internet.
Construindo o sentinela em Python
Vamos montar o script que fará o trabalho de vigilância. Crie uma pasta para o projeto no seu servidor Linux:
mkdir -p ~/sentinela-rede
cd ~/sentinela-rede
Crie o arquivo monitor_rede.py:
import os
import json
import asyncio
from datetime import datetime
# Dicionario basico de fabricantes OUI para resolucao offline imediata
OUI_DATABASE = {
"DC:A6:32": "Raspberry Pi Foundation",
"B8:27:EB": "Raspberry Pi Foundation",
"E4:5F:01": "Raspberry Pi Foundation",
"EC:FA:BC": "Espressif (Tuya / Smart Life / IoT)",
"30:AE:A4": "Espressif Systems (ESP32)",
"24:62:AB": "Espressif Systems (ESP8266)",
"AC:D1:B8": "Apple, Inc.",
"F0:18:98": "Apple, Inc.",
"24:4C:E3": "Samsung Electronics",
"B0:72:BF": "Samsung Electronics",
"18:66:DA": "Intel Corporation",
"00:1A:2B": "Cisco Systems",
"E4:CA:12": "Roteador / Gateway Principal",
}
KNOWN_DEVICES_FILE = os.path.expanduser("~/sentinela-rede/dispositivos_conhecidos.json")
def resolve_vendor(mac: str) -> str:
"""Extrai os tres primeiros octetos e identifica o fabricante."""
prefix = mac.upper()[:8]
return OUI_DATABASE.get(prefix, "Fabricante nao identificado")
def get_arp_devices() -> list:
"""Le a tabela ARP mantida pelo kernel do Linux na memoria."""
devices = []
arp_path = "/proc/net/arp"
if not os.path.exists(arp_path):
return devices
with open(arp_path, "r") as f:
lines = f.readlines()
# Ignora a primeira linha de cabecalho
for line in lines[1:]:
parts = line.split()
# Valida formato e descarta entradas incompletas (0x0) ou zeradas
if len(parts) >= 6 and parts[2] == "0x2" and parts[3] != "00:00:00:00:00:00":
ip = parts[0]
mac = parts[3].upper()
interface = parts[5]
devices.append({
"ip": ip,
"mac": mac,
"interface": interface,
"vendor": resolve_vendor(mac)
})
return devices
async def ping_sweep(subnet: str = "192.168.1"):
"""Dispara pings assincronos em lote na sub-rede para forcar atualizacao do ARP."""
async def ping_host(ip: str):
proc = await asyncio.create_subprocess_exec(
"ping", "-c", "1", "-W", "1", ip,
stdout=asyncio.subprocess.DEVNULL,
stderr=asyncio.subprocess.DEVNULL
)
await proc.wait()
tasks = [ping_host(f"{subnet}.{i}") for i in range(1, 255)]
await asyncio.gather(*tasks)
def carregar_conhecidos() -> dict:
if os.path.exists(KNOWN_DEVICES_FILE):
try:
with open(KNOWN_DEVICES_FILE, "r") as f:
return json.load(f)
except Exception:
return {}
return {}
def salvar_conhecidos(dados: dict):
with open(KNOWN_DEVICES_FILE, "w") as f:
json.dump(dados, f, indent=2)
def alertar_novo_dispositivo(device: dict):
horario = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
mensagem = (
f"[ALERTA DE INTRUSO/NOVO APARELHO]\n"
f"Horario: {horario}\n"
f"IP: {device['ip']}\n"
f"MAC: {device['mac']}\n"
f"Fabricante: {device['vendor']}\n"
f"Interface: {device['interface']}\n"
f"----------------------------------------"
)
print(mensagem)
# Dica: aqui voce pode disparar um webhook para Discord, Telegram ou Home Assistant
async def ciclo_monitoramento(subnet: str = "192.168.1"):
print(f"Iniciando ciclo de varredura na sub-rede {subnet}.0/24...")
# 1. Atualiza a tabela ARP enviando pings assincronos
await ping_sweep(subnet)
# 2. Le as entradas ativas do kernel
dispositivos_atuais = get_arp_devices()
conhecidos = carregar_conhecidos()
houve_alteracao = False
for dev in dispositivos_atuais:
mac = dev["mac"]
if mac not in conhecidos:
alertar_novo_dispositivo(dev)
conhecidos[mac] = {
"ip": dev["ip"],
"vendor": dev["vendor"],
"primeira_aparicao": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"nome_personalizado": ""
}
houve_alteracao = True
else:
# Atualiza o ultimo IP visto caso tenha mudado pelo DHCP
if conhecidos[mac].get("ip") != dev["ip"]:
conhecidos[mac]["ip"] = dev["ip"]
houve_alteracao = True
if houve_alteracao:
salvar_conhecidos(conhecidos)
print(f"Varredura concluida. {len(dispositivos_atuais)} dispositivos online registrados.")
if __name__ == "__main__":
# Ajuste aqui a faixa de IP correspondente ao seu roteador (ex: 192.168.0 ou 192.168.1)
asyncio.run(ciclo_monitoramento(subnet="192.168.1"))
Testando a execução manual
Antes de criar um serviço permanente, teste a execução direta no terminal:
python3 monitor_rede.py
Na primeira execução, o script criará o arquivo dispositivos_conhecidos.json e listará todos os aparelhos encontrados. Se um novo aparelho entrar no Wi-Fi minutos depois e você rodar o script novamente, o alerta será impresso no terminal apontando o endereço IP, o MAC e a fabricante associada.
Para ambientes onde você organiza hosts locais com nomes legíveis, combinar essa prática com o que ensinamos em como fazer o Linux reconhecer um nome de domínio local como um endereço IP permite identificar instantaneamente quem é quem.
Rodando 24 horas por dia com o Systemd
Para que o monitoramento seja contínuo e silencioso, podemos transformar o script em um serviço do systemd acompanhado de um timer que executa a cada 5 minutos.
Primeiro, crie o arquivo de serviço:
sudo nano /etc/systemd/system/sentinela-rede.service
Cole o conteúdo abaixo (lembre-se de trocar seu_usuario pelo nome de usuário correto da sua máquina):
[Unit]
Description=Sentinela de Rede Domestica ARP
After=network.target
[Service]
Type=oneshot
User=seu_usuario
WorkingDirectory=/home/seu_usuario/sentinela-rede
ExecStart=/usr/bin/python3 /home/seu_usuario/sentinela-rede/monitor_rede.py
[Install]
WantedBy=multi-user.target
Agora, crie o timer correspondente para executar o script em intervalos regulares:
sudo nano /etc/systemd/system/sentinela-rede.timer
Insira as instruções de agendamento:
[Unit]
Description=Executa o Sentinela de Rede a cada 5 minutos
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
Unit=sentinela-rede.service
[Install]
WantedBy=timers.target
Ative e inicie o timer no sistema:
sudo systemctl daemon-reload
sudo systemctl enable --now sentinela-rede.timer
Para verificar se o timer está agendado e funcionando perfeitamente:
systemctl list-timers --all | grep sentinela
E para acompanhar os registros do sistema:
journalctl -u sentinela-rede.service -n 50 --no-pager
Como avançar com automações e quarentena
Com esse micro-sentinela funcionando na sua rede local, você tem em mãos uma base sólida para criar automações inteligentes:
- Notificações em mensageiros: Você pode adicionar poucas linhas na função
alertar_novo_dispositivopara enviar uma requisição HTTP viaurllib.requestourequestspara um bot no Telegram ou um webhook no Discord. - Integração com Home Assistant: É possível enviar eventos via MQTT para acender uma luz na cor vermelha caso um dispositivo de fabricante desconhecido conecte de madrugada.
- Isolamento de porta: Em switches gerenciáveis, o evento pode disparar comandos automáticos para isolar uma VLAN ou bloquear conexões não autorizadas.
E se o seu servidor Linux estiver exposto a conexões externas além da rede local, não deixe de conferir também nosso checklist completo de hardening de SSH para garantir que, além do Wi-Fi, suas portas de acesso administrativo continuem trancadas.
Referências e Leituras Recomendadas
- Artigo original e discussão na comunidade: TabNews: Como Montar um SIEM Doméstico no Linux com Detecção de Intrusos ARP e Fabricante OUI por Evandro Carvalho.
- Documentação do Fymax Sentinel: Tutorial Completo: Sentinela de Rede no Fymax Sentinel.
- Documentação do kernel Linux sobre o subsistema de rede: Linux Kernel Networking Documentation.