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 }