ODPM 266: Go-libmemif + 2 examples.
[govpp.git] / vendor / github.com / google / gopacket / layers / ip4.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         "errors"
13         "fmt"
14         "net"
15         "strings"
16
17         "github.com/google/gopacket"
18 )
19
20 type IPv4Flag uint8
21
22 const (
23         IPv4EvilBit       IPv4Flag = 1 << 2 // http://tools.ietf.org/html/rfc3514 ;)
24         IPv4DontFragment  IPv4Flag = 1 << 1
25         IPv4MoreFragments IPv4Flag = 1 << 0
26 )
27
28 func (f IPv4Flag) String() string {
29         var s []string
30         if f&IPv4EvilBit != 0 {
31                 s = append(s, "Evil")
32         }
33         if f&IPv4DontFragment != 0 {
34                 s = append(s, "DF")
35         }
36         if f&IPv4MoreFragments != 0 {
37                 s = append(s, "MF")
38         }
39         return strings.Join(s, "|")
40 }
41
42 // IPv4 is the header of an IP packet.
43 type IPv4 struct {
44         BaseLayer
45         Version    uint8
46         IHL        uint8
47         TOS        uint8
48         Length     uint16
49         Id         uint16
50         Flags      IPv4Flag
51         FragOffset uint16
52         TTL        uint8
53         Protocol   IPProtocol
54         Checksum   uint16
55         SrcIP      net.IP
56         DstIP      net.IP
57         Options    []IPv4Option
58         Padding    []byte
59 }
60
61 // LayerType returns LayerTypeIPv4
62 func (i *IPv4) LayerType() gopacket.LayerType { return LayerTypeIPv4 }
63 func (i *IPv4) NetworkFlow() gopacket.Flow {
64         return gopacket.NewFlow(EndpointIPv4, i.SrcIP, i.DstIP)
65 }
66
67 type IPv4Option struct {
68         OptionType   uint8
69         OptionLength uint8
70         OptionData   []byte
71 }
72
73 func (i IPv4Option) String() string {
74         return fmt.Sprintf("IPv4Option(%v:%v)", i.OptionType, i.OptionData)
75 }
76
77 // for the current ipv4 options, return the number of bytes (including
78 // padding that the options used)
79 func (ip *IPv4) getIPv4OptionSize() uint8 {
80         optionSize := uint8(0)
81         for _, opt := range ip.Options {
82                 switch opt.OptionType {
83                 case 0:
84                         // this is the end of option lists
85                         optionSize++
86                 case 1:
87                         // this is the padding
88                         optionSize++
89                 default:
90                         optionSize += opt.OptionLength
91
92                 }
93         }
94         // make sure the options are aligned to 32 bit boundary
95         if (optionSize % 4) != 0 {
96                 optionSize += 4 - (optionSize % 4)
97         }
98         return optionSize
99 }
100
101 // SerializeTo writes the serialized form of this layer into the
102 // SerializationBuffer, implementing gopacket.SerializableLayer.
103 func (ip *IPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
104         optionLength := ip.getIPv4OptionSize()
105         bytes, err := b.PrependBytes(20 + int(optionLength))
106         if err != nil {
107                 return err
108         }
109         if opts.FixLengths {
110                 ip.IHL = 5 + (optionLength / 4)
111                 ip.Length = uint16(len(b.Bytes()))
112         }
113         bytes[0] = (ip.Version << 4) | ip.IHL
114         bytes[1] = ip.TOS
115         binary.BigEndian.PutUint16(bytes[2:], ip.Length)
116         binary.BigEndian.PutUint16(bytes[4:], ip.Id)
117         binary.BigEndian.PutUint16(bytes[6:], ip.flagsfrags())
118         bytes[8] = ip.TTL
119         bytes[9] = byte(ip.Protocol)
120         if err := ip.AddressTo4(); err != nil {
121                 return err
122         }
123         copy(bytes[12:16], ip.SrcIP)
124         copy(bytes[16:20], ip.DstIP)
125
126         curLocation := 20
127         // Now, we will encode the options
128         for _, opt := range ip.Options {
129                 switch opt.OptionType {
130                 case 0:
131                         // this is the end of option lists
132                         bytes[curLocation] = 0
133                         curLocation++
134                 case 1:
135                         // this is the padding
136                         bytes[curLocation] = 1
137                         curLocation++
138                 default:
139                         bytes[curLocation] = opt.OptionType
140                         bytes[curLocation+1] = opt.OptionLength
141
142                         // sanity checking to protect us from buffer overrun
143                         if len(opt.OptionData) > int(opt.OptionLength-2) {
144                                 return errors.New("option length is smaller than length of option data")
145                         }
146                         copy(bytes[curLocation+2:curLocation+int(opt.OptionLength)], opt.OptionData)
147                         curLocation += int(opt.OptionLength)
148                 }
149         }
150
151         if opts.ComputeChecksums {
152                 ip.Checksum = checksum(bytes)
153         }
154         binary.BigEndian.PutUint16(bytes[10:], ip.Checksum)
155         return nil
156 }
157
158 func checksum(bytes []byte) uint16 {
159         // Clear checksum bytes
160         bytes[10] = 0
161         bytes[11] = 0
162
163         // Compute checksum
164         var csum uint32
165         for i := 0; i < len(bytes); i += 2 {
166                 csum += uint32(bytes[i]) << 8
167                 csum += uint32(bytes[i+1])
168         }
169         for {
170                 // Break when sum is less or equals to 0xFFFF
171                 if csum <= 65535 {
172                         break
173                 }
174                 // Add carry to the sum
175                 csum = (csum >> 16) + uint32(uint16(csum))
176         }
177         // Flip all the bits
178         return ^uint16(csum)
179 }
180
181 func (ip *IPv4) flagsfrags() (ff uint16) {
182         ff |= uint16(ip.Flags) << 13
183         ff |= ip.FragOffset
184         return
185 }
186
187 // DecodeFromBytes decodes the given bytes into this layer.
188 func (ip *IPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
189         flagsfrags := binary.BigEndian.Uint16(data[6:8])
190
191         ip.Version = uint8(data[0]) >> 4
192         ip.IHL = uint8(data[0]) & 0x0F
193         ip.TOS = data[1]
194         ip.Length = binary.BigEndian.Uint16(data[2:4])
195         ip.Id = binary.BigEndian.Uint16(data[4:6])
196         ip.Flags = IPv4Flag(flagsfrags >> 13)
197         ip.FragOffset = flagsfrags & 0x1FFF
198         ip.TTL = data[8]
199         ip.Protocol = IPProtocol(data[9])
200         ip.Checksum = binary.BigEndian.Uint16(data[10:12])
201         ip.SrcIP = data[12:16]
202         ip.DstIP = data[16:20]
203         ip.Options = ip.Options[:0]
204         // Set up an initial guess for contents/payload... we'll reset these soon.
205         ip.BaseLayer = BaseLayer{Contents: data}
206
207         // This code is added for the following enviroment:
208         // * Windows 10 with TSO option activated. ( tested on Hyper-V, RealTek ethernet driver )
209         if ip.Length == 0 {
210                 // If using TSO(TCP Segmentation Offload), length is zero.
211                 // The actual packet length is the length of data.
212                 ip.Length = uint16(len(data))
213         }
214
215         if ip.Length < 20 {
216                 return fmt.Errorf("Invalid (too small) IP length (%d < 20)", ip.Length)
217         } else if ip.IHL < 5 {
218                 return fmt.Errorf("Invalid (too small) IP header length (%d < 5)", ip.IHL)
219         } else if int(ip.IHL*4) > int(ip.Length) {
220                 return fmt.Errorf("Invalid IP header length > IP length (%d > %d)", ip.IHL, ip.Length)
221         }
222         if cmp := len(data) - int(ip.Length); cmp > 0 {
223                 data = data[:ip.Length]
224         } else if cmp < 0 {
225                 df.SetTruncated()
226                 if int(ip.IHL)*4 > len(data) {
227                         return errors.New("Not all IP header bytes available")
228                 }
229         }
230         ip.Contents = data[:ip.IHL*4]
231         ip.Payload = data[ip.IHL*4:]
232         // From here on, data contains the header options.
233         data = data[20 : ip.IHL*4]
234         // Pull out IP options
235         for len(data) > 0 {
236                 if ip.Options == nil {
237                         // Pre-allocate to avoid growing the slice too much.
238                         ip.Options = make([]IPv4Option, 0, 4)
239                 }
240                 opt := IPv4Option{OptionType: data[0]}
241                 switch opt.OptionType {
242                 case 0: // End of options
243                         opt.OptionLength = 1
244                         ip.Options = append(ip.Options, opt)
245                         ip.Padding = data[1:]
246                         break
247                 case 1: // 1 byte padding
248                         opt.OptionLength = 1
249                 default:
250                         opt.OptionLength = data[1]
251                         opt.OptionData = data[2:opt.OptionLength]
252                 }
253                 if len(data) >= int(opt.OptionLength) {
254                         data = data[opt.OptionLength:]
255                 } else {
256                         return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength)
257                 }
258                 ip.Options = append(ip.Options, opt)
259         }
260         return nil
261 }
262
263 func (i *IPv4) CanDecode() gopacket.LayerClass {
264         return LayerTypeIPv4
265 }
266
267 func (i *IPv4) NextLayerType() gopacket.LayerType {
268         if i.Flags&IPv4MoreFragments != 0 || i.FragOffset != 0 {
269                 return gopacket.LayerTypeFragment
270         }
271         return i.Protocol.LayerType()
272 }
273
274 func decodeIPv4(data []byte, p gopacket.PacketBuilder) error {
275         ip := &IPv4{}
276         err := ip.DecodeFromBytes(data, p)
277         p.AddLayer(ip)
278         p.SetNetworkLayer(ip)
279         if err != nil {
280                 return err
281         }
282         return p.NextDecoder(ip.NextLayerType())
283 }
284
285 func checkIPv4Address(addr net.IP) (net.IP, error) {
286         if c := addr.To4(); c != nil {
287                 return c, nil
288         }
289         if len(addr) == net.IPv6len {
290                 return nil, errors.New("address is IPv6")
291         }
292         return nil, fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv4len)
293 }
294
295 func (ip *IPv4) AddressTo4() error {
296         var src, dst net.IP
297
298         if addr, err := checkIPv4Address(ip.SrcIP); err != nil {
299                 return fmt.Errorf("Invalid source IPv4 address (%s)", err)
300         } else {
301                 src = addr
302         }
303         if addr, err := checkIPv4Address(ip.DstIP); err != nil {
304                 return fmt.Errorf("Invalid destination IPv4 address (%s)", err)
305         } else {
306                 dst = addr
307         }
308         ip.SrcIP = src
309         ip.DstIP = dst
310         return nil
311 }