如何正确读取分为两个TCP段的HTTP Post消息?

时间:2018-11-16 16:33:35

标签: python tcp dpkt

当我在pcap文件上执行以下Python代码时:

if tcp.dport == 80:    
   try:
      http=dpkt.http.Request(tcp.data)
   except (dpkt.dpkt.NeedData):
      continue
   except (dpkt.dpkt.UnpackError):
      continue
if http.method == 'POST':
   print('POST Message')

诸如以下这样的数据包会产生问题: enter image description here

这些是单个HTTP Post消息,分为两个TCP段,每个消息都在不同的数据包中发送。但是,由于第一个段仅是TCP,第二个段被识别为HTTP,因此当dpkt.http.Request尝试将第一个段读取为HTTP时,它将失败。

到目前为止没有问题。可以失败,因为它实际上不是完整的HTTP消息。但是,问题是它似乎根本没有读取第二段(“ POST消息”未打印)!第二段完全被忽略,好像它不存在一样!!!唯一可能的解释是dpkt会自动读取第二个段,因为它识别到它们都是同一条消息的段。

问题是,尽管同时读取了两个TCP段(按照上述假设),但生成的tcp.data不能识别为HTTP数据包,而是仅将其识别为TCP,因为消息是仅TCP数据包。

那我该怎么做才能读取此类pcap文件的HTTP标头和数据?

3 个答案:

答案 0 :(得分:1)

dpkt仅在数据包级别起作用。 dpkt.http.Request希望完整的HTTP请求作为输入,而不仅仅是当前数据包中的部分。这意味着您必须从属于该连接的所有数据包中收集输入,即重新组装TCP数据流。

重新组装不仅是将数据包串联起来,而且还要确保没有丢失的数据包,没有重复的数据,并确保以正确的顺序重新组装数据包,而这可能不是线路上的顺序。本质上,您需要先完成OS内核将要执行的所有操作,然后再将提取的有效负载放入套接字缓冲区。

有关如何完成部分操作的示例,请参见Follow HTTP Stream (with decompression)。请注意,此处的示例盲目地假设数据包已经井然有序,完整且没有重复-并在现实生活中无法保证。

答案 1 :(得分:0)

也许有点晚。 @steffen Ullrich提出的观点是正确的。但是,假设您没有这些问题(即没有丢失,重复的pkts等),则可以像我重新组装散布在多个TLS数据包中的TLS框架一样进行一些基本的重组。您可以将类似的逻辑应用于HTTP通信。您可以在我发布的SO question中找到与TLS框架重组相关的类似问题的解决方案。顺便说一句,在我的解决方案中,我正在使用Scapy。

答案 2 :(得分:0)

或者您可以使用Scapy 2.4.3+中的内置功能 https://scapy.readthedocs.io/en/latest/layers/http.html

sniff(session=TCPSession, [...])