blob: 511176e560fd107cbc3be90a94589f862da54979 [file] [log] [blame]
// 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"
"errors"
"fmt"
"hash/crc32"
"github.com/google/gopacket"
)
// SCTP contains information on the top level of an SCTP packet.
type SCTP struct {
BaseLayer
SrcPort, DstPort SCTPPort
VerificationTag uint32
Checksum uint32
sPort, dPort []byte
}
// LayerType returns gopacket.LayerTypeSCTP
func (s *SCTP) LayerType() gopacket.LayerType { return LayerTypeSCTP }
func decodeSCTP(data []byte, p gopacket.PacketBuilder) error {
sctp := &SCTP{}
err := sctp.DecodeFromBytes(data, p)
p.AddLayer(sctp)
p.SetTransportLayer(sctp)
if err != nil {
return err
}
return p.NextDecoder(sctpChunkTypePrefixDecoder)
}
var sctpChunkTypePrefixDecoder = gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)
// TransportFlow returns a flow based on the source and destination SCTP port.
func (s *SCTP) TransportFlow() gopacket.Flow {
return gopacket.NewFlow(EndpointSCTPPort, s.sPort, s.dPort)
}
func decodeWithSCTPChunkTypePrefix(data []byte, p gopacket.PacketBuilder) error {
chunkType := SCTPChunkType(data[0])
return chunkType.Decode(data, p)
}
// SerializeTo is for gopacket.SerializableLayer.
func (s SCTP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(12)
if err != nil {
return err
}
binary.BigEndian.PutUint16(bytes[0:2], uint16(s.SrcPort))
binary.BigEndian.PutUint16(bytes[2:4], uint16(s.DstPort))
binary.BigEndian.PutUint32(bytes[4:8], s.VerificationTag)
if opts.ComputeChecksums {
// Note: MakeTable(Castagnoli) actually only creates the table once, then
// passes back a singleton on every other call, so this shouldn't cause
// excessive memory allocation.
binary.LittleEndian.PutUint32(bytes[8:12], crc32.Checksum(b.Bytes(), crc32.MakeTable(crc32.Castagnoli)))
}
return nil
}
func (sctp *SCTP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
if len(data) < 12 {
return errors.New("Invalid SCTP common header length")
}
sctp.SrcPort = SCTPPort(binary.BigEndian.Uint16(data[:2]))
sctp.sPort = data[:2]
sctp.DstPort = SCTPPort(binary.BigEndian.Uint16(data[2:4]))
sctp.dPort = data[2:4]
sctp.VerificationTag = binary.BigEndian.Uint32(data[4:8])
sctp.Checksum = binary.BigEndian.Uint32(data[8:12])
sctp.BaseLayer = BaseLayer{data[:12], data[12:]}
return nil
}
func (t *SCTP) CanDecode() gopacket.LayerClass {
return LayerTypeSCTP
}
func (t *SCTP) NextLayerType() gopacket.LayerType {
return gopacket.LayerTypePayload
}
// SCTPChunk contains the common fields in all SCTP chunks.
type SCTPChunk struct {
BaseLayer
Type SCTPChunkType
Flags uint8
Length uint16
// ActualLength is the total length of an SCTP chunk, including padding.
// SCTP chunks start and end on 4-byte boundaries. So if a chunk has a length
// of 18, it means that it has data up to and including byte 18, then padding
// up to the next 4-byte boundary, 20. In this case, Length would be 18, and
// ActualLength would be 20.
ActualLength int
}
func roundUpToNearest4(i int) int {
if i%4 == 0 {
return i
}
return i + 4 - (i % 4)
}
func decodeSCTPChunk(data []byte) (SCTPChunk, error) {
length := binary.BigEndian.Uint16(data[2:4])
if length < 4 {
return SCTPChunk{}, errors.New("invalid SCTP chunk length")
}
actual := roundUpToNearest4(int(length))
ct := SCTPChunkType(data[0])
// For SCTP Data, use a separate layer for the payload
delta := 0
if ct == SCTPChunkTypeData {
delta = int(actual) - int(length)
actual = 16
}
return SCTPChunk{
Type: ct,
Flags: data[1],
Length: length,
ActualLength: actual,
BaseLayer: BaseLayer{data[:actual], data[actual : len(data)-delta]},
}, nil
}
// SCTPParameter is a TLV parameter inside a SCTPChunk.
type SCTPParameter struct {
Type uint16
Length uint16
ActualLength int
Value []byte
}
func decodeSCTPParameter(data []byte) SCTPParameter {
length := binary.BigEndian.Uint16(data[2:4])
return SCTPParameter{
Type: binary.BigEndian.Uint16(data[0:2]),
Length: length,
Value: data[4:length],
ActualLength: roundUpToNearest4(int(length)),
}
}
func (p SCTPParameter) Bytes() []byte {
length := 4 + len(p.Value)
data := make([]byte, roundUpToNearest4(length))
binary.BigEndian.PutUint16(data[0:2], p.Type)
binary.BigEndian.PutUint16(data[2:4], uint16(length))
copy(data[4:], p.Value)
return data
}
// SCTPUnknownChunkType is the layer type returned when we don't recognize the
// chunk type. Since there's a length in a known location, we can skip over
// it even if we don't know what it is, and continue parsing the rest of the
// chunks. This chunk is stored as an ErrorLayer in the packet.
type SCTPUnknownChunkType struct {
SCTPChunk
bytes []byte
}
func decodeSCTPChunkTypeUnknown(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPUnknownChunkType{SCTPChunk: chunk}
sc.bytes = data[:sc.ActualLength]
p.AddLayer(sc)
p.SetErrorLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (s SCTPUnknownChunkType) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(s.ActualLength)
if err != nil {
return err
}
copy(bytes, s.bytes)
return nil
}
// LayerType returns gopacket.LayerTypeSCTPUnknownChunkType.
func (s *SCTPUnknownChunkType) LayerType() gopacket.LayerType { return LayerTypeSCTPUnknownChunkType }
// Payload returns all bytes in this header, including the decoded Type, Length,
// and Flags.
func (s *SCTPUnknownChunkType) Payload() []byte { return s.bytes }
// Error implements ErrorLayer.
func (s *SCTPUnknownChunkType) Error() error {
return fmt.Errorf("No decode method available for SCTP chunk type %s", s.Type)
}
// SCTPData is the SCTP Data chunk layer.
type SCTPData struct {
SCTPChunk
Unordered, BeginFragment, EndFragment bool
TSN uint32
StreamId uint16
StreamSequence uint16
PayloadProtocol SCTPPayloadProtocol
}
// LayerType returns gopacket.LayerTypeSCTPData.
func (s *SCTPData) LayerType() gopacket.LayerType { return LayerTypeSCTPData }
// SCTPPayloadProtocol represents a payload protocol
type SCTPPayloadProtocol uint32
// SCTPPayloadProtocol constonts from http://www.iana.org/assignments/sctp-parameters/sctp-parameters.xhtml
const (
SCTPProtocolReserved SCTPPayloadProtocol = 0
SCTPPayloadUIA = 1
SCTPPayloadM2UA = 2
SCTPPayloadM3UA = 3
SCTPPayloadSUA = 4
SCTPPayloadM2PA = 5
SCTPPayloadV5UA = 6
SCTPPayloadH248 = 7
SCTPPayloadBICC = 8
SCTPPayloadTALI = 9
SCTPPayloadDUA = 10
SCTPPayloadASAP = 11
SCTPPayloadENRP = 12
SCTPPayloadH323 = 13
SCTPPayloadQIPC = 14
SCTPPayloadSIMCO = 15
SCTPPayloadDDPSegment = 16
SCTPPayloadDDPStream = 17
SCTPPayloadS1AP = 18
)
func (p SCTPPayloadProtocol) String() string {
switch p {
case SCTPProtocolReserved:
return "Reserved"
case SCTPPayloadUIA:
return "UIA"
case SCTPPayloadM2UA:
return "M2UA"
case SCTPPayloadM3UA:
return "M3UA"
case SCTPPayloadSUA:
return "SUA"
case SCTPPayloadM2PA:
return "M2PA"
case SCTPPayloadV5UA:
return "V5UA"
case SCTPPayloadH248:
return "H.248"
case SCTPPayloadBICC:
return "BICC"
case SCTPPayloadTALI:
return "TALI"
case SCTPPayloadDUA:
return "DUA"
case SCTPPayloadASAP:
return "ASAP"
case SCTPPayloadENRP:
return "ENRP"
case SCTPPayloadH323:
return "H.323"
case SCTPPayloadQIPC:
return "QIPC"
case SCTPPayloadSIMCO:
return "SIMCO"
case SCTPPayloadDDPSegment:
return "DDPSegment"
case SCTPPayloadDDPStream:
return "DDPStream"
case SCTPPayloadS1AP:
return "S1AP"
}
return fmt.Sprintf("Unknown(%d)", p)
}
func decodeSCTPData(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPData{
SCTPChunk: chunk,
Unordered: data[1]&0x4 != 0,
BeginFragment: data[1]&0x2 != 0,
EndFragment: data[1]&0x1 != 0,
TSN: binary.BigEndian.Uint32(data[4:8]),
StreamId: binary.BigEndian.Uint16(data[8:10]),
StreamSequence: binary.BigEndian.Uint16(data[10:12]),
PayloadProtocol: SCTPPayloadProtocol(binary.BigEndian.Uint32(data[12:16])),
}
// Length is the length in bytes of the data, INCLUDING the 16-byte header.
p.AddLayer(sc)
return p.NextDecoder(gopacket.LayerTypePayload)
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPData) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
payload := b.Bytes()
// Pad the payload to a 32 bit boundary
if rem := len(payload) % 4; rem != 0 {
b.AppendBytes(4 - rem)
}
length := 16
bytes, err := b.PrependBytes(length)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
flags := uint8(0)
if sc.Unordered {
flags |= 0x4
}
if sc.BeginFragment {
flags |= 0x2
}
if sc.EndFragment {
flags |= 0x1
}
bytes[1] = flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length+len(payload)))
binary.BigEndian.PutUint32(bytes[4:8], sc.TSN)
binary.BigEndian.PutUint16(bytes[8:10], sc.StreamId)
binary.BigEndian.PutUint16(bytes[10:12], sc.StreamSequence)
binary.BigEndian.PutUint32(bytes[12:16], uint32(sc.PayloadProtocol))
return nil
}
// SCTPInitParameter is a parameter for an SCTP Init or InitAck packet.
type SCTPInitParameter SCTPParameter
// SCTPInit is used as the return value for both SCTPInit and SCTPInitAck
// messages.
type SCTPInit struct {
SCTPChunk
InitiateTag uint32
AdvertisedReceiverWindowCredit uint32
OutboundStreams, InboundStreams uint16
InitialTSN uint32
Parameters []SCTPInitParameter
}
// LayerType returns either gopacket.LayerTypeSCTPInit or gopacket.LayerTypeSCTPInitAck.
func (sc *SCTPInit) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeInitAck {
return LayerTypeSCTPInitAck
}
// sc.Type == SCTPChunkTypeInit
return LayerTypeSCTPInit
}
func decodeSCTPInit(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPInit{
SCTPChunk: chunk,
InitiateTag: binary.BigEndian.Uint32(data[4:8]),
AdvertisedReceiverWindowCredit: binary.BigEndian.Uint32(data[8:12]),
OutboundStreams: binary.BigEndian.Uint16(data[12:14]),
InboundStreams: binary.BigEndian.Uint16(data[14:16]),
InitialTSN: binary.BigEndian.Uint32(data[16:20]),
}
paramData := data[20:sc.ActualLength]
for len(paramData) > 0 {
p := SCTPInitParameter(decodeSCTPParameter(paramData))
paramData = paramData[p.ActualLength:]
sc.Parameters = append(sc.Parameters, p)
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPInit) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var payload []byte
for _, param := range sc.Parameters {
payload = append(payload, SCTPParameter(param).Bytes()...)
}
length := 20 + len(payload)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
binary.BigEndian.PutUint32(bytes[4:8], sc.InitiateTag)
binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit)
binary.BigEndian.PutUint16(bytes[12:14], sc.OutboundStreams)
binary.BigEndian.PutUint16(bytes[14:16], sc.InboundStreams)
binary.BigEndian.PutUint32(bytes[16:20], sc.InitialTSN)
copy(bytes[20:], payload)
return nil
}
// SCTPSack is the SCTP Selective ACK chunk layer.
type SCTPSack struct {
SCTPChunk
CumulativeTSNAck uint32
AdvertisedReceiverWindowCredit uint32
NumGapACKs, NumDuplicateTSNs uint16
GapACKs []uint16
DuplicateTSNs []uint32
}
// LayerType return LayerTypeSCTPSack
func (sc *SCTPSack) LayerType() gopacket.LayerType {
return LayerTypeSCTPSack
}
func decodeSCTPSack(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPSack{
SCTPChunk: chunk,
CumulativeTSNAck: binary.BigEndian.Uint32(data[4:8]),
AdvertisedReceiverWindowCredit: binary.BigEndian.Uint32(data[8:12]),
NumGapACKs: binary.BigEndian.Uint16(data[12:14]),
NumDuplicateTSNs: binary.BigEndian.Uint16(data[14:16]),
}
// We maximize gapAcks and dupTSNs here so we're not allocating tons
// of memory based on a user-controlable field. Our maximums are not exact,
// but should give us sane defaults... we'll still hit slice boundaries and
// fail if the user-supplied values are too high (in the for loops below), but
// the amount of memory we'll have allocated because of that should be small
// (< sc.ActualLength)
gapAcks := sc.SCTPChunk.ActualLength / 2
dupTSNs := (sc.SCTPChunk.ActualLength - gapAcks*2) / 4
if gapAcks > int(sc.NumGapACKs) {
gapAcks = int(sc.NumGapACKs)
}
if dupTSNs > int(sc.NumDuplicateTSNs) {
dupTSNs = int(sc.NumDuplicateTSNs)
}
sc.GapACKs = make([]uint16, 0, gapAcks)
sc.DuplicateTSNs = make([]uint32, 0, dupTSNs)
bytesRemaining := data[16:]
for i := 0; i < int(sc.NumGapACKs); i++ {
sc.GapACKs = append(sc.GapACKs, binary.BigEndian.Uint16(bytesRemaining[:2]))
bytesRemaining = bytesRemaining[2:]
}
for i := 0; i < int(sc.NumDuplicateTSNs); i++ {
sc.DuplicateTSNs = append(sc.DuplicateTSNs, binary.BigEndian.Uint32(bytesRemaining[:4]))
bytesRemaining = bytesRemaining[4:]
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPSack) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
length := 16 + 2*len(sc.GapACKs) + 4*len(sc.DuplicateTSNs)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck)
binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit)
binary.BigEndian.PutUint16(bytes[12:14], uint16(len(sc.GapACKs)))
binary.BigEndian.PutUint16(bytes[14:16], uint16(len(sc.DuplicateTSNs)))
for i, v := range sc.GapACKs {
binary.BigEndian.PutUint16(bytes[16+i*2:], v)
}
offset := 16 + 2*len(sc.GapACKs)
for i, v := range sc.DuplicateTSNs {
binary.BigEndian.PutUint32(bytes[offset+i*4:], v)
}
return nil
}
// SCTPHeartbeatParameter is the parameter type used by SCTP heartbeat and
// heartbeat ack layers.
type SCTPHeartbeatParameter SCTPParameter
// SCTPHeartbeat is the SCTP heartbeat layer, also used for heatbeat ack.
type SCTPHeartbeat struct {
SCTPChunk
Parameters []SCTPHeartbeatParameter
}
// LayerType returns gopacket.LayerTypeSCTPHeartbeat.
func (sc *SCTPHeartbeat) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeHeartbeatAck {
return LayerTypeSCTPHeartbeatAck
}
// sc.Type == SCTPChunkTypeHeartbeat
return LayerTypeSCTPHeartbeat
}
func decodeSCTPHeartbeat(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPHeartbeat{
SCTPChunk: chunk,
}
paramData := data[4:sc.Length]
for len(paramData) > 0 {
p := SCTPHeartbeatParameter(decodeSCTPParameter(paramData))
paramData = paramData[p.ActualLength:]
sc.Parameters = append(sc.Parameters, p)
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPHeartbeat) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var payload []byte
for _, param := range sc.Parameters {
payload = append(payload, SCTPParameter(param).Bytes()...)
}
length := 4 + len(payload)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
copy(bytes[4:], payload)
return nil
}
// SCTPErrorParameter is the parameter type used by SCTP Abort and Error layers.
type SCTPErrorParameter SCTPParameter
// SCTPError is the SCTP error layer, also used for SCTP aborts.
type SCTPError struct {
SCTPChunk
Parameters []SCTPErrorParameter
}
// LayerType returns LayerTypeSCTPAbort or LayerTypeSCTPError.
func (sc *SCTPError) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeAbort {
return LayerTypeSCTPAbort
}
// sc.Type == SCTPChunkTypeError
return LayerTypeSCTPError
}
func decodeSCTPError(data []byte, p gopacket.PacketBuilder) error {
// remarkably similar to decodeSCTPHeartbeat ;)
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPError{
SCTPChunk: chunk,
}
paramData := data[4:sc.Length]
for len(paramData) > 0 {
p := SCTPErrorParameter(decodeSCTPParameter(paramData))
paramData = paramData[p.ActualLength:]
sc.Parameters = append(sc.Parameters, p)
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPError) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
var payload []byte
for _, param := range sc.Parameters {
payload = append(payload, SCTPParameter(param).Bytes()...)
}
length := 4 + len(payload)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
copy(bytes[4:], payload)
return nil
}
// SCTPShutdown is the SCTP shutdown layer.
type SCTPShutdown struct {
SCTPChunk
CumulativeTSNAck uint32
}
// LayerType returns gopacket.LayerTypeSCTPShutdown.
func (sc *SCTPShutdown) LayerType() gopacket.LayerType { return LayerTypeSCTPShutdown }
func decodeSCTPShutdown(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPShutdown{
SCTPChunk: chunk,
CumulativeTSNAck: binary.BigEndian.Uint32(data[4:8]),
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPShutdown) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(8)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], 8)
binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck)
return nil
}
// SCTPShutdownAck is the SCTP shutdown layer.
type SCTPShutdownAck struct {
SCTPChunk
}
// LayerType returns gopacket.LayerTypeSCTPShutdownAck.
func (sc *SCTPShutdownAck) LayerType() gopacket.LayerType { return LayerTypeSCTPShutdownAck }
func decodeSCTPShutdownAck(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPShutdownAck{
SCTPChunk: chunk,
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPShutdownAck) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], 4)
return nil
}
// SCTPCookieEcho is the SCTP Cookie Echo layer.
type SCTPCookieEcho struct {
SCTPChunk
Cookie []byte
}
// LayerType returns gopacket.LayerTypeSCTPCookieEcho.
func (sc *SCTPCookieEcho) LayerType() gopacket.LayerType { return LayerTypeSCTPCookieEcho }
func decodeSCTPCookieEcho(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPCookieEcho{
SCTPChunk: chunk,
}
sc.Cookie = data[4:sc.Length]
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPCookieEcho) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
length := 4 + len(sc.Cookie)
bytes, err := b.PrependBytes(roundUpToNearest4(length))
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
copy(bytes[4:], sc.Cookie)
return nil
}
// This struct is used by all empty SCTP chunks (currently CookieAck and
// ShutdownComplete).
type SCTPEmptyLayer struct {
SCTPChunk
}
// LayerType returns either gopacket.LayerTypeSCTPShutdownComplete or
// LayerTypeSCTPCookieAck.
func (sc *SCTPEmptyLayer) LayerType() gopacket.LayerType {
if sc.Type == SCTPChunkTypeShutdownComplete {
return LayerTypeSCTPShutdownComplete
}
// sc.Type == SCTPChunkTypeCookieAck
return LayerTypeSCTPCookieAck
}
func decodeSCTPEmptyLayer(data []byte, p gopacket.PacketBuilder) error {
chunk, err := decodeSCTPChunk(data)
if err != nil {
return err
}
sc := &SCTPEmptyLayer{
SCTPChunk: chunk,
}
p.AddLayer(sc)
return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix))
}
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPEmptyLayer) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
bytes, err := b.PrependBytes(4)
if err != nil {
return err
}
bytes[0] = uint8(sc.Type)
bytes[1] = sc.Flags
binary.BigEndian.PutUint16(bytes[2:4], 4)
return nil
}