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

How to properly read an HTTP Post message segmented into two TCP segments?

当我在 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')

像下面这样的数据包会产生问题:

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

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

问题在于,尽管同时读取了两个 TCP 段(根据上述假设),结果 tcp.data 未被识别为 HTTP 数据包,而是仍被识别为 TCP,只是因为消息的第一段是仅 TCP 数据包。

那么如何读取这样的pcap文件的HTTP头和数据呢?

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

重组不仅仅是连接数据包,还要确保没有丢失数据包、没有重复数据包,并且数据包以正确的顺序重新组装,这可能不是网络上的顺序。本质上,在将提取的有效负载放入套接字缓冲区之前,您需要做 OS 内核会做的所有事情。

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

可能有点晚了。 @steffen Ullrich are correct. However, assuming you do not have those issues (i.e no lost, duplicate pkts, etc), you can do some rudimentary reassembly like I did for reassembling TLS frames spread over multiple TLS packets. You can apply similar logic to HTTP traffic. You can find my solution in my 提出的观点是我针对与 TLS 帧重组相关的类似问题发布的。顺便说一句,在我的解决方案中,我使用的是 scapy。

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

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