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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:20:34