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