Testes de brokers

Capturar tráfego MQTT com tcpdump

Receitas de tcpdump para MQTT em servidores, containers e gateways: filtros por porta e tipo de pacote, capturas rotativas, desconexões e análise de pcap.

Atualizado · 8 min de leitura

Capturar tráfego MQTT com tcpdump

O tcpdump é a ferramenta de captura de pacotes que já vem instalada — ou está a um pacote de distância — em quase todo servidor Linux, roteador e gateway. Ele não entende MQTT, mas nem precisa: capturar a conversa TCP na porta 1883 ou 8883 basta para provar quem conectou, quem fechou a conexão e se houve perda de pacotes no caminho. Quando você precisa dos detalhes do MQTT, abre o mesmo arquivo no Wireshark.

Este guia é um conjunto de receitas de tcpdump para MQTT: capturas básicas, filtros BPF que reconhecem tipos de pacote MQTT, capturas em Docker e Kubernetes, buffers rotativos de longa duração e como analisar o que foi capturado.

A captura MQTT básica

Capturar MQTT em todas as interfaces
# Uma linha por segmento (MQTT sem criptografia e TLS)
sudo tcpdump -i any -nn 'tcp port 1883 or tcp port 8883'

# Gravar em arquivo para o Wireshark
sudo tcpdump -i any -nn -w mqtt.pcap 'tcp port 1883 or tcp port 8883'

# Só o tráfego de um dispositivo
sudo tcpdump -i any -nn 'host 192.168.1.50 and tcp port 1883'

As opções que você mais vai usar:

OpçãoSignificado
-i any / -i eth0Interface de captura (tcpdump -D lista todas)
-nnNão resolver nomes de host nem de porta — mais rápido e sem ambiguidade
-w file.pcapGravar os pacotes em arquivo em vez de imprimir
-r file.pcapLer um arquivo de captura
-A / -XMostrar o payload em ASCII / em hex e ASCII
-c 200Parar após 200 pacotes
-UDescarregar cada pacote na hora (necessário ao gravar em um pipe)
-ttttData e hora completas em cada linha

Para ver algo útil logo de cara, publique em um topic de teste a partir de outro terminal e observe o payload em ASCII:

Ver uma mensagem de teste no fio
sudo tcpdump -i any -nn -A 'tcp port 1883' &
mosquitto_pub -h broker.connectmq.com -p 1883 -t 'testmqtt/tcpdump/hello' -m 'hello from tcpdump'

Você verá o topic testmqtt/tcpdump/hello e o payload em texto puro dentro do segmento PUBLISH. Na porta 8883 só aparecem bytes criptografados — que é exatamente o objetivo do TLS.

Onde capturar

O ponto de captura define o que você consegue provar. Uma captura no cliente mostra o que o dispositivo realmente enviou e o que voltou, incluindo retransmissões que a aplicação nunca percebe. Uma captura no host do broker mostra o que de fato chegou, depois que NAT, load balancers e proxies fizeram o seu trabalho. Quando as duas não batem, o problema está no meio.

Para um problema persistente, capture dos dois lados ao mesmo tempo com timestamps -tttt e compare. Se o cliente envia um PUBLISH que nunca aparece do lado do broker, investigue o caminho de rede; se o broker recebe e o subscriber nunca recebe, olhe as ACLs, filas e logs do broker.

Lendo a saída do tcpdump

Uma conexão MQTT típica fica assim (endereços encurtados):

Uma sessão MQTT curta
10:15:02.114 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [S], seq 1902...
10:15:02.139 IP 203.0.113.10.1883 > 10.0.0.12.52144: Flags [S.], seq 4471..., ack 1902...
10:15:02.139 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [.], ack 1
10:15:02.140 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [P.], length 35    <- CONNECT
10:15:02.166 IP 203.0.113.10.1883 > 10.0.0.12.52144: Flags [P.], length 4     <- CONNACK
10:15:02.167 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [P.], length 42    <- PUBLISH
10:15:02.168 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [P.], length 2     <- DISCONNECT
10:15:02.168 IP 10.0.0.12.52144 > 203.0.113.10.1883: Flags [F.], ...

Os flags TCP carregam a maior parte do diagnóstico:

  • [S] sem resposta [S.] — o SYN nunca foi respondido: firewall, roteamento ou IP errado. Veja diagnosticar problemas de rede no MQTT.
  • [S] respondido com [R.] — o host está no ar, mas nada escuta na porta (Connection refused).
  • [F.] — um encerramento ordenado. O lado que envia o primeiro FIN é quem decidiu terminar a sessão.
  • [R] — um reset abrupto. Se vier de um endereço que não é nem o cliente nem o broker, um equipamento intermediário derrubou a conexão.
  • O mesmo segmento [P.] repetido após um atraso — uma retransmissão, ou seja, perda no caminho.

Filtrar por tipo de pacote MQTT

O primeiro byte de todo pacote MQTT codifica o tipo nos quatro bits superiores. Uma expressão BPF consegue ler esse byte no início do payload TCP, o que permite ao tcpdump manter só certos tipos de pacote:

TipoPrimeiro byte (com máscara 0xf0)
CONNECT0x10
CONNACK0x20
PUBLISH0x30
SUBSCRIBE0x80
PINGREQ / PINGRESP0xc0 / 0xd0
DISCONNECT0xe0
Só pacotes CONNECT e CONNACK (MQTT sem criptografia, IPv4)
sudo tcpdump -i any -nn -A \
  'tcp port 1883 and tcp[tcpflags] & tcp-push != 0 and
   ((tcp[((tcp[12:1] & 0xf0) >> 2):1] & 0xf0) = 0x10 or
    (tcp[((tcp[12:1] & 0xf0) >> 2):1] & 0xf0) = 0x20)'

(tcp[12:1] & 0xf0) >> 2 é o tamanho do cabeçalho TCP, então a expressão lê o primeiro byte do payload. A condição tcp-push ignora segmentos ACK vazios. Dois limites: ela só enxerga o primeiro pacote MQTT de cada segmento (vários pacotes pequenos podem dividir um), e os offsets tcp[] funcionam apenas com IPv4. É um filtro para restringir a captura, não um decodificador — para respostas exatas, use o filtro mqtt.msgtype do Wireshark.

Detectar desconexões e reconexões

Dois filtros curtos respondem à pergunta mais comum em produção — "por que este cliente vive desconectando?":

Eventos do ciclo de vida da conexão
# Cada nova tentativa de conexão (SYN sem ACK)
sudo tcpdump -i any -nn 'tcp port 1883 and tcp[tcpflags] == tcp-syn'

# Cada encerramento ou reset, com timestamps
sudo tcpdump -i any -nn -tttt 'tcp port 1883 and tcp[tcpflags] & (tcp-fin|tcp-rst) != 0'

Leia os dois juntos:

  • Um FIN do broker cerca de um intervalo e meio de keep-alive depois do último pacote do cliente significa que o cliente parou de enviar PINGREQ — veja keep alive no MQTT.
  • Um RST após um longo período ocioso, muitas vezes sempre no mesmo intervalo, aponta para timeout de NAT ou firewall — veja timeout de NAT no MQTT.
  • Centenas de SYNs por segundo vindos de muitos dispositivos após uma queda é uma tempestade de reconexões.
  • Um FIN do broker logo após um novo SYN de outro endereço com o mesmo client ID indica que a sessão foi assumida por outro cliente. Dê a cada cliente de teste um ID distinto com o gerador de client ID.

Capturas de longa duração

Problemas intermitentes pedem capturas que rodem por horas sem encher o disco. O tcpdump consegue rotacionar os arquivos sozinho:

Buffer circular e arquivos por hora
# 10 arquivos de ~100 MB cada; o mais antigo é sobrescrito
sudo tcpdump -i any -nn -w /var/tmp/mqtt.pcap -C 100 -W 10 'tcp port 1883 or tcp port 8883'

# Um arquivo por hora, com o horário no nome
sudo tcpdump -i any -nn -G 3600 -w '/var/tmp/mqtt-%Y%m%d-%H%M.pcap' 'tcp port 1883'

Rode dentro do tmux ou como uma unit temporária do systemd, anote o horário em que o problema acontece e baixe só o arquivo relevante.

Containers, Kubernetes e hosts remotos

Um container de broker normalmente não tem tcpdump. Use emprestado o namespace de rede dele:

Docker: capturar o tráfego do container do broker
docker run --rm --net container:mosquitto nicolaka/netshoot \
  tcpdump -i any -nn -U -w - 'tcp port 1883' > broker.pcap
Kubernetes: container de debug efêmero
kubectl debug -it mosquitto-0 --image=nicolaka/netshoot --target=mosquitto -- \
  tcpdump -i any -nn 'tcp port 1883'

O container de debug precisa de permissão para capturar (root e a capability NET_RAW); políticas de segurança de pods restritivas podem bloqueá-lo. Mapeamentos de porta e redes bridge têm suas próprias armadilhas, tratadas em problemas de rede do MQTT no Docker.

Para acompanhar um servidor remoto ao vivo no Wireshark, transmita a captura por SSH (o usuário remoto precisa de sudo sem senha para o tcpdump):

Captura remota ao vivo no Wireshark
ssh admin@gateway.example "sudo tcpdump -i any -nn -U -w - 'tcp port 1883'" | wireshark -k -i -

Microcontroladores como o ESP32 não rodam tcpdump. Capture no gateway, no roteador Wi-Fi (o OpenWrt tem pacote de tcpdump) ou em uma porta espelhada do switch, filtrando pelo IP do dispositivo.

Analisando a captura

O tcpdump consegue fazer uma primeira passada em um arquivo salvo:

Análise rápida de um pcap
# Quantas tentativas de conexão, e de onde?
tcpdump -r mqtt.pcap -nn 'tcp[tcpflags] == tcp-syn' | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn

# Ler payloads em texto puro em torno de um horário
tcpdump -r mqtt.pcap -nn -tttt -A | less

# Passar para o tshark decodificar MQTT
tshark -r mqtt.pcap -Y mqtt -T fields -e frame.time -e ip.src -e mqtt.msgtype -e mqtt.topic

Para qualquer coisa além de contar, abra o arquivo no Wireshark: ele decodifica cada pacote MQTT e consegue descriptografar TLS com um key log. O fluxo completo está em depurar MQTT com Wireshark.

Confirme uma correção com uma captura

Uma captura também é o melhor teste de regressão para uma correção de rede. Depois de mudar o keep-alive, um timeout de firewall ou uma configuração de load balancer, rode o filtro de desconexões por mais tempo que o antigo intervalo de falha enquanto um cliente continua conectado — por exemplo, um subscriber no cliente MQTT online em testmqtt/tcpdump/#. Nenhum FIN ou RST nessa janela significa que a correção funciona.

Mantenha um subscriber de teste conectado durante a captura

O tcpdump transforma "a conexão cai às vezes" em timestamps, flags e endereços IP. Capture de forma restrita, deixe os flags dizerem quem fechou a conexão e passe para o Wireshark quando precisar ler os próprios pacotes MQTT.

Perguntas frequentes

Qual é o comando tcpdump para capturar MQTT?

sudo tcpdump -i any -nn -w mqtt.pcap 'tcp port 1883 or tcp port 8883' captura MQTT sem criptografia e com TLS em todas as interfaces, em um arquivo que você pode abrir no Wireshark. Remova -w e adicione -A para ver os payloads de MQTT sem criptografia direto no terminal.

O tcpdump consegue decodificar pacotes MQTT?

Não. O tcpdump mostra segmentos TCP, flags e bytes brutos, mas não tem decodificador MQTT. Capture com tcpdump e depois abra o pcap no Wireshark ou rode tshark -r arquivo.pcap -Y mqtt para ver CONNECT, PUBLISH e os outros pacotes MQTT.

Como rodar tcpdump para um broker dentro do Docker?

Conecte um container de ferramentas ao namespace de rede do broker, por exemplo docker run --rm --net container:mosquitto nicolaka/netshoot tcpdump -i any -nn port 1883. Ele vê exatamente o tráfego do container do broker sem instalar nada nele.