github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/tcpip/header/ipv6.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  	"strings"
    20  
    21  	"github.com/google/netstack/tcpip"
    22  )
    23  
    24  const (
    25  	versTCFL = 0
    26  	// IPv6PayloadLenOffset is the offset of the PayloadLength field in
    27  	// IPv6 header.
    28  	IPv6PayloadLenOffset = 4
    29  	nextHdr              = 6
    30  	hopLimit             = 7
    31  	v6SrcAddr            = 8
    32  	v6DstAddr            = v6SrcAddr + IPv6AddressSize
    33  )
    34  
    35  // IPv6Fields contains the fields of an IPv6 packet. It is used to describe the
    36  // fields of a packet that needs to be encoded.
    37  type IPv6Fields struct {
    38  	// TrafficClass is the "traffic class" field of an IPv6 packet.
    39  	TrafficClass uint8
    40  
    41  	// FlowLabel is the "flow label" field of an IPv6 packet.
    42  	FlowLabel uint32
    43  
    44  	// PayloadLength is the "payload length" field of an IPv6 packet.
    45  	PayloadLength uint16
    46  
    47  	// NextHeader is the "next header" field of an IPv6 packet.
    48  	NextHeader uint8
    49  
    50  	// HopLimit is the "hop limit" field of an IPv6 packet.
    51  	HopLimit uint8
    52  
    53  	// SrcAddr is the "source ip address" of an IPv6 packet.
    54  	SrcAddr tcpip.Address
    55  
    56  	// DstAddr is the "destination ip address" of an IPv6 packet.
    57  	DstAddr tcpip.Address
    58  }
    59  
    60  // IPv6 represents an ipv6 header stored in a byte array.
    61  // Most of the methods of IPv6 access to the underlying slice without
    62  // checking the boundaries and could panic because of 'index out of range'.
    63  // Always call IsValid() to validate an instance of IPv6 before using other methods.
    64  type IPv6 []byte
    65  
    66  const (
    67  	// IPv6MinimumSize is the minimum size of a valid IPv6 packet.
    68  	IPv6MinimumSize = 40
    69  
    70  	// IPv6AddressSize is the size, in bytes, of an IPv6 address.
    71  	IPv6AddressSize = 16
    72  
    73  	// IPv6ProtocolNumber is IPv6's network protocol number.
    74  	IPv6ProtocolNumber tcpip.NetworkProtocolNumber = 0x86dd
    75  
    76  	// IPv6Version is the version of the ipv6 protocol.
    77  	IPv6Version = 6
    78  
    79  	// IPv6AllNodesMulticastAddress is a link-local multicast group that
    80  	// all IPv6 nodes MUST join, as per RFC 4291, section 2.8. Packets
    81  	// destined to this address will reach all nodes on a link.
    82  	//
    83  	// The address is ff02::1.
    84  	IPv6AllNodesMulticastAddress tcpip.Address = "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
    85  
    86  	// IPv6MinimumMTU is the minimum MTU required by IPv6, per RFC 2460,
    87  	// section 5.
    88  	IPv6MinimumMTU = 1280
    89  
    90  	// IPv6Any is the non-routable IPv6 "any" meta address. It is also
    91  	// known as the unspecified address.
    92  	IPv6Any tcpip.Address = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    93  )
    94  
    95  // IPv6EmptySubnet is the empty IPv6 subnet. It may also be known as the
    96  // catch-all or wildcard subnet. That is, all IPv6 addresses are considered to
    97  // be contained within this subnet.
    98  var IPv6EmptySubnet = func() tcpip.Subnet {
    99  	subnet, err := tcpip.NewSubnet(IPv6Any, tcpip.AddressMask(IPv6Any))
   100  	if err != nil {
   101  		panic(err)
   102  	}
   103  	return subnet
   104  }()
   105  
   106  // IPv6LinkLocalPrefix is the prefix for IPv6 link-local addresses, as defined
   107  // by RFC 4291 section 2.5.6.
   108  //
   109  // The prefix is fe80::/64
   110  var IPv6LinkLocalPrefix = tcpip.AddressWithPrefix{
   111  	Address:   "\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
   112  	PrefixLen: 64,
   113  }
   114  
   115  // PayloadLength returns the value of the "payload length" field of the ipv6
   116  // header.
   117  func (b IPv6) PayloadLength() uint16 {
   118  	return binary.BigEndian.Uint16(b[IPv6PayloadLenOffset:])
   119  }
   120  
   121  // HopLimit returns the value of the "hop limit" field of the ipv6 header.
   122  func (b IPv6) HopLimit() uint8 {
   123  	return b[hopLimit]
   124  }
   125  
   126  // NextHeader returns the value of the "next header" field of the ipv6 header.
   127  func (b IPv6) NextHeader() uint8 {
   128  	return b[nextHdr]
   129  }
   130  
   131  // TransportProtocol implements Network.TransportProtocol.
   132  func (b IPv6) TransportProtocol() tcpip.TransportProtocolNumber {
   133  	return tcpip.TransportProtocolNumber(b.NextHeader())
   134  }
   135  
   136  // Payload implements Network.Payload.
   137  func (b IPv6) Payload() []byte {
   138  	return b[IPv6MinimumSize:][:b.PayloadLength()]
   139  }
   140  
   141  // SourceAddress returns the "source address" field of the ipv6 header.
   142  func (b IPv6) SourceAddress() tcpip.Address {
   143  	return tcpip.Address(b[v6SrcAddr:][:IPv6AddressSize])
   144  }
   145  
   146  // DestinationAddress returns the "destination address" field of the ipv6
   147  // header.
   148  func (b IPv6) DestinationAddress() tcpip.Address {
   149  	return tcpip.Address(b[v6DstAddr:][:IPv6AddressSize])
   150  }
   151  
   152  // Checksum implements Network.Checksum. Given that IPv6 doesn't have a
   153  // checksum, it just returns 0.
   154  func (IPv6) Checksum() uint16 {
   155  	return 0
   156  }
   157  
   158  // TOS returns the "traffic class" and "flow label" fields of the ipv6 header.
   159  func (b IPv6) TOS() (uint8, uint32) {
   160  	v := binary.BigEndian.Uint32(b[versTCFL:])
   161  	return uint8(v >> 20), v & 0xfffff
   162  }
   163  
   164  // SetTOS sets the "traffic class" and "flow label" fields of the ipv6 header.
   165  func (b IPv6) SetTOS(t uint8, l uint32) {
   166  	vtf := (6 << 28) | (uint32(t) << 20) | (l & 0xfffff)
   167  	binary.BigEndian.PutUint32(b[versTCFL:], vtf)
   168  }
   169  
   170  // SetPayloadLength sets the "payload length" field of the ipv6 header.
   171  func (b IPv6) SetPayloadLength(payloadLength uint16) {
   172  	binary.BigEndian.PutUint16(b[IPv6PayloadLenOffset:], payloadLength)
   173  }
   174  
   175  // SetSourceAddress sets the "source address" field of the ipv6 header.
   176  func (b IPv6) SetSourceAddress(addr tcpip.Address) {
   177  	copy(b[v6SrcAddr:][:IPv6AddressSize], addr)
   178  }
   179  
   180  // SetDestinationAddress sets the "destination address" field of the ipv6
   181  // header.
   182  func (b IPv6) SetDestinationAddress(addr tcpip.Address) {
   183  	copy(b[v6DstAddr:][:IPv6AddressSize], addr)
   184  }
   185  
   186  // SetNextHeader sets the value of the "next header" field of the ipv6 header.
   187  func (b IPv6) SetNextHeader(v uint8) {
   188  	b[nextHdr] = v
   189  }
   190  
   191  // SetChecksum implements Network.SetChecksum. Given that IPv6 doesn't have a
   192  // checksum, it is empty.
   193  func (IPv6) SetChecksum(uint16) {
   194  }
   195  
   196  // Encode encodes all the fields of the ipv6 header.
   197  func (b IPv6) Encode(i *IPv6Fields) {
   198  	b.SetTOS(i.TrafficClass, i.FlowLabel)
   199  	b.SetPayloadLength(i.PayloadLength)
   200  	b[nextHdr] = i.NextHeader
   201  	b[hopLimit] = i.HopLimit
   202  	b.SetSourceAddress(i.SrcAddr)
   203  	b.SetDestinationAddress(i.DstAddr)
   204  }
   205  
   206  // IsValid performs basic validation on the packet.
   207  func (b IPv6) IsValid(pktSize int) bool {
   208  	if len(b) < IPv6MinimumSize {
   209  		return false
   210  	}
   211  
   212  	dlen := int(b.PayloadLength())
   213  	if dlen > pktSize-IPv6MinimumSize {
   214  		return false
   215  	}
   216  
   217  	if IPVersion(b) != IPv6Version {
   218  		return false
   219  	}
   220  
   221  	return true
   222  }
   223  
   224  // IsV4MappedAddress determines if the provided address is an IPv4 mapped
   225  // address by checking if its prefix is 0:0:0:0:0:ffff::/96.
   226  func IsV4MappedAddress(addr tcpip.Address) bool {
   227  	if len(addr) != IPv6AddressSize {
   228  		return false
   229  	}
   230  
   231  	return strings.HasPrefix(string(addr), "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff")
   232  }
   233  
   234  // IsV6MulticastAddress determines if the provided address is an IPv6
   235  // multicast address (anything starting with FF).
   236  func IsV6MulticastAddress(addr tcpip.Address) bool {
   237  	if len(addr) != IPv6AddressSize {
   238  		return false
   239  	}
   240  	return addr[0] == 0xff
   241  }
   242  
   243  // IsV6UnicastAddress determines if the provided address is a valid IPv6
   244  // unicast (and specified) address. That is, IsV6UnicastAddress returns
   245  // true if addr contains IPv6AddressSize bytes, is not the unspecified
   246  // address and is not a multicast address.
   247  func IsV6UnicastAddress(addr tcpip.Address) bool {
   248  	if len(addr) != IPv6AddressSize {
   249  		return false
   250  	}
   251  
   252  	// Must not be unspecified
   253  	if addr == IPv6Any {
   254  		return false
   255  	}
   256  
   257  	// Return if not a multicast.
   258  	return addr[0] != 0xff
   259  }
   260  
   261  // SolicitedNodeAddr computes the solicited-node multicast address. This is
   262  // used for NDP. Described in RFC 4291. The argument must be a full-length IPv6
   263  // address.
   264  func SolicitedNodeAddr(addr tcpip.Address) tcpip.Address {
   265  	const solicitedNodeMulticastPrefix = "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff"
   266  	return solicitedNodeMulticastPrefix + addr[len(addr)-3:]
   267  }
   268  
   269  // LinkLocalAddr computes the default IPv6 link-local address from a link-layer
   270  // (MAC) address.
   271  func LinkLocalAddr(linkAddr tcpip.LinkAddress) tcpip.Address {
   272  	// Convert a 48-bit MAC to an EUI-64 and then prepend the link-local
   273  	// header, FE80::.
   274  	//
   275  	// The conversion is very nearly:
   276  	//	aa:bb:cc:dd:ee:ff => FE80::Aabb:ccFF:FEdd:eeff
   277  	// Note the capital A. The conversion aa->Aa involves a bit flip.
   278  	lladdrb := [16]byte{
   279  		0:  0xFE,
   280  		1:  0x80,
   281  		8:  linkAddr[0] ^ 2,
   282  		9:  linkAddr[1],
   283  		10: linkAddr[2],
   284  		11: 0xFF,
   285  		12: 0xFE,
   286  		13: linkAddr[3],
   287  		14: linkAddr[4],
   288  		15: linkAddr[5],
   289  	}
   290  	return tcpip.Address(lladdrb[:])
   291  }
   292  
   293  // IsV6LinkLocalAddress determines if the provided address is an IPv6
   294  // link-local address (fe80::/10).
   295  func IsV6LinkLocalAddress(addr tcpip.Address) bool {
   296  	if len(addr) != IPv6AddressSize {
   297  		return false
   298  	}
   299  	return addr[0] == 0xfe && (addr[1]&0xc0) == 0x80
   300  }