If I have data I'm putting through a DecodingLayerParser and some of that data could have IP Protocol 4 (IP-in-IP) packets included, how would I get it to capture BOTH IPv4 headers in the packet? I can only seem to get it to capture one of them.
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
}
How may I modify this in order to do this when DecodeLayers is called from the parser? It only seems to store the second IPv4 header's information in ipip4.
Why it does not work
The interface
DecodingLayerContaineris designed to index DecodingLayer by its LayerType (See Decoder(LayerType) (DecodingLayer, bool)). Sinceip4andipip4have the same LayerType (layers.LayerTypeIPv4), the latter will overwrite the former in the container. And every timeDecodingLayerParsergets a decoder from the container forlayers.LayerTypeIPv4, it getsipip4. So the state ofipip4will be changed again and again.A workaround
A workaround is to give
ip4andipip4differentLayerType. And makeip4chooseipip4as its next decoder when the packet is an IP in IP packet. Here comes the demo:I have tested with https://packetlife.net/media/captures/IP_in_IP.cap and test_ethernet.pcap in gopacket. The output looks like this:
Notes
DecodingLayerParseris faster, but it is also more rigid. whilePacketSourceis slower, it will handle any known type of packet safely and easily. (I'm sure you already know this).DecodingLayerParseris rigid and we have to handle other corner cases ourself.