如果我有数据,我通过DecodingLayerParser
和一些数据可以有IP协议4 (IP-in-IP)数据包包括,我怎么让它捕获两个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
}
当从解析器调用DecodeLayers
时,我如何修改此内容才能做到这一点?它似乎只存储第二个IPv4头的信息在ipip4
。
为什么不工作
接口DecodingLayerContainer
被设计为索引DecodingLayer的LayerType(参见Decoder(LayerType) (decoodinglayer, bool))。由于ip4
和ipip4
具有相同的LayerType (layers.LayerTypeIPv4
),后者将在容器中覆盖前者。每次DecodingLayerParser
从容器中获得layers.LayerTypeIPv4
的解码器时,它都会获得ipip4
。所以ipip4
的状态会被一次又一次的改变。
ip4
和ipip4
不同的LayerType
。并使ip4
在IP包中为IP时选择ipip4
作为下一个解码器。下面是演示:
package main
import (
"fmt"
"io"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
// 0-999 are reserved for the gopacket library. Numbers 1000-1999 should be
// used for common application-specific types.
var LayerTypeIPv4Inner = gopacket.RegisterLayerType(1000, gopacket.LayerTypeMetadata{Name: "IP_in_IP", Decoder: nil})
// IPv4Outer is like layers.IPv4 but it recognizes IP in IP and will choose
// its next decoder accordingly.
type IPv4Outer struct {
layers.IPv4
}
// NextLayerType overrides (*layers.IPv4).NextLayerType to recognize IP in IP.
func (i *IPv4Outer) NextLayerType() gopacket.LayerType {
if i.Flags&layers.IPv4MoreFragments != 0 || i.FragOffset != 0 {
return gopacket.LayerTypeFragment
}
// This is an IP in IP packet.
// See https://datatracker.ietf.org/doc/html/rfc2003#section-3.1
if i.Protocol == 4 {
return LayerTypeIPv4Inner
}
return i.Protocol.LayerType()
}
// IPv4Inner is like layers.IPv4 except that its type is LayerTypeIPv4Inner.
// gopacket.DecodingLayerParser finds next decoder based on this type.
type IPv4Inner struct {
layers.IPv4
}
// CanDecode overrides (*layers.IPv4).CanDecode to choose a type other than
// layers.LayerTypeIPv4.
func (i *IPv4Inner) CanDecode() gopacket.LayerClass {
return LayerTypeIPv4Inner
}
func main() {
handle, err := pcap.OpenOffline("./IP_in_IP.cap")
if err != nil {
panic(err)
}
var (
eth layers.Ethernet
ip4 IPv4Outer
ipip4 IPv4Inner
tcp layers.TCP
icmpv4 layers.ICMPv4
payload gopacket.Payload
)
parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &ipip4, &tcp, &icmpv4, &payload)
decodedLayers := make([]gopacket.LayerType, 0, 10)
for {
data, _, err := handle.ZeroCopyReadPacketData()
if err == io.EOF {
fmt.Println("done")
return
}
if err != nil {
panic(err)
}
err = parser.DecodeLayers(data, &decodedLayers)
if err != nil {
panic(err)
}
for _, typ := range decodedLayers {
if typ == layers.LayerTypeIPv4 {
fmt.Printf("Ipv4: %s => %sn", ip4.SrcIP, ip4.DstIP)
} else if typ == LayerTypeIPv4Inner {
fmt.Printf("IP in IP: %s => %sn", ipip4.SrcIP, ipip4.DstIP)
}
}
fmt.Printf("%vnn", decodedLayers)
}
}
我已经测试了https://packetlife.net/media/captures/IP_in_IP.cap和test_ethernet。Pcap在gopacket。输出如下所示:
Ipv4: 10.0.0.1 => 10.0.0.2
IP in IP: 1.1.1.1 => 2.2.2.2
[Ethernet IPv4 IP_in_IP ICMPv4 Payload]
Ipv4: 10.0.0.2 => 10.0.0.1
IP in IP: 2.2.2.2 => 1.1.1.1
[Ethernet IPv4 IP_in_IP ICMPv4 Payload]
Ipv4: 10.1.1.2 => 10.1.1.1
[Ethernet IPv4 TCP]
Ipv4: 10.1.1.1 => 10.1.1.2
[Ethernet IPv4 TCP]
指出DecodingLayerParser
更快,但也更严格。虽然PacketSource
较慢,但它可以安全轻松地处理任何已知类型的数据包。(我相信你已经知道了)。- 这只是一个变通方法。我不确定这是否是最佳实践。
- 演示的目的是说明解决此类问题的想法。对于一个数据包有多个IPv4报头的其他情况不起作用。例如,它不能正确解析这个文件:https://packetlife.net/media/captures/GRE.cap。我们知道
DecodingLayerParser
是刚性的,我们必须自己处理其他角落的情况。