我如何使用tcpdump过滤MongoDB副本设置心跳?

有时,在排除副本集的健康状况时,我想特别过滤掉心跳包,跟踪它们,然后回复(或缺less),而没有其他数据stream集。

不幸的是,这些数据包的结构与正常的命令/查询和响应非常相似。 虽然Wiresharkparsing器让我能够接触到MongoDB的有线协议,但是我不能用tcpdump的这个技术来过滤掉源数据包。

所以,问题是 – 如何过滤tcpdump中的MongoDB副本集心跳?

在这个文件的基础上,首先我们需要决定我们的特征是什么,以便filter是成功的,只有挑选出心跳。 然后,我们需要得到该标识符的hex表示。 从出站检测信号本身(本质上只是一个查询/命令)开始,它是一个pipe理命令,包含以下string:

replSetHeartBeat = 0x7265706c536574486561727446265174 (16 bytes) 

现在我们有了识别string,我们需要弄清楚TCP里面的内容。 偏移量计算如下:

TCP的32个字节让你到达MongoDB有线协议 ,然后:

  • 4个字节 – 消息长度
  • 4个字节 – 请求ID
  • 4个字节 – 响应
  • 4个字节 – 操作码
  • 4个字节 – 标志
  • 11个字节 – 集合名称(在这种情况下总是相同的,但可能会有所不同)
  • 4个字节 – numtoskip
  • 4个字节 – numtoreturn
  • 4个字节 – doc长度
  • 1个字节型

因此总的偏移量是:(32 + 4 + 4 + 4 + 4 + 4 + 11 + 4 + 4 + 4 + 1)= 76字节

因此,你会认为这样的是什么是必需的:

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

可悲的是,tcpdump一次最多只允许4个字节的匹配,所以你实际上需要把它分解成4×4个字节的块,并使用一个逻辑与来组合这些匹配:

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

这涵盖了心跳的外出部分,但是答复呢?

谢天谢地,对心跳的回复更容易匹配 – 我们正在寻找文档的rs:true部分,并且翻译如下,方便地适合4个字节:

 rs : true = 0x72730001 (4 bytes) 

以类似的方式计算偏移量(唯一真正的区别是8字节的光标ID而不是11字节的集合名称),我们得到一个73字节的偏移量,得到这个filter:

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

最后,让我们把这些放在一起,并添加一些我喜欢的tcpdump选项。 最后我们得到这个命令:

 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' 

(在Mac OS X和Linux上成功使用MongoDB 2.4.4进行testing)

当然,这也可以更一般地应用,您只需要制定出适当的匹配标准,偏移和字节匹配。

作为参考,您可以使用相同的标准,但使用稍微不同的语法来testingWireshark中的这种types的过滤。 上述标准的等效Wiresharkfilter是:

 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