gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/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  	"bytes"
    19  	"encoding/binary"
    20  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"math"
    24  	"time"
    25  
    26  	"gvisor.dev/gvisor/pkg/tcpip"
    27  )
    28  
    29  // ndpOptionIdentifier is an NDP option type identifier.
    30  type ndpOptionIdentifier uint8
    31  
    32  const (
    33  	// ndpSourceLinkLayerAddressOptionType is the type of the Source Link Layer
    34  	// Address option, as per RFC 4861 section 4.6.1.
    35  	ndpSourceLinkLayerAddressOptionType ndpOptionIdentifier = 1
    36  
    37  	// ndpTargetLinkLayerAddressOptionType is the type of the Target Link Layer
    38  	// Address option, as per RFC 4861 section 4.6.1.
    39  	ndpTargetLinkLayerAddressOptionType ndpOptionIdentifier = 2
    40  
    41  	// ndpPrefixInformationType is the type of the Prefix Information
    42  	// option, as per RFC 4861 section 4.6.2.
    43  	ndpPrefixInformationType ndpOptionIdentifier = 3
    44  
    45  	// ndpNonceOptionType is the type of the Nonce option, as per
    46  	// RFC 3971 section 5.3.2.
    47  	ndpNonceOptionType ndpOptionIdentifier = 14
    48  
    49  	// ndpRecursiveDNSServerOptionType is the type of the Recursive DNS
    50  	// Server option, as per RFC 8106 section 5.1.
    51  	ndpRecursiveDNSServerOptionType ndpOptionIdentifier = 25
    52  
    53  	// ndpDNSSearchListOptionType is the type of the DNS Search List option,
    54  	// as per RFC 8106 section 5.2.
    55  	ndpDNSSearchListOptionType ndpOptionIdentifier = 31
    56  )
    57  
    58  const (
    59  	// NDPLinkLayerAddressSize is the size of a Source or Target Link Layer
    60  	// Address option for an Ethernet address.
    61  	NDPLinkLayerAddressSize = 8
    62  
    63  	// ndpPrefixInformationLength is the expected length, in bytes, of the
    64  	// body of an NDP Prefix Information option, as per RFC 4861 section
    65  	// 4.6.2 which specifies that the Length field is 4. Given this, the
    66  	// expected length, in bytes, is 30 because 4 * lengthByteUnits (8) - 2
    67  	// (Type & Length) = 30.
    68  	ndpPrefixInformationLength = 30
    69  
    70  	// ndpPrefixInformationPrefixLengthOffset is the offset of the Prefix
    71  	// Length field within an NDPPrefixInformation.
    72  	ndpPrefixInformationPrefixLengthOffset = 0
    73  
    74  	// ndpPrefixInformationFlagsOffset is the offset of the flags byte
    75  	// within an NDPPrefixInformation.
    76  	ndpPrefixInformationFlagsOffset = 1
    77  
    78  	// ndpPrefixInformationOnLinkFlagMask is the mask of the On-Link Flag
    79  	// field in the flags byte within an NDPPrefixInformation.
    80  	ndpPrefixInformationOnLinkFlagMask = 1 << 7
    81  
    82  	// ndpPrefixInformationAutoAddrConfFlagMask is the mask of the
    83  	// Autonomous Address-Configuration flag field in the flags byte within
    84  	// an NDPPrefixInformation.
    85  	ndpPrefixInformationAutoAddrConfFlagMask = 1 << 6
    86  
    87  	// ndpPrefixInformationReserved1FlagsMask is the mask of the Reserved1
    88  	// field in the flags byte within an NDPPrefixInformation.
    89  	ndpPrefixInformationReserved1FlagsMask = 63
    90  
    91  	// ndpPrefixInformationValidLifetimeOffset is the start of the 4-byte
    92  	// Valid Lifetime field within an NDPPrefixInformation.
    93  	ndpPrefixInformationValidLifetimeOffset = 2
    94  
    95  	// ndpPrefixInformationPreferredLifetimeOffset is the start of the
    96  	// 4-byte Preferred Lifetime field within an NDPPrefixInformation.
    97  	ndpPrefixInformationPreferredLifetimeOffset = 6
    98  
    99  	// ndpPrefixInformationReserved2Offset is the start of the 4-byte
   100  	// Reserved2 field within an NDPPrefixInformation.
   101  	ndpPrefixInformationReserved2Offset = 10
   102  
   103  	// ndpPrefixInformationReserved2Length is the length of the Reserved2
   104  	// field.
   105  	//
   106  	// It is 4 bytes.
   107  	ndpPrefixInformationReserved2Length = 4
   108  
   109  	// ndpPrefixInformationPrefixOffset is the start of the Prefix field
   110  	// within an NDPPrefixInformation.
   111  	ndpPrefixInformationPrefixOffset = 14
   112  
   113  	// ndpRecursiveDNSServerLifetimeOffset is the start of the 4-byte
   114  	// Lifetime field within an NDPRecursiveDNSServer.
   115  	ndpRecursiveDNSServerLifetimeOffset = 2
   116  
   117  	// ndpRecursiveDNSServerAddressesOffset is the start of the addresses
   118  	// for IPv6 Recursive DNS Servers within an NDPRecursiveDNSServer.
   119  	ndpRecursiveDNSServerAddressesOffset = 6
   120  
   121  	// minNDPRecursiveDNSServerLength is the minimum NDP Recursive DNS Server
   122  	// option's body size when it contains at least one IPv6 address, as per
   123  	// RFC 8106 section 5.3.1.
   124  	minNDPRecursiveDNSServerBodySize = 22
   125  
   126  	// ndpDNSSearchListLifetimeOffset is the start of the 4-byte
   127  	// Lifetime field within an NDPDNSSearchList.
   128  	ndpDNSSearchListLifetimeOffset = 2
   129  
   130  	// ndpDNSSearchListDomainNamesOffset is the start of the DNS search list
   131  	// domain names within an NDPDNSSearchList.
   132  	ndpDNSSearchListDomainNamesOffset = 6
   133  
   134  	// minNDPDNSSearchListBodySize is the minimum NDP DNS Search List option's
   135  	// body size when it contains at least one domain name, as per RFC 8106
   136  	// section 5.3.1.
   137  	minNDPDNSSearchListBodySize = 14
   138  
   139  	// maxDomainNameLabelLength is the maximum length of a domain name
   140  	// label, as per RFC 1035 section 3.1.
   141  	maxDomainNameLabelLength = 63
   142  
   143  	// maxDomainNameLength is the maximum length of a domain name, including
   144  	// label AND label length octet, as per RFC 1035 section 3.1.
   145  	maxDomainNameLength = 255
   146  
   147  	// lengthByteUnits is the multiplier factor for the Length field of an
   148  	// NDP option. That is, the length field for NDP options is in units of
   149  	// 8 octets, as per RFC 4861 section 4.6.
   150  	lengthByteUnits = 8
   151  
   152  	// NDPInfiniteLifetime is a value that represents infinity for the
   153  	// 4-byte lifetime fields found in various NDP options. Its value is
   154  	// (2^32 - 1)s = 4294967295s.
   155  	NDPInfiniteLifetime = time.Second * math.MaxUint32
   156  )
   157  
   158  // NDPOptionIterator is an iterator of NDPOption.
   159  //
   160  // Note, between when an NDPOptionIterator is obtained and last used, no changes
   161  // to the NDPOptions may happen. Doing so may cause undefined and unexpected
   162  // behaviour. It is fine to obtain an NDPOptionIterator, iterate over the first
   163  // few NDPOption then modify the backing NDPOptions so long as the
   164  // NDPOptionIterator obtained before modification is no longer used.
   165  type NDPOptionIterator struct {
   166  	opts *bytes.Buffer
   167  }
   168  
   169  // Potential errors when iterating over an NDPOptions.
   170  var (
   171  	ErrNDPOptMalformedBody   = errors.New("NDP option has a malformed body")
   172  	ErrNDPOptMalformedHeader = errors.New("NDP option has a malformed header")
   173  )
   174  
   175  // Next returns the next element in the backing NDPOptions, or true if we are
   176  // done, or false if an error occurred.
   177  //
   178  // The return can be read as option, done, error. Note, option should only be
   179  // used if done is false and error is nil.
   180  func (i *NDPOptionIterator) Next() (NDPOption, bool, error) {
   181  	for {
   182  		// Do we still have elements to look at?
   183  		if i.opts.Len() == 0 {
   184  			return nil, true, nil
   185  		}
   186  
   187  		// Get the Type field.
   188  		temp, err := i.opts.ReadByte()
   189  		if err != nil {
   190  			if err != io.EOF {
   191  				// ReadByte should only ever return nil or io.EOF.
   192  				panic(fmt.Sprintf("unexpected error when reading the option's Type field: %s", err))
   193  			}
   194  
   195  			// We use io.ErrUnexpectedEOF as exhausting the buffer is unexpected once
   196  			// we start parsing an option; we expect the buffer to contain enough
   197  			// bytes for the whole option.
   198  			return nil, true, fmt.Errorf("unexpectedly exhausted buffer when reading the option's Type field: %w", io.ErrUnexpectedEOF)
   199  		}
   200  		kind := ndpOptionIdentifier(temp)
   201  
   202  		// Get the Length field.
   203  		length, err := i.opts.ReadByte()
   204  		if err != nil {
   205  			if err != io.EOF {
   206  				panic(fmt.Sprintf("unexpected error when reading the option's Length field for %s: %s", kind, err))
   207  			}
   208  
   209  			return nil, true, fmt.Errorf("unexpectedly exhausted buffer when reading the option's Length field for %s: %w", kind, io.ErrUnexpectedEOF)
   210  		}
   211  
   212  		// This would indicate an erroneous NDP option as the Length field should
   213  		// never be 0.
   214  		if length == 0 {
   215  			return nil, true, fmt.Errorf("zero valued Length field for %s: %w", kind, ErrNDPOptMalformedHeader)
   216  		}
   217  
   218  		// Get the body.
   219  		numBytes := int(length) * lengthByteUnits
   220  		numBodyBytes := numBytes - 2
   221  		body := i.opts.Next(numBodyBytes)
   222  		if len(body) < numBodyBytes {
   223  			return nil, true, fmt.Errorf("unexpectedly exhausted buffer when reading the option's Body for %s: %w", kind, io.ErrUnexpectedEOF)
   224  		}
   225  
   226  		switch kind {
   227  		case ndpSourceLinkLayerAddressOptionType:
   228  			return NDPSourceLinkLayerAddressOption(body), false, nil
   229  
   230  		case ndpTargetLinkLayerAddressOptionType:
   231  			return NDPTargetLinkLayerAddressOption(body), false, nil
   232  
   233  		case ndpNonceOptionType:
   234  			return NDPNonceOption(body), false, nil
   235  
   236  		case ndpRouteInformationType:
   237  			if numBodyBytes > ndpRouteInformationMaxLength {
   238  				return nil, true, fmt.Errorf("got %d bytes for NDP Route Information option's body, expected at max %d bytes: %w", numBodyBytes, ndpRouteInformationMaxLength, ErrNDPOptMalformedBody)
   239  			}
   240  			opt := NDPRouteInformation(body)
   241  			if err := opt.hasError(); err != nil {
   242  				return nil, true, err
   243  			}
   244  
   245  			return opt, false, nil
   246  
   247  		case ndpPrefixInformationType:
   248  			// Make sure the length of a Prefix Information option
   249  			// body is ndpPrefixInformationLength, as per RFC 4861
   250  			// section 4.6.2.
   251  			if numBodyBytes != ndpPrefixInformationLength {
   252  				return nil, true, fmt.Errorf("got %d bytes for NDP Prefix Information option's body, expected %d bytes: %w", numBodyBytes, ndpPrefixInformationLength, ErrNDPOptMalformedBody)
   253  			}
   254  
   255  			return NDPPrefixInformation(body), false, nil
   256  
   257  		case ndpRecursiveDNSServerOptionType:
   258  			opt := NDPRecursiveDNSServer(body)
   259  			if err := opt.checkAddresses(); err != nil {
   260  				return nil, true, err
   261  			}
   262  
   263  			return opt, false, nil
   264  
   265  		case ndpDNSSearchListOptionType:
   266  			opt := NDPDNSSearchList(body)
   267  			if err := opt.checkDomainNames(); err != nil {
   268  				return nil, true, err
   269  			}
   270  
   271  			return opt, false, nil
   272  
   273  		default:
   274  			// We do not yet recognize the option, just skip for
   275  			// now. This is okay because RFC 4861 allows us to
   276  			// skip/ignore any unrecognized options. However,
   277  			// we MUST recognized all the options in RFC 4861.
   278  			//
   279  			// TODO(b/141487990): Handle all NDP options as defined
   280  			//                    by RFC 4861.
   281  		}
   282  	}
   283  }
   284  
   285  // NDPOptions is a buffer of NDP options as defined by RFC 4861 section 4.6.
   286  type NDPOptions []byte
   287  
   288  // Iter returns an iterator of NDPOption.
   289  //
   290  // If check is true, Iter will do an integrity check on the options by iterating
   291  // over it and returning an error if detected.
   292  //
   293  // See NDPOptionIterator for more information.
   294  func (b NDPOptions) Iter(check bool) (NDPOptionIterator, error) {
   295  	it := NDPOptionIterator{
   296  		opts: bytes.NewBuffer(b),
   297  	}
   298  
   299  	if check {
   300  		it2 := NDPOptionIterator{
   301  			opts: bytes.NewBuffer(b),
   302  		}
   303  
   304  		for {
   305  			if _, done, err := it2.Next(); err != nil || done {
   306  				return it, err
   307  			}
   308  		}
   309  	}
   310  
   311  	return it, nil
   312  }
   313  
   314  // Serialize serializes the provided list of NDP options into b.
   315  //
   316  // Note, b must be of sufficient size to hold all the options in s. See
   317  // NDPOptionsSerializer.Length for details on the getting the total size
   318  // of a serialized NDPOptionsSerializer.
   319  //
   320  // Serialize may panic if b is not of sufficient size to hold all the options
   321  // in s.
   322  func (b NDPOptions) Serialize(s NDPOptionsSerializer) int {
   323  	done := 0
   324  
   325  	for _, o := range s {
   326  		l := paddedLength(o)
   327  
   328  		if l == 0 {
   329  			continue
   330  		}
   331  
   332  		b[0] = byte(o.kind())
   333  
   334  		// We know this safe because paddedLength would have returned
   335  		// 0 if o had an invalid length (> 255 * lengthByteUnits).
   336  		b[1] = uint8(l / lengthByteUnits)
   337  
   338  		// Serialize NDP option body.
   339  		used := o.serializeInto(b[2:])
   340  
   341  		// Zero out remaining (padding) bytes, if any exists.
   342  		if used+2 < l {
   343  			clear(b[used+2 : l])
   344  		}
   345  
   346  		b = b[l:]
   347  		done += l
   348  	}
   349  
   350  	return done
   351  }
   352  
   353  // NDPOption is the set of functions to be implemented by all NDP option types.
   354  type NDPOption interface {
   355  	fmt.Stringer
   356  
   357  	// kind returns the type of the receiver.
   358  	kind() ndpOptionIdentifier
   359  
   360  	// length returns the length of the body of the receiver, in bytes.
   361  	length() int
   362  
   363  	// serializeInto serializes the receiver into the provided byte
   364  	// buffer.
   365  	//
   366  	// Note, the caller MUST provide a byte buffer with size of at least
   367  	// Length. Implementers of this function may assume that the byte buffer
   368  	// is of sufficient size. serializeInto MAY panic if the provided byte
   369  	// buffer is not of sufficient size.
   370  	//
   371  	// serializeInto will return the number of bytes that was used to
   372  	// serialize the receiver. Implementers must only use the number of
   373  	// bytes required to serialize the receiver. Callers MAY provide a
   374  	// larger buffer than required to serialize into.
   375  	serializeInto([]byte) int
   376  }
   377  
   378  // paddedLength returns the length of o, in bytes, with any padding bytes, if
   379  // required.
   380  func paddedLength(o NDPOption) int {
   381  	l := o.length()
   382  
   383  	if l == 0 {
   384  		return 0
   385  	}
   386  
   387  	// Length excludes the 2 Type and Length bytes.
   388  	l += 2
   389  
   390  	// Add extra bytes if needed to make sure the option is
   391  	// lengthByteUnits-byte aligned. We do this by adding lengthByteUnits-1
   392  	// to l and then stripping off the last few LSBits from l. This will
   393  	// make sure that l is rounded up to the nearest unit of
   394  	// lengthByteUnits. This works since lengthByteUnits is a power of 2
   395  	// (= 8).
   396  	mask := lengthByteUnits - 1
   397  	l += mask
   398  	l &^= mask
   399  
   400  	if l/lengthByteUnits > 255 {
   401  		// Should never happen because an option can only have a max
   402  		// value of 255 for its Length field, so just return 0 so this
   403  		// option does not get serialized.
   404  		//
   405  		// Returning 0 here will make sure that this option does not get
   406  		// serialized when NDPOptions.Serialize is called with the
   407  		// NDPOptionsSerializer that holds this option, effectively
   408  		// skipping this option during serialization. Also note that
   409  		// a value of zero for the Length field in an NDP option is
   410  		// invalid so this is another sign to the caller that this NDP
   411  		// option is malformed, as per RFC 4861 section 4.6.
   412  		return 0
   413  	}
   414  
   415  	return l
   416  }
   417  
   418  // NDPOptionsSerializer is a serializer for NDP options.
   419  type NDPOptionsSerializer []NDPOption
   420  
   421  // Length returns the total number of bytes required to serialize.
   422  func (b NDPOptionsSerializer) Length() int {
   423  	l := 0
   424  
   425  	for _, o := range b {
   426  		l += paddedLength(o)
   427  	}
   428  
   429  	return l
   430  }
   431  
   432  // NDPNonceOption is the NDP Nonce Option as defined by RFC 3971 section 5.3.2.
   433  //
   434  // It is the first X bytes following the NDP option's Type and Length field
   435  // where X is the value in Length multiplied by lengthByteUnits - 2 bytes.
   436  type NDPNonceOption []byte
   437  
   438  // kind implements NDPOption.
   439  func (o NDPNonceOption) kind() ndpOptionIdentifier {
   440  	return ndpNonceOptionType
   441  }
   442  
   443  // length implements NDPOption.
   444  func (o NDPNonceOption) length() int {
   445  	return len(o)
   446  }
   447  
   448  // serializeInto implements NDPOption.
   449  func (o NDPNonceOption) serializeInto(b []byte) int {
   450  	return copy(b, o)
   451  }
   452  
   453  // String implements fmt.Stringer.
   454  func (o NDPNonceOption) String() string {
   455  	return fmt.Sprintf("%T(%x)", o, []byte(o))
   456  }
   457  
   458  // Nonce returns the nonce value this option holds.
   459  func (o NDPNonceOption) Nonce() []byte {
   460  	return o
   461  }
   462  
   463  // NDPSourceLinkLayerAddressOption is the NDP Source Link Layer Option
   464  // as defined by RFC 4861 section 4.6.1.
   465  //
   466  // It is the first X bytes following the NDP option's Type and Length field
   467  // where X is the value in Length multiplied by lengthByteUnits - 2 bytes.
   468  type NDPSourceLinkLayerAddressOption tcpip.LinkAddress
   469  
   470  // kind implements NDPOption.
   471  func (o NDPSourceLinkLayerAddressOption) kind() ndpOptionIdentifier {
   472  	return ndpSourceLinkLayerAddressOptionType
   473  }
   474  
   475  // length implements NDPOption.
   476  func (o NDPSourceLinkLayerAddressOption) length() int {
   477  	return len(o)
   478  }
   479  
   480  // serializeInto implements NDPOption.
   481  func (o NDPSourceLinkLayerAddressOption) serializeInto(b []byte) int {
   482  	return copy(b, o)
   483  }
   484  
   485  // String implements fmt.Stringer.
   486  func (o NDPSourceLinkLayerAddressOption) String() string {
   487  	return fmt.Sprintf("%T(%s)", o, tcpip.LinkAddress(o))
   488  }
   489  
   490  // EthernetAddress will return an ethernet (MAC) address if the
   491  // NDPSourceLinkLayerAddressOption's body has at minimum EthernetAddressSize
   492  // bytes. If the body has more than EthernetAddressSize bytes, only the first
   493  // EthernetAddressSize bytes are returned as that is all that is needed for an
   494  // Ethernet address.
   495  func (o NDPSourceLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress {
   496  	if len(o) >= EthernetAddressSize {
   497  		return tcpip.LinkAddress(o[:EthernetAddressSize])
   498  	}
   499  
   500  	return tcpip.LinkAddress([]byte(nil))
   501  }
   502  
   503  // NDPTargetLinkLayerAddressOption is the NDP Target Link Layer Option
   504  // as defined by RFC 4861 section 4.6.1.
   505  //
   506  // It is the first X bytes following the NDP option's Type and Length field
   507  // where X is the value in Length multiplied by lengthByteUnits - 2 bytes.
   508  type NDPTargetLinkLayerAddressOption tcpip.LinkAddress
   509  
   510  // kind implements NDPOption.
   511  func (o NDPTargetLinkLayerAddressOption) kind() ndpOptionIdentifier {
   512  	return ndpTargetLinkLayerAddressOptionType
   513  }
   514  
   515  // length implements NDPOption.
   516  func (o NDPTargetLinkLayerAddressOption) length() int {
   517  	return len(o)
   518  }
   519  
   520  // serializeInto implements NDPOption.
   521  func (o NDPTargetLinkLayerAddressOption) serializeInto(b []byte) int {
   522  	return copy(b, o)
   523  }
   524  
   525  // String implements fmt.Stringer.
   526  func (o NDPTargetLinkLayerAddressOption) String() string {
   527  	return fmt.Sprintf("%T(%s)", o, tcpip.LinkAddress(o))
   528  }
   529  
   530  // EthernetAddress will return an ethernet (MAC) address if the
   531  // NDPTargetLinkLayerAddressOption's body has at minimum EthernetAddressSize
   532  // bytes. If the body has more than EthernetAddressSize bytes, only the first
   533  // EthernetAddressSize bytes are returned as that is all that is needed for an
   534  // Ethernet address.
   535  func (o NDPTargetLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress {
   536  	if len(o) >= EthernetAddressSize {
   537  		return tcpip.LinkAddress(o[:EthernetAddressSize])
   538  	}
   539  
   540  	return tcpip.LinkAddress([]byte(nil))
   541  }
   542  
   543  // NDPPrefixInformation is the NDP Prefix Information option as defined by
   544  // RFC 4861 section 4.6.2.
   545  //
   546  // The length, in bytes, of a valid NDP Prefix Information option body MUST be
   547  // ndpPrefixInformationLength bytes.
   548  type NDPPrefixInformation []byte
   549  
   550  // kind implements NDPOption.
   551  func (o NDPPrefixInformation) kind() ndpOptionIdentifier {
   552  	return ndpPrefixInformationType
   553  }
   554  
   555  // length implements NDPOption.
   556  func (o NDPPrefixInformation) length() int {
   557  	return ndpPrefixInformationLength
   558  }
   559  
   560  // serializeInto implements NDPOption.
   561  func (o NDPPrefixInformation) serializeInto(b []byte) int {
   562  	used := copy(b, o)
   563  
   564  	// Zero out the Reserved1 field.
   565  	b[ndpPrefixInformationFlagsOffset] &^= ndpPrefixInformationReserved1FlagsMask
   566  
   567  	// Zero out the Reserved2 field.
   568  	reserved2 := b[ndpPrefixInformationReserved2Offset:][:ndpPrefixInformationReserved2Length]
   569  	clear(reserved2)
   570  
   571  	return used
   572  }
   573  
   574  // String implements fmt.Stringer.
   575  func (o NDPPrefixInformation) String() string {
   576  	return fmt.Sprintf("%T(O=%t, A=%t, PL=%s, VL=%s, Prefix=%s)",
   577  		o,
   578  		o.OnLinkFlag(),
   579  		o.AutonomousAddressConfigurationFlag(),
   580  		o.PreferredLifetime(),
   581  		o.ValidLifetime(),
   582  		o.Subnet())
   583  }
   584  
   585  // PrefixLength returns the value in the number of leading bits in the Prefix
   586  // that are valid.
   587  //
   588  // Valid values are in the range [0, 128], but o may not always contain valid
   589  // values. It is up to the caller to valdiate the Prefix Information option.
   590  func (o NDPPrefixInformation) PrefixLength() uint8 {
   591  	return o[ndpPrefixInformationPrefixLengthOffset]
   592  }
   593  
   594  // OnLinkFlag returns true of the prefix is considered on-link. On-link means
   595  // that a forwarding node is not needed to send packets to other nodes on the
   596  // same prefix.
   597  //
   598  // Note, when this function returns false, no statement is made about the
   599  // on-link property of a prefix. That is, if OnLinkFlag returns false, the
   600  // caller MUST NOT conclude that the prefix is off-link and MUST NOT update any
   601  // previously stored state for this prefix about its on-link status.
   602  func (o NDPPrefixInformation) OnLinkFlag() bool {
   603  	return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationOnLinkFlagMask != 0
   604  }
   605  
   606  // AutonomousAddressConfigurationFlag returns true if the prefix can be used for
   607  // Stateless Address Auto-Configuration (as specified in RFC 4862).
   608  func (o NDPPrefixInformation) AutonomousAddressConfigurationFlag() bool {
   609  	return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationAutoAddrConfFlagMask != 0
   610  }
   611  
   612  // ValidLifetime returns the length of time that the prefix is valid for the
   613  // purpose of on-link determination. This value is relative to the send time of
   614  // the packet that the Prefix Information option was present in.
   615  //
   616  // Note, a value of 0 implies the prefix should not be considered as on-link,
   617  // and a value of infinity/forever is represented by
   618  // NDPInfiniteLifetime.
   619  func (o NDPPrefixInformation) ValidLifetime() time.Duration {
   620  	// The field is the time in seconds, as per RFC 4861 section 4.6.2.
   621  	return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationValidLifetimeOffset:]))
   622  }
   623  
   624  // PreferredLifetime returns the length of time that an address generated from
   625  // the prefix via Stateless Address Auto-Configuration remains preferred. This
   626  // value is relative to the send time of the packet that the Prefix Information
   627  // option was present in.
   628  //
   629  // Note, a value of 0 implies that addresses generated from the prefix should
   630  // no longer remain preferred, and a value of infinity is represented by
   631  // NDPInfiniteLifetime.
   632  //
   633  // Also note that the value of this field MUST NOT exceed the Valid Lifetime
   634  // field to avoid preferring addresses that are no longer valid, for the
   635  // purpose of Stateless Address Auto-Configuration.
   636  func (o NDPPrefixInformation) PreferredLifetime() time.Duration {
   637  	// The field is the time in seconds, as per RFC 4861 section 4.6.2.
   638  	return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationPreferredLifetimeOffset:]))
   639  }
   640  
   641  // Prefix returns an IPv6 address or a prefix of an IPv6 address. The Prefix
   642  // Length field (see NDPPrefixInformation.PrefixLength) contains the number
   643  // of valid leading bits in the prefix.
   644  //
   645  // Hosts SHOULD ignore an NDP Prefix Information option where the Prefix field
   646  // holds the link-local prefix (fe80::).
   647  func (o NDPPrefixInformation) Prefix() tcpip.Address {
   648  	return tcpip.AddrFrom16Slice(o[ndpPrefixInformationPrefixOffset:][:IPv6AddressSize])
   649  }
   650  
   651  // Subnet returns the Prefix field and Prefix Length field represented in a
   652  // tcpip.Subnet.
   653  func (o NDPPrefixInformation) Subnet() tcpip.Subnet {
   654  	addrWithPrefix := tcpip.AddressWithPrefix{
   655  		Address:   o.Prefix(),
   656  		PrefixLen: int(o.PrefixLength()),
   657  	}
   658  	return addrWithPrefix.Subnet()
   659  }
   660  
   661  // NDPRecursiveDNSServer is the NDP Recursive DNS Server option, as defined by
   662  // RFC 8106 section 5.1.
   663  //
   664  // To make sure that the option meets its minimum length and does not end in the
   665  // middle of a DNS server's IPv6 address, the length of a valid
   666  // NDPRecursiveDNSServer must meet the following constraint:
   667  //
   668  //	(Length - ndpRecursiveDNSServerAddressesOffset) % IPv6AddressSize == 0
   669  type NDPRecursiveDNSServer []byte
   670  
   671  // Type returns the type of an NDP Recursive DNS Server option.
   672  //
   673  // kind implements NDPOption.
   674  func (NDPRecursiveDNSServer) kind() ndpOptionIdentifier {
   675  	return ndpRecursiveDNSServerOptionType
   676  }
   677  
   678  // length implements NDPOption.
   679  func (o NDPRecursiveDNSServer) length() int {
   680  	return len(o)
   681  }
   682  
   683  // serializeInto implements NDPOption.
   684  func (o NDPRecursiveDNSServer) serializeInto(b []byte) int {
   685  	used := copy(b, o)
   686  
   687  	// Zero out the reserved bytes that are before the Lifetime field.
   688  	clear(b[0:ndpRecursiveDNSServerLifetimeOffset])
   689  
   690  	return used
   691  }
   692  
   693  // String implements fmt.Stringer.
   694  func (o NDPRecursiveDNSServer) String() string {
   695  	lt := o.Lifetime()
   696  	addrs, err := o.Addresses()
   697  	if err != nil {
   698  		return fmt.Sprintf("%T([] valid for %s; err = %s)", o, lt, err)
   699  	}
   700  	return fmt.Sprintf("%T(%s valid for %s)", o, addrs, lt)
   701  }
   702  
   703  // Lifetime returns the length of time that the DNS server addresses
   704  // in this option may be used for name resolution.
   705  //
   706  // Note, a value of 0 implies the addresses should no longer be used,
   707  // and a value of infinity/forever is represented by NDPInfiniteLifetime.
   708  //
   709  // Lifetime may panic if o does not have enough bytes to hold the Lifetime
   710  // field.
   711  func (o NDPRecursiveDNSServer) Lifetime() time.Duration {
   712  	// The field is the time in seconds, as per RFC 8106 section 5.1.
   713  	return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpRecursiveDNSServerLifetimeOffset:]))
   714  }
   715  
   716  // Addresses returns the recursive DNS server IPv6 addresses that may be
   717  // used for name resolution.
   718  //
   719  // Note, the addresses MAY be link-local addresses.
   720  func (o NDPRecursiveDNSServer) Addresses() ([]tcpip.Address, error) {
   721  	var addrs []tcpip.Address
   722  	return addrs, o.iterAddresses(func(addr tcpip.Address) { addrs = append(addrs, addr) })
   723  }
   724  
   725  // checkAddresses iterates over the addresses in an NDP Recursive DNS Server
   726  // option and returns any error it encounters.
   727  func (o NDPRecursiveDNSServer) checkAddresses() error {
   728  	return o.iterAddresses(nil)
   729  }
   730  
   731  // iterAddresses iterates over the addresses in an NDP Recursive DNS Server
   732  // option and calls a function with each valid unicast IPv6 address.
   733  //
   734  // Note, the addresses MAY be link-local addresses.
   735  func (o NDPRecursiveDNSServer) iterAddresses(fn func(tcpip.Address)) error {
   736  	if l := len(o); l < minNDPRecursiveDNSServerBodySize {
   737  		return fmt.Errorf("got %d bytes for NDP Recursive DNS Server option's body, expected at least %d bytes: %w", l, minNDPRecursiveDNSServerBodySize, io.ErrUnexpectedEOF)
   738  	}
   739  
   740  	o = o[ndpRecursiveDNSServerAddressesOffset:]
   741  	l := len(o)
   742  	if l%IPv6AddressSize != 0 {
   743  		return fmt.Errorf("NDP Recursive DNS Server option's body ends in the middle of an IPv6 address (addresses body size = %d bytes): %w", l, ErrNDPOptMalformedBody)
   744  	}
   745  
   746  	for i := 0; len(o) != 0; i++ {
   747  		addr := tcpip.AddrFrom16Slice(o[:IPv6AddressSize])
   748  		if !IsV6UnicastAddress(addr) {
   749  			return fmt.Errorf("%d-th address (%s) in NDP Recursive DNS Server option is not a valid unicast IPv6 address: %w", i, addr, ErrNDPOptMalformedBody)
   750  		}
   751  
   752  		if fn != nil {
   753  			fn(addr)
   754  		}
   755  
   756  		o = o[IPv6AddressSize:]
   757  	}
   758  
   759  	return nil
   760  }
   761  
   762  // NDPDNSSearchList is the NDP DNS Search List option, as defined by
   763  // RFC 8106 section 5.2.
   764  type NDPDNSSearchList []byte
   765  
   766  // kind implements NDPOption.
   767  func (o NDPDNSSearchList) kind() ndpOptionIdentifier {
   768  	return ndpDNSSearchListOptionType
   769  }
   770  
   771  // length implements NDPOption.
   772  func (o NDPDNSSearchList) length() int {
   773  	return len(o)
   774  }
   775  
   776  // serializeInto implements NDPOption.
   777  func (o NDPDNSSearchList) serializeInto(b []byte) int {
   778  	used := copy(b, o)
   779  
   780  	// Zero out the reserved bytes that are before the Lifetime field.
   781  	clear(b[0:ndpDNSSearchListLifetimeOffset])
   782  
   783  	return used
   784  }
   785  
   786  // String implements fmt.Stringer.
   787  func (o NDPDNSSearchList) String() string {
   788  	lt := o.Lifetime()
   789  	domainNames, err := o.DomainNames()
   790  	if err != nil {
   791  		return fmt.Sprintf("%T([] valid for %s; err = %s)", o, lt, err)
   792  	}
   793  	return fmt.Sprintf("%T(%s valid for %s)", o, domainNames, lt)
   794  }
   795  
   796  // Lifetime returns the length of time that the DNS search list of domain names
   797  // in this option may be used for name resolution.
   798  //
   799  // Note, a value of 0 implies the domain names should no longer be used,
   800  // and a value of infinity/forever is represented by NDPInfiniteLifetime.
   801  func (o NDPDNSSearchList) Lifetime() time.Duration {
   802  	// The field is the time in seconds, as per RFC 8106 section 5.1.
   803  	return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpDNSSearchListLifetimeOffset:]))
   804  }
   805  
   806  // DomainNames returns a DNS search list of domain names.
   807  //
   808  // DomainNames will parse the backing buffer as outlined by RFC 1035 section
   809  // 3.1 and return a list of strings, with all domain names in lower case.
   810  func (o NDPDNSSearchList) DomainNames() ([]string, error) {
   811  	var domainNames []string
   812  	return domainNames, o.iterDomainNames(func(domainName string) { domainNames = append(domainNames, domainName) })
   813  }
   814  
   815  // checkDomainNames iterates over the domain names in an NDP DNS Search List
   816  // option and returns any error it encounters.
   817  func (o NDPDNSSearchList) checkDomainNames() error {
   818  	return o.iterDomainNames(nil)
   819  }
   820  
   821  // iterDomainNames iterates over the domain names in an NDP DNS Search List
   822  // option and calls a function with each valid domain name.
   823  func (o NDPDNSSearchList) iterDomainNames(fn func(string)) error {
   824  	if l := len(o); l < minNDPDNSSearchListBodySize {
   825  		return fmt.Errorf("got %d bytes for NDP DNS Search List  option's body, expected at least %d bytes: %w", l, minNDPDNSSearchListBodySize, io.ErrUnexpectedEOF)
   826  	}
   827  
   828  	var searchList bytes.Reader
   829  	searchList.Reset(o[ndpDNSSearchListDomainNamesOffset:])
   830  
   831  	var scratch [maxDomainNameLength]byte
   832  	domainName := bytes.NewBuffer(scratch[:])
   833  
   834  	// Parse the domain names, as per RFC 1035 section 3.1.
   835  	for searchList.Len() != 0 {
   836  		domainName.Reset()
   837  
   838  		// Parse a label within a domain name, as per RFC 1035 section 3.1.
   839  		for {
   840  			// The first byte is the label length.
   841  			labelLenByte, err := searchList.ReadByte()
   842  			if err != nil {
   843  				if err != io.EOF {
   844  					// ReadByte should only ever return nil or io.EOF.
   845  					panic(fmt.Sprintf("unexpected error when reading a label's length: %s", err))
   846  				}
   847  
   848  				// We use io.ErrUnexpectedEOF as exhausting the buffer is unexpected
   849  				// once we start parsing a domain name; we expect the buffer to contain
   850  				// enough bytes for the whole domain name.
   851  				return fmt.Errorf("unexpected exhausted buffer while parsing a new label for a domain from NDP Search List option: %w", io.ErrUnexpectedEOF)
   852  			}
   853  			labelLen := int(labelLenByte)
   854  
   855  			// A zero-length label implies the end of a domain name.
   856  			if labelLen == 0 {
   857  				// If the domain name is empty or we have no callback function, do
   858  				// nothing further with the current domain name.
   859  				if domainName.Len() == 0 || fn == nil {
   860  					break
   861  				}
   862  
   863  				// Ignore the trailing period in the parsed domain name.
   864  				domainName.Truncate(domainName.Len() - 1)
   865  				fn(domainName.String())
   866  				break
   867  			}
   868  
   869  			// The label's length must not exceed the maximum length for a label.
   870  			if labelLen > maxDomainNameLabelLength {
   871  				return fmt.Errorf("label length of %d bytes is greater than the max label length of %d bytes for an NDP Search List option: %w", labelLen, maxDomainNameLabelLength, ErrNDPOptMalformedBody)
   872  			}
   873  
   874  			// The label (and trailing period) must not make the domain name too long.
   875  			if labelLen+1 > domainName.Cap()-domainName.Len() {
   876  				return fmt.Errorf("label would make an NDP Search List option's domain name longer than the max domain name length of %d bytes: %w", maxDomainNameLength, ErrNDPOptMalformedBody)
   877  			}
   878  
   879  			// Copy the label and add a trailing period.
   880  			for i := 0; i < labelLen; i++ {
   881  				b, err := searchList.ReadByte()
   882  				if err != nil {
   883  					if err != io.EOF {
   884  						panic(fmt.Sprintf("unexpected error when reading domain name's label: %s", err))
   885  					}
   886  
   887  					return fmt.Errorf("read %d out of %d bytes for a domain name's label from NDP Search List option: %w", i, labelLen, io.ErrUnexpectedEOF)
   888  				}
   889  
   890  				// As per RFC 1035 section 2.3.1:
   891  				//  1) the label must only contain ASCII include letters, digits and
   892  				//     hyphens
   893  				//  2) the first character in a label must be a letter
   894  				//  3) the last letter in a label must be a letter or digit
   895  
   896  				if !isLetter(b) {
   897  					if i == 0 {
   898  						return fmt.Errorf("first character of a domain name's label in an NDP Search List option must be a letter, got character code = %d: %w", b, ErrNDPOptMalformedBody)
   899  					}
   900  
   901  					if b == '-' {
   902  						if i == labelLen-1 {
   903  							return fmt.Errorf("last character of a domain name's label in an NDP Search List option must not be a hyphen (-): %w", ErrNDPOptMalformedBody)
   904  						}
   905  					} else if !isDigit(b) {
   906  						return fmt.Errorf("domain name's label in an NDP Search List option may only contain letters, digits and hyphens, got character code = %d: %w", b, ErrNDPOptMalformedBody)
   907  					}
   908  				}
   909  
   910  				// If b is an upper case character, make it lower case.
   911  				if isUpperLetter(b) {
   912  					b = b - 'A' + 'a'
   913  				}
   914  
   915  				if err := domainName.WriteByte(b); err != nil {
   916  					panic(fmt.Sprintf("unexpected error writing label to domain name buffer: %s", err))
   917  				}
   918  			}
   919  			if err := domainName.WriteByte('.'); err != nil {
   920  				panic(fmt.Sprintf("unexpected error writing trailing period to domain name buffer: %s", err))
   921  			}
   922  		}
   923  	}
   924  
   925  	return nil
   926  }
   927  
   928  func isLetter(b byte) bool {
   929  	return b >= 'a' && b <= 'z' || isUpperLetter(b)
   930  }
   931  
   932  func isUpperLetter(b byte) bool {
   933  	return b >= 'A' && b <= 'Z'
   934  }
   935  
   936  func isDigit(b byte) bool {
   937  	return b >= '0' && b <= '9'
   938  }
   939  
   940  // As per RFC 4191 section 2.3,
   941  //
   942  //	2.3.  Route Information Option
   943  //
   944  //	    0                   1                   2                   3
   945  //	     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   946  //	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   947  //	    |     Type      |    Length     | Prefix Length |Resvd|Prf|Resvd|
   948  //	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   949  //	    |                        Route Lifetime                         |
   950  //	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   951  //	    |                   Prefix (Variable Length)                    |
   952  //	    .                                                               .
   953  //	    .                                                               .
   954  //	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   955  //
   956  //	 Fields:
   957  //
   958  //	 Type        24
   959  //
   960  //
   961  //	 Length      8-bit unsigned integer.  The length of the option
   962  //	             (including the Type and Length fields) in units of 8
   963  //	             octets.  The Length field is 1, 2, or 3 depending on the
   964  //	             Prefix Length.  If Prefix Length is greater than 64, then
   965  //	             Length must be 3.  If Prefix Length is greater than 0,
   966  //	             then Length must be 2 or 3.  If Prefix Length is zero,
   967  //	             then Length must be 1, 2, or 3.
   968  const (
   969  	ndpRouteInformationType      = ndpOptionIdentifier(24)
   970  	ndpRouteInformationMaxLength = 22
   971  
   972  	ndpRouteInformationPrefixLengthIdx  = 0
   973  	ndpRouteInformationFlagsIdx         = 1
   974  	ndpRouteInformationPrfShift         = 3
   975  	ndpRouteInformationPrfMask          = 3 << ndpRouteInformationPrfShift
   976  	ndpRouteInformationRouteLifetimeIdx = 2
   977  	ndpRouteInformationRoutePrefixIdx   = 6
   978  )
   979  
   980  // NDPRouteInformation is the NDP Router Information option, as defined by
   981  // RFC 4191 section 2.3.
   982  type NDPRouteInformation []byte
   983  
   984  func (NDPRouteInformation) kind() ndpOptionIdentifier {
   985  	return ndpRouteInformationType
   986  }
   987  
   988  func (o NDPRouteInformation) length() int {
   989  	return len(o)
   990  }
   991  
   992  func (o NDPRouteInformation) serializeInto(b []byte) int {
   993  	return copy(b, o)
   994  }
   995  
   996  // String implements fmt.Stringer.
   997  func (o NDPRouteInformation) String() string {
   998  	return fmt.Sprintf("%T", o)
   999  }
  1000  
  1001  // PrefixLength returns the length of the prefix.
  1002  func (o NDPRouteInformation) PrefixLength() uint8 {
  1003  	return o[ndpRouteInformationPrefixLengthIdx]
  1004  }
  1005  
  1006  // RoutePreference returns the preference of the route over other routes to the
  1007  // same destination but through a different router.
  1008  func (o NDPRouteInformation) RoutePreference() NDPRoutePreference {
  1009  	return NDPRoutePreference((o[ndpRouteInformationFlagsIdx] & ndpRouteInformationPrfMask) >> ndpRouteInformationPrfShift)
  1010  }
  1011  
  1012  // RouteLifetime returns the lifetime of the route.
  1013  //
  1014  // Note, a value of 0 implies the route is now invalid and a value of
  1015  // infinity/forever is represented by NDPInfiniteLifetime.
  1016  func (o NDPRouteInformation) RouteLifetime() time.Duration {
  1017  	return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpRouteInformationRouteLifetimeIdx:]))
  1018  }
  1019  
  1020  // Prefix returns the prefix of the destination subnet this route is for.
  1021  func (o NDPRouteInformation) Prefix() (tcpip.Subnet, error) {
  1022  	prefixLength := int(o.PrefixLength())
  1023  	if max := IPv6AddressSize * 8; prefixLength > max {
  1024  		return tcpip.Subnet{}, fmt.Errorf("got prefix length = %d, want <= %d", prefixLength, max)
  1025  	}
  1026  
  1027  	prefix := o[ndpRouteInformationRoutePrefixIdx:]
  1028  	var addrBytes [IPv6AddressSize]byte
  1029  	if n := copy(addrBytes[:], prefix); n != len(prefix) {
  1030  		panic(fmt.Sprintf("got copy(addrBytes, prefix) = %d, want = %d", n, len(prefix)))
  1031  	}
  1032  
  1033  	return tcpip.AddressWithPrefix{
  1034  		Address:   tcpip.AddrFrom16(addrBytes),
  1035  		PrefixLen: prefixLength,
  1036  	}.Subnet(), nil
  1037  }
  1038  
  1039  func (o NDPRouteInformation) hasError() error {
  1040  	l := len(o)
  1041  	if l < ndpRouteInformationRoutePrefixIdx {
  1042  		return fmt.Errorf("%T too small, got = %d bytes: %w", o, l, ErrNDPOptMalformedBody)
  1043  	}
  1044  
  1045  	prefixLength := int(o.PrefixLength())
  1046  	if max := IPv6AddressSize * 8; prefixLength > max {
  1047  		return fmt.Errorf("got prefix length = %d, want <= %d: %w", prefixLength, max, ErrNDPOptMalformedBody)
  1048  	}
  1049  
  1050  	//   Length      8-bit unsigned integer.  The length of the option
  1051  	//               (including the Type and Length fields) in units of 8
  1052  	//               octets.  The Length field is 1, 2, or 3 depending on the
  1053  	//               Prefix Length.  If Prefix Length is greater than 64, then
  1054  	//               Length must be 3.  If Prefix Length is greater than 0,
  1055  	//               then Length must be 2 or 3.  If Prefix Length is zero,
  1056  	//               then Length must be 1, 2, or 3.
  1057  	l += 2 // Add 2 bytes for the type and length bytes.
  1058  	lengthField := l / lengthByteUnits
  1059  	if prefixLength > 64 {
  1060  		if lengthField != 3 {
  1061  			return fmt.Errorf("Length field must be 3 when Prefix Length (%d) is > 64 (got = %d): %w", prefixLength, lengthField, ErrNDPOptMalformedBody)
  1062  		}
  1063  	} else if prefixLength > 0 {
  1064  		if lengthField != 2 && lengthField != 3 {
  1065  			return fmt.Errorf("Length field must be 2 or 3 when Prefix Length (%d) is between 0 and 64 (got = %d): %w", prefixLength, lengthField, ErrNDPOptMalformedBody)
  1066  		}
  1067  	} else if lengthField == 0 || lengthField > 3 {
  1068  		return fmt.Errorf("Length field must be 1, 2, or 3 when Prefix Length is zero (got = %d): %w", lengthField, ErrNDPOptMalformedBody)
  1069  	}
  1070  
  1071  	return nil
  1072  }