使用Scapy发送UDP数据包时Payload前8字节丢失的原因排查
UDP Payload前8字节被截断的原因分析与解决办法
看了你的代码和调试输出,这个问题的核心其实是Scapy的自动协议解析逻辑在搞鬼,咱们一步步拆解:
问题线索:从调试输出找原因
先看接收端的调试结果:
(Pdb) p packet[UDP].payload <DNS id=8827 qr=0 opcode=4 aa=0 tc=0 rd=0 ra=0 z=1 ad=0 cd=1 rcode=12 qdcount=8804 ancount=25447 nscount=25715 arcount=26218 qd='' an='' ns='' ar='' |<Raw load='fghtimec\"': 33:44.120154, \"sequence\": 0}"' |>>
注意到这里的UDP payload被Scapy解析成了<DNS ...>结构,而真正的业务数据只出现在DNS后面的Raw部分。DNS协议的头部正好是8字节——这就是你丢失前8字节的直接原因:Scapy把Payload的前8字节当成DNS头部解析了,剩下的才是你能看到的内容。
为什么会被误识别成DNS?
有两个关键因素:
- Scapy的自动解析逻辑:Scapy会根据UDP/TCP端口尝试匹配常见协议,即使你用的是5555端口(非标准DNS端口53),它也可能尝试解析DNS(尤其是当Payload开头的字节结构和DNS头有相似性时)。
- 客户端代码的冗余序列化:你的客户端代码里做了两次JSON处理:
这会导致最终的Payload开头是# 先手动拼接了一个类JSON字符串 payload = '{ "dcgdsfjfghtimec": ' + str(datetime.now().strftime('%M:%S.%f')) + ', "sequence": ' + str(sequenceNum)+'}' # 然后又用json.dumps把这个字符串再序列化一次 packet = .../Raw(load=json.dumps(payload))"(字节0x22),加上后续字符,恰好让Scapy误判为DNS头部格式,触发了自动解析。
解决办法
1. 修正客户端的Payload生成逻辑
先构造Python字典,再做一次JSON序列化即可,避免手动拼接和重复序列化:
import json from datetime import datetime from scapy.all import IP, UDP, Raw sequenceNum = 0 # 正确构造字典 payload_data = { "dcgdsfjfghtimec": datetime.now().strftime('%M:%S.%f'), "sequence": sequenceNum } # 一次序列化即可,并且转成字节(Scapy的Raw.load需要字节类型) payload_bytes = json.dumps(payload_data).encode('utf-8') # 构造数据包,确保UDP后直接跟Raw packet = IP(dst="127.0.0.1", src="10.0.0.1")/UDP(dport=5555)/Raw(load=payload_bytes)
这样生成的Payload是标准的JSON字节,不会出现多余的转义,也不容易被Scapy误识别。
2. 接收端绕过自动解析,直接获取原始负载
不管Scapy怎么解析,直接获取UDP层的原始字节数据:
from scapy.all import sniff, UDP def packet_callback(packet): if UDP in packet: # 获取UDP层的原始负载字节,跳过Scapy的自动协议解析 raw_payload = bytes(packet[UDP].payload) # 转成字符串(如果是JSON的话还可以反序列化) payload_str = raw_payload.decode('utf-8') print(payload_str) while True: sniff(filter="dst port 5555", prn=packet_callback, store=0)
如果Scapy已经把Payload解析成了DNS,你也可以通过packet[DNS].payload获取后面的Raw数据,但直接取UDP的原始负载更可靠。
3. 强制Scapy不自动解析后续协议(可选)
在构造数据包时,可以显式用Raw层封装业务数据,Scapy默认不会再解析Raw之后的内容,这样就能避免自动匹配DNS等协议的问题。
验证效果
修正后,客户端的Packet调试输出里的Raw load应该是标准的JSON字符串(没有外层多余的引号),接收端也能完整获取整个Payload,不会再丢失前8字节。
内容的提问来源于stack exchange,提问作者SudipM
相关产品推荐
相关产品推荐

