blob: 2b3c0c6bff9f3e676a125f1fa4a064b8b7451d1a [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// 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
8package layers
9
10import (
11 "encoding/binary"
12 "errors"
13 "fmt"
14 "net"
15 "strings"
16
17 "github.com/google/gopacket"
18)
19
20type IPv4Flag uint8
21
22const (
23 IPv4EvilBit IPv4Flag = 1 << 2 // http://tools.ietf.org/html/rfc3514 ;)
24 IPv4DontFragment IPv4Flag = 1 << 1
25 IPv4MoreFragments IPv4Flag = 1 << 0
26)
27
28func (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.
43type 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
62func (i *IPv4) LayerType() gopacket.LayerType { return LayerTypeIPv4 }
63func (i *IPv4) NetworkFlow() gopacket.Flow {
64 return gopacket.NewFlow(EndpointIPv4, i.SrcIP, i.DstIP)
65}
66
67type IPv4Option struct {
68 OptionType uint8
69 OptionLength uint8
70 OptionData []byte
71}
72
73func (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)
79func (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.
103func (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
158func 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
181func (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.
188func (ip *IPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
189 if len(data) < 20 {
190 df.SetTruncated()
191 return fmt.Errorf("Invalid ip4 header. Length %d less than 20", len(data))
192 }
193 flagsfrags := binary.BigEndian.Uint16(data[6:8])
194
195 ip.Version = uint8(data[0]) >> 4
196 ip.IHL = uint8(data[0]) & 0x0F
197 ip.TOS = data[1]
198 ip.Length = binary.BigEndian.Uint16(data[2:4])
199 ip.Id = binary.BigEndian.Uint16(data[4:6])
200 ip.Flags = IPv4Flag(flagsfrags >> 13)
201 ip.FragOffset = flagsfrags & 0x1FFF
202 ip.TTL = data[8]
203 ip.Protocol = IPProtocol(data[9])
204 ip.Checksum = binary.BigEndian.Uint16(data[10:12])
205 ip.SrcIP = data[12:16]
206 ip.DstIP = data[16:20]
207 ip.Options = ip.Options[:0]
208 ip.Padding = nil
209 // Set up an initial guess for contents/payload... we'll reset these soon.
210 ip.BaseLayer = BaseLayer{Contents: data}
211
212 // This code is added for the following enviroment:
213 // * Windows 10 with TSO option activated. ( tested on Hyper-V, RealTek ethernet driver )
214 if ip.Length == 0 {
215 // If using TSO(TCP Segmentation Offload), length is zero.
216 // The actual packet length is the length of data.
217 ip.Length = uint16(len(data))
218 }
219
220 if ip.Length < 20 {
221 return fmt.Errorf("Invalid (too small) IP length (%d < 20)", ip.Length)
222 } else if ip.IHL < 5 {
223 return fmt.Errorf("Invalid (too small) IP header length (%d < 5)", ip.IHL)
224 } else if int(ip.IHL*4) > int(ip.Length) {
225 return fmt.Errorf("Invalid IP header length > IP length (%d > %d)", ip.IHL, ip.Length)
226 }
227 if cmp := len(data) - int(ip.Length); cmp > 0 {
228 data = data[:ip.Length]
229 } else if cmp < 0 {
230 df.SetTruncated()
231 if int(ip.IHL)*4 > len(data) {
232 return errors.New("Not all IP header bytes available")
233 }
234 }
235 ip.Contents = data[:ip.IHL*4]
236 ip.Payload = data[ip.IHL*4:]
237 // From here on, data contains the header options.
238 data = data[20 : ip.IHL*4]
239 // Pull out IP options
240 for len(data) > 0 {
241 if ip.Options == nil {
242 // Pre-allocate to avoid growing the slice too much.
243 ip.Options = make([]IPv4Option, 0, 4)
244 }
245 opt := IPv4Option{OptionType: data[0]}
246 switch opt.OptionType {
247 case 0: // End of options
248 opt.OptionLength = 1
249 ip.Options = append(ip.Options, opt)
250 ip.Padding = data[1:]
251 return nil
252 case 1: // 1 byte padding
253 opt.OptionLength = 1
254 data = data[1:]
255 ip.Options = append(ip.Options, opt)
256 default:
257 if len(data) < 2 {
258 df.SetTruncated()
259 return fmt.Errorf("Invalid ip4 option length. Length %d less than 2", len(data))
260 }
261 opt.OptionLength = data[1]
262 if len(data) < int(opt.OptionLength) {
263 df.SetTruncated()
264 return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength)
265 }
266 if opt.OptionLength <= 2 {
267 return fmt.Errorf("Invalid IP option type %v length %d. Must be greater than 2", opt.OptionType, opt.OptionLength)
268 }
269 opt.OptionData = data[2:opt.OptionLength]
270 data = data[opt.OptionLength:]
271 ip.Options = append(ip.Options, opt)
272 }
273 }
274 return nil
275}
276
277func (i *IPv4) CanDecode() gopacket.LayerClass {
278 return LayerTypeIPv4
279}
280
281func (i *IPv4) NextLayerType() gopacket.LayerType {
282 if i.Flags&IPv4MoreFragments != 0 || i.FragOffset != 0 {
283 return gopacket.LayerTypeFragment
284 }
285 return i.Protocol.LayerType()
286}
287
288func decodeIPv4(data []byte, p gopacket.PacketBuilder) error {
289 ip := &IPv4{}
290 err := ip.DecodeFromBytes(data, p)
291 p.AddLayer(ip)
292 p.SetNetworkLayer(ip)
293 if err != nil {
294 return err
295 }
296 return p.NextDecoder(ip.NextLayerType())
297}
298
299func checkIPv4Address(addr net.IP) (net.IP, error) {
300 if c := addr.To4(); c != nil {
301 return c, nil
302 }
303 if len(addr) == net.IPv6len {
304 return nil, errors.New("address is IPv6")
305 }
306 return nil, fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv4len)
307}
308
309func (ip *IPv4) AddressTo4() error {
310 var src, dst net.IP
311
312 if addr, err := checkIPv4Address(ip.SrcIP); err != nil {
313 return fmt.Errorf("Invalid source IPv4 address (%s)", err)
314 } else {
315 src = addr
316 }
317 if addr, err := checkIPv4Address(ip.DstIP); err != nil {
318 return fmt.Errorf("Invalid destination IPv4 address (%s)", err)
319 } else {
320 dst = addr
321 }
322 ip.SrcIP = src
323 ip.DstIP = dst
324 return nil
325}