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  }