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

使用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?

有两个关键因素:

  1. Scapy的自动解析逻辑:Scapy会根据UDP/TCP端口尝试匹配常见协议,即使你用的是5555端口(非标准DNS端口53),它也可能尝试解析DNS(尤其是当Payload开头的字节结构和DNS头有相似性时)。
  2. 客户端代码的冗余序列化:你的客户端代码里做了两次JSON处理:
    # 先手动拼接了一个类JSON字符串
    payload = '{ "dcgdsfjfghtimec": ' + str(datetime.now().strftime('%M:%S.%f')) + ', "sequence": ' + str(sequenceNum)+'}'
    # 然后又用json.dumps把这个字符串再序列化一次
    packet = .../Raw(load=json.dumps(payload))
    
    这会导致最终的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:53:40