Como Montar um SIEM Doméstico no Linux com Detecção de Intrusos ARP e Fabricante OUI
Fala pessoal!
Quem aqui tem servidor em casa ou vários dispositivos conectados já deve ter passado por aquela situação clássica: abrir o painel do roteador da operadora e dar de cara com uma lista de MACs misteriosos conectados na rede, sem saber se aquilo é uma lâmpada inteligente, um aparelho da sua casa ou alguém que descobriu a senha do seu Wi-Fi.
A maioria dos firmwares comerciais é horrível para isso. Eles demoram para atualizar o lease do DHCP, não alertam em tempo real e não resolvem quem é o fabricante do hardware.
Recentemente estruturei um "Micro-SIEM" caseiro em Python para rodar 24h no meu servidor local (um mini PC com Linux) e queria compartilhar a lógica enxuta que usei, porque ela não consome nada de CPU e avisa na hora quando qualquer aparelho desconhecido conecta.
Como funciona sem pesar o sistema?
Muita gente tenta rodar Nmap em loop, mas isso gera muito ruído na LAN e pode travar módulos ESP8266/ESP32 de lâmpadas e tomadas inteligentes.
A sacada é usar o que o próprio kernel do Linux já faz nativamente:
- Leitura direta do
/proc/net/arp: O kernel mantém a tabela ARP na memória RAM. Ler esse arquivo pseudo-sistema consome 0% de CPU. - Ping sweep assíncrono rápido: A cada 3 minutos, um script em
asynciodispara pings rápidos em lote na sub-rede/24. A varredura completa dura menos de 2 segundos. - Resolução de Fabricante IEEE OUI Offline: Cruzando os primeiros 3 octetos do MAC (ex:
EC:FA:BCpara chips Espressif de IoT,DC:A6:32para Raspberry Pi,24:4C:E3para Samsung), o sistema já classifica o tipo de dispositivo sem depender de nenhuma API externa.
O script base em Python:
import os
import asyncio
OUI_DATABASE = {
"DC:A6:32": "Raspberry Pi",
"EC:FA:BC": "Espressif (Tuya/IoT)",
"30:AE:A4": "Espressif Systems",
"AC:D1:B8": "Apple, Inc.",
"24:4C:E3": "Samsung",
"18:66:DA": "Intel",
}
def resolve_vendor(mac: str) -> str:
prefix = mac.upper()[:8]
return OUI_DATABASE.get(prefix, "Desconhecido")
def get_arp_devices():
devices = []
if not os.path.exists("/proc/net/arp"):
return devices
with open("/proc/net/arp", "r") as f:
for line in f.readlines()[1:]:
parts = line.split()
if len(parts) >= 6 and parts[2] == "0x2" and parts[3] != "00:00:00:00:00:00":
devices.append({
"ip": parts[0],
"mac": parts[3].upper(),
"interface": parts[5],
"vendor": resolve_vendor(parts[3])
})
return devices
async def ping_sweep(subnet="192.168.1"):
async def ping(ip):
proc = await asyncio.create_subprocess_exec(
"ping", "-c", "1", "-W", "1", ip,
stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL
)
await proc.wait()
await asyncio.gather(*[ping(f"{subnet}.{i}") for i in range(1, 255)])
Ao comparar a lista atual com a anterior armazenada em banco (ou JSON simples), no instante em que surge um MAC inédito, o script dispara um evento NEW_DEVICE para notificação ou isolamento.
Escrevi o artigo com a integração completa de serviço no systemd e práticas de quarentena de rede lá no meu blog:
👉 Tutorial Completo: Sentinela de Rede no Fymax Sentinel
Como vocês fazem o monitoramento de rede e inventário de nós no laboratório ou na casa de vocês? Usam alguma solução pronta como Wazuh/Pi-hole ou também preferem automações sob medida?