Como posso filtrar o MongoDB Replica Set Heartbeats com o tcpdump?

6

Ocasionalmente, ao solucionar problemas de integridade de um conjunto de réplicas, gostaria de filtrar os pacotes de heartbeat especificamente, rastreá-los e a resposta subsequente (ou a falta deles) sem todo o ruído dos outros dados. fluindo entre os conjuntos.

Infelizmente, esses pacotes são estruturados da mesma maneira que comandos / consultas e respostas normais. Embora o Wireshark tenha dissecadores que me permitam acessar o protocolo do MongoDB, não posso usar essa técnica para o tcpdump filtrar os pacotes em fonte.

Então, a questão é: como filtrar as pulsações do conjunto de réplicas do MongoDB no tcpdump?

    
por Adam C 09.07.2013 / 18:00

1 resposta

10

Com base no este documento , primeiro precisamos decidir qual é a nossa característica de identificação, para que o filtro é bem sucedido e só escolhe os batimentos cardíacos. Então, precisamos obter a representação hexadecimal desse identificador. Começando com a própria pulsação de saída (que é essencialmente apenas uma consulta / comando), é um comando admin e contém a seguinte cadeia:

replSetHeartBeat = 0x7265706c536574486561727446265174 (16 bytes)

Agora que temos a string de identificação, precisamos descobrir onde procurar dentro do TCP. O deslocamento é calculado da seguinte forma:

32 bytes para o TCP leva você ao protocolo de transferência do MongoDB , e depois:

  • 4 bytes - tamanho da mensagem
  • 4 bytes - ID do pedido
  • 4 bytes - resposta a
  • 4 bytes - opcode
  • 4 bytes - sinalizadores
  • 11 bytes - nome da coleta (sempre é o mesmo neste caso, mas pode variar em geral)
  • 4 bytes - numtoskip
  • 4 bytes - numtoreturn
  • 4 bytes - comprimento do documento
  • 1 byte - tipo

Portanto, o deslocamento total é: (32 + 4 + 4 + 4 + 4 + 4 + 11 + 4 + 4 + 4 + 1) = 76 bytes

Assim, você pensaria que algo assim é o que é necessário:

sudo tcpdump -i eth0 'tcp[76:16] = 0x7265706c536574486561727446265174'

Infelizmente, o tcpdump permite apenas correspondências de até 4 bytes por vez, portanto, é necessário dividi-lo em blocos de 4 x 4 bytes e usar um AND lógico para combinar as correspondências:

sudo tcpdump -i eth0 '(tcp[76:4] = 0x7265706c) and (tcp[80:4] = 0x53657448) and (tcp[84:4] = 0x65617274) and (tcp[88:4] = 0x62656174)'

Isso cobre a parte de saída da pulsação, mas e a resposta?

Felizmente a resposta no heartbeat é muito mais fácil de combinar - estamos procurando a parte rs: true do documento, e isso se traduz da seguinte maneira, cabendo facilmente em 4 bytes:

rs : true = 0x72730001 (4 bytes)

Calculando o deslocamento de maneira semelhante (a única diferença real é um ID do cursor de 8 bytes em vez do nome da coleção de 11 bytes) obtemos um deslocamento de 73 bytes e isso nos leva a esse filtro:

sudo tcpdump -i eth0 'tcp[73:4] = 0x72730001'

Finalmente, vamos juntar tudo isso e adicionar algumas das minhas opções preferidas do tcpdump. No final, recebemos este comando:

sudo tcpdump -Xs0 -nnpi eth0 -w heartbeats.pcap '((tcp[76:4] = 0x7265706c) and (tcp[80:4] = 0x53657448) and (tcp[84:4] = 0x65617274) and (tcp[88:4] = 0x62656174)) or tcp[73:4] = 0x72730001'

(Testado com sucesso usando o MongoDB 2.4.4 no Mac OS X e no Linux)

É claro que isso também pode ser aplicado de forma mais geral, você só precisa descobrir os critérios de correspondência, deslocamento e byte correspondentes.

Para referência, você pode usar os mesmos critérios, mas com uma sintaxe ligeiramente diferente para testar esse tipo de filtragem no Wireshark. Os filtros Wireshark equivalentes para os critérios acima são:

tcp[76:16]==72:65:70:6c:53:65:74:48:65:61:72:74:62:65:61:74
tcp[73:4]==72:73:00:01
    
por 09.07.2013 / 18:00