ndp_options.go raw

   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  }
1073