github.com/lightlus/netstack@v1.2.0/tcpip/header/ipv4.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package header
    16  
    17  import (
    18  	"encoding/binary"
    19  
    20  	"github.com/lightlus/netstack/tcpip"
    21  )
    22  
    23  const (
    24  	versIHL = 0
    25  	tos     = 1
    26  	// IPv4TotalLenOffset is the offset of the total length field in the
    27  	// IPv4 header.
    28  	IPv4TotalLenOffset = 2
    29  	id                 = 4
    30  	flagsFO            = 6
    31  	ttl                = 8
    32  	protocol           = 9
    33  	checksum           = 10
    34  	srcAddr            = 12
    35  	dstAddr            = 16
    36  )
    37  
    38  // IPv4Fields contains the fields of an IPv4 packet. It is used to describe the
    39  // fields of a packet that needs to be encoded.
    40  type IPv4Fields struct {
    41  	// IHL is the "internet header length" field of an IPv4 packet.
    42  	IHL uint8
    43  
    44  	// TOS is the "type of service" field of an IPv4 packet.
    45  	TOS uint8
    46  
    47  	// TotalLength is the "total length" field of an IPv4 packet.
    48  	TotalLength uint16
    49  
    50  	// ID is the "identification" field of an IPv4 packet.
    51  	ID uint16
    52  
    53  	// Flags is the "flags" field of an IPv4 packet.
    54  	Flags uint8
    55  
    56  	// FragmentOffset is the "fragment offset" field of an IPv4 packet.
    57  	FragmentOffset uint16
    58  
    59  	// TTL is the "time to live" field of an IPv4 packet.
    60  	TTL uint8
    61  
    62  	// Protocol is the "protocol" field of an IPv4 packet.
    63  	Protocol uint8
    64  
    65  	// Checksum is the "checksum" field of an IPv4 packet.
    66  	Checksum uint16
    67  
    68  	// SrcAddr is the "source ip address" of an IPv4 packet.
    69  	SrcAddr tcpip.Address
    70  
    71  	// DstAddr is the "destination ip address" of an IPv4 packet.
    72  	DstAddr tcpip.Address
    73  }
    74  
    75  // IPv4 represents an ipv4 header stored in a byte array.
    76  // Most of the methods of IPv4 access to the underlying slice without
    77  // checking the boundaries and could panic because of 'index out of range'.
    78  // Always call IsValid() to validate an instance of IPv4 before using other methods.
    79  type IPv4 []byte
    80  
    81  const (
    82  	// IPv4MinimumSize is the minimum size of a valid IPv4 packet.
    83  	IPv4MinimumSize = 20
    84  
    85  	// IPv4MaximumHeaderSize is the maximum size of an IPv4 header. Given
    86  	// that there are only 4 bits to represents the header length in 32-bit
    87  	// units, the header cannot exceed 15*4 = 60 bytes.
    88  	IPv4MaximumHeaderSize = 60
    89  
    90  	// MinIPFragmentPayloadSize is the minimum number of payload bytes that
    91  	// the first fragment must carry when an IPv4 packet is fragmented.
    92  	MinIPFragmentPayloadSize = 8
    93  
    94  	// IPv4AddressSize is the size, in bytes, of an IPv4 address.
    95  	IPv4AddressSize = 4
    96  
    97  	// IPv4ProtocolNumber is IPv4's network protocol number.
    98  	IPv4ProtocolNumber tcpip.NetworkProtocolNumber = 0x0800
    99  
   100  	// IPv4Version is the version of the ipv4 protocol.
   101  	IPv4Version = 4
   102  
   103  	// IPv4Broadcast is the broadcast address of the IPv4 procotol.
   104  	IPv4Broadcast tcpip.Address = "\xff\xff\xff\xff"
   105  
   106  	// IPv4Any is the non-routable IPv4 "any" meta address.
   107  	IPv4Any tcpip.Address = "\x00\x00\x00\x00"
   108  
   109  	// IPv4MinimumProcessableDatagramSize is the minimum size of an IP
   110  	// packet that every IPv4 capable host must be able to
   111  	// process/reassemble.
   112  	IPv4MinimumProcessableDatagramSize = 576
   113  )
   114  
   115  // Flags that may be set in an IPv4 packet.
   116  const (
   117  	IPv4FlagMoreFragments = 1 << iota
   118  	IPv4FlagDontFragment
   119  )
   120  
   121  // IPv4EmptySubnet is the empty IPv4 subnet.
   122  var IPv4EmptySubnet = func() tcpip.Subnet {
   123  	subnet, err := tcpip.NewSubnet(IPv4Any, tcpip.AddressMask(IPv4Any))
   124  	if err != nil {
   125  		panic(err)
   126  	}
   127  	return subnet
   128  }()
   129  
   130  // IPVersion returns the version of IP used in the given packet. It returns -1
   131  // if the packet is not large enough to contain the version field.
   132  func IPVersion(b []byte) int {
   133  	// Length must be at least offset+length of version field.
   134  	if len(b) < versIHL+1 {
   135  		return -1
   136  	}
   137  	return int(b[versIHL] >> 4)
   138  }
   139  
   140  // HeaderLength returns the value of the "header length" field of the ipv4
   141  // header.
   142  func (b IPv4) HeaderLength() uint8 {
   143  	return (b[versIHL] & 0xf) * 4
   144  }
   145  
   146  // ID returns the value of the identifier field of the ipv4 header.
   147  func (b IPv4) ID() uint16 {
   148  	return binary.BigEndian.Uint16(b[id:])
   149  }
   150  
   151  // Protocol returns the value of the protocol field of the ipv4 header.
   152  func (b IPv4) Protocol() uint8 {
   153  	return b[protocol]
   154  }
   155  
   156  // Flags returns the "flags" field of the ipv4 header.
   157  func (b IPv4) Flags() uint8 {
   158  	return uint8(binary.BigEndian.Uint16(b[flagsFO:]) >> 13)
   159  }
   160  
   161  // TTL returns the "TTL" field of the ipv4 header.
   162  func (b IPv4) TTL() uint8 {
   163  	return b[ttl]
   164  }
   165  
   166  // FragmentOffset returns the "fragment offset" field of the ipv4 header.
   167  func (b IPv4) FragmentOffset() uint16 {
   168  	return binary.BigEndian.Uint16(b[flagsFO:]) << 3
   169  }
   170  
   171  // TotalLength returns the "total length" field of the ipv4 header.
   172  func (b IPv4) TotalLength() uint16 {
   173  	return binary.BigEndian.Uint16(b[IPv4TotalLenOffset:])
   174  }
   175  
   176  // Checksum returns the checksum field of the ipv4 header.
   177  func (b IPv4) Checksum() uint16 {
   178  	return binary.BigEndian.Uint16(b[checksum:])
   179  }
   180  
   181  // SourceAddress returns the "source address" field of the ipv4 header.
   182  func (b IPv4) SourceAddress() tcpip.Address {
   183  	return tcpip.Address(b[srcAddr : srcAddr+IPv4AddressSize])
   184  }
   185  
   186  // DestinationAddress returns the "destination address" field of the ipv4
   187  // header.
   188  func (b IPv4) DestinationAddress() tcpip.Address {
   189  	return tcpip.Address(b[dstAddr : dstAddr+IPv4AddressSize])
   190  }
   191  
   192  // TransportProtocol implements Network.TransportProtocol.
   193  func (b IPv4) TransportProtocol() tcpip.TransportProtocolNumber {
   194  	return tcpip.TransportProtocolNumber(b.Protocol())
   195  }
   196  
   197  // Payload implements Network.Payload.
   198  func (b IPv4) Payload() []byte {
   199  	return b[b.HeaderLength():][:b.PayloadLength()]
   200  }
   201  
   202  // PayloadLength returns the length of the payload portion of the ipv4 packet.
   203  func (b IPv4) PayloadLength() uint16 {
   204  	return b.TotalLength() - uint16(b.HeaderLength())
   205  }
   206  
   207  // TOS returns the "type of service" field of the ipv4 header.
   208  func (b IPv4) TOS() (uint8, uint32) {
   209  	return b[tos], 0
   210  }
   211  
   212  // SetTOS sets the "type of service" field of the ipv4 header.
   213  func (b IPv4) SetTOS(v uint8, _ uint32) {
   214  	b[tos] = v
   215  }
   216  
   217  // SetTotalLength sets the "total length" field of the ipv4 header.
   218  func (b IPv4) SetTotalLength(totalLength uint16) {
   219  	binary.BigEndian.PutUint16(b[IPv4TotalLenOffset:], totalLength)
   220  }
   221  
   222  // SetChecksum sets the checksum field of the ipv4 header.
   223  func (b IPv4) SetChecksum(v uint16) {
   224  	binary.BigEndian.PutUint16(b[checksum:], v)
   225  }
   226  
   227  // SetFlagsFragmentOffset sets the "flags" and "fragment offset" fields of the
   228  // ipv4 header.
   229  func (b IPv4) SetFlagsFragmentOffset(flags uint8, offset uint16) {
   230  	v := (uint16(flags) << 13) | (offset >> 3)
   231  	binary.BigEndian.PutUint16(b[flagsFO:], v)
   232  }
   233  
   234  // SetID sets the identification field.
   235  func (b IPv4) SetID(v uint16) {
   236  	binary.BigEndian.PutUint16(b[id:], v)
   237  }
   238  
   239  // SetSourceAddress sets the "source address" field of the ipv4 header.
   240  func (b IPv4) SetSourceAddress(addr tcpip.Address) {
   241  	copy(b[srcAddr:srcAddr+IPv4AddressSize], addr)
   242  }
   243  
   244  // SetDestinationAddress sets the "destination address" field of the ipv4
   245  // header.
   246  func (b IPv4) SetDestinationAddress(addr tcpip.Address) {
   247  	copy(b[dstAddr:dstAddr+IPv4AddressSize], addr)
   248  }
   249  
   250  // CalculateChecksum calculates the checksum of the ipv4 header.
   251  func (b IPv4) CalculateChecksum() uint16 {
   252  	return Checksum(b[:b.HeaderLength()], 0)
   253  }
   254  
   255  // Encode encodes all the fields of the ipv4 header.
   256  func (b IPv4) Encode(i *IPv4Fields) {
   257  	b[versIHL] = (4 << 4) | ((i.IHL / 4) & 0xf)
   258  	b[tos] = i.TOS
   259  	b.SetTotalLength(i.TotalLength)
   260  	binary.BigEndian.PutUint16(b[id:], i.ID)
   261  	b.SetFlagsFragmentOffset(i.Flags, i.FragmentOffset)
   262  	b[ttl] = i.TTL
   263  	b[protocol] = i.Protocol
   264  	b.SetChecksum(i.Checksum)
   265  	copy(b[srcAddr:srcAddr+IPv4AddressSize], i.SrcAddr)
   266  	copy(b[dstAddr:dstAddr+IPv4AddressSize], i.DstAddr)
   267  }
   268  
   269  // EncodePartial updates the total length and checksum fields of ipv4 header,
   270  // taking in the partial checksum, which is the checksum of the header without
   271  // the total length and checksum fields. It is useful in cases when similar
   272  // packets are produced.
   273  func (b IPv4) EncodePartial(partialChecksum, totalLength uint16) {
   274  	b.SetTotalLength(totalLength)
   275  	checksum := Checksum(b[IPv4TotalLenOffset:IPv4TotalLenOffset+2], partialChecksum)
   276  	b.SetChecksum(^checksum)
   277  }
   278  
   279  // IsValid performs basic validation on the packet.
   280  func (b IPv4) IsValid(pktSize int) bool {
   281  	if len(b) < IPv4MinimumSize {
   282  		return false
   283  	}
   284  
   285  	hlen := int(b.HeaderLength())
   286  	tlen := int(b.TotalLength())
   287  	if hlen < IPv4MinimumSize || hlen > tlen || tlen > pktSize {
   288  		return false
   289  	}
   290  
   291  	if IPVersion(b) != IPv4Version {
   292  		return false
   293  	}
   294  
   295  	return true
   296  }
   297  
   298  // IsV4MulticastAddress determines if the provided address is an IPv4 multicast
   299  // address (range 224.0.0.0 to 239.255.255.255). The four most significant bits
   300  // will be 1110 = 0xe0.
   301  func IsV4MulticastAddress(addr tcpip.Address) bool {
   302  	if len(addr) != IPv4AddressSize {
   303  		return false
   304  	}
   305  	return (addr[0] & 0xf0) == 0xe0
   306  }