1 // Copyright 2012 Google, Inc. All rights reserved.
2 // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
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
17 "github.com/google/gopacket"
23 IPv4EvilBit IPv4Flag = 1 << 2 // http://tools.ietf.org/html/rfc3514 ;)
24 IPv4DontFragment IPv4Flag = 1 << 1
25 IPv4MoreFragments IPv4Flag = 1 << 0
28 func (f IPv4Flag) String() string {
30 if f&IPv4EvilBit != 0 {
33 if f&IPv4DontFragment != 0 {
36 if f&IPv4MoreFragments != 0 {
39 return strings.Join(s, "|")
42 // IPv4 is the header of an IP packet.
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)
67 type IPv4Option struct {
73 func (i IPv4Option) String() string {
74 return fmt.Sprintf("IPv4Option(%v:%v)", i.OptionType, i.OptionData)
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 {
84 // this is the end of option lists
87 // this is the padding
90 optionSize += opt.OptionLength
94 // make sure the options are aligned to 32 bit boundary
95 if (optionSize % 4) != 0 {
96 optionSize += 4 - (optionSize % 4)
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))
110 ip.IHL = 5 + (optionLength / 4)
111 ip.Length = uint16(len(b.Bytes()))
113 bytes[0] = (ip.Version << 4) | ip.IHL
115 binary.BigEndian.PutUint16(bytes[2:], ip.Length)
116 binary.BigEndian.PutUint16(bytes[4:], ip.Id)
117 binary.BigEndian.PutUint16(bytes[6:], ip.flagsfrags())
119 bytes[9] = byte(ip.Protocol)
120 if err := ip.AddressTo4(); err != nil {
123 copy(bytes[12:16], ip.SrcIP)
124 copy(bytes[16:20], ip.DstIP)
127 // Now, we will encode the options
128 for _, opt := range ip.Options {
129 switch opt.OptionType {
131 // this is the end of option lists
132 bytes[curLocation] = 0
135 // this is the padding
136 bytes[curLocation] = 1
139 bytes[curLocation] = opt.OptionType
140 bytes[curLocation+1] = opt.OptionLength
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")
146 copy(bytes[curLocation+2:curLocation+int(opt.OptionLength)], opt.OptionData)
147 curLocation += int(opt.OptionLength)
151 if opts.ComputeChecksums {
152 ip.Checksum = checksum(bytes)
154 binary.BigEndian.PutUint16(bytes[10:], ip.Checksum)
158 func checksum(bytes []byte) uint16 {
159 // Clear checksum bytes
165 for i := 0; i < len(bytes); i += 2 {
166 csum += uint32(bytes[i]) << 8
167 csum += uint32(bytes[i+1])
170 // Break when sum is less or equals to 0xFFFF
174 // Add carry to the sum
175 csum = (csum >> 16) + uint32(uint16(csum))
181 func (ip *IPv4) flagsfrags() (ff uint16) {
182 ff |= uint16(ip.Flags) << 13
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])
191 ip.Version = uint8(data[0]) >> 4
192 ip.IHL = uint8(data[0]) & 0x0F
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
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}
207 // This code is added for the following enviroment:
208 // * Windows 10 with TSO option activated. ( tested on Hyper-V, RealTek ethernet driver )
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))
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)
222 if cmp := len(data) - int(ip.Length); cmp > 0 {
223 data = data[:ip.Length]
226 if int(ip.IHL)*4 > len(data) {
227 return errors.New("Not all IP header bytes available")
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
236 if ip.Options == nil {
237 // Pre-allocate to avoid growing the slice too much.
238 ip.Options = make([]IPv4Option, 0, 4)
240 opt := IPv4Option{OptionType: data[0]}
241 switch opt.OptionType {
242 case 0: // End of options
244 ip.Options = append(ip.Options, opt)
245 ip.Padding = data[1:]
247 case 1: // 1 byte padding
250 opt.OptionLength = data[1]
251 opt.OptionData = data[2:opt.OptionLength]
253 if len(data) >= int(opt.OptionLength) {
254 data = data[opt.OptionLength:]
256 return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength)
258 ip.Options = append(ip.Options, opt)
263 func (i *IPv4) CanDecode() gopacket.LayerClass {
267 func (i *IPv4) NextLayerType() gopacket.LayerType {
268 if i.Flags&IPv4MoreFragments != 0 || i.FragOffset != 0 {
269 return gopacket.LayerTypeFragment
271 return i.Protocol.LayerType()
274 func decodeIPv4(data []byte, p gopacket.PacketBuilder) error {
276 err := ip.DecodeFromBytes(data, p)
278 p.SetNetworkLayer(ip)
282 return p.NextDecoder(ip.NextLayerType())
285 func checkIPv4Address(addr net.IP) (net.IP, error) {
286 if c := addr.To4(); c != nil {
289 if len(addr) == net.IPv6len {
290 return nil, errors.New("address is IPv6")
292 return nil, fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv4len)
295 func (ip *IPv4) AddressTo4() error {
298 if addr, err := checkIPv4Address(ip.SrcIP); err != nil {
299 return fmt.Errorf("Invalid source IPv4 address (%s)", err)
303 if addr, err := checkIPv4Address(ip.DstIP); err != nil {
304 return fmt.Errorf("Invalid destination IPv4 address (%s)", err)