123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- // 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/google/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 {
- fmt.Println(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 {
- 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())
- }
|