File: linux_sll2.go

package info (click to toggle)
golang-github-gopacket-gopacket 1.3.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,004 kB
  • sloc: sh: 301; python: 76; makefile: 10
file content (176 lines) | stat: -rw-r--r-- 5,624 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright 2022 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 (
	"encoding/binary"
	"errors"
	"fmt"
	"net"

	"github.com/gopacket/gopacket"
)

// The ARPHardwareType contains a Linux ARPHRD_ value for the link-layer device type
type ARPHardwareType uint16

const (
	ARPHardwareTypeEthernet      ARPHardwareType = 1
	ARPHardwareTypeFRAD          ARPHardwareType = 770
	ARPHardwareTypeLoopback      ARPHardwareType = 772
	ARPHardwareTypeIPGRE         ARPHardwareType = 778
	ARPHardwareTypeDot11Radiotap ARPHardwareType = 803
)

func (l ARPHardwareType) String() string {
	switch l {
	case ARPHardwareTypeEthernet:
		return "Ethernet"
	case ARPHardwareTypeFRAD:
		return "Frame Relay Access Device"
	case ARPHardwareTypeLoopback:
		return "Loopback device"
	case ARPHardwareTypeIPGRE:
		return "GRE over IP"
	case ARPHardwareTypeDot11Radiotap:
		return "IEEE 802.11 + radiotap header"
	}

	return fmt.Sprintf("Unknown(%d)", int(l))
}

// The LinuxSLL2PacketType can contain the same values as LinuxSLLPacketType accept it is a uint8 instread of a uint16
type LinuxSLL2PacketType uint8

const (
	LinuxSLL2PacketTypeHost      LinuxSLL2PacketType = 0 // To us
	LinuxSLL2PacketTypeBroadcast LinuxSLL2PacketType = 1 // To all
	LinuxSLL2PacketTypeMulticast LinuxSLL2PacketType = 2 // To group
	LinuxSLL2PacketTypeOtherhost LinuxSLL2PacketType = 3 // To someone else
	LinuxSLL2PacketTypeOutgoing  LinuxSLL2PacketType = 4 // Outgoing of any type
	// These ones are invisible by user level
	LinuxSLL2PacketTypeLoopback  LinuxSLL2PacketType = 5 // MC/BRD frame looped back
	LinuxSLL2PacketTypeFastroute LinuxSLL2PacketType = 6 // Fastrouted frame
)

func (l LinuxSLL2PacketType) String() string {
	switch l {
	case LinuxSLL2PacketTypeHost:
		return "host"
	case LinuxSLL2PacketTypeBroadcast:
		return "broadcast"
	case LinuxSLL2PacketTypeMulticast:
		return "multicast"
	case LinuxSLL2PacketTypeOtherhost:
		return "otherhost"
	case LinuxSLL2PacketTypeOutgoing:
		return "outgoing"
	case LinuxSLL2PacketTypeLoopback:
		return "loopback"
	case LinuxSLL2PacketTypeFastroute:
		return "fastroute"
	}
	return fmt.Sprintf("Unknown(%d)", int(l))
}

const (
	LinuxSLL2EthernetTypeDot3    EthernetType = 0x0001
	LinuxSLL2EthernetTypeUnknown EthernetType = 0x0003
	LinuxSLL2EthernetTypeLLC     EthernetType = 0x0004
	LinuxSLL2EthernetTypeCAN     EthernetType = 0x000C
)

// LinuxSLL2 is the second version of the Linux "cooked" capture encapsulation protocol. It is used to encapsulate
// packets within packet capture files, particularly by libpcap/tcpdump when making a packet capture with -i any
// https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html
type LinuxSLL2 struct {
	BaseLayer
	ProtocolType    EthernetType
	InterfaceIndex  uint32
	ARPHardwareType ARPHardwareType
	PacketType      LinuxSLL2PacketType
	AddrLength      uint8
	Addr            net.HardwareAddr
}

// LayerType returns LayerTypeLinuxSLL.
func (sll *LinuxSLL2) LayerType() gopacket.LayerType { return LayerTypeLinuxSLL2 }

func (sll *LinuxSLL2) CanDecode() gopacket.LayerClass {
	return LayerTypeLinuxSLL2
}

func (sll *LinuxSLL2) LinkFlow() gopacket.Flow {
	return gopacket.NewFlow(EndpointMAC, sll.Addr, nil)
}

func (sll *LinuxSLL2) NextLayerType() gopacket.LayerType {
	switch sll.ARPHardwareType {
	case ARPHardwareTypeFRAD:
		// If the ARPHRD_ type is ARPHRD_FRAD (770), the protocol type field is ignored,
		// and the payload following the LINKTYPE_LINUX_SLL header is a Frame Relay LAPF frame,
		// beginning with a ITU-T Recommendation Q.922 LAPF header starting with the address field,
		// and without an FCS at the end of the frame.
		return gopacket.LayerTypeZero // LAPF layer not yet implemented

	case ARPHardwareTypeDot11Radiotap:
		return LayerTypeRadioTap

	case ARPHardwareTypeIPGRE:
		// Docs: If the ARPHRD_ type is ARPHRD_IPGRE (778), the protocol type field contains a GRE protocol type.
		//
		// It doesn't clearly state if if the next header should be GRE or Ethernet in this case. Will assume ethernet
		// for now
		return LayerTypeEthernet

	default:
		switch sll.ProtocolType {
		case LinuxSLL2EthernetTypeDot3:
			// Docs: if the frame is a Novell 802.3 frame without an 802.2 LLC header
			return gopacket.LayerTypeZero // Novell 802.3 frame layer not yet implemented

		case LinuxSLL2EthernetTypeUnknown:
			// Docs: in some mysterious cases;
			return gopacket.LayerTypeZero // Mysterious cases not implemented

		case LinuxSLL2EthernetTypeLLC:
			return LayerTypeLLC

		case LinuxSLL2EthernetTypeCAN:
			// Docs: if the frame is a CAN bus frame that begins with a header of the form
			return gopacket.LayerTypeZero
		}

		return sll.ProtocolType.LayerType()
	}
}

func (sll *LinuxSLL2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 20 {
		return errors.New("Linux SLL2 packet too small")
	}
	sll.ProtocolType = EthernetType(binary.BigEndian.Uint16(data[0:2]))
	sll.InterfaceIndex = binary.BigEndian.Uint32(data[4:8])
	sll.ARPHardwareType = ARPHardwareType(binary.BigEndian.Uint16(data[8:10]))
	sll.PacketType = LinuxSLL2PacketType(data[10])
	sll.AddrLength = data[11]
	sll.Addr = data[12:20]
	sll.Addr = sll.Addr[:sll.AddrLength]
	sll.BaseLayer = BaseLayer{data[:20], data[20:]}

	return nil
}

func decodeLinuxSLL2(data []byte, p gopacket.PacketBuilder) error {
	sll := &LinuxSLL2{}
	if err := sll.DecodeFromBytes(data, p); err != nil {
		return err
	}
	p.AddLayer(sll)
	p.SetLinkLayer(sll)
	return p.NextDecoder(sll.NextLayerType())
}