forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ctp.go
108 lines (94 loc) · 3.4 KB
/
ctp.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
// Copyright 2012 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"
"fmt"
"github.com/tsg/gopacket"
)
// EthernetCTPFunction is the function code used by the EthernetCTP protocol to identify each
// EthernetCTP layer.
type EthernetCTPFunction uint16
const (
EthernetCTPFunctionReply EthernetCTPFunction = 1
EthernetCTPFunctionForwardData EthernetCTPFunction = 2
)
// EthernetCTP implements the EthernetCTP protocol, see http://www.mit.edu/people/jhawk/ctp.html.
// We split EthernetCTP up into the top-level EthernetCTP layer, followed by zero or more
// EthernetCTPForwardData layers, followed by a final EthernetCTPReply layer.
type EthernetCTP struct {
BaseLayer
SkipCount uint16
}
// LayerType returns gopacket.LayerTypeEthernetCTP.
func (c *EthernetCTP) LayerType() gopacket.LayerType {
return LayerTypeEthernetCTP
}
// EthernetCTPForwardData is the ForwardData layer inside EthernetCTP. See EthernetCTP's docs for more
// details.
type EthernetCTPForwardData struct {
BaseLayer
Function EthernetCTPFunction
ForwardAddress []byte
}
// LayerType returns gopacket.LayerTypeEthernetCTPForwardData.
func (c *EthernetCTPForwardData) LayerType() gopacket.LayerType {
return LayerTypeEthernetCTPForwardData
}
// ForwardEndpoint returns the EthernetCTPForwardData ForwardAddress as an endpoint.
func (c *EthernetCTPForwardData) ForwardEndpoint() gopacket.Endpoint {
return gopacket.NewEndpoint(EndpointMAC, c.ForwardAddress)
}
// EthernetCTPReply is the Reply layer inside EthernetCTP. See EthernetCTP's docs for more details.
type EthernetCTPReply struct {
BaseLayer
Function EthernetCTPFunction
ReceiptNumber uint16
Data []byte
}
// LayerType returns gopacket.LayerTypeEthernetCTPReply.
func (c *EthernetCTPReply) LayerType() gopacket.LayerType {
return LayerTypeEthernetCTPReply
}
// Payload returns the EthernetCTP reply's Data bytes.
func (c *EthernetCTPReply) Payload() []byte { return c.Data }
func decodeEthernetCTP(data []byte, p gopacket.PacketBuilder) error {
c := &EthernetCTP{
SkipCount: binary.LittleEndian.Uint16(data[:2]),
BaseLayer: BaseLayer{data[:2], data[2:]},
}
if c.SkipCount%2 != 0 {
return fmt.Errorf("EthernetCTP skip count is odd: %d", c.SkipCount)
}
p.AddLayer(c)
return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType))
}
// decodeEthernetCTPFromFunctionType reads in the first 2 bytes to determine the EthernetCTP
// layer type to decode next, then decodes based on that.
func decodeEthernetCTPFromFunctionType(data []byte, p gopacket.PacketBuilder) error {
function := EthernetCTPFunction(binary.LittleEndian.Uint16(data[:2]))
switch function {
case EthernetCTPFunctionReply:
reply := &EthernetCTPReply{
Function: function,
ReceiptNumber: binary.LittleEndian.Uint16(data[2:4]),
Data: data[4:],
BaseLayer: BaseLayer{data, nil},
}
p.AddLayer(reply)
p.SetApplicationLayer(reply)
return nil
case EthernetCTPFunctionForwardData:
forward := &EthernetCTPForwardData{
Function: function,
ForwardAddress: data[2:8],
BaseLayer: BaseLayer{data[:8], data[8:]},
}
p.AddLayer(forward)
return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType))
}
return fmt.Errorf("Unknown EthernetCTP function type %v", function)
}