如何让gopacket的DecodingLayerParser捕获IP-in-IP数据包的双IPv4头?
解决gopacket中DecodingLayerParser无法同时捕获IP-in-IP两个IPv4头的问题
问题描述
使用gopacket的DecodingLayerParser处理数据包时,遇到IP协议号为4的IP-in-IP数据包,当前代码仅能将第二个IPv4头的信息存储到ipip4字段,第一个IPv4头的信息无法被正确捕获保留。现有Decoder结构体已定义ip4和ipip4两个layers.IPv4字段,需修改代码实现同时捕获两个IPv4头。
当前代码实现:
type Decoder struct { eth layers.Ethernet ip4 layers.IPv4 ipip4 layers.IPv4 ip6 layers.IPv6 icmp4 layers.ICMPv4 icmp6 layers.ICMPv6 tcp layers.TCP udp layers.UDP //sip layers.SIP //dns layers.DNS //ntp layers.NTP pay gopacket.Payload parser *gopacket.DecodingLayerParser types []gopacket.LayerType unknowns map[string]uint } // NewDecoder allocates and initialises a new Decoder. func NewDecoder() *Decoder { d := new(Decoder) d.parser = gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &d.eth, &d.ip4, &d.ipip4, &d.ip6, &d.icmp4, &d.icmp6, &d.tcp, &d.udp, &d.pay) //&d.sip, &d.dns, &d.ntp, &d.pay) d.types = make([]gopacket.LayerType, 10, 10) d.parser.IgnoreUnsupported = true d.unknowns = make(map[string]uint) return d }
解决方案
问题根源
默认的DecodingLayerParser按固定顺序匹配层类型,解析完第一个IPv4头后,会根据其协议号自动选择下一层解析器,但不会主动触发第二个IPv4头的解析逻辑,导致第一个IPv4头的信息无法留存。
修改方案
为第一个IPv4层(ip4)添加自定义协议映射,当检测到协议号为4(IP-in-IP)时,指定后续解析使用ipip4层,同时保留原有协议的解析逻辑。
修改后的完整代码
type Decoder struct { eth layers.Ethernet ip4 layers.IPv4 ipip4 layers.IPv4 ip6 layers.IPv6 icmp4 layers.ICMPv4 icmp6 layers.ICMPv6 tcp layers.TCP udp layers.UDP //sip layers.SIP //dns layers.DNS //ntp layers.NTP pay gopacket.Payload parser *gopacket.DecodingLayerParser types []gopacket.LayerType unknowns map[string]uint } // NewDecoder allocates and initialises a new Decoder. func NewDecoder() *Decoder { d := new(Decoder) d.parser = gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &d.eth, &d.ip4, &d.ipip4, &d.ip6, &d.icmp4, &d.icmp6, &d.tcp, &d.udp, &d.pay) // 自定义IP层的协议映射:当协议号为4(IP-in-IP)时,解析到ipip4层 d.parser.DecodeMetadata[layers.LayerTypeIPv4] = &gopacket.DecodeMetadata{ NextLayerType: func(layer gopacket.Layer) gopacket.LayerType { ip, ok := layer.(*layers.IPv4) if !ok { return gopacket.LayerTypePayload } // 协议号4对应IP-in-IP,指定下一层为第二个IPv4头 if ip.Protocol == layers.IPProtocolIPv4 { return layers.LayerTypeIPv4 } // 其他协议按默认逻辑处理 return ip.NextLayerType() }, } d.types = make([]gopacket.LayerType, 10, 10) d.parser.IgnoreUnsupported = true d.unknowns = make(map[string]uint) return d }
关键修改说明
- 通过
d.parser.DecodeMetadata[layers.LayerTypeIPv4]为IPv4层添加自定义NextLayerType函数。 - 当检测到当前IPv4头的协议号为
layers.IPProtocolIPv4(即4)时,返回layers.LayerTypeIPv4,告诉解析器下一层继续解析IPv4头,此时会使用ipip4字段存储第二个IPv4头。 - 其他协议类型仍按默认的
ip.NextLayerType()逻辑处理,保证原有功能不受影响。
使用验证
调用DecodeLayers后,d.ip4会存储外层IPv4头信息,d.ipip4会存储内层IPv4头信息,实现同时捕获两个IPv4头的需求。
内容的提问来源于stack exchange,提问作者markzz
相关产品推荐
相关产品推荐

