github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/header/ndp_test.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 "regexp" 24 "strings" 25 "testing" 26 "time" 27 28 "github.com/google/go-cmp/cmp" 29 "github.com/SagerNet/gvisor/pkg/tcpip" 30 "github.com/SagerNet/gvisor/pkg/tcpip/testutil" 31 ) 32 33 // TestNDPNeighborSolicit tests the functions of NDPNeighborSolicit. 34 func TestNDPNeighborSolicit(t *testing.T) { 35 b := []byte{ 36 0, 0, 0, 0, 37 1, 2, 3, 4, 38 5, 6, 7, 8, 39 9, 10, 11, 12, 40 13, 14, 15, 16, 41 } 42 43 // Test getting the Target Address. 44 ns := NDPNeighborSolicit(b) 45 addr := testutil.MustParse6("102:304:506:708:90a:b0c:d0e:f10") 46 if got := ns.TargetAddress(); got != addr { 47 t.Errorf("got ns.TargetAddress = %s, want %s", got, addr) 48 } 49 50 // Test updating the Target Address. 51 addr2 := testutil.MustParse6("1112:1314:1516:1718:191a:1b1c:1d1e:1f11") 52 ns.SetTargetAddress(addr2) 53 if got := ns.TargetAddress(); got != addr2 { 54 t.Errorf("got ns.TargetAddress = %s, want %s", got, addr2) 55 } 56 // Make sure the address got updated in the backing buffer. 57 if got := tcpip.Address(b[ndpNSTargetAddessOffset:][:IPv6AddressSize]); got != addr2 { 58 t.Errorf("got targetaddress buffer = %s, want %s", got, addr2) 59 } 60 } 61 62 func TestNDPRouteInformationOption(t *testing.T) { 63 tests := []struct { 64 name string 65 66 length uint8 67 prefixLength uint8 68 prf NDPRoutePreference 69 lifetimeS uint32 70 prefixBytes []byte 71 expectedPrefix tcpip.Subnet 72 73 expectedErr error 74 }{ 75 { 76 name: "Length=1 with Prefix Length = 0", 77 length: 1, 78 prefixLength: 0, 79 prf: MediumRoutePreference, 80 lifetimeS: 1, 81 prefixBytes: nil, 82 expectedPrefix: IPv6EmptySubnet, 83 }, 84 { 85 name: "Length=1 but Prefix Length > 0", 86 length: 1, 87 prefixLength: 1, 88 prf: MediumRoutePreference, 89 lifetimeS: 1, 90 prefixBytes: nil, 91 expectedErr: ErrNDPOptMalformedBody, 92 }, 93 { 94 name: "Length=2 with Prefix Length = 0", 95 length: 2, 96 prefixLength: 0, 97 prf: MediumRoutePreference, 98 lifetimeS: 1, 99 prefixBytes: nil, 100 expectedPrefix: IPv6EmptySubnet, 101 }, 102 { 103 name: "Length=2 with Prefix Length in [1, 64] (1)", 104 length: 2, 105 prefixLength: 1, 106 prf: LowRoutePreference, 107 lifetimeS: 1, 108 prefixBytes: nil, 109 expectedPrefix: tcpip.AddressWithPrefix{ 110 Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), 111 PrefixLen: 1, 112 }.Subnet(), 113 }, 114 { 115 name: "Length=2 with Prefix Length in [1, 64] (64)", 116 length: 2, 117 prefixLength: 64, 118 prf: HighRoutePreference, 119 lifetimeS: 1, 120 prefixBytes: nil, 121 expectedPrefix: tcpip.AddressWithPrefix{ 122 Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), 123 PrefixLen: 64, 124 }.Subnet(), 125 }, 126 { 127 name: "Length=2 with Prefix Length > 64", 128 length: 2, 129 prefixLength: 65, 130 prf: HighRoutePreference, 131 lifetimeS: 1, 132 prefixBytes: nil, 133 expectedErr: ErrNDPOptMalformedBody, 134 }, 135 { 136 name: "Length=3 with Prefix Length = 0", 137 length: 3, 138 prefixLength: 0, 139 prf: MediumRoutePreference, 140 lifetimeS: 1, 141 prefixBytes: nil, 142 expectedPrefix: IPv6EmptySubnet, 143 }, 144 { 145 name: "Length=3 with Prefix Length in [1, 64] (1)", 146 length: 3, 147 prefixLength: 1, 148 prf: LowRoutePreference, 149 lifetimeS: 1, 150 prefixBytes: nil, 151 expectedPrefix: tcpip.AddressWithPrefix{ 152 Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), 153 PrefixLen: 1, 154 }.Subnet(), 155 }, 156 { 157 name: "Length=3 with Prefix Length in [1, 64] (64)", 158 length: 3, 159 prefixLength: 64, 160 prf: HighRoutePreference, 161 lifetimeS: 1, 162 prefixBytes: nil, 163 expectedPrefix: tcpip.AddressWithPrefix{ 164 Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), 165 PrefixLen: 64, 166 }.Subnet(), 167 }, 168 { 169 name: "Length=3 with Prefix Length in [65, 128] (65)", 170 length: 3, 171 prefixLength: 65, 172 prf: HighRoutePreference, 173 lifetimeS: 1, 174 prefixBytes: nil, 175 expectedPrefix: tcpip.AddressWithPrefix{ 176 Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), 177 PrefixLen: 65, 178 }.Subnet(), 179 }, 180 { 181 name: "Length=3 with Prefix Length in [65, 128] (128)", 182 length: 3, 183 prefixLength: 128, 184 prf: HighRoutePreference, 185 lifetimeS: 1, 186 prefixBytes: nil, 187 expectedPrefix: tcpip.AddressWithPrefix{ 188 Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), 189 PrefixLen: 128, 190 }.Subnet(), 191 }, 192 { 193 name: "Length=3 with (invalid) Prefix Length > 128", 194 length: 3, 195 prefixLength: 129, 196 prf: HighRoutePreference, 197 lifetimeS: 1, 198 prefixBytes: nil, 199 expectedErr: ErrNDPOptMalformedBody, 200 }, 201 } 202 203 for _, test := range tests { 204 t.Run(test.name, func(t *testing.T) { 205 expectedRouteInformationBytes := [...]byte{ 206 // Type, Length 207 24, test.length, 208 209 // Prefix Length, Prf 210 uint8(test.prefixLength), uint8(test.prf) << 3, 211 212 // Route Lifetime 213 0, 0, 0, 0, 214 215 0, 0, 0, 0, 216 0, 0, 0, 0, 217 0, 0, 0, 0, 218 0, 0, 0, 0, 219 } 220 binary.BigEndian.PutUint32(expectedRouteInformationBytes[4:], test.lifetimeS) 221 _ = copy(expectedRouteInformationBytes[8:], test.prefixBytes) 222 223 opts := NDPOptions(expectedRouteInformationBytes[:test.length*lengthByteUnits]) 224 it, err := opts.Iter(false) 225 if err != nil { 226 t.Fatalf("got Iter(false) = (_, %s), want = (_, nil)", err) 227 } 228 opt, done, err := it.Next() 229 if !errors.Is(err, test.expectedErr) { 230 t.Fatalf("got Next() = (_, _, %s), want = (_, _, %s)", err, test.expectedErr) 231 } 232 if want := test.expectedErr != nil; done != want { 233 t.Fatalf("got Next() = (_, %t, _), want = (_, %t, _)", done, want) 234 } 235 if test.expectedErr != nil { 236 return 237 } 238 239 if got := opt.kind(); got != ndpRouteInformationType { 240 t.Errorf("got kind() = %d, want = %d", got, ndpRouteInformationType) 241 } 242 243 ri, ok := opt.(NDPRouteInformation) 244 if !ok { 245 t.Fatalf("got opt = %T, want = NDPRouteInformation", opt) 246 } 247 248 if got := ri.PrefixLength(); got != test.prefixLength { 249 t.Errorf("got PrefixLength() = %d, want = %d", got, test.prefixLength) 250 } 251 if got := ri.RoutePreference(); got != test.prf { 252 t.Errorf("got RoutePreference() = %d, want = %d", got, test.prf) 253 } 254 if got, want := ri.RouteLifetime(), time.Duration(test.lifetimeS)*time.Second; got != want { 255 t.Errorf("got RouteLifetime() = %s, want = %s", got, want) 256 } 257 if got, err := ri.Prefix(); err != nil { 258 t.Errorf("Prefix(): %s", err) 259 } else if got != test.expectedPrefix { 260 t.Errorf("got Prefix() = %s, want = %s", got, test.expectedPrefix) 261 } 262 263 // Iterator should not return anything else. 264 { 265 next, done, err := it.Next() 266 if err != nil { 267 t.Errorf("got Next() = (_, _, %s), want = (_, _, nil)", err) 268 } 269 if !done { 270 t.Error("got Next() = (_, false, _), want = (_, true, _)") 271 } 272 if next != nil { 273 t.Errorf("got Next() = (%x, _, _), want = (nil, _, _)", next) 274 } 275 } 276 }) 277 } 278 } 279 280 // TestNDPNeighborAdvert tests the functions of NDPNeighborAdvert. 281 func TestNDPNeighborAdvert(t *testing.T) { 282 b := []byte{ 283 160, 0, 0, 0, 284 1, 2, 3, 4, 285 5, 6, 7, 8, 286 9, 10, 11, 12, 287 13, 14, 15, 16, 288 } 289 290 // Test getting the Target Address. 291 na := NDPNeighborAdvert(b) 292 addr := testutil.MustParse6("102:304:506:708:90a:b0c:d0e:f10") 293 if got := na.TargetAddress(); got != addr { 294 t.Errorf("got TargetAddress = %s, want %s", got, addr) 295 } 296 297 // Test getting the Router Flag. 298 if got := na.RouterFlag(); !got { 299 t.Errorf("got RouterFlag = false, want = true") 300 } 301 302 // Test getting the Solicited Flag. 303 if got := na.SolicitedFlag(); got { 304 t.Errorf("got SolicitedFlag = true, want = false") 305 } 306 307 // Test getting the Override Flag. 308 if got := na.OverrideFlag(); !got { 309 t.Errorf("got OverrideFlag = false, want = true") 310 } 311 312 // Test updating the Target Address. 313 addr2 := testutil.MustParse6("1112:1314:1516:1718:191a:1b1c:1d1e:1f11") 314 na.SetTargetAddress(addr2) 315 if got := na.TargetAddress(); got != addr2 { 316 t.Errorf("got TargetAddress = %s, want %s", got, addr2) 317 } 318 // Make sure the address got updated in the backing buffer. 319 if got := tcpip.Address(b[ndpNATargetAddressOffset:][:IPv6AddressSize]); got != addr2 { 320 t.Errorf("got targetaddress buffer = %s, want %s", got, addr2) 321 } 322 323 // Test updating the Router Flag. 324 na.SetRouterFlag(false) 325 if got := na.RouterFlag(); got { 326 t.Errorf("got RouterFlag = true, want = false") 327 } 328 329 // Test updating the Solicited Flag. 330 na.SetSolicitedFlag(true) 331 if got := na.SolicitedFlag(); !got { 332 t.Errorf("got SolicitedFlag = false, want = true") 333 } 334 335 // Test updating the Override Flag. 336 na.SetOverrideFlag(false) 337 if got := na.OverrideFlag(); got { 338 t.Errorf("got OverrideFlag = true, want = false") 339 } 340 341 // Make sure flags got updated in the backing buffer. 342 if got := b[ndpNAFlagsOffset]; got != 64 { 343 t.Errorf("got flags byte = %d, want = 64", got) 344 } 345 } 346 347 func TestNDPRouterAdvert(t *testing.T) { 348 tests := []struct { 349 hopLimit uint8 350 managedFlag, otherConfFlag bool 351 prf NDPRoutePreference 352 routerLifetimeS uint16 353 reachableTimeMS, retransTimerMS uint32 354 }{ 355 { 356 hopLimit: 1, 357 managedFlag: false, 358 otherConfFlag: true, 359 prf: HighRoutePreference, 360 routerLifetimeS: 2, 361 reachableTimeMS: 3, 362 retransTimerMS: 4, 363 }, 364 { 365 hopLimit: 64, 366 managedFlag: true, 367 otherConfFlag: false, 368 prf: LowRoutePreference, 369 routerLifetimeS: 258, 370 reachableTimeMS: 78492, 371 retransTimerMS: 13213, 372 }, 373 } 374 375 for i, test := range tests { 376 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 377 flags := uint8(0) 378 if test.managedFlag { 379 flags |= 1 << 7 380 } 381 if test.otherConfFlag { 382 flags |= 1 << 6 383 } 384 flags |= uint8(test.prf) << 3 385 386 b := []byte{ 387 test.hopLimit, flags, 1, 2, 388 3, 4, 5, 6, 389 7, 8, 9, 10, 390 } 391 binary.BigEndian.PutUint16(b[2:], test.routerLifetimeS) 392 binary.BigEndian.PutUint32(b[4:], test.reachableTimeMS) 393 binary.BigEndian.PutUint32(b[8:], test.retransTimerMS) 394 395 ra := NDPRouterAdvert(b) 396 397 if got := ra.CurrHopLimit(); got != test.hopLimit { 398 t.Errorf("got ra.CurrHopLimit() = %d, want = %d", got, test.hopLimit) 399 } 400 401 if got := ra.ManagedAddrConfFlag(); got != test.managedFlag { 402 t.Errorf("got ManagedAddrConfFlag() = %t, want = %t", got, test.managedFlag) 403 } 404 405 if got := ra.OtherConfFlag(); got != test.otherConfFlag { 406 t.Errorf("got OtherConfFlag() = %t, want = %t", got, test.otherConfFlag) 407 } 408 409 if got := ra.DefaultRouterPreference(); got != test.prf { 410 t.Errorf("got DefaultRouterPreference() = %d, want = %d", got, test.prf) 411 } 412 413 if got, want := ra.RouterLifetime(), time.Second*time.Duration(test.routerLifetimeS); got != want { 414 t.Errorf("got ra.RouterLifetime() = %d, want = %d", got, want) 415 } 416 417 if got, want := ra.ReachableTime(), time.Millisecond*time.Duration(test.reachableTimeMS); got != want { 418 t.Errorf("got ra.ReachableTime() = %d, want = %d", got, want) 419 } 420 421 if got, want := ra.RetransTimer(), time.Millisecond*time.Duration(test.retransTimerMS); got != want { 422 t.Errorf("got ra.RetransTimer() = %d, want = %d", got, want) 423 } 424 }) 425 } 426 } 427 428 // TestNDPSourceLinkLayerAddressOptionEthernetAddress tests getting the 429 // Ethernet address from an NDPSourceLinkLayerAddressOption. 430 func TestNDPSourceLinkLayerAddressOptionEthernetAddress(t *testing.T) { 431 tests := []struct { 432 name string 433 buf []byte 434 expected tcpip.LinkAddress 435 }{ 436 { 437 "ValidMAC", 438 []byte{1, 2, 3, 4, 5, 6}, 439 tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"), 440 }, 441 { 442 "SLLBodyTooShort", 443 []byte{1, 2, 3, 4, 5}, 444 tcpip.LinkAddress([]byte(nil)), 445 }, 446 { 447 "SLLBodyLargerThanNeeded", 448 []byte{1, 2, 3, 4, 5, 6, 7, 8}, 449 tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"), 450 }, 451 } 452 453 for _, test := range tests { 454 t.Run(test.name, func(t *testing.T) { 455 sll := NDPSourceLinkLayerAddressOption(test.buf) 456 if got := sll.EthernetAddress(); got != test.expected { 457 t.Errorf("got sll.EthernetAddress = %s, want = %s", got, test.expected) 458 } 459 }) 460 } 461 } 462 463 // TestNDPTargetLinkLayerAddressOptionEthernetAddress tests getting the 464 // Ethernet address from an NDPTargetLinkLayerAddressOption. 465 func TestNDPTargetLinkLayerAddressOptionEthernetAddress(t *testing.T) { 466 tests := []struct { 467 name string 468 buf []byte 469 expected tcpip.LinkAddress 470 }{ 471 { 472 "ValidMAC", 473 []byte{1, 2, 3, 4, 5, 6}, 474 tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"), 475 }, 476 { 477 "TLLBodyTooShort", 478 []byte{1, 2, 3, 4, 5}, 479 tcpip.LinkAddress([]byte(nil)), 480 }, 481 { 482 "TLLBodyLargerThanNeeded", 483 []byte{1, 2, 3, 4, 5, 6, 7, 8}, 484 tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"), 485 }, 486 } 487 488 for _, test := range tests { 489 t.Run(test.name, func(t *testing.T) { 490 tll := NDPTargetLinkLayerAddressOption(test.buf) 491 if got := tll.EthernetAddress(); got != test.expected { 492 t.Errorf("got tll.EthernetAddress = %s, want = %s", got, test.expected) 493 } 494 }) 495 } 496 } 497 498 func TestOpts(t *testing.T) { 499 const optionHeaderLen = 2 500 501 checkNonce := func(expectedNonce []byte) func(*testing.T, NDPOption) { 502 return func(t *testing.T, opt NDPOption) { 503 if got := opt.kind(); got != ndpNonceOptionType { 504 t.Errorf("got kind() = %d, want = %d", got, ndpNonceOptionType) 505 } 506 nonce, ok := opt.(NDPNonceOption) 507 if !ok { 508 t.Fatalf("got nonce = %T, want = NDPNonceOption", opt) 509 } 510 if diff := cmp.Diff(expectedNonce, nonce.Nonce()); diff != "" { 511 t.Errorf("nonce mismatch (-want +got):\n%s", diff) 512 } 513 } 514 } 515 516 checkTLL := func(expectedAddr tcpip.LinkAddress) func(*testing.T, NDPOption) { 517 return func(t *testing.T, opt NDPOption) { 518 if got := opt.kind(); got != ndpTargetLinkLayerAddressOptionType { 519 t.Errorf("got kind() = %d, want = %d", got, ndpTargetLinkLayerAddressOptionType) 520 } 521 tll, ok := opt.(NDPTargetLinkLayerAddressOption) 522 if !ok { 523 t.Fatalf("got tll = %T, want = NDPTargetLinkLayerAddressOption", opt) 524 } 525 if got, want := tll.EthernetAddress(), expectedAddr; got != want { 526 t.Errorf("got tll.EthernetAddress = %s, want = %s", got, want) 527 } 528 } 529 } 530 531 checkSLL := func(expectedAddr tcpip.LinkAddress) func(*testing.T, NDPOption) { 532 return func(t *testing.T, opt NDPOption) { 533 if got := opt.kind(); got != ndpSourceLinkLayerAddressOptionType { 534 t.Errorf("got kind() = %d, want = %d", got, ndpSourceLinkLayerAddressOptionType) 535 } 536 sll, ok := opt.(NDPSourceLinkLayerAddressOption) 537 if !ok { 538 t.Fatalf("got sll = %T, want = NDPSourceLinkLayerAddressOption", opt) 539 } 540 if got, want := sll.EthernetAddress(), expectedAddr; got != want { 541 t.Errorf("got sll.EthernetAddress = %s, want = %s", got, want) 542 } 543 } 544 } 545 546 const validLifetimeSeconds = 16909060 547 address := testutil.MustParse6("90a:b0c:d0e:f10:1112:1314:1516:1718") 548 549 expectedRDNSSBytes := [...]byte{ 550 // Type, Length 551 25, 3, 552 553 // Reserved 554 0, 0, 555 556 // Lifetime 557 1, 2, 4, 8, 558 559 // Address 560 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 561 } 562 binary.BigEndian.PutUint32(expectedRDNSSBytes[4:], validLifetimeSeconds) 563 if n := copy(expectedRDNSSBytes[8:], address); n != IPv6AddressSize { 564 t.Fatalf("got copy(...) = %d, want = %d", n, IPv6AddressSize) 565 } 566 // Update reserved fields to non zero values to make sure serializing sets 567 // them to zero. 568 rdnssBytes := expectedRDNSSBytes 569 rdnssBytes[1] = 1 570 rdnssBytes[2] = 2 571 572 const searchListPaddingBytes = 3 573 const domainName = "abc.abcd.e" 574 expectedSearchListBytes := [...]byte{ 575 // Type, Length 576 31, 3, 577 578 // Reserved 579 0, 0, 580 581 // Lifetime 582 1, 0, 0, 0, 583 584 // Domain names 585 3, 'a', 'b', 'c', 586 4, 'a', 'b', 'c', 'd', 587 1, 'e', 588 0, 589 0, 0, 0, 0, 590 } 591 binary.BigEndian.PutUint32(expectedSearchListBytes[4:], validLifetimeSeconds) 592 // Update reserved fields to non zero values to make sure serializing sets 593 // them to zero. 594 searchListBytes := expectedSearchListBytes 595 searchListBytes[2] = 1 596 searchListBytes[3] = 2 597 598 const prefixLength = 43 599 const onLinkFlag = false 600 const slaacFlag = true 601 const preferredLifetimeSeconds = 84281096 602 const onLinkFlagBit = 7 603 const slaacFlagBit = 6 604 boolToByte := func(v bool) byte { 605 if v { 606 return 1 607 } 608 return 0 609 } 610 flags := boolToByte(onLinkFlag)<<onLinkFlagBit | boolToByte(slaacFlag)<<slaacFlagBit 611 expectedPrefixInformationBytes := [...]byte{ 612 // Type, Length 613 3, 4, 614 615 prefixLength, flags, 616 617 // Valid Lifetime 618 1, 2, 3, 4, 619 620 // Preferred Lifetime 621 5, 6, 7, 8, 622 623 // Reserved2 624 0, 0, 0, 0, 625 626 // Address 627 9, 10, 11, 12, 628 13, 14, 15, 16, 629 17, 18, 19, 20, 630 21, 22, 23, 24, 631 } 632 binary.BigEndian.PutUint32(expectedPrefixInformationBytes[4:], validLifetimeSeconds) 633 binary.BigEndian.PutUint32(expectedPrefixInformationBytes[8:], preferredLifetimeSeconds) 634 if n := copy(expectedPrefixInformationBytes[16:], address); n != IPv6AddressSize { 635 t.Fatalf("got copy(...) = %d, want = %d", n, IPv6AddressSize) 636 } 637 // Update reserved fields to non zero values to make sure serializing sets 638 // them to zero. 639 prefixInformationBytes := expectedPrefixInformationBytes 640 prefixInformationBytes[3] |= (1 << slaacFlagBit) - 1 641 binary.BigEndian.PutUint32(prefixInformationBytes[12:], validLifetimeSeconds+1) 642 tests := []struct { 643 name string 644 buf []byte 645 opt NDPOption 646 expectedBuf []byte 647 check func(*testing.T, NDPOption) 648 }{ 649 { 650 name: "Nonce", 651 buf: make([]byte, 8), 652 opt: NDPNonceOption([]byte{1, 2, 3, 4, 5, 6}), 653 expectedBuf: []byte{14, 1, 1, 2, 3, 4, 5, 6}, 654 check: checkNonce([]byte{1, 2, 3, 4, 5, 6}), 655 }, 656 { 657 name: "Nonce with padding", 658 buf: []byte{1, 1, 1, 1, 1, 1, 1, 1}, 659 opt: NDPNonceOption([]byte{1, 2, 3, 4, 5}), 660 expectedBuf: []byte{14, 1, 1, 2, 3, 4, 5, 0}, 661 check: checkNonce([]byte{1, 2, 3, 4, 5, 0}), 662 }, 663 664 { 665 name: "TLL Ethernet", 666 buf: make([]byte, 8), 667 opt: NDPTargetLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06"), 668 expectedBuf: []byte{2, 1, 1, 2, 3, 4, 5, 6}, 669 check: checkTLL("\x01\x02\x03\x04\x05\x06"), 670 }, 671 { 672 name: "TLL Padding", 673 buf: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 674 opt: NDPTargetLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06\x07\x08"), 675 expectedBuf: []byte{2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0}, 676 check: checkTLL("\x01\x02\x03\x04\x05\x06"), 677 }, 678 { 679 name: "TLL Empty", 680 buf: nil, 681 opt: NDPTargetLinkLayerAddressOption(""), 682 expectedBuf: nil, 683 }, 684 685 { 686 name: "SLL Ethernet", 687 buf: make([]byte, 8), 688 opt: NDPSourceLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06"), 689 expectedBuf: []byte{1, 1, 1, 2, 3, 4, 5, 6}, 690 check: checkSLL("\x01\x02\x03\x04\x05\x06"), 691 }, 692 { 693 name: "SLL Padding", 694 buf: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 695 opt: NDPSourceLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06\x07\x08"), 696 expectedBuf: []byte{1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0}, 697 check: checkSLL("\x01\x02\x03\x04\x05\x06"), 698 }, 699 { 700 name: "SLL Empty", 701 buf: nil, 702 opt: NDPSourceLinkLayerAddressOption(""), 703 expectedBuf: nil, 704 }, 705 706 { 707 name: "RDNSS", 708 buf: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 709 // NDPRecursiveDNSServer holds the option after the header bytes. 710 opt: NDPRecursiveDNSServer(rdnssBytes[optionHeaderLen:]), 711 expectedBuf: expectedRDNSSBytes[:], 712 check: func(t *testing.T, opt NDPOption) { 713 if got := opt.kind(); got != ndpRecursiveDNSServerOptionType { 714 t.Errorf("got kind() = %d, want = %d", got, ndpRecursiveDNSServerOptionType) 715 } 716 rdnss, ok := opt.(NDPRecursiveDNSServer) 717 if !ok { 718 t.Fatalf("got opt = %T, want = NDPRecursiveDNSServer", opt) 719 } 720 if got, want := rdnss.length(), len(expectedRDNSSBytes[optionHeaderLen:]); got != want { 721 t.Errorf("got length() = %d, want = %d", got, want) 722 } 723 if got, want := rdnss.Lifetime(), validLifetimeSeconds*time.Second; got != want { 724 t.Errorf("got Lifetime() = %s, want = %s", got, want) 725 } 726 if addrs, err := rdnss.Addresses(); err != nil { 727 t.Errorf("Addresses(): %s", err) 728 } else if diff := cmp.Diff([]tcpip.Address{address}, addrs); diff != "" { 729 t.Errorf("mismatched addresses (-want +got):\n%s", diff) 730 } 731 }, 732 }, 733 734 { 735 name: "Search list", 736 buf: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 737 opt: NDPDNSSearchList(searchListBytes[optionHeaderLen:]), 738 expectedBuf: expectedSearchListBytes[:], 739 check: func(t *testing.T, opt NDPOption) { 740 if got := opt.kind(); got != ndpDNSSearchListOptionType { 741 t.Errorf("got kind() = %d, want = %d", got, ndpDNSSearchListOptionType) 742 } 743 744 dnssl, ok := opt.(NDPDNSSearchList) 745 if !ok { 746 t.Fatalf("got opt = %T, want = NDPDNSSearchList", opt) 747 } 748 if got, want := dnssl.length(), len(expectedRDNSSBytes[optionHeaderLen:]); got != want { 749 t.Errorf("got length() = %d, want = %d", got, want) 750 } 751 if got, want := dnssl.Lifetime(), validLifetimeSeconds*time.Second; got != want { 752 t.Errorf("got Lifetime() = %s, want = %s", got, want) 753 } 754 755 if domainNames, err := dnssl.DomainNames(); err != nil { 756 t.Errorf("DomainNames(): %s", err) 757 } else if diff := cmp.Diff([]string{domainName}, domainNames); diff != "" { 758 t.Errorf("domain names mismatch (-want +got):\n%s", diff) 759 } 760 }, 761 }, 762 763 { 764 name: "Prefix Information", 765 buf: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 766 // NDPPrefixInformation holds the option after the header bytes. 767 opt: NDPPrefixInformation(prefixInformationBytes[optionHeaderLen:]), 768 expectedBuf: expectedPrefixInformationBytes[:], 769 check: func(t *testing.T, opt NDPOption) { 770 if got := opt.kind(); got != ndpPrefixInformationType { 771 t.Errorf("got kind() = %d, want = %d", got, ndpPrefixInformationType) 772 } 773 774 pi, ok := opt.(NDPPrefixInformation) 775 if !ok { 776 t.Fatalf("got opt = %T, want = NDPPrefixInformation", opt) 777 } 778 779 if got, want := pi.length(), len(expectedPrefixInformationBytes[optionHeaderLen:]); got != want { 780 t.Errorf("got length() = %d, want = %d", got, want) 781 } 782 if got := pi.PrefixLength(); got != prefixLength { 783 t.Errorf("got PrefixLength() = %d, want = %d", got, prefixLength) 784 } 785 if got := pi.OnLinkFlag(); got != onLinkFlag { 786 t.Errorf("got OnLinkFlag() = %t, want = %t", got, onLinkFlag) 787 } 788 if got := pi.AutonomousAddressConfigurationFlag(); got != slaacFlag { 789 t.Errorf("got AutonomousAddressConfigurationFlag() = %t, want = %t", got, slaacFlag) 790 } 791 if got, want := pi.ValidLifetime(), validLifetimeSeconds*time.Second; got != want { 792 t.Errorf("got ValidLifetime() = %s, want = %s", got, want) 793 } 794 if got, want := pi.PreferredLifetime(), preferredLifetimeSeconds*time.Second; got != want { 795 t.Errorf("got PreferredLifetime() = %s, want = %s", got, want) 796 } 797 if got := pi.Prefix(); got != address { 798 t.Errorf("got Prefix() = %s, want = %s", got, address) 799 } 800 }, 801 }, 802 } 803 804 for _, test := range tests { 805 t.Run(test.name, func(t *testing.T) { 806 opts := NDPOptions(test.buf) 807 serializer := NDPOptionsSerializer{ 808 test.opt, 809 } 810 if got, want := int(serializer.Length()), len(test.expectedBuf); got != want { 811 t.Fatalf("got Length() = %d, want = %d", got, want) 812 } 813 opts.Serialize(serializer) 814 if diff := cmp.Diff(test.expectedBuf, test.buf); diff != "" { 815 t.Fatalf("serialized buffer mismatch (-want +got):\n%s", diff) 816 } 817 818 it, err := opts.Iter(true) 819 if err != nil { 820 t.Fatalf("got Iter(true) = (_, %s), want = (_, nil)", err) 821 } 822 823 if len(test.expectedBuf) > 0 { 824 next, done, err := it.Next() 825 if err != nil { 826 t.Fatalf("got Next() = (_, _, %s), want = (_, _, nil)", err) 827 } 828 if done { 829 t.Fatal("got Next() = (_, true, _), want = (_, false, _)") 830 } 831 test.check(t, next) 832 } 833 834 // Iterator should not return anything else. 835 next, done, err := it.Next() 836 if err != nil { 837 t.Errorf("got Next() = (_, _, %s), want = (_, _, nil)", err) 838 } 839 if !done { 840 t.Error("got Next() = (_, false, _), want = (_, true, _)") 841 } 842 if next != nil { 843 t.Errorf("got Next() = (%x, _, _), want = (nil, _, _)", next) 844 } 845 }) 846 } 847 } 848 849 func TestNDPRecursiveDNSServerOption(t *testing.T) { 850 tests := []struct { 851 name string 852 buf []byte 853 lifetime time.Duration 854 addrs []tcpip.Address 855 }{ 856 { 857 "Valid1Addr", 858 []byte{ 859 25, 3, 0, 0, 860 0, 0, 0, 0, 861 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 862 }, 863 0, 864 []tcpip.Address{ 865 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 866 }, 867 }, 868 { 869 "Valid2Addr", 870 []byte{ 871 25, 5, 0, 0, 872 0, 0, 0, 0, 873 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 874 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 875 }, 876 0, 877 []tcpip.Address{ 878 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 879 "\x11\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x10", 880 }, 881 }, 882 { 883 "Valid3Addr", 884 []byte{ 885 25, 7, 0, 0, 886 0, 0, 0, 0, 887 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 888 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 889 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 890 }, 891 0, 892 []tcpip.Address{ 893 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 894 "\x11\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x10", 895 "\x11\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x11", 896 }, 897 }, 898 } 899 900 for _, test := range tests { 901 t.Run(test.name, func(t *testing.T) { 902 opts := NDPOptions(test.buf) 903 it, err := opts.Iter(true) 904 if err != nil { 905 t.Fatalf("got Iter = (_, %s), want = (_, nil)", err) 906 } 907 908 // Iterator should get our option. 909 next, done, err := it.Next() 910 if err != nil { 911 t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) 912 } 913 if done { 914 t.Fatal("got Next = (_, true, _), want = (_, false, _)") 915 } 916 if got := next.kind(); got != ndpRecursiveDNSServerOptionType { 917 t.Fatalf("got Type = %d, want = %d", got, ndpRecursiveDNSServerOptionType) 918 } 919 920 opt, ok := next.(NDPRecursiveDNSServer) 921 if !ok { 922 t.Fatalf("next (type = %T) cannot be casted to an NDPRecursiveDNSServer", next) 923 } 924 if got := opt.Lifetime(); got != test.lifetime { 925 t.Errorf("got Lifetime = %d, want = %d", got, test.lifetime) 926 } 927 addrs, err := opt.Addresses() 928 if err != nil { 929 t.Errorf("opt.Addresses() = %s", err) 930 } 931 if diff := cmp.Diff(addrs, test.addrs); diff != "" { 932 t.Errorf("mismatched addresses (-want +got):\n%s", diff) 933 } 934 935 // Iterator should not return anything else. 936 next, done, err = it.Next() 937 if err != nil { 938 t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err) 939 } 940 if !done { 941 t.Error("got Next = (_, false, _), want = (_, true, _)") 942 } 943 if next != nil { 944 t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next) 945 } 946 }) 947 } 948 } 949 950 // TestNDPDNSSearchListOption tests the getters of NDPDNSSearchList. 951 func TestNDPDNSSearchListOption(t *testing.T) { 952 tests := []struct { 953 name string 954 buf []byte 955 lifetime time.Duration 956 domainNames []string 957 err error 958 }{ 959 { 960 name: "Valid1Label", 961 buf: []byte{ 962 0, 0, 963 0, 0, 0, 1, 964 3, 'a', 'b', 'c', 965 0, 966 0, 0, 0, 967 }, 968 lifetime: time.Second, 969 domainNames: []string{ 970 "abc", 971 }, 972 err: nil, 973 }, 974 { 975 name: "Valid2Label", 976 buf: []byte{ 977 0, 0, 978 0, 0, 0, 5, 979 3, 'a', 'b', 'c', 980 4, 'a', 'b', 'c', 'd', 981 0, 982 0, 0, 0, 0, 0, 0, 983 }, 984 lifetime: 5 * time.Second, 985 domainNames: []string{ 986 "abc.abcd", 987 }, 988 err: nil, 989 }, 990 { 991 name: "Valid3Label", 992 buf: []byte{ 993 0, 0, 994 1, 0, 0, 0, 995 3, 'a', 'b', 'c', 996 4, 'a', 'b', 'c', 'd', 997 1, 'e', 998 0, 999 0, 0, 0, 0, 1000 }, 1001 lifetime: 16777216 * time.Second, 1002 domainNames: []string{ 1003 "abc.abcd.e", 1004 }, 1005 err: nil, 1006 }, 1007 { 1008 name: "Valid2Domains", 1009 buf: []byte{ 1010 0, 0, 1011 1, 2, 3, 4, 1012 3, 'a', 'b', 'c', 1013 0, 1014 2, 'd', 'e', 1015 3, 'x', 'y', 'z', 1016 0, 1017 0, 0, 0, 1018 }, 1019 lifetime: 16909060 * time.Second, 1020 domainNames: []string{ 1021 "abc", 1022 "de.xyz", 1023 }, 1024 err: nil, 1025 }, 1026 { 1027 name: "Valid3DomainsMixedCase", 1028 buf: []byte{ 1029 0, 0, 1030 0, 0, 0, 0, 1031 3, 'a', 'B', 'c', 1032 0, 1033 2, 'd', 'E', 1034 3, 'X', 'y', 'z', 1035 0, 1036 1, 'J', 1037 0, 1038 }, 1039 lifetime: 0, 1040 domainNames: []string{ 1041 "abc", 1042 "de.xyz", 1043 "j", 1044 }, 1045 err: nil, 1046 }, 1047 { 1048 name: "ValidDomainAfterNULL", 1049 buf: []byte{ 1050 0, 0, 1051 0, 0, 0, 0, 1052 3, 'a', 'B', 'c', 1053 0, 0, 0, 0, 1054 2, 'd', 'E', 1055 3, 'X', 'y', 'z', 1056 0, 1057 }, 1058 lifetime: 0, 1059 domainNames: []string{ 1060 "abc", 1061 "de.xyz", 1062 }, 1063 err: nil, 1064 }, 1065 { 1066 name: "Valid0Domains", 1067 buf: []byte{ 1068 0, 0, 1069 0, 0, 0, 0, 1070 0, 1071 0, 0, 0, 0, 0, 0, 0, 1072 }, 1073 lifetime: 0, 1074 domainNames: nil, 1075 err: nil, 1076 }, 1077 { 1078 name: "NoTrailingNull", 1079 buf: []byte{ 1080 0, 0, 1081 0, 0, 0, 0, 1082 7, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 1083 }, 1084 lifetime: 0, 1085 domainNames: nil, 1086 err: io.ErrUnexpectedEOF, 1087 }, 1088 { 1089 name: "IncorrectLength", 1090 buf: []byte{ 1091 0, 0, 1092 0, 0, 0, 0, 1093 8, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 1094 }, 1095 lifetime: 0, 1096 domainNames: nil, 1097 err: io.ErrUnexpectedEOF, 1098 }, 1099 { 1100 name: "IncorrectLengthWithNULL", 1101 buf: []byte{ 1102 0, 0, 1103 0, 0, 0, 0, 1104 7, 'a', 'b', 'c', 'd', 'e', 'f', 1105 0, 1106 }, 1107 lifetime: 0, 1108 domainNames: nil, 1109 err: ErrNDPOptMalformedBody, 1110 }, 1111 { 1112 name: "LabelOfLength63", 1113 buf: []byte{ 1114 0, 0, 1115 0, 0, 0, 0, 1116 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1117 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1118 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1119 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1120 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1121 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1122 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1123 'i', 'j', 'k', 1124 0, 1125 }, 1126 lifetime: 0, 1127 domainNames: []string{ 1128 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk", 1129 }, 1130 err: nil, 1131 }, 1132 { 1133 name: "LabelOfLength64", 1134 buf: []byte{ 1135 0, 0, 1136 0, 0, 0, 0, 1137 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1138 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1139 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1140 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1141 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1142 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1143 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1144 'i', 'j', 'k', 'l', 1145 0, 1146 }, 1147 lifetime: 0, 1148 domainNames: nil, 1149 err: ErrNDPOptMalformedBody, 1150 }, 1151 { 1152 name: "DomainNameOfLength255", 1153 buf: []byte{ 1154 0, 0, 1155 0, 0, 0, 0, 1156 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1157 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1158 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1159 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1160 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1161 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1162 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1163 'i', 'j', 'k', 1164 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1165 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1166 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1167 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1168 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1169 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1170 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1171 'i', 'j', 'k', 1172 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1173 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1174 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1175 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1176 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1177 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1178 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1179 'i', 'j', 'k', 1180 62, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1181 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1182 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1183 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1184 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1185 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1186 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1187 'i', 'j', 1188 0, 1189 }, 1190 lifetime: 0, 1191 domainNames: []string{ 1192 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij", 1193 }, 1194 err: nil, 1195 }, 1196 { 1197 name: "DomainNameOfLength256", 1198 buf: []byte{ 1199 0, 0, 1200 0, 0, 0, 0, 1201 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1202 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1203 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1204 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1205 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1206 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1207 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1208 'i', 'j', 'k', 1209 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1210 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1211 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1212 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1213 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1214 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1215 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1216 'i', 'j', 'k', 1217 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1218 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1219 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1220 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1221 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1222 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1223 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1224 'i', 'j', 'k', 1225 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1226 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1227 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1228 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1229 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1230 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1231 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1232 'i', 'j', 'k', 1233 0, 1234 }, 1235 lifetime: 0, 1236 domainNames: nil, 1237 err: ErrNDPOptMalformedBody, 1238 }, 1239 { 1240 name: "StartingDigitForLabel", 1241 buf: []byte{ 1242 0, 0, 1243 0, 0, 0, 1, 1244 3, '9', 'b', 'c', 1245 0, 1246 0, 0, 0, 1247 }, 1248 lifetime: time.Second, 1249 domainNames: nil, 1250 err: ErrNDPOptMalformedBody, 1251 }, 1252 { 1253 name: "StartingHyphenForLabel", 1254 buf: []byte{ 1255 0, 0, 1256 0, 0, 0, 1, 1257 3, '-', 'b', 'c', 1258 0, 1259 0, 0, 0, 1260 }, 1261 lifetime: time.Second, 1262 domainNames: nil, 1263 err: ErrNDPOptMalformedBody, 1264 }, 1265 { 1266 name: "EndingHyphenForLabel", 1267 buf: []byte{ 1268 0, 0, 1269 0, 0, 0, 1, 1270 3, 'a', 'b', '-', 1271 0, 1272 0, 0, 0, 1273 }, 1274 lifetime: time.Second, 1275 domainNames: nil, 1276 err: ErrNDPOptMalformedBody, 1277 }, 1278 { 1279 name: "EndingDigitForLabel", 1280 buf: []byte{ 1281 0, 0, 1282 0, 0, 0, 1, 1283 3, 'a', 'b', '9', 1284 0, 1285 0, 0, 0, 1286 }, 1287 lifetime: time.Second, 1288 domainNames: []string{ 1289 "ab9", 1290 }, 1291 err: nil, 1292 }, 1293 } 1294 1295 for _, test := range tests { 1296 t.Run(test.name, func(t *testing.T) { 1297 opt := NDPDNSSearchList(test.buf) 1298 1299 if got := opt.Lifetime(); got != test.lifetime { 1300 t.Errorf("got Lifetime = %d, want = %d", got, test.lifetime) 1301 } 1302 domainNames, err := opt.DomainNames() 1303 if !errors.Is(err, test.err) { 1304 t.Errorf("opt.DomainNames() = %s", err) 1305 } 1306 if diff := cmp.Diff(domainNames, test.domainNames); diff != "" { 1307 t.Errorf("mismatched domain names (-want +got):\n%s", diff) 1308 } 1309 }) 1310 } 1311 } 1312 1313 func TestNDPSearchListOptionDomainNameLabelInvalidSymbols(t *testing.T) { 1314 for r := rune(0); r <= 255; r++ { 1315 t.Run(fmt.Sprintf("RuneVal=%d", r), func(t *testing.T) { 1316 buf := []byte{ 1317 0, 0, 1318 0, 0, 0, 0, 1319 3, 'a', 0 /* will be replaced */, 'c', 1320 0, 1321 0, 0, 0, 1322 } 1323 buf[8] = uint8(r) 1324 opt := NDPDNSSearchList(buf) 1325 1326 // As per RFC 1035 section 2.3.1, the label must only include ASCII 1327 // letters, digits and hyphens (a-z, A-Z, 0-9, -). 1328 var expectedErr error 1329 re := regexp.MustCompile(`[a-zA-Z0-9-]`) 1330 if !re.Match([]byte{byte(r)}) { 1331 expectedErr = ErrNDPOptMalformedBody 1332 } 1333 1334 if domainNames, err := opt.DomainNames(); !errors.Is(err, expectedErr) { 1335 t.Errorf("got opt.DomainNames() = (%s, %v), want = (_, %v)", domainNames, err, ErrNDPOptMalformedBody) 1336 } 1337 }) 1338 } 1339 } 1340 1341 // TestNDPOptionsIterCheck tests that Iter will return false if the NDPOptions 1342 // the iterator was returned for is malformed. 1343 func TestNDPOptionsIterCheck(t *testing.T) { 1344 tests := []struct { 1345 name string 1346 buf []byte 1347 expectedErr error 1348 }{ 1349 { 1350 name: "ZeroLengthField", 1351 buf: []byte{0, 0, 0, 0, 0, 0, 0, 0}, 1352 expectedErr: ErrNDPOptMalformedHeader, 1353 }, 1354 { 1355 name: "ValidSourceLinkLayerAddressOption", 1356 buf: []byte{1, 1, 1, 2, 3, 4, 5, 6}, 1357 expectedErr: nil, 1358 }, 1359 { 1360 name: "TooSmallSourceLinkLayerAddressOption", 1361 buf: []byte{1, 1, 1, 2, 3, 4, 5}, 1362 expectedErr: io.ErrUnexpectedEOF, 1363 }, 1364 { 1365 name: "ValidTargetLinkLayerAddressOption", 1366 buf: []byte{2, 1, 1, 2, 3, 4, 5, 6}, 1367 expectedErr: nil, 1368 }, 1369 { 1370 name: "TooSmallTargetLinkLayerAddressOption", 1371 buf: []byte{2, 1, 1, 2, 3, 4, 5}, 1372 expectedErr: io.ErrUnexpectedEOF, 1373 }, 1374 { 1375 name: "ValidPrefixInformation", 1376 buf: []byte{ 1377 3, 4, 43, 64, 1378 1, 2, 3, 4, 1379 5, 6, 7, 8, 1380 0, 0, 0, 0, 1381 9, 10, 11, 12, 1382 13, 14, 15, 16, 1383 17, 18, 19, 20, 1384 21, 22, 23, 24, 1385 }, 1386 expectedErr: nil, 1387 }, 1388 { 1389 name: "TooSmallPrefixInformation", 1390 buf: []byte{ 1391 3, 4, 43, 64, 1392 1, 2, 3, 4, 1393 5, 6, 7, 8, 1394 0, 0, 0, 0, 1395 9, 10, 11, 12, 1396 13, 14, 15, 16, 1397 17, 18, 19, 20, 1398 21, 22, 23, 1399 }, 1400 expectedErr: io.ErrUnexpectedEOF, 1401 }, 1402 { 1403 name: "InvalidPrefixInformationLength", 1404 buf: []byte{ 1405 3, 3, 43, 64, 1406 1, 2, 3, 4, 1407 5, 6, 7, 8, 1408 0, 0, 0, 0, 1409 9, 10, 11, 12, 1410 13, 14, 15, 16, 1411 }, 1412 expectedErr: ErrNDPOptMalformedBody, 1413 }, 1414 { 1415 name: "ValidSourceAndTargetLinkLayerAddressWithPrefixInformation", 1416 buf: []byte{ 1417 // Source Link-Layer Address. 1418 1, 1, 1, 2, 3, 4, 5, 6, 1419 1420 // Target Link-Layer Address. 1421 2, 1, 7, 8, 9, 10, 11, 12, 1422 1423 // Prefix information. 1424 3, 4, 43, 64, 1425 1, 2, 3, 4, 1426 5, 6, 7, 8, 1427 0, 0, 0, 0, 1428 9, 10, 11, 12, 1429 13, 14, 15, 16, 1430 17, 18, 19, 20, 1431 21, 22, 23, 24, 1432 }, 1433 expectedErr: nil, 1434 }, 1435 { 1436 name: "ValidSourceAndTargetLinkLayerAddressWithPrefixInformationWithUnrecognized", 1437 buf: []byte{ 1438 // Source Link-Layer Address. 1439 1, 1, 1, 2, 3, 4, 5, 6, 1440 1441 // Target Link-Layer Address. 1442 2, 1, 7, 8, 9, 10, 11, 12, 1443 1444 // 255 is an unrecognized type. If 255 ends up 1445 // being the type for some recognized type, 1446 // update 255 to some other unrecognized value. 1447 255, 2, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 1448 1449 // Prefix information. 1450 3, 4, 43, 64, 1451 1, 2, 3, 4, 1452 5, 6, 7, 8, 1453 0, 0, 0, 0, 1454 9, 10, 11, 12, 1455 13, 14, 15, 16, 1456 17, 18, 19, 20, 1457 21, 22, 23, 24, 1458 }, 1459 expectedErr: nil, 1460 }, 1461 { 1462 name: "InvalidRecursiveDNSServerCutsOffAddress", 1463 buf: []byte{ 1464 25, 4, 0, 0, 1465 0, 0, 0, 0, 1466 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1467 0, 1, 2, 3, 4, 5, 6, 7, 1468 }, 1469 expectedErr: ErrNDPOptMalformedBody, 1470 }, 1471 { 1472 name: "InvalidRecursiveDNSServerInvalidLengthField", 1473 buf: []byte{ 1474 25, 2, 0, 0, 1475 0, 0, 0, 0, 1476 0, 1, 2, 3, 4, 5, 6, 7, 8, 1477 }, 1478 expectedErr: io.ErrUnexpectedEOF, 1479 }, 1480 { 1481 name: "RecursiveDNSServerTooSmall", 1482 buf: []byte{ 1483 25, 1, 0, 0, 1484 0, 0, 0, 1485 }, 1486 expectedErr: io.ErrUnexpectedEOF, 1487 }, 1488 { 1489 name: "RecursiveDNSServerMulticast", 1490 buf: []byte{ 1491 25, 3, 0, 0, 1492 0, 0, 0, 0, 1493 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1494 }, 1495 expectedErr: ErrNDPOptMalformedBody, 1496 }, 1497 { 1498 name: "RecursiveDNSServerUnspecified", 1499 buf: []byte{ 1500 25, 3, 0, 0, 1501 0, 0, 0, 0, 1502 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1503 }, 1504 expectedErr: ErrNDPOptMalformedBody, 1505 }, 1506 { 1507 name: "DNSSearchListLargeCompliantRFC1035", 1508 buf: []byte{ 1509 31, 33, 0, 0, 1510 0, 0, 0, 0, 1511 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1512 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1513 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1514 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1515 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1516 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1517 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1518 'i', 'j', 'k', 1519 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1520 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1521 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1522 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1523 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1524 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1525 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1526 'i', 'j', 'k', 1527 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1528 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1529 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1530 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1531 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1532 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1533 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1534 'i', 'j', 'k', 1535 62, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1536 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1537 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1538 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1539 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1540 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1541 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1542 'i', 'j', 1543 0, 1544 }, 1545 expectedErr: nil, 1546 }, 1547 { 1548 name: "DNSSearchListNonCompliantRFC1035", 1549 buf: []byte{ 1550 31, 33, 0, 0, 1551 0, 0, 0, 0, 1552 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1553 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1554 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1555 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1556 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1557 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1558 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1559 'i', 'j', 'k', 1560 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1561 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1562 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1563 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1564 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1565 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1566 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1567 'i', 'j', 'k', 1568 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1569 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1570 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1571 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1572 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1573 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1574 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1575 'i', 'j', 'k', 1576 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1577 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1578 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1579 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1580 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 1581 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1582 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 1583 'i', 'j', 'k', 1584 0, 1585 0, 0, 0, 0, 0, 0, 0, 0, 1586 }, 1587 expectedErr: ErrNDPOptMalformedBody, 1588 }, 1589 { 1590 name: "DNSSearchListValidSmall", 1591 buf: []byte{ 1592 31, 2, 0, 0, 1593 0, 0, 0, 0, 1594 6, 'a', 'b', 'c', 'd', 'e', 'f', 1595 0, 1596 }, 1597 expectedErr: nil, 1598 }, 1599 { 1600 name: "DNSSearchListTooSmall", 1601 buf: []byte{ 1602 31, 1, 0, 0, 1603 0, 0, 0, 1604 }, 1605 expectedErr: io.ErrUnexpectedEOF, 1606 }, 1607 } 1608 1609 for _, test := range tests { 1610 t.Run(test.name, func(t *testing.T) { 1611 opts := NDPOptions(test.buf) 1612 1613 if _, err := opts.Iter(true); !errors.Is(err, test.expectedErr) { 1614 t.Fatalf("got Iter(true) = (_, %v), want = (_, %v)", err, test.expectedErr) 1615 } 1616 1617 // test.buf may be malformed but we chose not to check 1618 // the iterator so it must return true. 1619 if _, err := opts.Iter(false); err != nil { 1620 t.Fatalf("got Iter(false) = (_, %s), want = (_, nil)", err) 1621 } 1622 }) 1623 } 1624 } 1625 1626 // TestNDPOptionsIter tests that we can iterator over a valid NDPOptions. Note, 1627 // this test does not actually check any of the option's getters, it simply 1628 // checks the option Type and Body. We have other tests that tests the option 1629 // field gettings given an option body and don't need to duplicate those tests 1630 // here. 1631 func TestNDPOptionsIter(t *testing.T) { 1632 buf := []byte{ 1633 // Source Link-Layer Address. 1634 1, 1, 1, 2, 3, 4, 5, 6, 1635 1636 // Target Link-Layer Address. 1637 2, 1, 7, 8, 9, 10, 11, 12, 1638 1639 // 255 is an unrecognized type. If 255 ends up being the type 1640 // for some recognized type, update 255 to some other 1641 // unrecognized value. Note, this option should be skipped when 1642 // iterating. 1643 255, 2, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 1644 1645 // Prefix information. 1646 3, 4, 43, 64, 1647 1, 2, 3, 4, 1648 5, 6, 7, 8, 1649 0, 0, 0, 0, 1650 9, 10, 11, 12, 1651 13, 14, 15, 16, 1652 17, 18, 19, 20, 1653 21, 22, 23, 24, 1654 } 1655 1656 opts := NDPOptions(buf) 1657 it, err := opts.Iter(true) 1658 if err != nil { 1659 t.Fatalf("got Iter = (_, %s), want = (_, nil)", err) 1660 } 1661 1662 // Test the first (Source Link-Layer) option. 1663 next, done, err := it.Next() 1664 if err != nil { 1665 t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) 1666 } 1667 if done { 1668 t.Fatal("got Next = (_, true, _), want = (_, false, _)") 1669 } 1670 if got, want := []byte(next.(NDPSourceLinkLayerAddressOption)), buf[2:][:6]; !bytes.Equal(got, want) { 1671 t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want) 1672 } 1673 if got := next.kind(); got != ndpSourceLinkLayerAddressOptionType { 1674 t.Errorf("got Type = %d, want = %d", got, ndpSourceLinkLayerAddressOptionType) 1675 } 1676 1677 // Test the next (Target Link-Layer) option. 1678 next, done, err = it.Next() 1679 if err != nil { 1680 t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) 1681 } 1682 if done { 1683 t.Fatal("got Next = (_, true, _), want = (_, false, _)") 1684 } 1685 if got, want := []byte(next.(NDPTargetLinkLayerAddressOption)), buf[10:][:6]; !bytes.Equal(got, want) { 1686 t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want) 1687 } 1688 if got := next.kind(); got != ndpTargetLinkLayerAddressOptionType { 1689 t.Errorf("got Type = %d, want = %d", got, ndpTargetLinkLayerAddressOptionType) 1690 } 1691 1692 // Test the next (Prefix Information) option. 1693 // Note, the unrecognized option should be skipped. 1694 next, done, err = it.Next() 1695 if err != nil { 1696 t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) 1697 } 1698 if done { 1699 t.Fatal("got Next = (_, true, _), want = (_, false, _)") 1700 } 1701 if got, want := next.(NDPPrefixInformation), buf[34:][:30]; !bytes.Equal(got, want) { 1702 t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want) 1703 } 1704 if got := next.kind(); got != ndpPrefixInformationType { 1705 t.Errorf("got Type = %d, want = %d", got, ndpPrefixInformationType) 1706 } 1707 1708 // Iterator should not return anything else. 1709 next, done, err = it.Next() 1710 if err != nil { 1711 t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err) 1712 } 1713 if !done { 1714 t.Error("got Next = (_, false, _), want = (_, true, _)") 1715 } 1716 if next != nil { 1717 t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next) 1718 } 1719 } 1720 1721 func TestNDPRoutePreferenceStringer(t *testing.T) { 1722 p := NDPRoutePreference(0) 1723 for { 1724 var wantStr string 1725 switch p { 1726 case 0b01: 1727 wantStr = "HighRoutePreference" 1728 case 0b00: 1729 wantStr = "MediumRoutePreference" 1730 case 0b11: 1731 wantStr = "LowRoutePreference" 1732 case 0b10: 1733 wantStr = "ReservedRoutePreference" 1734 default: 1735 wantStr = fmt.Sprintf("NDPRoutePreference(%d)", p) 1736 } 1737 1738 if gotStr := p.String(); gotStr != wantStr { 1739 t.Errorf("got NDPRoutePreference(%d).String() = %s, want = %s", p, gotStr, wantStr) 1740 } 1741 1742 p++ 1743 if p == 0 { 1744 // Overflowed, we hit all values. 1745 break 1746 } 1747 } 1748 }