-
Notifications
You must be signed in to change notification settings - Fork 4
/
trailer.go
87 lines (79 loc) · 2.65 KB
/
trailer.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
package main
import (
"encoding/binary"
"fmt"
"net"
"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
)
// EthernetBroadcast is the broadcast MAC address used by Ethernet.
// var EthernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
// EthernetWithTrailer is the layer for Ethernet frame headers.
type EthernetWithTrailer struct {
layers.BaseLayer
SrcMAC, DstMAC net.HardwareAddr
EthernetType layers.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
Trailer []byte
}
// LayerType returns LayerTypeEthernet
func (e *EthernetWithTrailer) LayerType() gopacket.LayerType { return layers.LayerTypeEthernet }
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (e *EthernetWithTrailer) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
if len(e.DstMAC) != 6 {
return fmt.Errorf("invalid dst MAC: %v", e.DstMAC)
}
if len(e.SrcMAC) != 6 {
return fmt.Errorf("invalid src MAC: %v", e.SrcMAC)
}
payload := b.Bytes()
bytes, err := b.PrependBytes(14)
if err != nil {
return err
}
copy(bytes, e.DstMAC)
copy(bytes[6:], e.SrcMAC)
if e.Length != 0 || e.EthernetType == layers.EthernetTypeLLC {
if opts.FixLengths {
e.Length = uint16(len(payload))
}
if e.EthernetType != layers.EthernetTypeLLC {
return fmt.Errorf("ethernet type %v not compatible with length value %v", e.EthernetType, e.Length)
} else if e.Length > 0x0600 {
return fmt.Errorf("invalid ethernet length %v", e.Length)
}
binary.BigEndian.PutUint16(bytes[12:], e.Length)
} else {
binary.BigEndian.PutUint16(bytes[12:], uint16(e.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[:])
}
//todo: find a way to put the trailer here
trailer, err := b.AppendBytes(len(e.Trailer))
if err != nil {
return err
}
copy(trailer, e.Trailer)
// todo: some of this gets gobbled up as framecheck sequence, putting a 4 byte 0 in the trailer to avoid that
checksum, err := b.AppendBytes(4)
if err != nil {
return err
}
copy(checksum, lotsOfZeros[:])
return nil
}
var lotsOfZeros [1024]byte