-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
202 lines (183 loc) · 5.71 KB
/
main.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
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Copyright 2023 Louis Royer. All rights reserved.
// Copyright 2017 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.
// SPDX-Licence-Identifier: BSD-3-Clause
package gopacket_gtp
import (
"encoding/binary"
"fmt"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
const gtpMinimumSizeInBytes int = 8
// GTPExtensionHeader is used to carry extra data and enable future extensions of the GTP without the need to use another version number.
type GTPExtensionHeader struct {
Type uint8
Content []byte
}
// GTPv1U protocol is used to exchange user data over GTP tunnels across the Sx interfaces.
// Defined in https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1595
type GTPv1U struct {
layers.BaseLayer
Version uint8
ProtocolType uint8
Reserved uint8
ExtensionHeaderFlag bool
SequenceNumberFlag bool
NPDUFlag bool
MessageType uint8
MessageLength uint16
TEID uint32
SequenceNumber uint16
NPDU uint8
GTPExtensionHeaders []GTPExtensionHeader
}
// LayerType returns LayerTypeGTPV1U
func (g *GTPv1U) LayerType() gopacket.LayerType { return layers.LayerTypeGTPv1U }
// DecodeFromBytes analyses a byte slice and attempts to decode it as a GTPv1U packet
func (g *GTPv1U) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
hLen := gtpMinimumSizeInBytes
dLen := len(data)
if dLen < hLen {
return fmt.Errorf("GTP packet too small: %d bytes", dLen)
}
g.Version = (data[0] >> 5) & 0x07
g.ProtocolType = (data[0] >> 4) & 0x01
g.Reserved = (data[0] >> 3) & 0x01
g.SequenceNumberFlag = ((data[0] >> 1) & 0x01) == 1
g.NPDUFlag = (data[0] & 0x01) == 1
g.ExtensionHeaderFlag = ((data[0] >> 2) & 0x01) == 1
g.MessageType = data[1]
g.MessageLength = binary.BigEndian.Uint16(data[2:4])
pLen := 8 + g.MessageLength
if uint16(dLen) < pLen {
return fmt.Errorf("GTP packet too small: %d bytes", dLen)
}
// Field used to multiplex different connections in the same GTP tunnel.
g.TEID = binary.BigEndian.Uint32(data[4:8])
cIndex := uint16(hLen)
if g.SequenceNumberFlag || g.NPDUFlag || g.ExtensionHeaderFlag {
hLen += 4
cIndex += 4
if dLen < hLen {
return fmt.Errorf("GTP packet too small: %d bytes", dLen)
}
if g.SequenceNumberFlag {
g.SequenceNumber = binary.BigEndian.Uint16(data[8:10])
}
if g.NPDUFlag {
g.NPDU = data[10]
}
if g.ExtensionHeaderFlag {
extensionFlag := true
for extensionFlag {
extensionType := uint8(data[cIndex-1])
extensionLength := uint(data[cIndex])
if extensionLength == 0 {
return fmt.Errorf("GTP packet with invalid extension header")
}
// extensionLength is in 4-octet units
lIndex := cIndex + (uint16(extensionLength) * 4)
if uint16(dLen) < lIndex {
return fmt.Errorf("GTP packet with small extension header: %d bytes", dLen)
}
content := data[cIndex+1 : lIndex-1]
eh := GTPExtensionHeader{Type: extensionType, Content: content}
g.GTPExtensionHeaders = append(g.GTPExtensionHeaders, eh)
cIndex = lIndex
// Check if coming bytes are from an extension header
extensionFlag = data[cIndex-1] != 0
}
}
}
g.BaseLayer = layers.BaseLayer{Contents: data[:cIndex], Payload: data[cIndex:]}
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 (g *GTPv1U) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
extHeadersLen := 0
if len(g.GTPExtensionHeaders) > 0 {
g.ExtensionHeaderFlag = true
}
if g.ExtensionHeaderFlag || g.SequenceNumberFlag || g.NPDUFlag {
extHeadersLen += 4
for _, eh := range g.GTPExtensionHeaders {
extHeadersLen += len(eh.Content) + 2 // 2 bytes for Type + Length
}
}
data, err := b.PrependBytes(gtpMinimumSizeInBytes + extHeadersLen)
if err != nil {
return err
}
data[0] = 0
data[0] |= (g.Version << 5)
data[0] |= (1 << 4)
if len(g.GTPExtensionHeaders) > 0 {
data[0] |= 0x04
g.ExtensionHeaderFlag = true
}
if g.SequenceNumberFlag {
data[0] |= 0x02
}
if g.NPDUFlag {
data[0] |= 0x01
}
data[1] = g.MessageType
binary.BigEndian.PutUint16(data[2:4], g.MessageLength)
binary.BigEndian.PutUint32(data[4:8], g.TEID)
if g.SequenceNumberFlag {
binary.BigEndian.PutUint16(data[8:10], g.SequenceNumber)
}
if g.NPDUFlag {
data[10] = g.NPDU
}
if g.ExtensionHeaderFlag {
index := 11
for _, eh := range g.GTPExtensionHeaders {
data[index] = eh.Type
index++
lContent := len(eh.Content)
// extensionLength is in 4-octet units
extensionLength := (lContent + 2) / 4
data[index] = byte(extensionLength)
index++
copy(data[index:index+lContent], eh.Content)
index += lContent
}
// last type is 0x00 (No nore extension headers)
data[index] = 0x00
}
return nil
}
// CanDecode returns a set of layers that GTP objects can decode.
func (g *GTPv1U) CanDecode() gopacket.LayerClass {
return layers.LayerTypeGTPv1U
}
// NextLayerType specifies the next layer that GoPacket should attempt to
func (g *GTPv1U) NextLayerType() gopacket.LayerType {
if len(g.LayerPayload()) == 0 {
return gopacket.LayerTypeZero
}
version := uint8(g.LayerPayload()[0]) >> 4
if version == 4 {
return layers.LayerTypeIPv4
} else if version == 6 {
return layers.LayerTypeIPv6
} else {
return layers.LayerTypePPP
}
}
func decodeGTPv1u(data []byte, p gopacket.PacketBuilder) error {
gtp := >Pv1U{}
err := gtp.DecodeFromBytes(data, p)
if err != nil {
return err
}
p.AddLayer(gtp)
return p.NextDecoder(gtp.NextLayerType())
}