You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scapy解析PCAP时answers方法无法匹配全部HTTP请求响应对

问题描述

现象更新

我尝试使用zeek解析PCAP文件(执行命令zeek -C -r sample.pcap),生成的http.log文件共有7条记录,由此可确定Scapy存在解析异常,推测问题出在数据包解封装、识别HTTPResponse层的环节。

核心需求为从pcap文件中完成HTTP请求与对应响应的映射匹配,最初实现时调用搭配TCPSession参数的sniff()函数,代码如下:

from scapy.all import *

load_layer("http")

pcap_file = "sample.pcap"


def callback_method(packet):
    if packet.haslayer('HTTPRequest'):
        request_list.append(packet)
    elif packet.haslayer('HTTPResponse'):
        response_list.append(packet)
    else:
        logging.debug("other")


logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S')

request_list = []
response_list = []

sessions = sniff(offline=pcap_file, prn=callback_method, session=TCPSession).sessions()

logging.info(f"Number of HTTPRequest: {len(request_list)}")
logging.info(f"Number of HTTPResponse: {len(response_list)}")

for http_request in request_list:
    for http_response in response_list:
        if http_response.answers(http_request) == 1:
            logging.info(f"HTTPResponse found !!!")
            break

代码运行输出如下:

06-Jun-22 14:46:04 - INFO - Number of HTTPRequest: 7
06-Jun-22 14:46:04 - INFO - Number of HTTPResponse : 7
06-Jun-22 14:46:04 - INFO - HTTPResponse found !!!
06-Jun-22 14:46:04 - INFO - HTTPResponse found !!!
06-Jun-22 14:46:04 - INFO - HTTPResponse found !!!
06-Jun-22 14:46:04 - INFO - HTTPResponse found !!!

运行结果不符合预期:pcap文件中实际存在7条HTTP请求与对应的7条HTTP响应,但代码仅匹配到4组请求-响应对,因此怀疑http_response.answers(http_request)方法存在偶发的匹配失效问题。

验证过程

使用tshark执行如下命令校验TCP流与HTTP事务对应关系:

tshark -r "$1" -2 -R "tcp and (http.request or http.response)" -T fields -e tcp.stream | sort -n | uniq

命令输出结果为:

20
20
90
90
91
91
99
100
100
99
108
108
122
122

该结果证实pcap内确实存在7组完整的HTTP请求-响应对,分别对应TCP流编号20、90、91、99、100、108、122。

问题根因

answers()方法不存在偶发匹配失效的bug,匹配不全的核心原因有两点:

  • 匹配逻辑设计缺陷:最初实现把所有请求、响应分别存入两个全局列表做双层全量循环,一旦某个响应匹配到靠前的请求就直接break,但answers()本身仅校验五元组、TCP序列号/确认号的基础对应关系,不会识别HTTP层事务边界,很容易出现同流内多个请求误匹配同一个响应、后续请求找不到对应响应的问题。
  • Scapy HTTP解析兼容性问题:虽然开启了TCPSession做TCP流重组,但Scapy自带的HTTP层解析对跨TCP段拆分的HTTP头、HTTP chunked编码场景兼容不足,部分HTTPResponse层的TCP序列号、确认号字段没有被正确赋值,会直接导致answers()校验不通过,这也和zeek能正常解析出7条完整HTTP记录的现象吻合。
修复方案

不要用全局列表全量遍历匹配,直接基于TCP会话维度做同流顺序匹配,匹配逻辑完全贴合HTTP 1.1同TCP流串行处理事务的特性,可靠性更高:

  • 遍历sniff()返回的sessions对象,过滤非TCP类会话
  • 对单条TCP流内的所有数据包按时间戳排序,还原真实传输顺序
  • 同流内按顺序遍历,遇到HTTPRequest就标记为待匹配请求,遇到的第一个符合answers()校验的HTTPResponse就是该请求的对应响应,匹配完成后清空待匹配标记

修正后的核心实现代码如下:

from scapy.all import *
import logging

load_layer("http")
pcap_file = "sample.pcap"

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S')

matched_pairs = []
sessions = sniff(offline=pcap_file, session=TCPSession).sessions()

for session_key, packets in sessions.items():
    # 过滤非TCP会话
    if "TCP" not in session_key:
        continue
    # 按时间戳重排同流数据包,保证顺序和实际传输一致
    sorted_pkts = sorted(packets, key=lambda x: x.time)
    pending_req = None
    for pkt in sorted_pkts:
        if pkt.haslayer('HTTPRequest'):
            # 遇到新请求,更新待匹配请求标记
            pending_req = pkt
        elif pkt.haslayer('HTTPResponse') and pending_req is not None:
            if pkt.answers(pending_req):
                matched_pairs.append((pending_req, pkt))
                logging.info("HTTPResponse found !!!")
                # 匹配完成后清空待匹配标记,避免误匹配后续响应
                pending_req = None

logging.info(f"Total matched HTTP request-response pairs: {len(matched_pairs)}")

内容的提问来源于stack exchange,提问作者Jacques Coeur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 03:15:43