This repository has been archived by the owner on Sep 14, 2023. It is now read-only.
forked from google/gopacket
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ethernet.go
123 lines (112 loc) · 3.67 KB
/
ethernet.go
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
// 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 (
"encoding/binary"
"errors"
"fmt"
"github.com/fako1024/gopacket"
"net"
)
// EthernetBroadcast is the broadcast MAC address used by Ethernet.
var EthernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
// Ethernet is the layer for Ethernet frame headers.
type Ethernet struct {
BaseLayer
SrcMAC, DstMAC net.HardwareAddr
EthernetType EthernetType
// Length is only set if a length field exists within this header. Ethernet
// headers follow two different standards, one that uses an EthernetType, the
// other which defines a length the follows with a LLC header (802.3). If the
// former is the case, we set EthernetType and Length stays 0. In the latter
// case, we set Length and EthernetType = EthernetTypeLLC.
Length uint16
}
// LayerType returns LayerTypeEthernet
func (e *Ethernet) LayerType() gopacket.LayerType { return LayerTypeEthernet }
func (e *Ethernet) LinkFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointMAC, e.SrcMAC, e.DstMAC)
}
func (eth *Ethernet) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 14 {
return errors.New("Ethernet packet too small")
}
eth.DstMAC = net.HardwareAddr(data[0:6])
eth.SrcMAC = net.HardwareAddr(data[6:12])
eth.EthernetType = EthernetType(binary.BigEndian.Uint16(data[12:14]))
eth.BaseLayer = BaseLayer{data[:14], data[14:]}
eth.Length = 0
if eth.EthernetType < 0x0600 {
eth.Length = uint16(eth.EthernetType)
eth.EthernetType = EthernetTypeLLC
if cmp := len(eth.Payload) - int(eth.Length); cmp < 0 {
df.SetTruncated()
} else if cmp > 0 {
// Strip off bytes at the end, since we have too many bytes
eth.Payload = eth.Payload[:len(eth.Payload)-cmp]
}
// fmt.Println(eth)
}
return nil
}
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (eth *Ethernet) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if len(eth.DstMAC) != 6 {
return fmt.Errorf("invalid dst MAC: %v", eth.DstMAC)
}
if len(eth.SrcMAC) != 6 {
return fmt.Errorf("invalid src MAC: %v", eth.SrcMAC)
}
payload := b.Bytes()
bytes, err := b.PrependBytes(14)
if err != nil {
return err
}
copy(bytes, eth.DstMAC)
copy(bytes[6:], eth.SrcMAC)
if eth.Length != 0 || eth.EthernetType == EthernetTypeLLC {
if opts.FixLengths {
eth.Length = uint16(len(payload))
}
if eth.EthernetType != EthernetTypeLLC {
return fmt.Errorf("ethernet type %v not compatible with length value %v", eth.EthernetType, eth.Length)
} else if eth.Length > 0x0600 {
return fmt.Errorf("invalid ethernet length %v", eth.Length)
}
binary.BigEndian.PutUint16(bytes[12:], eth.Length)
} else {
binary.BigEndian.PutUint16(bytes[12:], uint16(eth.EthernetType))
}
length := len(b.Bytes())
if length < 60 {
// Pad out to 60 bytes.
padding, err := b.AppendBytes(60 - length)
if err != nil {
return err
}
copy(padding, lotsOfZeros[:])
}
return nil
}
func (eth *Ethernet) CanDecode() gopacket.LayerClass {
return LayerTypeEthernet
}
func (eth *Ethernet) NextLayerType() gopacket.LayerType {
return eth.EthernetType.LayerType()
}
func decodeEthernet(data []byte, p gopacket.PacketBuilder) error {
eth := &Ethernet{}
err := eth.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(eth)
p.SetLinkLayer(eth)
return p.NextDecoder(eth.EthernetType)
}