github.com/polevpn/netstack@v1.10.9/tcpip/header/ndp_options.go (about)

     1  // Copyright 2019 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  	"errors"
    20  	"time"
    21  
    22  	"github.com/polevpn/netstack/tcpip"
    23  )
    24  
    25  const (
    26  	// NDPTargetLinkLayerAddressOptionType is the type of the Target
    27  	// Link-Layer Address option, as per RFC 4861 section 4.6.1.
    28  	NDPTargetLinkLayerAddressOptionType = 2
    29  
    30  	// ndpTargetEthernetLinkLayerAddressSize is the size of a Target
    31  	// Link Layer Option for an Ethernet address.
    32  	ndpTargetEthernetLinkLayerAddressSize = 8
    33  
    34  	// NDPPrefixInformationType is the type of the Prefix Information
    35  	// option, as per RFC 4861 section 4.6.2.
    36  	NDPPrefixInformationType = 3
    37  
    38  	// ndpPrefixInformationLength is the expected length, in bytes, of the
    39  	// body of an NDP Prefix Information option, as per RFC 4861 section
    40  	// 4.6.2 which specifies that the Length field is 4. Given this, the
    41  	// expected length, in bytes, is 30 becuase 4 * lengthByteUnits (8) - 2
    42  	// (Type & Length) = 30.
    43  	ndpPrefixInformationLength = 30
    44  
    45  	// ndpPrefixInformationPrefixLengthOffset is the offset of the Prefix
    46  	// Length field within an NDPPrefixInformation.
    47  	ndpPrefixInformationPrefixLengthOffset = 0
    48  
    49  	// ndpPrefixInformationFlagsOffset is the offset of the flags byte
    50  	// within an NDPPrefixInformation.
    51  	ndpPrefixInformationFlagsOffset = 1
    52  
    53  	// ndpPrefixInformationOnLinkFlagMask is the mask of the On-Link Flag
    54  	// field in the flags byte within an NDPPrefixInformation.
    55  	ndpPrefixInformationOnLinkFlagMask = (1 << 7)
    56  
    57  	// ndpPrefixInformationAutoAddrConfFlagMask is the mask of the
    58  	// Autonomous Address-Configuration flag field in the flags byte within
    59  	// an NDPPrefixInformation.
    60  	ndpPrefixInformationAutoAddrConfFlagMask = (1 << 6)
    61  
    62  	// ndpPrefixInformationReserved1FlagsMask is the mask of the Reserved1
    63  	// field in the flags byte within an NDPPrefixInformation.
    64  	ndpPrefixInformationReserved1FlagsMask = 63
    65  
    66  	// ndpPrefixInformationValidLifetimeOffset is the start of the 4-byte
    67  	// Valid Lifetime field within an NDPPrefixInformation.
    68  	ndpPrefixInformationValidLifetimeOffset = 2
    69  
    70  	// ndpPrefixInformationPreferredLifetimeOffset is the start of the
    71  	// 4-byte Preferred Lifetime field within an NDPPrefixInformation.
    72  	ndpPrefixInformationPreferredLifetimeOffset = 6
    73  
    74  	// ndpPrefixInformationReserved2Offset is the start of the 4-byte
    75  	// Reserved2 field within an NDPPrefixInformation.
    76  	ndpPrefixInformationReserved2Offset = 10
    77  
    78  	// ndpPrefixInformationReserved2Length is the length of the Reserved2
    79  	// field.
    80  	//
    81  	// It is 4 bytes.
    82  	ndpPrefixInformationReserved2Length = 4
    83  
    84  	// ndpPrefixInformationPrefixOffset is the start of the Prefix field
    85  	// within an NDPPrefixInformation.
    86  	ndpPrefixInformationPrefixOffset = 14
    87  
    88  	// lengthByteUnits is the multiplier factor for the Length field of an
    89  	// NDP option. That is, the length field for NDP options is in units of
    90  	// 8 octets, as per RFC 4861 section 4.6.
    91  	lengthByteUnits = 8
    92  )
    93  
    94  var (
    95  	// NDPPrefixInformationInfiniteLifetime is a value that represents
    96  	// infinity for the Valid and Preferred Lifetime fields in a NDP Prefix
    97  	// Information option. Its value is (2^32 - 1)s = 4294967295s
    98  	//
    99  	// This is a variable instead of a constant so that tests can change
   100  	// this value to a smaller value. It should only be modified by tests.
   101  	NDPPrefixInformationInfiniteLifetime = time.Second * 4294967295
   102  )
   103  
   104  // NDPOptionIterator is an iterator of NDPOption.
   105  //
   106  // Note, between when an NDPOptionIterator is obtained and last used, no changes
   107  // to the NDPOptions may happen. Doing so may cause undefined and unexpected
   108  // behaviour. It is fine to obtain an NDPOptionIterator, iterate over the first
   109  // few NDPOption then modify the backing NDPOptions so long as the
   110  // NDPOptionIterator obtained before modification is no longer used.
   111  type NDPOptionIterator struct {
   112  	// The NDPOptions this NDPOptionIterator is iterating over.
   113  	opts NDPOptions
   114  }
   115  
   116  // Potential errors when iterating over an NDPOptions.
   117  var (
   118  	ErrNDPOptBufExhausted  = errors.New("Buffer unexpectedly exhausted")
   119  	ErrNDPOptZeroLength    = errors.New("NDP option has zero-valued Length field")
   120  	ErrNDPOptMalformedBody = errors.New("NDP option has a malformed body")
   121  )
   122  
   123  // Next returns the next element in the backing NDPOptions, or true if we are
   124  // done, or false if an error occured.
   125  //
   126  // The return can be read as option, done, error. Note, option should only be
   127  // used if done is false and error is nil.
   128  func (i *NDPOptionIterator) Next() (NDPOption, bool, error) {
   129  	for {
   130  		// Do we still have elements to look at?
   131  		if len(i.opts) == 0 {
   132  			return nil, true, nil
   133  		}
   134  
   135  		// Do we have enough bytes for an NDP option that has a Length
   136  		// field of at least 1? Note, 0 in the Length field is invalid.
   137  		if len(i.opts) < lengthByteUnits {
   138  			return nil, true, ErrNDPOptBufExhausted
   139  		}
   140  
   141  		// Get the Type field.
   142  		t := i.opts[0]
   143  
   144  		// Get the Length field.
   145  		l := i.opts[1]
   146  
   147  		// This would indicate an erroneous NDP option as the Length
   148  		// field should never be 0.
   149  		if l == 0 {
   150  			return nil, true, ErrNDPOptZeroLength
   151  		}
   152  
   153  		// How many bytes are in the option body?
   154  		numBytes := int(l) * lengthByteUnits
   155  		numBodyBytes := numBytes - 2
   156  
   157  		potentialBody := i.opts[2:]
   158  
   159  		// This would indicate an erroenous NDPOptions buffer as we ran
   160  		// out of the buffer in the middle of an NDP option.
   161  		if left := len(potentialBody); left < numBodyBytes {
   162  			return nil, true, ErrNDPOptBufExhausted
   163  		}
   164  
   165  		// Get only the options body, leaving the rest of the options
   166  		// buffer alone.
   167  		body := potentialBody[:numBodyBytes]
   168  
   169  		// Update opts with the remaining options body.
   170  		i.opts = i.opts[numBytes:]
   171  
   172  		switch t {
   173  		case NDPTargetLinkLayerAddressOptionType:
   174  			return NDPTargetLinkLayerAddressOption(body), false, nil
   175  
   176  		case NDPPrefixInformationType:
   177  			// Make sure the length of a Prefix Information option
   178  			// body is ndpPrefixInformationLength, as per RFC 4861
   179  			// section 4.6.2.
   180  			if numBodyBytes != ndpPrefixInformationLength {
   181  				return nil, true, ErrNDPOptMalformedBody
   182  			}
   183  
   184  			return NDPPrefixInformation(body), false, nil
   185  		default:
   186  			// We do not yet recognize the option, just skip for
   187  			// now. This is okay because RFC 4861 allows us to
   188  			// skip/ignore any unrecognized options. However,
   189  			// we MUST recognized all the options in RFC 4861.
   190  			//
   191  			// TODO(b/141487990): Handle all NDP options as defined
   192  			//                    by RFC 4861.
   193  		}
   194  	}
   195  }
   196  
   197  // NDPOptions is a buffer of NDP options as defined by RFC 4861 section 4.6.
   198  type NDPOptions []byte
   199  
   200  // Iter returns an iterator of NDPOption.
   201  //
   202  // If check is true, Iter will do an integrity check on the options by iterating
   203  // over it and returning an error if detected.
   204  //
   205  // See NDPOptionIterator for more information.
   206  func (b NDPOptions) Iter(check bool) (NDPOptionIterator, error) {
   207  	it := NDPOptionIterator{opts: b}
   208  
   209  	if check {
   210  		for it2 := it; true; {
   211  			if _, done, err := it2.Next(); err != nil || done {
   212  				return it, err
   213  			}
   214  		}
   215  	}
   216  
   217  	return it, nil
   218  }
   219  
   220  // Serialize serializes the provided list of NDP options into o.
   221  //
   222  // Note, b must be of sufficient size to hold all the options in s. See
   223  // NDPOptionsSerializer.Length for details on the getting the total size
   224  // of a serialized NDPOptionsSerializer.
   225  //
   226  // Serialize may panic if b is not of sufficient size to hold all the options
   227  // in s.
   228  func (b NDPOptions) Serialize(s NDPOptionsSerializer) int {
   229  	done := 0
   230  
   231  	for _, o := range s {
   232  		l := paddedLength(o)
   233  
   234  		if l == 0 {
   235  			continue
   236  		}
   237  
   238  		b[0] = o.Type()
   239  
   240  		// We know this safe because paddedLength would have returned
   241  		// 0 if o had an invalid length (> 255 * lengthByteUnits).
   242  		b[1] = uint8(l / lengthByteUnits)
   243  
   244  		// Serialize NDP option body.
   245  		used := o.serializeInto(b[2:])
   246  
   247  		// Zero out remaining (padding) bytes, if any exists.
   248  		for i := used + 2; i < l; i++ {
   249  			b[i] = 0
   250  		}
   251  
   252  		b = b[l:]
   253  		done += l
   254  	}
   255  
   256  	return done
   257  }
   258  
   259  // NDPOption is the set of functions to be implemented by all NDP option types.
   260  type NDPOption interface {
   261  	// Type returns the type of the receiver.
   262  	Type() uint8
   263  
   264  	// Length returns the length of the body of the receiver, in bytes.
   265  	Length() int
   266  
   267  	// serializeInto serializes the receiver into the provided byte
   268  	// buffer.
   269  	//
   270  	// Note, the caller MUST provide a byte buffer with size of at least
   271  	// Length. Implementers of this function may assume that the byte buffer
   272  	// is of sufficient size. serializeInto MAY panic if the provided byte
   273  	// buffer is not of sufficient size.
   274  	//
   275  	// serializeInto will return the number of bytes that was used to
   276  	// serialize the receiver. Implementers must only use the number of
   277  	// bytes required to serialize the receiver. Callers MAY provide a
   278  	// larger buffer than required to serialize into.
   279  	serializeInto([]byte) int
   280  }
   281  
   282  // paddedLength returns the length of o, in bytes, with any padding bytes, if
   283  // required.
   284  func paddedLength(o NDPOption) int {
   285  	l := o.Length()
   286  
   287  	if l == 0 {
   288  		return 0
   289  	}
   290  
   291  	// Length excludes the 2 Type and Length bytes.
   292  	l += 2
   293  
   294  	// Add extra bytes if needed to make sure the option is
   295  	// lengthByteUnits-byte aligned. We do this by adding lengthByteUnits-1
   296  	// to l and then stripping off the last few LSBits from l. This will
   297  	// make sure that l is rounded up to the nearest unit of
   298  	// lengthByteUnits. This works since lengthByteUnits is a power of 2
   299  	// (= 8).
   300  	mask := lengthByteUnits - 1
   301  	l += mask
   302  	l &^= mask
   303  
   304  	if l/lengthByteUnits > 255 {
   305  		// Should never happen because an option can only have a max
   306  		// value of 255 for its Length field, so just return 0 so this
   307  		// option does not get serialized.
   308  		//
   309  		// Returning 0 here will make sure that this option does not get
   310  		// serialized when NDPOptions.Serialize is called with the
   311  		// NDPOptionsSerializer that holds this option, effectively
   312  		// skipping this option during serialization. Also note that
   313  		// a value of zero for the Length field in an NDP option is
   314  		// invalid so this is another sign to the caller that this NDP
   315  		// option is malformed, as per RFC 4861 section 4.6.
   316  		return 0
   317  	}
   318  
   319  	return l
   320  }
   321  
   322  // NDPOptionsSerializer is a serializer for NDP options.
   323  type NDPOptionsSerializer []NDPOption
   324  
   325  // Length returns the total number of bytes required to serialize.
   326  func (b NDPOptionsSerializer) Length() int {
   327  	l := 0
   328  
   329  	for _, o := range b {
   330  		l += paddedLength(o)
   331  	}
   332  
   333  	return l
   334  }
   335  
   336  // NDPTargetLinkLayerAddressOption is the NDP Target Link Layer Option
   337  // as defined by RFC 4861 section 4.6.1.
   338  //
   339  // It is the first X bytes following the NDP option's Type and Length field
   340  // where X is the value in Length multiplied by lengthByteUnits - 2 bytes.
   341  type NDPTargetLinkLayerAddressOption tcpip.LinkAddress
   342  
   343  // Type implements NDPOption.Type.
   344  func (o NDPTargetLinkLayerAddressOption) Type() uint8 {
   345  	return NDPTargetLinkLayerAddressOptionType
   346  }
   347  
   348  // Length implements NDPOption.Length.
   349  func (o NDPTargetLinkLayerAddressOption) Length() int {
   350  	return len(o)
   351  }
   352  
   353  // serializeInto implements NDPOption.serializeInto.
   354  func (o NDPTargetLinkLayerAddressOption) serializeInto(b []byte) int {
   355  	return copy(b, o)
   356  }
   357  
   358  // EthernetAddress will return an ethernet (MAC) address if the
   359  // NDPTargetLinkLayerAddressOption's body has at minimum EthernetAddressSize
   360  // bytes. If the body has more than EthernetAddressSize bytes, only the first
   361  // EthernetAddressSize bytes are returned as that is all that is needed for an
   362  // Ethernet address.
   363  func (o NDPTargetLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress {
   364  	if len(o) >= EthernetAddressSize {
   365  		return tcpip.LinkAddress(o[:EthernetAddressSize])
   366  	}
   367  
   368  	return tcpip.LinkAddress([]byte(nil))
   369  }
   370  
   371  // NDPPrefixInformation is the NDP Prefix Information option as defined by
   372  // RFC 4861 section 4.6.2.
   373  //
   374  // The length, in bytes, of a valid NDP Prefix Information option body MUST be
   375  // ndpPrefixInformationLength bytes.
   376  type NDPPrefixInformation []byte
   377  
   378  // Type implements NDPOption.Type.
   379  func (o NDPPrefixInformation) Type() uint8 {
   380  	return NDPPrefixInformationType
   381  }
   382  
   383  // Length implements NDPOption.Length.
   384  func (o NDPPrefixInformation) Length() int {
   385  	return ndpPrefixInformationLength
   386  }
   387  
   388  // serializeInto implements NDPOption.serializeInto.
   389  func (o NDPPrefixInformation) serializeInto(b []byte) int {
   390  	used := copy(b, o)
   391  
   392  	// Zero out the Reserved1 field.
   393  	b[ndpPrefixInformationFlagsOffset] &^= ndpPrefixInformationReserved1FlagsMask
   394  
   395  	// Zero out the Reserved2 field.
   396  	reserved2 := b[ndpPrefixInformationReserved2Offset:][:ndpPrefixInformationReserved2Length]
   397  	for i := range reserved2 {
   398  		reserved2[i] = 0
   399  	}
   400  
   401  	return used
   402  }
   403  
   404  // PrefixLength returns the value in the number of leading bits in the Prefix
   405  // that are valid.
   406  //
   407  // Valid values are in the range [0, 128], but o may not always contain valid
   408  // values. It is up to the caller to valdiate the Prefix Information option.
   409  func (o NDPPrefixInformation) PrefixLength() uint8 {
   410  	return o[ndpPrefixInformationPrefixLengthOffset]
   411  }
   412  
   413  // OnLinkFlag returns true of the prefix is considered on-link. On-link means
   414  // that a forwarding node is not needed to send packets to other nodes on the
   415  // same prefix.
   416  //
   417  // Note, when this function returns false, no statement is made about the
   418  // on-link property of a prefix. That is, if OnLinkFlag returns false, the
   419  // caller MUST NOT conclude that the prefix is off-link and MUST NOT update any
   420  // previously stored state for this prefix about its on-link status.
   421  func (o NDPPrefixInformation) OnLinkFlag() bool {
   422  	return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationOnLinkFlagMask != 0
   423  }
   424  
   425  // AutonomousAddressConfigurationFlag returns true if the prefix can be used for
   426  // Stateless Address Auto-Configuration (as specified in RFC 4862).
   427  func (o NDPPrefixInformation) AutonomousAddressConfigurationFlag() bool {
   428  	return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationAutoAddrConfFlagMask != 0
   429  }
   430  
   431  // ValidLifetime returns the length of time that the prefix is valid for the
   432  // purpose of on-link determination. This value is relative to the send time of
   433  // the packet that the Prefix Information option was present in.
   434  //
   435  // Note, a value of 0 implies the prefix should not be considered as on-link,
   436  // and a value of infinity/forever is represented by
   437  // NDPPrefixInformationInfiniteLifetime.
   438  func (o NDPPrefixInformation) ValidLifetime() time.Duration {
   439  	// The field is the time in seconds, as per RFC 4861 section 4.6.2.
   440  	return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationValidLifetimeOffset:]))
   441  }
   442  
   443  // PreferredLifetime returns the length of time that an address generated from
   444  // the prefix via Stateless Address Auto-Configuration remains preferred. This
   445  // value is relative to the send time of the packet that the Prefix Information
   446  // option was present in.
   447  //
   448  // Note, a value of 0 implies that addresses generated from the prefix should
   449  // no longer remain preferred, and a value of infinity is represented by
   450  // NDPPrefixInformationInfiniteLifetime.
   451  //
   452  // Also note that the value of this field MUST NOT exceed the Valid Lifetime
   453  // field to avoid preferring addresses that are no longer valid, for the
   454  // purpose of Stateless Address Auto-Configuration.
   455  func (o NDPPrefixInformation) PreferredLifetime() time.Duration {
   456  	// The field is the time in seconds, as per RFC 4861 section 4.6.2.
   457  	return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationPreferredLifetimeOffset:]))
   458  }
   459  
   460  // Prefix returns an IPv6 address or a prefix of an IPv6 address. The Prefix
   461  // Length field (see NDPPrefixInformation.PrefixLength) contains the number
   462  // of valid leading bits in the prefix.
   463  //
   464  // Hosts SHOULD ignore an NDP Prefix Information option where the Prefix field
   465  // holds the link-local prefix (fe80::).
   466  func (o NDPPrefixInformation) Prefix() tcpip.Address {
   467  	return tcpip.Address(o[ndpPrefixInformationPrefixOffset:][:IPv6AddressSize])
   468  }
   469  
   470  // Subnet returns the Prefix field and Prefix Length field represented in a
   471  // tcpip.Subnet.
   472  func (o NDPPrefixInformation) Subnet() tcpip.Subnet {
   473  	addrWithPrefix := tcpip.AddressWithPrefix{
   474  		Address:   o.Prefix(),
   475  		PrefixLen: int(o.PrefixLength()),
   476  	}
   477  	return addrWithPrefix.Subnet()
   478  }