aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gopacket/layers/tcp.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/gopacket/layers/tcp.go')
-rw-r--r--vendor/github.com/google/gopacket/layers/tcp.go327
1 files changed, 327 insertions, 0 deletions
diff --git a/vendor/github.com/google/gopacket/layers/tcp.go b/vendor/github.com/google/gopacket/layers/tcp.go
new file mode 100644
index 0000000..fb731da
--- /dev/null
+++ b/vendor/github.com/google/gopacket/layers/tcp.go
@@ -0,0 +1,327 @@
+// Copyright 2012 Google, Inc. All rights reserved.
+// Copyright 2009-2011 Andreas Krennmair. 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"
+ "encoding/hex"
+ "errors"
+ "fmt"
+
+ "github.com/google/gopacket"
+)
+
+// TCP is the layer for TCP headers.
+type TCP struct {
+ BaseLayer
+ SrcPort, DstPort TCPPort
+ Seq uint32
+ Ack uint32
+ DataOffset uint8
+ FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool
+ Window uint16
+ Checksum uint16
+ Urgent uint16
+ sPort, dPort []byte
+ Options []TCPOption
+ Padding []byte
+ opts [4]TCPOption
+ tcpipchecksum
+}
+
+// TCPOptionKind represents a TCP option code.
+type TCPOptionKind uint8
+
+const (
+ TCPOptionKindEndList = 0
+ TCPOptionKindNop = 1
+ TCPOptionKindMSS = 2 // len = 4
+ TCPOptionKindWindowScale = 3 // len = 3
+ TCPOptionKindSACKPermitted = 4 // len = 2
+ TCPOptionKindSACK = 5 // len = n
+ TCPOptionKindEcho = 6 // len = 6, obsolete
+ TCPOptionKindEchoReply = 7 // len = 6, obsolete
+ TCPOptionKindTimestamps = 8 // len = 10
+ TCPOptionKindPartialOrderConnectionPermitted = 9 // len = 2, obsolete
+ TCPOptionKindPartialOrderServiceProfile = 10 // len = 3, obsolete
+ TCPOptionKindCC = 11 // obsolete
+ TCPOptionKindCCNew = 12 // obsolete
+ TCPOptionKindCCEcho = 13 // obsolete
+ TCPOptionKindAltChecksum = 14 // len = 3, obsolete
+ TCPOptionKindAltChecksumData = 15 // len = n, obsolete
+)
+
+func (k TCPOptionKind) String() string {
+ switch k {
+ case TCPOptionKindEndList:
+ return "EndList"
+ case TCPOptionKindNop:
+ return "NOP"
+ case TCPOptionKindMSS:
+ return "MSS"
+ case TCPOptionKindWindowScale:
+ return "WindowScale"
+ case TCPOptionKindSACKPermitted:
+ return "SACKPermitted"
+ case TCPOptionKindSACK:
+ return "SACK"
+ case TCPOptionKindEcho:
+ return "Echo"
+ case TCPOptionKindEchoReply:
+ return "EchoReply"
+ case TCPOptionKindTimestamps:
+ return "Timestamps"
+ case TCPOptionKindPartialOrderConnectionPermitted:
+ return "PartialOrderConnectionPermitted"
+ case TCPOptionKindPartialOrderServiceProfile:
+ return "PartialOrderServiceProfile"
+ case TCPOptionKindCC:
+ return "CC"
+ case TCPOptionKindCCNew:
+ return "CCNew"
+ case TCPOptionKindCCEcho:
+ return "CCEcho"
+ case TCPOptionKindAltChecksum:
+ return "AltChecksum"
+ case TCPOptionKindAltChecksumData:
+ return "AltChecksumData"
+ default:
+ return fmt.Sprintf("Unknown(%d)", k)
+ }
+}
+
+type TCPOption struct {
+ OptionType TCPOptionKind
+ OptionLength uint8
+ OptionData []byte
+}
+
+func (t TCPOption) String() string {
+ hd := hex.EncodeToString(t.OptionData)
+ if len(hd) > 0 {
+ hd = " 0x" + hd
+ }
+ switch t.OptionType {
+ case TCPOptionKindMSS:
+ return fmt.Sprintf("TCPOption(%s:%v%s)",
+ t.OptionType,
+ binary.BigEndian.Uint16(t.OptionData),
+ hd)
+
+ case TCPOptionKindTimestamps:
+ if len(t.OptionData) == 8 {
+ return fmt.Sprintf("TCPOption(%s:%v/%v%s)",
+ t.OptionType,
+ binary.BigEndian.Uint32(t.OptionData[:4]),
+ binary.BigEndian.Uint32(t.OptionData[4:8]),
+ hd)
+ }
+ }
+ return fmt.Sprintf("TCPOption(%s:%s)", t.OptionType, hd)
+}
+
+// LayerType returns gopacket.LayerTypeTCP
+func (t *TCP) LayerType() gopacket.LayerType { return LayerTypeTCP }
+
+// SerializeTo writes the serialized form of this layer into the
+// SerializationBuffer, implementing gopacket.SerializableLayer.
+// See the docs for gopacket.SerializableLayer for more info.
+func (t *TCP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
+ var optionLength int
+ for _, o := range t.Options {
+ switch o.OptionType {
+ case 0, 1:
+ optionLength += 1
+ default:
+ optionLength += 2 + len(o.OptionData)
+ }
+ }
+ if opts.FixLengths {
+ if rem := optionLength % 4; rem != 0 {
+ t.Padding = lotsOfZeros[:4-rem]
+ }
+ t.DataOffset = uint8((len(t.Padding) + optionLength + 20) / 4)
+ }
+ bytes, err := b.PrependBytes(20 + optionLength + len(t.Padding))
+ if err != nil {
+ return err
+ }
+ binary.BigEndian.PutUint16(bytes, uint16(t.SrcPort))
+ binary.BigEndian.PutUint16(bytes[2:], uint16(t.DstPort))
+ binary.BigEndian.PutUint32(bytes[4:], t.Seq)
+ binary.BigEndian.PutUint32(bytes[8:], t.Ack)
+ binary.BigEndian.PutUint16(bytes[12:], t.flagsAndOffset())
+ binary.BigEndian.PutUint16(bytes[14:], t.Window)
+ binary.BigEndian.PutUint16(bytes[18:], t.Urgent)
+ start := 20
+ for _, o := range t.Options {
+ bytes[start] = byte(o.OptionType)
+ switch o.OptionType {
+ case 0, 1:
+ start++
+ default:
+ if opts.FixLengths {
+ o.OptionLength = uint8(len(o.OptionData) + 2)
+ }
+ bytes[start+1] = o.OptionLength
+ copy(bytes[start+2:start+len(o.OptionData)+2], o.OptionData)
+ start += int(o.OptionLength)
+ }
+ }
+ copy(bytes[start:], t.Padding)
+ if opts.ComputeChecksums {
+ // zero out checksum bytes in current serialization.
+ bytes[16] = 0
+ bytes[17] = 0
+ csum, err := t.computeChecksum(b.Bytes(), IPProtocolTCP)
+ if err != nil {
+ return err
+ }
+ t.Checksum = csum
+ }
+ binary.BigEndian.PutUint16(bytes[16:], t.Checksum)
+ return nil
+}
+
+func (t *TCP) ComputeChecksum() (uint16, error) {
+ return t.computeChecksum(append(t.Contents, t.Payload...), IPProtocolTCP)
+}
+
+func (t *TCP) flagsAndOffset() uint16 {
+ f := uint16(t.DataOffset) << 12
+ if t.FIN {
+ f |= 0x0001
+ }
+ if t.SYN {
+ f |= 0x0002
+ }
+ if t.RST {
+ f |= 0x0004
+ }
+ if t.PSH {
+ f |= 0x0008
+ }
+ if t.ACK {
+ f |= 0x0010
+ }
+ if t.URG {
+ f |= 0x0020
+ }
+ if t.ECE {
+ f |= 0x0040
+ }
+ if t.CWR {
+ f |= 0x0080
+ }
+ if t.NS {
+ f |= 0x0100
+ }
+ return f
+}
+
+func (tcp *TCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
+ tcp.SrcPort = TCPPort(binary.BigEndian.Uint16(data[0:2]))
+ tcp.sPort = data[0:2]
+ tcp.DstPort = TCPPort(binary.BigEndian.Uint16(data[2:4]))
+ tcp.dPort = data[2:4]
+ tcp.Seq = binary.BigEndian.Uint32(data[4:8])
+ tcp.Ack = binary.BigEndian.Uint32(data[8:12])
+ tcp.DataOffset = data[12] >> 4
+ tcp.FIN = data[13]&0x01 != 0
+ tcp.SYN = data[13]&0x02 != 0
+ tcp.RST = data[13]&0x04 != 0
+ tcp.PSH = data[13]&0x08 != 0
+ tcp.ACK = data[13]&0x10 != 0
+ tcp.URG = data[13]&0x20 != 0
+ tcp.ECE = data[13]&0x40 != 0
+ tcp.CWR = data[13]&0x80 != 0
+ tcp.NS = data[12]&0x01 != 0
+ tcp.Window = binary.BigEndian.Uint16(data[14:16])
+ tcp.Checksum = binary.BigEndian.Uint16(data[16:18])
+ tcp.Urgent = binary.BigEndian.Uint16(data[18:20])
+ tcp.Options = tcp.opts[:0]
+ if tcp.DataOffset < 5 {
+ return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset)
+ }
+ dataStart := int(tcp.DataOffset) * 4
+ if dataStart > len(data) {
+ df.SetTruncated()
+ tcp.Payload = nil
+ tcp.Contents = data
+ return errors.New("TCP data offset greater than packet length")
+ }
+ tcp.Contents = data[:dataStart]
+ tcp.Payload = data[dataStart:]
+ // From here on, data points just to the header options.
+ data = data[20:dataStart]
+ for len(data) > 0 {
+ if tcp.Options == nil {
+ // Pre-allocate to avoid allocating a slice.
+ tcp.Options = tcp.opts[:0]
+ }
+ tcp.Options = append(tcp.Options, TCPOption{OptionType: TCPOptionKind(data[0])})
+ opt := &tcp.Options[len(tcp.Options)-1]
+ switch opt.OptionType {
+ case TCPOptionKindEndList: // End of options
+ opt.OptionLength = 1
+ tcp.Padding = data[1:]
+ break
+ case TCPOptionKindNop: // 1 byte padding
+ opt.OptionLength = 1
+ default:
+ opt.OptionLength = data[1]
+ if opt.OptionLength < 2 {
+ return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength)
+ } else if int(opt.OptionLength) > len(data) {
+ return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(data))
+ }
+ opt.OptionData = data[2:opt.OptionLength]
+ }
+ data = data[opt.OptionLength:]
+ }
+ return nil
+}
+
+func (t *TCP) CanDecode() gopacket.LayerClass {
+ return LayerTypeTCP
+}
+
+func (t *TCP) NextLayerType() gopacket.LayerType {
+ lt := t.DstPort.LayerType()
+ if lt == gopacket.LayerTypePayload {
+ lt = t.SrcPort.LayerType()
+ }
+ return lt
+}
+
+func decodeTCP(data []byte, p gopacket.PacketBuilder) error {
+ tcp := &TCP{}
+ err := tcp.DecodeFromBytes(data, p)
+ p.AddLayer(tcp)
+ p.SetTransportLayer(tcp)
+ if err != nil {
+ return err
+ }
+ if p.DecodeOptions().DecodeStreamsAsDatagrams {
+ return p.NextDecoder(tcp.NextLayerType())
+ } else {
+ return p.NextDecoder(gopacket.LayerTypePayload)
+ }
+}
+
+func (t *TCP) TransportFlow() gopacket.Flow {
+ return gopacket.NewFlow(EndpointTCPPort, t.sPort, t.dPort)
+}
+
+// For testing only
+func (t *TCP) SetInternalPortsForTesting() {
+ t.sPort = make([]byte, 2)
+ t.dPort = make([]byte, 2)
+ binary.BigEndian.PutUint16(t.sPort, uint16(t.SrcPort))
+ binary.BigEndian.PutUint16(t.dPort, uint16(t.DstPort))
+}