使用gopacket从原始字节构造数据包写入pcap文件报错如何解决
问题原因
通过gopacket.NewPacket手动生成的数据包对象,其元数据中的CaptureInfo字段不会自动填充,CaptureLength和Length默认值为0,和实际数据包长度不符,因此触发capture length 0 does not match data length 60报错。
另外你的序列化参数未配置,会导致生成的IP、UDP包头的长度、校验和为无效值,写入pcap后也无法正常解析。
修复方案
第一步:补全序列化配置
修改SerializeOptions并绑定网络层用于校验和计算:
// 初始化序列化参数 options = gopacket.SerializeOptions{ FixLengths: true, // 自动计算各层包头的长度字段 ComputeChecksums: true, // 自动计算各层的校验和字段 } rawBytes := []byte{10, 20, 30} buffer = gopacket.NewSerializeBuffer() // 给UDP层绑定IP层,用于计算UDP校验和 udpLayer.SetNetworkLayerForChecksum(ipLayer) gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, udpLayer, gopacket.Payload(rawBytes), ) outgoingPacket := buffer.Bytes()
第二步:调整写入逻辑
不需要额外将序列化后的字节解析为Packet对象,直接手动构造捕获信息写入即可,性能更高:
f, err := os.Create("temp.pcap") if err != nil { log.Fatal(err) } defer f.Close() w := pcapgo.NewWriter(f) // 写入pcap文件头 if err := w.WriteFileHeader(uint32(snapshot_len), layers.LinkTypeEthernet); err != nil { log.Fatal(err) } // 手动构造捕获元信息 captureInfo := gopacket.CaptureInfo{ Timestamp: time.Now(), // 可自定义包的时间戳 CaptureLength: len(outgoingPacket), Length: len(outgoingPacket), InterfaceIndex: 0, } // 写入数据包 if err := w.WritePacket(captureInfo, outgoingPacket); err != nil { log.Fatal(err) }
如果需要批量写入数据包,只需循环构造序列化后的包字节,重复调用w.WritePacket即可,不需要重复创建文件和Writer对象。
内容的提问来源于stack exchange,提问作者mmeda
相关产品推荐
相关产品推荐

