Golang ICMP数据包转发时SerializeTo丢失Payload问题求助
解决gopacket ICMPv4序列化丢失负载的问题
我刚好碰到过类似的gopacket ICMP序列化问题,你的情况是因为ICMPv4结构体的SerializeTo方法只负责序列化ICMP的8字节头部(类型、代码、校验和、ID、序列号),并不会自动把BaseLayer.Payload里的负载数据写入到缓冲区里。这就是为什么你抓包发现负载丢了。
下面给你两种可行的解决办法:
方法1:添加Payload层到序列化列表
把ICMP的负载封装成gopacket.Payload类型的层,在调用SerializeLayers时把它作为最后一个参数传入。这样序列化流程会先处理完以太网、IP、ICMP头部,再自动写入负载数据:
opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true} buff := gopacket.NewSerializeBuffer() // 将ICMP负载转为Payload层 payloadLayer := gopacket.Payload(icmpLayer.Payload) // 序列化时包含所有层(包括Payload层) err := gopacket.SerializeLayers(buff, opts, ethLayer, ipLayer, icmpLayer, payloadLayer) if err != nil { // 这里记得处理错误,比如log.Fatal(err) }
方法2:手动写入负载到缓冲区
如果不想多添加一个层,也可以在完成头部序列化后,直接把ICMP负载写入到序列化缓冲区中:
opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true} buff := gopacket.NewSerializeBuffer() // 先序列化以太网、IP、ICMP头部 err := gopacket.SerializeLayers(buff, opts, ethLayer, ipLayer, icmpLayer) if err != nil { // 处理错误 } // 手动将ICMP负载写入缓冲区 _, err = buff.Write(icmpLayer.Payload) if err != nil { // 处理错误 }
额外注意点
- 你设置了
FixLengths: true,gopacket会自动修正IP层的总长度字段,所以不用手动计算IP包的总长度(IP头部+ICMP头部+负载)。 ComputeChecksums: true会自动计算ICMP的校验和,而且这个校验和是基于ICMP头部+负载的完整数据计算的,不用担心校验和不匹配的问题。
你可以在序列化后打印buff.Bytes()的长度,对比之前的长度,应该会增加负载的字节数,再通过抓包工具验证WAN侧的数据包是否包含了完整的ICMP负载。
内容的提问来源于stack exchange,提问作者toothflower
相关产品推荐
相关产品推荐

