fb731da1c9cdd6050eef74c5851b8b360c116409
[govpp.git] / vendor / github.com / google / gopacket / layers / tcp.go
1 // Copyright 2012 Google, Inc. All rights reserved.
2 // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style license
5 // that can be found in the LICENSE file in the root of the source
6 // tree.
7
8 package layers
9
10 import (
11         "encoding/binary"
12         "encoding/hex"
13         "errors"
14         "fmt"
15
16         "github.com/google/gopacket"
17 )
18
19 // TCP is the layer for TCP headers.
20 type TCP struct {
21         BaseLayer
22         SrcPort, DstPort                           TCPPort
23         Seq                                        uint32
24         Ack                                        uint32
25         DataOffset                                 uint8
26         FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool
27         Window                                     uint16
28         Checksum                                   uint16
29         Urgent                                     uint16
30         sPort, dPort                               []byte
31         Options                                    []TCPOption
32         Padding                                    []byte
33         opts                                       [4]TCPOption
34         tcpipchecksum
35 }
36
37 // TCPOptionKind represents a TCP option code.
38 type TCPOptionKind uint8
39
40 const (
41         TCPOptionKindEndList                         = 0
42         TCPOptionKindNop                             = 1
43         TCPOptionKindMSS                             = 2  // len = 4
44         TCPOptionKindWindowScale                     = 3  // len = 3
45         TCPOptionKindSACKPermitted                   = 4  // len = 2
46         TCPOptionKindSACK                            = 5  // len = n
47         TCPOptionKindEcho                            = 6  // len = 6, obsolete
48         TCPOptionKindEchoReply                       = 7  // len = 6, obsolete
49         TCPOptionKindTimestamps                      = 8  // len = 10
50         TCPOptionKindPartialOrderConnectionPermitted = 9  // len = 2, obsolete
51         TCPOptionKindPartialOrderServiceProfile      = 10 // len = 3, obsolete
52         TCPOptionKindCC                              = 11 // obsolete
53         TCPOptionKindCCNew                           = 12 // obsolete
54         TCPOptionKindCCEcho                          = 13 // obsolete
55         TCPOptionKindAltChecksum                     = 14 // len = 3, obsolete
56         TCPOptionKindAltChecksumData                 = 15 // len = n, obsolete
57 )
58
59 func (k TCPOptionKind) String() string {
60         switch k {
61         case TCPOptionKindEndList:
62                 return "EndList"
63         case TCPOptionKindNop:
64                 return "NOP"
65         case TCPOptionKindMSS:
66                 return "MSS"
67         case TCPOptionKindWindowScale:
68                 return "WindowScale"
69         case TCPOptionKindSACKPermitted:
70                 return "SACKPermitted"
71         case TCPOptionKindSACK:
72                 return "SACK"
73         case TCPOptionKindEcho:
74                 return "Echo"
75         case TCPOptionKindEchoReply:
76                 return "EchoReply"
77         case TCPOptionKindTimestamps:
78                 return "Timestamps"
79         case TCPOptionKindPartialOrderConnectionPermitted:
80                 return "PartialOrderConnectionPermitted"
81         case TCPOptionKindPartialOrderServiceProfile:
82                 return "PartialOrderServiceProfile"
83         case TCPOptionKindCC:
84                 return "CC"
85         case TCPOptionKindCCNew:
86                 return "CCNew"
87         case TCPOptionKindCCEcho:
88                 return "CCEcho"
89         case TCPOptionKindAltChecksum:
90                 return "AltChecksum"
91         case TCPOptionKindAltChecksumData:
92                 return "AltChecksumData"
93         default:
94                 return fmt.Sprintf("Unknown(%d)", k)
95         }
96 }
97
98 type TCPOption struct {
99         OptionType   TCPOptionKind
100         OptionLength uint8
101         OptionData   []byte
102 }
103
104 func (t TCPOption) String() string {
105         hd := hex.EncodeToString(t.OptionData)
106         if len(hd) > 0 {
107                 hd = " 0x" + hd
108         }
109         switch t.OptionType {
110         case TCPOptionKindMSS:
111                 return fmt.Sprintf("TCPOption(%s:%v%s)",
112                         t.OptionType,
113                         binary.BigEndian.Uint16(t.OptionData),
114                         hd)
115
116         case TCPOptionKindTimestamps:
117                 if len(t.OptionData) == 8 {
118                         return fmt.Sprintf("TCPOption(%s:%v/%v%s)",
119                                 t.OptionType,
120                                 binary.BigEndian.Uint32(t.OptionData[:4]),
121                                 binary.BigEndian.Uint32(t.OptionData[4:8]),
122                                 hd)
123                 }
124         }
125         return fmt.Sprintf("TCPOption(%s:%s)", t.OptionType, hd)
126 }
127
128 // LayerType returns gopacket.LayerTypeTCP
129 func (t *TCP) LayerType() gopacket.LayerType { return LayerTypeTCP }
130
131 // SerializeTo writes the serialized form of this layer into the
132 // SerializationBuffer, implementing gopacket.SerializableLayer.
133 // See the docs for gopacket.SerializableLayer for more info.
134 func (t *TCP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
135         var optionLength int
136         for _, o := range t.Options {
137                 switch o.OptionType {
138                 case 0, 1:
139                         optionLength += 1
140                 default:
141                         optionLength += 2 + len(o.OptionData)
142                 }
143         }
144         if opts.FixLengths {
145                 if rem := optionLength % 4; rem != 0 {
146                         t.Padding = lotsOfZeros[:4-rem]
147                 }
148                 t.DataOffset = uint8((len(t.Padding) + optionLength + 20) / 4)
149         }
150         bytes, err := b.PrependBytes(20 + optionLength + len(t.Padding))
151         if err != nil {
152                 return err
153         }
154         binary.BigEndian.PutUint16(bytes, uint16(t.SrcPort))
155         binary.BigEndian.PutUint16(bytes[2:], uint16(t.DstPort))
156         binary.BigEndian.PutUint32(bytes[4:], t.Seq)
157         binary.BigEndian.PutUint32(bytes[8:], t.Ack)
158         binary.BigEndian.PutUint16(bytes[12:], t.flagsAndOffset())
159         binary.BigEndian.PutUint16(bytes[14:], t.Window)
160         binary.BigEndian.PutUint16(bytes[18:], t.Urgent)
161         start := 20
162         for _, o := range t.Options {
163                 bytes[start] = byte(o.OptionType)
164                 switch o.OptionType {
165                 case 0, 1:
166                         start++
167                 default:
168                         if opts.FixLengths {
169                                 o.OptionLength = uint8(len(o.OptionData) + 2)
170                         }
171                         bytes[start+1] = o.OptionLength
172                         copy(bytes[start+2:start+len(o.OptionData)+2], o.OptionData)
173                         start += int(o.OptionLength)
174                 }
175         }
176         copy(bytes[start:], t.Padding)
177         if opts.ComputeChecksums {
178                 // zero out checksum bytes in current serialization.
179                 bytes[16] = 0
180                 bytes[17] = 0
181                 csum, err := t.computeChecksum(b.Bytes(), IPProtocolTCP)
182                 if err != nil {
183                         return err
184                 }
185                 t.Checksum = csum
186         }
187         binary.BigEndian.PutUint16(bytes[16:], t.Checksum)
188         return nil
189 }
190
191 func (t *TCP) ComputeChecksum() (uint16, error) {
192         return t.computeChecksum(append(t.Contents, t.Payload...), IPProtocolTCP)
193 }
194
195 func (t *TCP) flagsAndOffset() uint16 {
196         f := uint16(t.DataOffset) << 12
197         if t.FIN {
198                 f |= 0x0001
199         }
200         if t.SYN {
201                 f |= 0x0002
202         }
203         if t.RST {
204                 f |= 0x0004
205         }
206         if t.PSH {
207                 f |= 0x0008
208         }
209         if t.ACK {
210                 f |= 0x0010
211         }
212         if t.URG {
213                 f |= 0x0020
214         }
215         if t.ECE {
216                 f |= 0x0040
217         }
218         if t.CWR {
219                 f |= 0x0080
220         }
221         if t.NS {
222                 f |= 0x0100
223         }
224         return f
225 }
226
227 func (tcp *TCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
228         tcp.SrcPort = TCPPort(binary.BigEndian.Uint16(data[0:2]))
229         tcp.sPort = data[0:2]
230         tcp.DstPort = TCPPort(binary.BigEndian.Uint16(data[2:4]))
231         tcp.dPort = data[2:4]
232         tcp.Seq = binary.BigEndian.Uint32(data[4:8])
233         tcp.Ack = binary.BigEndian.Uint32(data[8:12])
234         tcp.DataOffset = data[12] >> 4
235         tcp.FIN = data[13]&0x01 != 0
236         tcp.SYN = data[13]&0x02 != 0
237         tcp.RST = data[13]&0x04 != 0
238         tcp.PSH = data[13]&0x08 != 0
239         tcp.ACK = data[13]&0x10 != 0
240         tcp.URG = data[13]&0x20 != 0
241         tcp.ECE = data[13]&0x40 != 0
242         tcp.CWR = data[13]&0x80 != 0
243         tcp.NS = data[12]&0x01 != 0
244         tcp.Window = binary.BigEndian.Uint16(data[14:16])
245         tcp.Checksum = binary.BigEndian.Uint16(data[16:18])
246         tcp.Urgent = binary.BigEndian.Uint16(data[18:20])
247         tcp.Options = tcp.opts[:0]
248         if tcp.DataOffset < 5 {
249                 return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset)
250         }
251         dataStart := int(tcp.DataOffset) * 4
252         if dataStart > len(data) {
253                 df.SetTruncated()
254                 tcp.Payload = nil
255                 tcp.Contents = data
256                 return errors.New("TCP data offset greater than packet length")
257         }
258         tcp.Contents = data[:dataStart]
259         tcp.Payload = data[dataStart:]
260         // From here on, data points just to the header options.
261         data = data[20:dataStart]
262         for len(data) > 0 {
263                 if tcp.Options == nil {
264                         // Pre-allocate to avoid allocating a slice.
265                         tcp.Options = tcp.opts[:0]
266                 }
267                 tcp.Options = append(tcp.Options, TCPOption{OptionType: TCPOptionKind(data[0])})
268                 opt := &tcp.Options[len(tcp.Options)-1]
269                 switch opt.OptionType {
270                 case TCPOptionKindEndList: // End of options
271                         opt.OptionLength = 1
272                         tcp.Padding = data[1:]
273                         break
274                 case TCPOptionKindNop: // 1 byte padding
275                         opt.OptionLength = 1
276                 default:
277                         opt.OptionLength = data[1]
278                         if opt.OptionLength < 2 {
279                                 return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength)
280                         } else if int(opt.OptionLength) > len(data) {
281                                 return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(data))
282                         }
283                         opt.OptionData = data[2:opt.OptionLength]
284                 }
285                 data = data[opt.OptionLength:]
286         }
287         return nil
288 }
289
290 func (t *TCP) CanDecode() gopacket.LayerClass {
291         return LayerTypeTCP
292 }
293
294 func (t *TCP) NextLayerType() gopacket.LayerType {
295         lt := t.DstPort.LayerType()
296         if lt == gopacket.LayerTypePayload {
297                 lt = t.SrcPort.LayerType()
298         }
299         return lt
300 }
301
302 func decodeTCP(data []byte, p gopacket.PacketBuilder) error {
303         tcp := &TCP{}
304         err := tcp.DecodeFromBytes(data, p)
305         p.AddLayer(tcp)
306         p.SetTransportLayer(tcp)
307         if err != nil {
308                 return err
309         }
310         if p.DecodeOptions().DecodeStreamsAsDatagrams {
311                 return p.NextDecoder(tcp.NextLayerType())
312         } else {
313                 return p.NextDecoder(gopacket.LayerTypePayload)
314         }
315 }
316
317 func (t *TCP) TransportFlow() gopacket.Flow {
318         return gopacket.NewFlow(EndpointTCPPort, t.sPort, t.dPort)
319 }
320
321 // For testing only
322 func (t *TCP) SetInternalPortsForTesting() {
323         t.sPort = make([]byte, 2)
324         t.dPort = make([]byte, 2)
325         binary.BigEndian.PutUint16(t.sPort, uint16(t.SrcPort))
326         binary.BigEndian.PutUint16(t.dPort, uint16(t.DstPort))
327 }