From 188215eeb18343ce1d5b1c01d1a9a30e2c506bc2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 2 Jun 2017 11:45:52 +0800 Subject: [PATCH 1/2] Modify type for the raw link layer According to http://www.tcpdump.org/linktypes.html the value is 101 but in reality it is 12 (and on OpenBSD 14). While browsing through the list on OpenBSD the DLT_LOOP is 12 (and not 108). In the long it might make sense to back these values with cgo (and pcap/bpf.h). --- layers/enums.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layers/enums.go b/layers/enums.go index 963f4d8..d251233 100644 --- a/layers/enums.go +++ b/layers/enums.go @@ -88,7 +88,7 @@ const ( type LinkType uint8 const ( - // According to pcap-linktype(7). + // According to pcap-linktype(7) with fixes from pcap/bpf.h LinkTypeNull LinkType = 0 LinkTypeEthernet LinkType = 1 LinkTypeTokenRing LinkType = 6 @@ -97,7 +97,7 @@ const ( LinkTypePPP LinkType = 9 LinkTypeFDDI LinkType = 10 LinkTypeATM_RFC1483 LinkType = 100 - LinkTypeRaw LinkType = 101 + LinkTypeRaw LinkType = 12 LinkTypePPP_HDLC LinkType = 50 LinkTypePPPEthernet LinkType = 51 LinkTypeC_HDLC LinkType = 104 From 9a9a563f8429cde646a34c3890ea7c34820d4c86 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 2 Jun 2017 16:01:21 +0800 Subject: [PATCH 2/2] raw: Create LayerTypeRaw layer type for the raw link layer Create a Raw struct and make it implement the LayerType interface. Add a testcase to decode a raw IPv4/ICMPv4 frames. Remove decodeIPv4or6 that was only used for the raw ip link type. The DecodeFromBytes method is not tested/used yet and packetbeat might be the first user. --- layers/enums.go | 14 +-------- layers/layertypes.go | 1 + layers/raw.go | 68 ++++++++++++++++++++++++++++++++++++++++++++ layers/raw_test.go | 52 +++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 layers/raw.go create mode 100644 layers/raw_test.go diff --git a/layers/enums.go b/layers/enums.go index d251233..5a21ce2 100644 --- a/layers/enums.go +++ b/layers/enums.go @@ -358,18 +358,6 @@ func (a Dot11Type) LayerType() gopacket.LayerType { return Dot11TypeMetadata[a].LayerType } -// Decode a raw v4 or v6 IP packet. -func decodeIPv4or6(data []byte, p gopacket.PacketBuilder) error { - version := data[0] >> 4 - switch version { - case 4: - return decodeIPv4(data, p) - case 6: - return decodeIPv6(data, p) - } - return fmt.Errorf("Invalid IP packet version %v", version) -} - func init() { // Here we link up all enumerations with their respective names and decoders. for i := 0; i < 65536; i++ { @@ -479,7 +467,7 @@ func init() { LinkTypeMetadata[LinkTypeFDDI] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeFDDI), Name: "FDDI"} LinkTypeMetadata[LinkTypeNull] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLoopback), Name: "Null"} LinkTypeMetadata[LinkTypeLoop] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLoopback), Name: "Loop"} - LinkTypeMetadata[LinkTypeRaw] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4or6), Name: "Raw"} + LinkTypeMetadata[LinkTypeRaw] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeRawIP), Name: "Raw"} LinkTypeMetadata[LinkTypePFLog] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePFLog), Name: "PFLog"} LinkTypeMetadata[LinkTypeIEEE80211Radio] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeRadioTap), Name: "RadioTap"} LinkTypeMetadata[LinkTypeLinuxUSB] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSB), Name: "USB"} diff --git a/layers/layertypes.go b/layers/layertypes.go index 61e14a1..c787621 100644 --- a/layers/layertypes.go +++ b/layers/layertypes.go @@ -115,6 +115,7 @@ var ( LayerTypeUSBInterrupt = gopacket.RegisterLayerType(111, gopacket.LayerTypeMetadata{"USBInterrupt", gopacket.DecodeFunc(decodeUSBInterrupt)}) LayerTypeUSBBulk = gopacket.RegisterLayerType(112, gopacket.LayerTypeMetadata{"USBBulk", gopacket.DecodeFunc(decodeUSBBulk)}) LayerTypeLinuxSLL = gopacket.RegisterLayerType(113, gopacket.LayerTypeMetadata{"Linux SLL", gopacket.DecodeFunc(decodeLinuxSLL)}) + LayerTypeRaw = gopacket.RegisterLayerType(114, gopacket.LayerTypeMetadata{"RAW", gopacket.DecodeFunc(decodeRawIP)}) ) var ( diff --git a/layers/raw.go b/layers/raw.go new file mode 100644 index 0000000..fd7441d --- /dev/null +++ b/layers/raw.go @@ -0,0 +1,68 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// Copyright 2009-2011 Andreas Krennmair. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package layers + +import ( + "fmt" + "github.com/tsg/gopacket" +) + +// RawIP (DLT_RAW) contains no header and we start with the IP header +type Raw struct { + BaseLayer + Family ProtocolFamily +} + +func (r *Raw) LayerType() gopacket.LayerType { return LayerTypeRaw } + +func (r *Raw) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 1 { + return fmt.Errorf("Raw packet too small") + } + + family, err := versionToFamily(data[0] >> 4) + if err != nil { + return err + } + r.Family = family + r.BaseLayer = BaseLayer{make([]byte, 0), data} + return nil +} + +func (r *Raw) CanDecode() gopacket.LayerClass { + return LayerTypeRaw +} + +func (r *Raw) NextLayerType() gopacket.LayerType { + return r.Family.LayerType() +} + +func versionToFamily(version uint8) (ProtocolFamily, error) { + switch version { + case 4: + return ProtocolFamilyIPv4, nil + case 6: + return ProtocolFamilyIPv6Linux, nil + default: + return 0, fmt.Errorf("Unknown protocol version %d", version) + } +} + +// Decode a raw v4 or v6 IP packet. +func decodeRawIP(data []byte, p gopacket.PacketBuilder) error { + family, err := versionToFamily(data[0] >> 4) + if err != nil { + return err + } + r := &Raw{ + BaseLayer: BaseLayer{make([]byte, 0), data}, + Family: family, + } + p.AddLayer(r) + return p.NextDecoder(r.Family) +} diff --git a/layers/raw_test.go b/layers/raw_test.go new file mode 100644 index 0000000..3c72dda --- /dev/null +++ b/layers/raw_test.go @@ -0,0 +1,52 @@ +// Copyright 2017 Holger Hans Peter Freyther, Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package layers + +import ( + "testing" + + "github.com/tsg/gopacket" +) + +// testPacketPacket0 is the packet: +// 12:13:21.217957 IP 10.8.254.8 > 8.8.8.8: ICMP echo request, id 20348, seq 1, length 64 +// 0x0000: 4500 0054 1530 4000 4001 0d59 0a08 fe08 E..T.0@.@..Y.... +// 0x0010: 0808 0808 0800 d81d 4f7c 0001 e1e5 3059 ........O|....0Y +// 0x0020: 0000 0000 fc52 0300 0000 0000 1011 1213 .....R.......... +// 0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"# +// 0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123 +// 0x0050: 3435 3637 4567 +var testPacketPacket0 = []byte{ + 0x45, 0x00, 0x00, 0x54, 0x15, 0x30, 0x40, 0x00, 0x40, 0x01, 0x0d, 0x59, 0x0a, 0x08, 0xfe, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0xd8, 0x1d, 0x4f, 0x7c, 0x00, 0x01, 0xe1, 0xe5, 0x30, 0x59, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x52, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, +} + +func TestPacketRawIPICMPv4(t *testing.T) { + p := gopacket.NewPacket(testPacketPacket0, LinkTypeRaw, gopacket.Default) + if p.ErrorLayer() != nil { + t.Error("Failed to decode packet:", p.ErrorLayer().Error()) + } + checkLayers(p, []gopacket.LayerType{LayerTypeRaw, LayerTypeIPv4, LayerTypeICMPv4, gopacket.LayerTypePayload}, t) + // If ICMPv4 is found we most likely parse at the right offset. Skip detailed tests. Just verify + // that the Contents of the BaseLayer is an empty array + if got, ok := p.Layer(LayerTypeRaw).(*Raw); ok { + if len(got.BaseLayer.Contents) != 0 { + t.Error("RAW layer not empty", len(got.BaseLayer.Contents)) + } + } else { + t.Error("RAW packet processing failed to get right layer") + } +} +func BenchmarkDecodePacketRawIPICMPv4(b *testing.B) { + for i := 0; i < b.N; i++ { + gopacket.NewPacket(testPacketPacket0, LinkTypeRaw, gopacket.NoCopy) + } +}