Scapy捕获TCP二进制数据时末尾字节异常的原因排查
Scapy捕获TCP二进制流量末尾字节异常的问题解决
我写了一个用Scapy嗅探源端口5555的TCP流量并保存为二进制文件的程序,但每次捕获时,最后几个数据段总会出现0-4个错误字节。已经排除了bytes()函数的问题,从Wireshark抓包和Scapy输出的原始数据来看,异常就出在Scapy获取的TCP payload里。
原程序代码:
import scapy.all as scapy from scapy.layers.inet import IP, TCP, Ether, NoPayload ba = bytearray() def packet_handler(packet): if packet.haslayer(TCP): tcp_packet = packet[TCP] if tcp_packet.sport == 5555: # print(tcp_packet.flags) if tcp_packet.flags == 'PA': data = tcp_packet.payload ba.extend(bytes(data)) pkts = scapy.sniff(filter="tcp", # and src port 5555 timeout=5, prn=packet_handler, iface="Software Loopback Interface 1") with open('test.bin', 'wb') as file: file.write(bytes(ba))
问题原因分析
- TCP流未重组:TCP是面向流的协议,数据可能被拆分成多个分段传输,原程序直接逐个处理单个TCP包的payload,没有做流重组,容易出现分段顺序错乱或末尾分段不完整的情况。
- 抓包提前终止:用
timeout=5固定时间停止抓包,可能在最后一个完整数据包还没传输完成就停止,导致捕获到不完整的payload。 - Payload处理不严谨:直接将
tcp_packet.payload转bytes,当payload是NoPayload或存在无效封装时,可能引入错误字节。
解决方案
改用Scapy的TCP流重组功能,并优化抓包停止条件,确保拿到完整的数据流:
修改后的代码:
import scapy.all as scapy from scapy.layers.inet import IP, TCP from scapy.contrib.tcp_reassembly import TCP_Reassembler # 存储重组后的完整TCP流数据 stream_data = {} def tcp_reassembly_handler(session): # 只处理源端口为5555的TCP流 if session.src[1] == 5555: # 用源/目的IP+端口作为唯一标识,区分不同流 stream_key = (session.src[0], session.src[1], session.dst[0], session.dst[1]) stream_data[stream_key] = b"" # 遍历重组后的所有分段,拼接有效数据 for seg in session.segments: if seg.payload: stream_data[stream_key] += bytes(seg.payload) # 初始化TCP流重组器 reassembler = TCP_Reassembler() def packet_handler(packet): if packet.haslayer(TCP): # 将捕获的包交给重组器处理 reassembler.process(packet) # 开始抓包:过滤源端口5555的TCP流量,捕获到FIN标志时停止(表示传输结束) pkts = scapy.sniff( filter="tcp and src port 5555", prn=packet_handler, iface="Software Loopback Interface 1", stop_filter=lambda p: p.haslayer(TCP) and p[TCP].flags == 'F' ) # 将所有捕获的完整流数据写入文件 with open('test.bin', 'wb') as file: for data in stream_data.values(): file.write(data)
关键修改点说明
- TCP流重组:用
TCP_Reassembler自动重组同一TCP流的所有分段,确保数据完整且顺序正确。 - 动态停止抓包:通过
stop_filter监听TCP的FIN标志,只有当发送方发送结束包时才停止抓包,避免提前截断。 - 严谨的Payload处理:只拼接有有效payload的分段,跳过空数据的情况。
额外排查建议
- 确认抓包接口
iface设置正确,避免捕获到其他接口的无关流量。 - 对比Wireshark中重组后的TCP流数据和程序输出的文件,验证是否解决了字节错误问题。
内容的提问来源于stack exchange,提问作者Владимир Епифанцев
相关产品推荐
相关产品推荐

