github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/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 "github.com/MerlinKodo/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 becuase 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 occured. 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 for i := used + 2; i < l; i++ { 343 b[i] = 0 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 for i := range reserved2 { 570 reserved2[i] = 0 571 } 572 573 return used 574 } 575 576 // String implements fmt.Stringer. 577 func (o NDPPrefixInformation) String() string { 578 return fmt.Sprintf("%T(O=%t, A=%t, PL=%s, VL=%s, Prefix=%s)", 579 o, 580 o.OnLinkFlag(), 581 o.AutonomousAddressConfigurationFlag(), 582 o.PreferredLifetime(), 583 o.ValidLifetime(), 584 o.Subnet()) 585 } 586 587 // PrefixLength returns the value in the number of leading bits in the Prefix 588 // that are valid. 589 // 590 // Valid values are in the range [0, 128], but o may not always contain valid 591 // values. It is up to the caller to valdiate the Prefix Information option. 592 func (o NDPPrefixInformation) PrefixLength() uint8 { 593 return o[ndpPrefixInformationPrefixLengthOffset] 594 } 595 596 // OnLinkFlag returns true of the prefix is considered on-link. On-link means 597 // that a forwarding node is not needed to send packets to other nodes on the 598 // same prefix. 599 // 600 // Note, when this function returns false, no statement is made about the 601 // on-link property of a prefix. That is, if OnLinkFlag returns false, the 602 // caller MUST NOT conclude that the prefix is off-link and MUST NOT update any 603 // previously stored state for this prefix about its on-link status. 604 func (o NDPPrefixInformation) OnLinkFlag() bool { 605 return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationOnLinkFlagMask != 0 606 } 607 608 // AutonomousAddressConfigurationFlag returns true if the prefix can be used for 609 // Stateless Address Auto-Configuration (as specified in RFC 4862). 610 func (o NDPPrefixInformation) AutonomousAddressConfigurationFlag() bool { 611 return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationAutoAddrConfFlagMask != 0 612 } 613 614 // ValidLifetime returns the length of time that the prefix is valid for the 615 // purpose of on-link determination. This value is relative to the send time of 616 // the packet that the Prefix Information option was present in. 617 // 618 // Note, a value of 0 implies the prefix should not be considered as on-link, 619 // and a value of infinity/forever is represented by 620 // NDPInfiniteLifetime. 621 func (o NDPPrefixInformation) ValidLifetime() time.Duration { 622 // The field is the time in seconds, as per RFC 4861 section 4.6.2. 623 return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationValidLifetimeOffset:])) 624 } 625 626 // PreferredLifetime returns the length of time that an address generated from 627 // the prefix via Stateless Address Auto-Configuration remains preferred. This 628 // value is relative to the send time of the packet that the Prefix Information 629 // option was present in. 630 // 631 // Note, a value of 0 implies that addresses generated from the prefix should 632 // no longer remain preferred, and a value of infinity is represented by 633 // NDPInfiniteLifetime. 634 // 635 // Also note that the value of this field MUST NOT exceed the Valid Lifetime 636 // field to avoid preferring addresses that are no longer valid, for the 637 // purpose of Stateless Address Auto-Configuration. 638 func (o NDPPrefixInformation) PreferredLifetime() time.Duration { 639 // The field is the time in seconds, as per RFC 4861 section 4.6.2. 640 return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationPreferredLifetimeOffset:])) 641 } 642 643 // Prefix returns an IPv6 address or a prefix of an IPv6 address. The Prefix 644 // Length field (see NDPPrefixInformation.PrefixLength) contains the number 645 // of valid leading bits in the prefix. 646 // 647 // Hosts SHOULD ignore an NDP Prefix Information option where the Prefix field 648 // holds the link-local prefix (fe80::). 649 func (o NDPPrefixInformation) Prefix() tcpip.Address { 650 return tcpip.AddrFrom16Slice(o[ndpPrefixInformationPrefixOffset:][:IPv6AddressSize]) 651 } 652 653 // Subnet returns the Prefix field and Prefix Length field represented in a 654 // tcpip.Subnet. 655 func (o NDPPrefixInformation) Subnet() tcpip.Subnet { 656 addrWithPrefix := tcpip.AddressWithPrefix{ 657 Address: o.Prefix(), 658 PrefixLen: int(o.PrefixLength()), 659 } 660 return addrWithPrefix.Subnet() 661 } 662 663 // NDPRecursiveDNSServer is the NDP Recursive DNS Server option, as defined by 664 // RFC 8106 section 5.1. 665 // 666 // To make sure that the option meets its minimum length and does not end in the 667 // middle of a DNS server's IPv6 address, the length of a valid 668 // NDPRecursiveDNSServer must meet the following constraint: 669 // 670 // (Length - ndpRecursiveDNSServerAddressesOffset) % IPv6AddressSize == 0 671 type NDPRecursiveDNSServer []byte 672 673 // Type returns the type of an NDP Recursive DNS Server option. 674 // 675 // kind implements NDPOption. 676 func (NDPRecursiveDNSServer) kind() ndpOptionIdentifier { 677 return ndpRecursiveDNSServerOptionType 678 } 679 680 // length implements NDPOption. 681 func (o NDPRecursiveDNSServer) length() int { 682 return len(o) 683 } 684 685 // serializeInto implements NDPOption. 686 func (o NDPRecursiveDNSServer) serializeInto(b []byte) int { 687 used := copy(b, o) 688 689 // Zero out the reserved bytes that are before the Lifetime field. 690 for i := 0; i < ndpRecursiveDNSServerLifetimeOffset; i++ { 691 b[i] = 0 692 } 693 694 return used 695 } 696 697 // String implements fmt.Stringer. 698 func (o NDPRecursiveDNSServer) String() string { 699 lt := o.Lifetime() 700 addrs, err := o.Addresses() 701 if err != nil { 702 return fmt.Sprintf("%T([] valid for %s; err = %s)", o, lt, err) 703 } 704 return fmt.Sprintf("%T(%s valid for %s)", o, addrs, lt) 705 } 706 707 // Lifetime returns the length of time that the DNS server addresses 708 // in this option may be used for name resolution. 709 // 710 // Note, a value of 0 implies the addresses should no longer be used, 711 // and a value of infinity/forever is represented by NDPInfiniteLifetime. 712 // 713 // Lifetime may panic if o does not have enough bytes to hold the Lifetime 714 // field. 715 func (o NDPRecursiveDNSServer) Lifetime() time.Duration { 716 // The field is the time in seconds, as per RFC 8106 section 5.1. 717 return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpRecursiveDNSServerLifetimeOffset:])) 718 } 719 720 // Addresses returns the recursive DNS server IPv6 addresses that may be 721 // used for name resolution. 722 // 723 // Note, the addresses MAY be link-local addresses. 724 func (o NDPRecursiveDNSServer) Addresses() ([]tcpip.Address, error) { 725 var addrs []tcpip.Address 726 return addrs, o.iterAddresses(func(addr tcpip.Address) { addrs = append(addrs, addr) }) 727 } 728 729 // checkAddresses iterates over the addresses in an NDP Recursive DNS Server 730 // option and returns any error it encounters. 731 func (o NDPRecursiveDNSServer) checkAddresses() error { 732 return o.iterAddresses(nil) 733 } 734 735 // iterAddresses iterates over the addresses in an NDP Recursive DNS Server 736 // option and calls a function with each valid unicast IPv6 address. 737 // 738 // Note, the addresses MAY be link-local addresses. 739 func (o NDPRecursiveDNSServer) iterAddresses(fn func(tcpip.Address)) error { 740 if l := len(o); l < minNDPRecursiveDNSServerBodySize { 741 return fmt.Errorf("got %d bytes for NDP Recursive DNS Server option's body, expected at least %d bytes: %w", l, minNDPRecursiveDNSServerBodySize, io.ErrUnexpectedEOF) 742 } 743 744 o = o[ndpRecursiveDNSServerAddressesOffset:] 745 l := len(o) 746 if l%IPv6AddressSize != 0 { 747 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) 748 } 749 750 for i := 0; len(o) != 0; i++ { 751 addr := tcpip.AddrFrom16Slice(o[:IPv6AddressSize]) 752 if !IsV6UnicastAddress(addr) { 753 return fmt.Errorf("%d-th address (%s) in NDP Recursive DNS Server option is not a valid unicast IPv6 address: %w", i, addr, ErrNDPOptMalformedBody) 754 } 755 756 if fn != nil { 757 fn(addr) 758 } 759 760 o = o[IPv6AddressSize:] 761 } 762 763 return nil 764 } 765 766 // NDPDNSSearchList is the NDP DNS Search List option, as defined by 767 // RFC 8106 section 5.2. 768 type NDPDNSSearchList []byte 769 770 // kind implements NDPOption. 771 func (o NDPDNSSearchList) kind() ndpOptionIdentifier { 772 return ndpDNSSearchListOptionType 773 } 774 775 // length implements NDPOption. 776 func (o NDPDNSSearchList) length() int { 777 return len(o) 778 } 779 780 // serializeInto implements NDPOption. 781 func (o NDPDNSSearchList) serializeInto(b []byte) int { 782 used := copy(b, o) 783 784 // Zero out the reserved bytes that are before the Lifetime field. 785 for i := 0; i < ndpDNSSearchListLifetimeOffset; i++ { 786 b[i] = 0 787 } 788 789 return used 790 } 791 792 // String implements fmt.Stringer. 793 func (o NDPDNSSearchList) String() string { 794 lt := o.Lifetime() 795 domainNames, err := o.DomainNames() 796 if err != nil { 797 return fmt.Sprintf("%T([] valid for %s; err = %s)", o, lt, err) 798 } 799 return fmt.Sprintf("%T(%s valid for %s)", o, domainNames, lt) 800 } 801 802 // Lifetime returns the length of time that the DNS search list of domain names 803 // in this option may be used for name resolution. 804 // 805 // Note, a value of 0 implies the domain names should no longer be used, 806 // and a value of infinity/forever is represented by NDPInfiniteLifetime. 807 func (o NDPDNSSearchList) Lifetime() time.Duration { 808 // The field is the time in seconds, as per RFC 8106 section 5.1. 809 return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpDNSSearchListLifetimeOffset:])) 810 } 811 812 // DomainNames returns a DNS search list of domain names. 813 // 814 // DomainNames will parse the backing buffer as outlined by RFC 1035 section 815 // 3.1 and return a list of strings, with all domain names in lower case. 816 func (o NDPDNSSearchList) DomainNames() ([]string, error) { 817 var domainNames []string 818 return domainNames, o.iterDomainNames(func(domainName string) { domainNames = append(domainNames, domainName) }) 819 } 820 821 // checkDomainNames iterates over the domain names in an NDP DNS Search List 822 // option and returns any error it encounters. 823 func (o NDPDNSSearchList) checkDomainNames() error { 824 return o.iterDomainNames(nil) 825 } 826 827 // iterDomainNames iterates over the domain names in an NDP DNS Search List 828 // option and calls a function with each valid domain name. 829 func (o NDPDNSSearchList) iterDomainNames(fn func(string)) error { 830 if l := len(o); l < minNDPDNSSearchListBodySize { 831 return fmt.Errorf("got %d bytes for NDP DNS Search List option's body, expected at least %d bytes: %w", l, minNDPDNSSearchListBodySize, io.ErrUnexpectedEOF) 832 } 833 834 var searchList bytes.Reader 835 searchList.Reset(o[ndpDNSSearchListDomainNamesOffset:]) 836 837 var scratch [maxDomainNameLength]byte 838 domainName := bytes.NewBuffer(scratch[:]) 839 840 // Parse the domain names, as per RFC 1035 section 3.1. 841 for searchList.Len() != 0 { 842 domainName.Reset() 843 844 // Parse a label within a domain name, as per RFC 1035 section 3.1. 845 for { 846 // The first byte is the label length. 847 labelLenByte, err := searchList.ReadByte() 848 if err != nil { 849 if err != io.EOF { 850 // ReadByte should only ever return nil or io.EOF. 851 panic(fmt.Sprintf("unexpected error when reading a label's length: %s", err)) 852 } 853 854 // We use io.ErrUnexpectedEOF as exhausting the buffer is unexpected 855 // once we start parsing a domain name; we expect the buffer to contain 856 // enough bytes for the whole domain name. 857 return fmt.Errorf("unexpected exhausted buffer while parsing a new label for a domain from NDP Search List option: %w", io.ErrUnexpectedEOF) 858 } 859 labelLen := int(labelLenByte) 860 861 // A zero-length label implies the end of a domain name. 862 if labelLen == 0 { 863 // If the domain name is empty or we have no callback function, do 864 // nothing further with the current domain name. 865 if domainName.Len() == 0 || fn == nil { 866 break 867 } 868 869 // Ignore the trailing period in the parsed domain name. 870 domainName.Truncate(domainName.Len() - 1) 871 fn(domainName.String()) 872 break 873 } 874 875 // The label's length must not exceed the maximum length for a label. 876 if labelLen > maxDomainNameLabelLength { 877 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) 878 } 879 880 // The label (and trailing period) must not make the domain name too long. 881 if labelLen+1 > domainName.Cap()-domainName.Len() { 882 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) 883 } 884 885 // Copy the label and add a trailing period. 886 for i := 0; i < labelLen; i++ { 887 b, err := searchList.ReadByte() 888 if err != nil { 889 if err != io.EOF { 890 panic(fmt.Sprintf("unexpected error when reading domain name's label: %s", err)) 891 } 892 893 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) 894 } 895 896 // As per RFC 1035 section 2.3.1: 897 // 1) the label must only contain ASCII include letters, digits and 898 // hyphens 899 // 2) the first character in a label must be a letter 900 // 3) the last letter in a label must be a letter or digit 901 902 if !isLetter(b) { 903 if i == 0 { 904 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) 905 } 906 907 if b == '-' { 908 if i == labelLen-1 { 909 return fmt.Errorf("last character of a domain name's label in an NDP Search List option must not be a hyphen (-): %w", ErrNDPOptMalformedBody) 910 } 911 } else if !isDigit(b) { 912 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) 913 } 914 } 915 916 // If b is an upper case character, make it lower case. 917 if isUpperLetter(b) { 918 b = b - 'A' + 'a' 919 } 920 921 if err := domainName.WriteByte(b); err != nil { 922 panic(fmt.Sprintf("unexpected error writing label to domain name buffer: %s", err)) 923 } 924 } 925 if err := domainName.WriteByte('.'); err != nil { 926 panic(fmt.Sprintf("unexpected error writing trailing period to domain name buffer: %s", err)) 927 } 928 } 929 } 930 931 return nil 932 } 933 934 func isLetter(b byte) bool { 935 return b >= 'a' && b <= 'z' || isUpperLetter(b) 936 } 937 938 func isUpperLetter(b byte) bool { 939 return b >= 'A' && b <= 'Z' 940 } 941 942 func isDigit(b byte) bool { 943 return b >= '0' && b <= '9' 944 } 945 946 // As per RFC 4191 section 2.3, 947 // 948 // 2.3. Route Information Option 949 // 950 // 0 1 2 3 951 // 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 952 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 953 // | Type | Length | Prefix Length |Resvd|Prf|Resvd| 954 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 955 // | Route Lifetime | 956 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 957 // | Prefix (Variable Length) | 958 // . . 959 // . . 960 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 961 // 962 // Fields: 963 // 964 // Type 24 965 // 966 // 967 // Length 8-bit unsigned integer. The length of the option 968 // (including the Type and Length fields) in units of 8 969 // octets. The Length field is 1, 2, or 3 depending on the 970 // Prefix Length. If Prefix Length is greater than 64, then 971 // Length must be 3. If Prefix Length is greater than 0, 972 // then Length must be 2 or 3. If Prefix Length is zero, 973 // then Length must be 1, 2, or 3. 974 const ( 975 ndpRouteInformationType = ndpOptionIdentifier(24) 976 ndpRouteInformationMaxLength = 22 977 978 ndpRouteInformationPrefixLengthIdx = 0 979 ndpRouteInformationFlagsIdx = 1 980 ndpRouteInformationPrfShift = 3 981 ndpRouteInformationPrfMask = 3 << ndpRouteInformationPrfShift 982 ndpRouteInformationRouteLifetimeIdx = 2 983 ndpRouteInformationRoutePrefixIdx = 6 984 ) 985 986 // NDPRouteInformation is the NDP Router Information option, as defined by 987 // RFC 4191 section 2.3. 988 type NDPRouteInformation []byte 989 990 func (NDPRouteInformation) kind() ndpOptionIdentifier { 991 return ndpRouteInformationType 992 } 993 994 func (o NDPRouteInformation) length() int { 995 return len(o) 996 } 997 998 func (o NDPRouteInformation) serializeInto(b []byte) int { 999 return copy(b, o) 1000 } 1001 1002 // String implements fmt.Stringer. 1003 func (o NDPRouteInformation) String() string { 1004 return fmt.Sprintf("%T", o) 1005 } 1006 1007 // PrefixLength returns the length of the prefix. 1008 func (o NDPRouteInformation) PrefixLength() uint8 { 1009 return o[ndpRouteInformationPrefixLengthIdx] 1010 } 1011 1012 // RoutePreference returns the preference of the route over other routes to the 1013 // same destination but through a different router. 1014 func (o NDPRouteInformation) RoutePreference() NDPRoutePreference { 1015 return NDPRoutePreference((o[ndpRouteInformationFlagsIdx] & ndpRouteInformationPrfMask) >> ndpRouteInformationPrfShift) 1016 } 1017 1018 // RouteLifetime returns the lifetime of the route. 1019 // 1020 // Note, a value of 0 implies the route is now invalid and a value of 1021 // infinity/forever is represented by NDPInfiniteLifetime. 1022 func (o NDPRouteInformation) RouteLifetime() time.Duration { 1023 return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpRouteInformationRouteLifetimeIdx:])) 1024 } 1025 1026 // Prefix returns the prefix of the destination subnet this route is for. 1027 func (o NDPRouteInformation) Prefix() (tcpip.Subnet, error) { 1028 prefixLength := int(o.PrefixLength()) 1029 if max := IPv6AddressSize * 8; prefixLength > max { 1030 return tcpip.Subnet{}, fmt.Errorf("got prefix length = %d, want <= %d", prefixLength, max) 1031 } 1032 1033 prefix := o[ndpRouteInformationRoutePrefixIdx:] 1034 var addrBytes [IPv6AddressSize]byte 1035 if n := copy(addrBytes[:], prefix); n != len(prefix) { 1036 panic(fmt.Sprintf("got copy(addrBytes, prefix) = %d, want = %d", n, len(prefix))) 1037 } 1038 1039 return tcpip.AddressWithPrefix{ 1040 Address: tcpip.AddrFrom16(addrBytes), 1041 PrefixLen: prefixLength, 1042 }.Subnet(), nil 1043 } 1044 1045 func (o NDPRouteInformation) hasError() error { 1046 l := len(o) 1047 if l < ndpRouteInformationRoutePrefixIdx { 1048 return fmt.Errorf("%T too small, got = %d bytes: %w", o, l, ErrNDPOptMalformedBody) 1049 } 1050 1051 prefixLength := int(o.PrefixLength()) 1052 if max := IPv6AddressSize * 8; prefixLength > max { 1053 return fmt.Errorf("got prefix length = %d, want <= %d: %w", prefixLength, max, ErrNDPOptMalformedBody) 1054 } 1055 1056 // Length 8-bit unsigned integer. The length of the option 1057 // (including the Type and Length fields) in units of 8 1058 // octets. The Length field is 1, 2, or 3 depending on the 1059 // Prefix Length. If Prefix Length is greater than 64, then 1060 // Length must be 3. If Prefix Length is greater than 0, 1061 // then Length must be 2 or 3. If Prefix Length is zero, 1062 // then Length must be 1, 2, or 3. 1063 l += 2 // Add 2 bytes for the type and length bytes. 1064 lengthField := l / lengthByteUnits 1065 if prefixLength > 64 { 1066 if lengthField != 3 { 1067 return fmt.Errorf("Length field must be 3 when Prefix Length (%d) is > 64 (got = %d): %w", prefixLength, lengthField, ErrNDPOptMalformedBody) 1068 } 1069 } else if prefixLength > 0 { 1070 if lengthField != 2 && lengthField != 3 { 1071 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) 1072 } 1073 } else if lengthField == 0 || lengthField > 3 { 1074 return fmt.Errorf("Length field must be 1, 2, or 3 when Prefix Length is zero (got = %d): %w", lengthField, ErrNDPOptMalformedBody) 1075 } 1076 1077 return nil 1078 }