github.com/gopacket/gopacket@v1.1.0/layers/ip4.go (about) 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/gopacket/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 if len(data) < 20 { 190 df.SetTruncated() 191 return fmt.Errorf("Invalid ip4 header. Length %d less than 20", len(data)) 192 } 193 194 ip.Length = binary.BigEndian.Uint16(data[2:4]) 195 ip.IHL = uint8(data[0]) & 0x0F 196 197 // This code is added for the following enviroment: 198 // * Windows 10 with TSO option activated. ( tested on Hyper-V, RealTek ethernet driver ) 199 if ip.Length == 0 { 200 // If using TSO(TCP Segmentation Offload), length is zero. 201 // The actual packet length is the length of data. 202 ip.Length = uint16(len(data)) 203 } 204 205 if ip.Length < 20 { 206 return fmt.Errorf("Invalid (too small) IP length (%d < 20)", ip.Length) 207 } else if ip.IHL < 5 { 208 return fmt.Errorf("Invalid (too small) IP header length (%d < 5)", ip.IHL) 209 } else if int(ip.IHL*4) > int(ip.Length) { 210 return fmt.Errorf("Invalid IP header length > IP length (%d > %d)", ip.IHL, ip.Length) 211 } 212 213 if cmp := len(data) - int(ip.Length); cmp > 0 { 214 data = data[:ip.Length] 215 } else if cmp < 0 { 216 df.SetTruncated() 217 if int(ip.IHL)*4 > len(data) { 218 return errors.New("Not all IP header bytes available") 219 } 220 } 221 222 ip.Options = ip.Options[:0] 223 ip.Contents = data[:ip.IHL*4] 224 ip.Payload = data[ip.IHL*4:] 225 226 // From here on, data contains the header options. 227 headerOptionsData := data[20 : ip.IHL*4] 228 // Pull out IP options 229 for len(headerOptionsData) > 0 { 230 if ip.Options == nil { 231 // Pre-allocate to avoid growing the slice too much. 232 ip.Options = make([]IPv4Option, 0, 4) 233 } 234 235 opt := IPv4Option{OptionType: headerOptionsData[0]} 236 switch opt.OptionType { 237 case 0: // End of options 238 opt.OptionLength = 1 239 ip.Options = append(ip.Options, opt) 240 ip.Padding = headerOptionsData[1:] 241 242 return nil 243 case 1: // 1 byte padding 244 opt.OptionLength = 1 245 headerOptionsData = headerOptionsData[1:] 246 ip.Options = append(ip.Options, opt) 247 default: 248 if len(headerOptionsData) < 2 { 249 df.SetTruncated() 250 return fmt.Errorf("Invalid ip4 option length. Length %d less than 2", len(headerOptionsData)) 251 } 252 253 opt.OptionLength = headerOptionsData[1] 254 if len(headerOptionsData) < int(opt.OptionLength) { 255 df.SetTruncated() 256 return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength) 257 } 258 if opt.OptionLength <= 2 { 259 return fmt.Errorf("Invalid IP option type %v length %d. Must be greater than 2", opt.OptionType, opt.OptionLength) 260 } 261 opt.OptionData = headerOptionsData[2:opt.OptionLength] 262 headerOptionsData = headerOptionsData[opt.OptionLength:] 263 ip.Options = append(ip.Options, opt) 264 } 265 } 266 267 flagsfrags := binary.BigEndian.Uint16(data[6:8]) 268 ip.Version = data[0] >> 4 269 ip.TOS = data[1] 270 ip.Id = binary.BigEndian.Uint16(data[4:6]) 271 ip.Flags = IPv4Flag(flagsfrags >> 13) 272 ip.FragOffset = flagsfrags & 0x1FFF 273 ip.TTL = data[8] 274 ip.Protocol = IPProtocol(data[9]) 275 ip.Checksum = binary.BigEndian.Uint16(data[10:12]) 276 ip.SrcIP = data[12:16] 277 ip.DstIP = data[16:20] 278 ip.Padding = nil 279 280 return nil 281 } 282 283 func (i *IPv4) CanDecode() gopacket.LayerClass { 284 return LayerTypeIPv4 285 } 286 287 func (i *IPv4) NextLayerType() gopacket.LayerType { 288 if i.Flags&IPv4MoreFragments != 0 || i.FragOffset != 0 { 289 return gopacket.LayerTypeFragment 290 } 291 return i.Protocol.LayerType() 292 } 293 294 func decodeIPv4(data []byte, p gopacket.PacketBuilder) error { 295 ip := &IPv4{} 296 err := ip.DecodeFromBytes(data, p) 297 p.AddLayer(ip) 298 p.SetNetworkLayer(ip) 299 if err != nil { 300 return err 301 } 302 return p.NextDecoder(ip.NextLayerType()) 303 } 304 305 func checkIPv4Address(addr net.IP) (net.IP, error) { 306 if c := addr.To4(); c != nil { 307 return c, nil 308 } 309 if len(addr) == net.IPv6len { 310 return nil, errors.New("address is IPv6") 311 } 312 return nil, fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv4len) 313 } 314 315 func (ip *IPv4) AddressTo4() error { 316 var src, dst net.IP 317 318 if addr, err := checkIPv4Address(ip.SrcIP); err != nil { 319 return fmt.Errorf("Invalid source IPv4 address (%s)", err) 320 } else { 321 src = addr 322 } 323 if addr, err := checkIPv4Address(ip.DstIP); err != nil { 324 return fmt.Errorf("Invalid destination IPv4 address (%s)", err) 325 } else { 326 dst = addr 327 } 328 ip.SrcIP = src 329 ip.DstIP = dst 330 return nil 331 }