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
|
// 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.
//
package layers
import (
"encoding/binary"
"fmt"
"github.com/gopacket/gopacket"
)
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 {
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 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 = 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 {
data, err := b.PrependBytes(gtpMinimumSizeInBytes)
if err != nil {
return err
}
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.ExtensionHeaderFlag || g.SequenceNumberFlag || g.NPDUFlag {
data, err := b.AppendBytes(4)
if err != nil {
return err
}
binary.BigEndian.PutUint16(data[:2], g.SequenceNumber)
data[2] = g.NPDU
for _, eh := range g.GTPExtensionHeaders {
data[len(data)-1] = eh.Type
lContent := len(eh.Content)
// extensionLength is in 4-octet units
extensionLength := (lContent + 2) / 4
// Get two extra byte for the next extension header type and length
data, err = b.AppendBytes(lContent + 2)
if err != nil {
return err
}
data[0] = byte(extensionLength)
copy(data[1:lContent+1], eh.Content)
}
}
return nil
}
// CanDecode returns a set of layers that GTP objects can decode.
func (g *GTPv1U) CanDecode() gopacket.LayerClass {
return 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 LayerTypeIPv4
} else if version == 6 {
return LayerTypeIPv6
} else {
return 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())
}
|