gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/ipv6/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 ipv6 16 17 import ( 18 "math/rand" 19 "strings" 20 "testing" 21 "time" 22 23 "github.com/google/go-cmp/cmp" 24 "gvisor.dev/gvisor/pkg/buffer" 25 "gvisor.dev/gvisor/pkg/tcpip" 26 "gvisor.dev/gvisor/pkg/tcpip/checker" 27 "gvisor.dev/gvisor/pkg/tcpip/checksum" 28 "gvisor.dev/gvisor/pkg/tcpip/faketime" 29 "gvisor.dev/gvisor/pkg/tcpip/header" 30 "gvisor.dev/gvisor/pkg/tcpip/link/channel" 31 "gvisor.dev/gvisor/pkg/tcpip/prependable" 32 "gvisor.dev/gvisor/pkg/tcpip/stack" 33 "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" 34 ) 35 36 var _ NDPDispatcher = (*testNDPDispatcher)(nil) 37 38 // testNDPDispatcher is an NDPDispatcher only allows default router discovery. 39 type testNDPDispatcher struct { 40 addr tcpip.Address 41 } 42 43 func (*testNDPDispatcher) OnDuplicateAddressDetectionResult(tcpip.NICID, tcpip.Address, stack.DADResult) { 44 } 45 46 func (t *testNDPDispatcher) OnOffLinkRouteUpdated(_ tcpip.NICID, _ tcpip.Subnet, addr tcpip.Address, _ header.NDPRoutePreference) { 47 t.addr = addr 48 } 49 50 func (t *testNDPDispatcher) OnOffLinkRouteInvalidated(_ tcpip.NICID, _ tcpip.Subnet, addr tcpip.Address) { 51 t.addr = addr 52 } 53 54 func (*testNDPDispatcher) OnOnLinkPrefixDiscovered(tcpip.NICID, tcpip.Subnet) { 55 } 56 57 func (*testNDPDispatcher) OnOnLinkPrefixInvalidated(tcpip.NICID, tcpip.Subnet) { 58 } 59 60 func (*testNDPDispatcher) OnAutoGenAddress(tcpip.NICID, tcpip.AddressWithPrefix) stack.AddressDispatcher { 61 return nil 62 } 63 64 func (*testNDPDispatcher) OnAutoGenAddressDeprecated(tcpip.NICID, tcpip.AddressWithPrefix) { 65 } 66 67 func (*testNDPDispatcher) OnAutoGenAddressInvalidated(tcpip.NICID, tcpip.AddressWithPrefix) { 68 } 69 70 func (*testNDPDispatcher) OnRecursiveDNSServerOption(tcpip.NICID, []tcpip.Address, time.Duration) { 71 } 72 73 func (*testNDPDispatcher) OnDNSSearchListOption(tcpip.NICID, []string, time.Duration) { 74 } 75 76 func (*testNDPDispatcher) OnDHCPv6Configuration(tcpip.NICID, DHCPv6ConfigurationFromNDPRA) { 77 } 78 79 func TestStackNDPEndpointInvalidateDefaultRouter(t *testing.T) { 80 var ndpDisp testNDPDispatcher 81 s := stack.New(stack.Options{ 82 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocolWithOptions(Options{ 83 NDPDisp: &ndpDisp, 84 })}, 85 }) 86 defer s.Close() 87 88 if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil { 89 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 90 } 91 92 ep, err := s.GetNetworkEndpoint(nicID, ProtocolNumber) 93 if err != nil { 94 t.Fatalf("s.GetNetworkEndpoint(%d, %d): %s", nicID, ProtocolNumber, err) 95 } 96 97 ipv6EP := ep.(*endpoint) 98 ipv6EP.mu.Lock() 99 ipv6EP.mu.ndp.handleOffLinkRouteDiscovery(offLinkRoute{dest: header.IPv6EmptySubnet, router: lladdr1}, time.Hour, header.MediumRoutePreference) 100 ipv6EP.mu.Unlock() 101 102 if ndpDisp.addr != lladdr1 { 103 t.Fatalf("got ndpDisp.addr = %s, want = %s", ndpDisp.addr, lladdr1) 104 } 105 106 ndpDisp.addr = tcpip.Address{} 107 ndpEP := ep.(stack.NDPEndpoint) 108 ndpEP.InvalidateDefaultRouter(lladdr1) 109 if ndpDisp.addr != lladdr1 { 110 t.Fatalf("got ndpDisp.addr = %s, want = %s", ndpDisp.addr, lladdr1) 111 } 112 } 113 114 // TestNeighborSolicitationWithSourceLinkLayerOption tests that receiving a 115 // valid NDP NS message with the Source Link Layer Address option results in a 116 // new entry in the link address cache for the sender of the message. 117 func TestNeighborSolicitationWithSourceLinkLayerOption(t *testing.T) { 118 const nicID = 1 119 120 tests := []struct { 121 name string 122 optsBuf []byte 123 expectedLinkAddr tcpip.LinkAddress 124 }{ 125 { 126 name: "Valid", 127 optsBuf: []byte{1, 1, 2, 3, 4, 5, 6, 7}, 128 expectedLinkAddr: "\x02\x03\x04\x05\x06\x07", 129 }, 130 { 131 name: "Too Small", 132 optsBuf: []byte{1, 1, 2, 3, 4, 5, 6}, 133 }, 134 { 135 name: "Invalid Length", 136 optsBuf: []byte{1, 2, 2, 3, 4, 5, 6, 7}, 137 }, 138 } 139 140 for _, test := range tests { 141 t.Run(test.name, func(t *testing.T) { 142 c := newTestContext() 143 defer c.cleanup() 144 s := c.s 145 146 e := channel.New(0, 1280, linkAddr0) 147 defer e.Close() 148 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 149 if err := s.CreateNIC(nicID, e); err != nil { 150 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 151 } 152 protocolAddr := tcpip.ProtocolAddress{ 153 Protocol: ProtocolNumber, 154 AddressWithPrefix: lladdr0.WithPrefix(), 155 } 156 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 157 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 158 } 159 160 ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize + len(test.optsBuf) 161 hdr := prependable.New(header.IPv6MinimumSize + ndpNSSize) 162 pkt := header.ICMPv6(hdr.Prepend(ndpNSSize)) 163 pkt.SetType(header.ICMPv6NeighborSolicit) 164 ns := header.NDPNeighborSolicit(pkt.MessageBody()) 165 ns.SetTargetAddress(lladdr0) 166 opts := ns.Options() 167 copy(opts, test.optsBuf) 168 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 169 Header: pkt, 170 Src: lladdr1, 171 Dst: lladdr0, 172 })) 173 payloadLength := hdr.UsedLength() 174 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 175 ip.Encode(&header.IPv6Fields{ 176 PayloadLength: uint16(payloadLength), 177 TransportProtocol: header.ICMPv6ProtocolNumber, 178 HopLimit: 255, 179 SrcAddr: lladdr1, 180 DstAddr: lladdr0, 181 }) 182 183 invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid 184 185 // Invalid count should initially be 0. 186 if got := invalid.Value(); got != 0 { 187 t.Fatalf("got invalid = %d, want = 0", got) 188 } 189 190 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 191 Payload: buffer.MakeWithData(hdr.View()), 192 }) 193 e.InjectInbound(ProtocolNumber, pktBuf) 194 pktBuf.DecRef() 195 196 neighbors, err := s.Neighbors(nicID, ProtocolNumber) 197 if err != nil { 198 t.Fatalf("s.Neighbors(%d, %d): %s", nicID, ProtocolNumber, err) 199 } 200 201 neighborByAddr := make(map[tcpip.Address]stack.NeighborEntry) 202 for _, n := range neighbors { 203 if existing, ok := neighborByAddr[n.Addr]; ok { 204 if diff := cmp.Diff(existing, n); diff != "" { 205 t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry (-existing +got):\n%s", nicID, ProtocolNumber, diff) 206 } 207 t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry: %#v", nicID, ProtocolNumber, existing) 208 } 209 neighborByAddr[n.Addr] = n 210 } 211 212 if neigh, ok := neighborByAddr[lladdr1]; len(test.expectedLinkAddr) != 0 { 213 // Invalid count should not have increased. 214 if got := invalid.Value(); got != 0 { 215 t.Errorf("got invalid = %d, want = 0", got) 216 } 217 218 if !ok { 219 t.Fatalf("expected a neighbor entry for %q", lladdr1) 220 } 221 if neigh.LinkAddr != test.expectedLinkAddr { 222 t.Errorf("got link address = %s, want = %s", neigh.LinkAddr, test.expectedLinkAddr) 223 } 224 if neigh.State != stack.Stale { 225 t.Errorf("got NUD state = %s, want = %s", neigh.State, stack.Stale) 226 } 227 } else { 228 // Invalid count should have increased. 229 if got := invalid.Value(); got != 1 { 230 t.Errorf("got invalid = %d, want = 1", got) 231 } 232 233 if ok { 234 t.Fatalf("unexpectedly got neighbor entry: %#v", neigh) 235 } 236 } 237 }) 238 } 239 } 240 241 func TestNeighborSolicitationResponse(t *testing.T) { 242 const nicID = 1 243 nicAddr := lladdr0 244 remoteAddr := lladdr1 245 nicAddrSNMC := header.SolicitedNodeAddr(nicAddr) 246 nicLinkAddr := linkAddr0 247 remoteLinkAddr0 := linkAddr1 248 remoteLinkAddr1 := linkAddr2 249 250 tests := []struct { 251 name string 252 nsOpts header.NDPOptionsSerializer 253 nsSrc tcpip.Address 254 nsDst tcpip.Address 255 nsInvalid bool 256 naDstLinkAddr tcpip.LinkAddress 257 naSolicited bool 258 naSrc tcpip.Address 259 naDst tcpip.Address 260 performsLinkResolution bool 261 forwardingEnabled bool 262 }{ 263 { 264 name: "Unspecified source to solicited-node multicast destination", 265 nsOpts: nil, 266 nsSrc: header.IPv6Any, 267 nsDst: nicAddrSNMC, 268 nsInvalid: false, 269 naDstLinkAddr: header.EthernetAddressFromMulticastIPv6Address(header.IPv6AllNodesMulticastAddress), 270 naSolicited: false, 271 naSrc: nicAddr, 272 naDst: header.IPv6AllNodesMulticastAddress, 273 }, 274 { 275 name: "Unspecified source with source ll option to multicast destination", 276 nsOpts: header.NDPOptionsSerializer{ 277 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]), 278 }, 279 nsSrc: header.IPv6Any, 280 nsDst: nicAddrSNMC, 281 nsInvalid: true, 282 }, 283 { 284 name: "Unspecified source to unicast destination", 285 nsOpts: nil, 286 nsSrc: header.IPv6Any, 287 nsDst: nicAddr, 288 nsInvalid: true, 289 }, 290 { 291 name: "Unspecified source with source ll option to unicast destination", 292 nsOpts: header.NDPOptionsSerializer{ 293 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]), 294 }, 295 nsSrc: header.IPv6Any, 296 nsDst: nicAddr, 297 nsInvalid: true, 298 }, 299 { 300 name: "Specified source with 1 source ll to multicast destination", 301 nsOpts: header.NDPOptionsSerializer{ 302 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]), 303 }, 304 nsSrc: remoteAddr, 305 nsDst: nicAddrSNMC, 306 nsInvalid: false, 307 naDstLinkAddr: remoteLinkAddr0, 308 naSolicited: true, 309 naSrc: nicAddr, 310 naDst: remoteAddr, 311 }, 312 { 313 name: "Specified source with 1 source ll different from route to multicast destination", 314 nsOpts: header.NDPOptionsSerializer{ 315 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]), 316 }, 317 nsSrc: remoteAddr, 318 nsDst: nicAddrSNMC, 319 nsInvalid: false, 320 naDstLinkAddr: remoteLinkAddr1, 321 naSolicited: true, 322 naSrc: nicAddr, 323 naDst: remoteAddr, 324 }, 325 { 326 name: "Specified source to multicast destination", 327 nsOpts: nil, 328 nsSrc: remoteAddr, 329 nsDst: nicAddrSNMC, 330 nsInvalid: true, 331 }, 332 { 333 name: "Specified source with 2 source ll to multicast destination", 334 nsOpts: header.NDPOptionsSerializer{ 335 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]), 336 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]), 337 }, 338 nsSrc: remoteAddr, 339 nsDst: nicAddrSNMC, 340 nsInvalid: true, 341 }, 342 343 { 344 name: "Specified source to unicast destination", 345 nsOpts: nil, 346 nsSrc: remoteAddr, 347 nsDst: nicAddr, 348 nsInvalid: false, 349 naDstLinkAddr: remoteLinkAddr0, 350 naSolicited: true, 351 naSrc: nicAddr, 352 naDst: remoteAddr, 353 // Since we send a unicast solicitations to a node without an entry for 354 // the remote, the node needs to perform neighbor discovery to get the 355 // remote's link address to send the advertisement response. 356 performsLinkResolution: true, 357 }, 358 { 359 name: "Specified source with 1 source ll to unicast destination", 360 nsOpts: header.NDPOptionsSerializer{ 361 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]), 362 }, 363 nsSrc: remoteAddr, 364 nsDst: nicAddr, 365 nsInvalid: false, 366 naDstLinkAddr: remoteLinkAddr0, 367 naSolicited: true, 368 naSrc: nicAddr, 369 naDst: remoteAddr, 370 }, 371 { 372 name: "Specified source with 1 source ll different from route to unicast destination", 373 nsOpts: header.NDPOptionsSerializer{ 374 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]), 375 }, 376 nsSrc: remoteAddr, 377 nsDst: nicAddr, 378 nsInvalid: false, 379 naDstLinkAddr: remoteLinkAddr1, 380 naSolicited: true, 381 naSrc: nicAddr, 382 naDst: remoteAddr, 383 }, 384 { 385 name: "Specified source with 2 source ll to unicast destination", 386 nsOpts: header.NDPOptionsSerializer{ 387 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]), 388 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]), 389 }, 390 nsSrc: remoteAddr, 391 nsDst: nicAddr, 392 nsInvalid: true, 393 }, 394 { 395 name: "Specified source with 1 source ll to multicast destination with forwarding enabled", 396 nsOpts: header.NDPOptionsSerializer{ 397 header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]), 398 }, 399 nsSrc: remoteAddr, 400 nsDst: nicAddrSNMC, 401 nsInvalid: false, 402 naDstLinkAddr: remoteLinkAddr0, 403 naSolicited: true, 404 naSrc: nicAddr, 405 naDst: remoteAddr, 406 forwardingEnabled: true, 407 }, 408 } 409 410 for _, test := range tests { 411 t.Run(test.name, func(t *testing.T) { 412 c := newTestContext() 413 defer c.cleanup() 414 s := c.s 415 416 if err := s.SetForwardingDefaultAndAllNICs(header.IPv6ProtocolNumber, test.forwardingEnabled); err != nil { 417 t.Fatalf("SetForwardingDefaultAndAllNICs(%t): %s", test.forwardingEnabled, err) 418 } 419 420 e := channel.New(1, 1280, nicLinkAddr) 421 defer e.Close() 422 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 423 if err := s.CreateNIC(nicID, e); err != nil { 424 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 425 } 426 protocolAddr := tcpip.ProtocolAddress{ 427 Protocol: ProtocolNumber, 428 AddressWithPrefix: nicAddr.WithPrefix(), 429 } 430 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 431 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 432 } 433 434 s.SetRouteTable([]tcpip.Route{ 435 { 436 Destination: header.IPv6EmptySubnet, 437 NIC: 1, 438 }, 439 }) 440 441 ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize + test.nsOpts.Length() 442 hdr := prependable.New(header.IPv6MinimumSize + ndpNSSize) 443 pkt := header.ICMPv6(hdr.Prepend(ndpNSSize)) 444 pkt.SetType(header.ICMPv6NeighborSolicit) 445 ns := header.NDPNeighborSolicit(pkt.MessageBody()) 446 ns.SetTargetAddress(nicAddr) 447 opts := ns.Options() 448 opts.Serialize(test.nsOpts) 449 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 450 Header: pkt, 451 Src: test.nsSrc, 452 Dst: test.nsDst, 453 })) 454 payloadLength := hdr.UsedLength() 455 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 456 ip.Encode(&header.IPv6Fields{ 457 PayloadLength: uint16(payloadLength), 458 TransportProtocol: header.ICMPv6ProtocolNumber, 459 HopLimit: 255, 460 SrcAddr: test.nsSrc, 461 DstAddr: test.nsDst, 462 }) 463 464 invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid 465 466 // Invalid count should initially be 0. 467 if got := invalid.Value(); got != 0 { 468 t.Fatalf("got invalid = %d, want = 0", got) 469 } 470 471 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 472 Payload: buffer.MakeWithData(hdr.View()), 473 }) 474 e.InjectInbound(ProtocolNumber, pktBuf) 475 pktBuf.DecRef() 476 477 if test.nsInvalid { 478 if got := invalid.Value(); got != 1 { 479 t.Fatalf("got invalid = %d, want = 1", got) 480 } 481 482 if p := e.Read(); p != nil { 483 t.Fatalf("unexpected response to an invalid NS = %+v", p) 484 } 485 486 // If we expected the NS to be invalid, we have nothing else to check. 487 return 488 } 489 490 if got := invalid.Value(); got != 0 { 491 t.Fatalf("got invalid = %d, want = 0", got) 492 } 493 494 if test.performsLinkResolution { 495 c.clock.RunImmediatelyScheduledJobs() 496 p := e.Read() 497 if p == nil { 498 t.Fatal("expected an NDP NS response") 499 } 500 501 respNSDst := header.SolicitedNodeAddr(test.nsSrc) 502 var want stack.RouteInfo 503 want.NetProto = ProtocolNumber 504 want.LocalLinkAddress = nicLinkAddr 505 want.RemoteLinkAddress = header.EthernetAddressFromMulticastIPv6Address(respNSDst) 506 if diff := cmp.Diff(want, p.EgressRoute, cmp.AllowUnexported(want)); diff != "" { 507 t.Errorf("route info mismatch (-want +got):\n%s", diff) 508 } 509 510 payload := stack.PayloadSince(p.NetworkHeader()) 511 defer payload.Release() 512 checker.IPv6(t, payload, 513 checker.SrcAddr(nicAddr), 514 checker.DstAddr(respNSDst), 515 checker.TTL(header.NDPHopLimit), 516 checker.NDPNS( 517 checker.NDPNSTargetAddress(test.nsSrc), 518 checker.NDPNSOptions([]header.NDPOption{ 519 header.NDPSourceLinkLayerAddressOption(nicLinkAddr), 520 }), 521 )) 522 p.DecRef() 523 524 ser := header.NDPOptionsSerializer{ 525 header.NDPTargetLinkLayerAddressOption(linkAddr1), 526 } 527 ndpNASize := header.ICMPv6NeighborAdvertMinimumSize + ser.Length() 528 hdr := prependable.New(header.IPv6MinimumSize + ndpNASize) 529 pkt := header.ICMPv6(hdr.Prepend(ndpNASize)) 530 pkt.SetType(header.ICMPv6NeighborAdvert) 531 na := header.NDPNeighborAdvert(pkt.MessageBody()) 532 na.SetSolicitedFlag(true) 533 na.SetOverrideFlag(true) 534 na.SetRouterFlag(test.forwardingEnabled) 535 na.SetTargetAddress(test.nsSrc) 536 na.Options().Serialize(ser) 537 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 538 Header: pkt, 539 Src: test.nsSrc, 540 Dst: nicAddr, 541 })) 542 payloadLength := hdr.UsedLength() 543 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 544 ip.Encode(&header.IPv6Fields{ 545 PayloadLength: uint16(payloadLength), 546 TransportProtocol: header.ICMPv6ProtocolNumber, 547 HopLimit: header.NDPHopLimit, 548 SrcAddr: test.nsSrc, 549 DstAddr: nicAddr, 550 }) 551 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 552 Payload: buffer.MakeWithData(hdr.View()), 553 }) 554 e.InjectInbound(ProtocolNumber, pktBuf) 555 pktBuf.DecRef() 556 } 557 558 c.clock.RunImmediatelyScheduledJobs() 559 p := e.Read() 560 if p == nil { 561 t.Fatal("expected an NDP NA response") 562 } 563 defer p.DecRef() 564 565 if p.EgressRoute.LocalAddress != test.naSrc { 566 t.Errorf("got p.EgressRoute.LocalAddress = %s, want = %s", p.EgressRoute.LocalAddress, test.naSrc) 567 } 568 if p.EgressRoute.LocalLinkAddress != nicLinkAddr { 569 t.Errorf("p.EgressRoute.LocalLinkAddress = %s, want = %s", p.EgressRoute.LocalLinkAddress, nicLinkAddr) 570 } 571 if p.EgressRoute.RemoteAddress != test.naDst { 572 t.Errorf("got p.EgressRoute.RemoteAddress = %s, want = %s", p.EgressRoute.RemoteAddress, test.naDst) 573 } 574 if p.EgressRoute.RemoteLinkAddress != test.naDstLinkAddr { 575 t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, test.naDstLinkAddr) 576 } 577 578 payload := stack.PayloadSince(p.NetworkHeader()) 579 defer payload.Release() 580 checker.IPv6(t, payload, 581 checker.SrcAddr(test.naSrc), 582 checker.DstAddr(test.naDst), 583 checker.TTL(header.NDPHopLimit), 584 checker.NDPNA( 585 checker.NDPNASolicitedFlag(test.naSolicited), 586 checker.NDPNATargetAddress(nicAddr), 587 checker.NDPNAOptions([]header.NDPOption{ 588 header.NDPTargetLinkLayerAddressOption(nicLinkAddr[:]), 589 }), 590 )) 591 }) 592 } 593 } 594 595 // TestNeighborAdvertisementWithTargetLinkLayerOption tests that receiving a 596 // valid NDP NA message with the Target Link Layer Address option does not 597 // result in a new entry in the neighbor cache for the target of the message. 598 func TestNeighborAdvertisementWithTargetLinkLayerOption(t *testing.T) { 599 const nicID = 1 600 601 tests := []struct { 602 name string 603 optsBuf []byte 604 isValid bool 605 }{ 606 { 607 name: "Valid", 608 optsBuf: []byte{2, 1, 2, 3, 4, 5, 6, 7}, 609 isValid: true, 610 }, 611 { 612 name: "Too Small", 613 optsBuf: []byte{2, 1, 2, 3, 4, 5, 6}, 614 }, 615 { 616 name: "Invalid Length", 617 optsBuf: []byte{2, 2, 2, 3, 4, 5, 6, 7}, 618 }, 619 { 620 name: "Multiple", 621 optsBuf: []byte{ 622 2, 1, 2, 3, 4, 5, 6, 7, 623 2, 1, 2, 3, 4, 5, 6, 8, 624 }, 625 }, 626 } 627 628 for _, test := range tests { 629 t.Run(test.name, func(t *testing.T) { 630 c := newTestContext() 631 defer c.cleanup() 632 s := c.s 633 634 e := channel.New(0, 1280, linkAddr0) 635 defer e.Close() 636 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 637 if err := s.CreateNIC(nicID, e); err != nil { 638 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 639 } 640 protocolAddr := tcpip.ProtocolAddress{ 641 Protocol: ProtocolNumber, 642 AddressWithPrefix: lladdr0.WithPrefix(), 643 } 644 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 645 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 646 } 647 648 ndpNASize := header.ICMPv6NeighborAdvertMinimumSize + len(test.optsBuf) 649 hdr := prependable.New(header.IPv6MinimumSize + ndpNASize) 650 pkt := header.ICMPv6(hdr.Prepend(ndpNASize)) 651 pkt.SetType(header.ICMPv6NeighborAdvert) 652 ns := header.NDPNeighborAdvert(pkt.MessageBody()) 653 ns.SetTargetAddress(lladdr1) 654 opts := ns.Options() 655 copy(opts, test.optsBuf) 656 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 657 Header: pkt, 658 Src: lladdr1, 659 Dst: lladdr0, 660 })) 661 payloadLength := hdr.UsedLength() 662 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 663 ip.Encode(&header.IPv6Fields{ 664 PayloadLength: uint16(payloadLength), 665 TransportProtocol: header.ICMPv6ProtocolNumber, 666 HopLimit: 255, 667 SrcAddr: lladdr1, 668 DstAddr: lladdr0, 669 }) 670 671 invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid 672 673 // Invalid count should initially be 0. 674 if got := invalid.Value(); got != 0 { 675 t.Fatalf("got invalid = %d, want = 0", got) 676 } 677 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 678 Payload: buffer.MakeWithData(hdr.View()), 679 }) 680 e.InjectInbound(ProtocolNumber, pktBuf) 681 pktBuf.DecRef() 682 683 neighbors, err := s.Neighbors(nicID, ProtocolNumber) 684 if err != nil { 685 t.Fatalf("s.Neighbors(%d, %d): %s", nicID, ProtocolNumber, err) 686 } 687 688 neighborByAddr := make(map[tcpip.Address]stack.NeighborEntry) 689 for _, n := range neighbors { 690 if existing, ok := neighborByAddr[n.Addr]; ok { 691 if diff := cmp.Diff(existing, n); diff != "" { 692 t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry (-existing +got):\n%s", nicID, ProtocolNumber, diff) 693 } 694 t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry: %#v", nicID, ProtocolNumber, existing) 695 } 696 neighborByAddr[n.Addr] = n 697 } 698 699 if neigh, ok := neighborByAddr[lladdr1]; ok { 700 t.Fatalf("unexpectedly got neighbor entry: %#v", neigh) 701 } 702 703 if test.isValid { 704 // Invalid count should not have increased. 705 if got := invalid.Value(); got != 0 { 706 t.Errorf("got invalid = %d, want = 0", got) 707 } 708 } else { 709 // Invalid count should have increased. 710 if got := invalid.Value(); got != 1 { 711 t.Errorf("got invalid = %d, want = 1", got) 712 } 713 } 714 }) 715 } 716 } 717 718 func TestNDPValidation(t *testing.T) { 719 const nicID = 1 720 721 handleIPv6Payload := func(payload []byte, hopLimit uint8, atomicFragment bool, ep stack.NetworkEndpoint) { 722 var extHdrs header.IPv6ExtHdrSerializer 723 if atomicFragment { 724 extHdrs = append(extHdrs, &header.IPv6SerializableFragmentExtHdr{}) 725 } 726 extHdrsLen := extHdrs.Length() 727 728 ip := make([]byte, header.IPv6MinimumSize+extHdrsLen) 729 header.IPv6(ip).Encode(&header.IPv6Fields{ 730 PayloadLength: uint16(len(payload) + extHdrsLen), 731 TransportProtocol: header.ICMPv6ProtocolNumber, 732 HopLimit: hopLimit, 733 SrcAddr: lladdr1, 734 DstAddr: lladdr0, 735 ExtensionHeaders: extHdrs, 736 }) 737 buf := buffer.MakeWithData(ip) 738 buf.Append(buffer.NewViewWithData(payload)) 739 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 740 Payload: buf, 741 }) 742 ep.HandlePacket(pkt) 743 pkt.DecRef() 744 } 745 746 var tllData [header.NDPLinkLayerAddressSize]byte 747 header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{ 748 header.NDPTargetLinkLayerAddressOption(linkAddr1), 749 }) 750 751 var sllData [header.NDPLinkLayerAddressSize]byte 752 header.NDPOptions(sllData[:]).Serialize(header.NDPOptionsSerializer{ 753 header.NDPSourceLinkLayerAddressOption(linkAddr1), 754 }) 755 756 types := []struct { 757 name string 758 typ header.ICMPv6Type 759 size int 760 extraData []byte 761 statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter 762 routerOnly bool 763 }{ 764 { 765 name: "RouterSolicit", 766 typ: header.ICMPv6RouterSolicit, 767 size: header.ICMPv6MinimumSize, 768 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 769 return stats.RouterSolicit 770 }, 771 routerOnly: true, 772 }, 773 { 774 name: "RouterAdvert", 775 typ: header.ICMPv6RouterAdvert, 776 size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize, 777 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 778 return stats.RouterAdvert 779 }, 780 }, 781 { 782 name: "NeighborSolicit", 783 typ: header.ICMPv6NeighborSolicit, 784 size: header.ICMPv6NeighborSolicitMinimumSize, 785 extraData: sllData[:], 786 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 787 return stats.NeighborSolicit 788 }, 789 }, 790 { 791 name: "NeighborAdvert", 792 typ: header.ICMPv6NeighborAdvert, 793 size: header.ICMPv6NeighborAdvertMinimumSize, 794 extraData: tllData[:], 795 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 796 return stats.NeighborAdvert 797 }, 798 }, 799 { 800 name: "RedirectMsg", 801 typ: header.ICMPv6RedirectMsg, 802 size: header.ICMPv6MinimumSize, 803 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 804 return stats.RedirectMsg 805 }, 806 }, 807 } 808 809 subTests := []struct { 810 name string 811 atomicFragment bool 812 hopLimit uint8 813 code header.ICMPv6Code 814 valid bool 815 }{ 816 { 817 name: "Valid", 818 atomicFragment: false, 819 hopLimit: header.NDPHopLimit, 820 code: 0, 821 valid: true, 822 }, 823 { 824 name: "Fragmented", 825 atomicFragment: true, 826 hopLimit: header.NDPHopLimit, 827 code: 0, 828 valid: false, 829 }, 830 { 831 name: "Invalid hop limit", 832 atomicFragment: false, 833 hopLimit: header.NDPHopLimit - 1, 834 code: 0, 835 valid: false, 836 }, 837 { 838 name: "Invalid ICMPv6 code", 839 atomicFragment: false, 840 hopLimit: header.NDPHopLimit, 841 code: 1, 842 valid: false, 843 }, 844 } 845 846 subnet, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr0.Len()))) 847 if err != nil { 848 t.Fatal(err) 849 } 850 851 for _, typ := range types { 852 for _, isRouter := range []bool{false, true} { 853 name := typ.name 854 if isRouter { 855 name += " (Router)" 856 } 857 858 t.Run(name, func(t *testing.T) { 859 for _, test := range subTests { 860 t.Run(test.name, func(t *testing.T) { 861 c := newTestContext() 862 defer c.cleanup() 863 s := c.s 864 865 if isRouter { 866 if err := s.SetForwardingDefaultAndAllNICs(ProtocolNumber, true); err != nil { 867 t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ProtocolNumber, err) 868 } 869 } 870 871 if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil { 872 t.Fatalf("CreateNIC(%d, _): %s", nicID, err) 873 } 874 875 protocolAddr := tcpip.ProtocolAddress{ 876 Protocol: ProtocolNumber, 877 AddressWithPrefix: lladdr0.WithPrefix(), 878 } 879 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 880 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 881 } 882 883 ep, err := s.GetNetworkEndpoint(nicID, ProtocolNumber) 884 if err != nil { 885 t.Fatal("cannot find network endpoint instance for IPv6") 886 } 887 888 s.SetRouteTable([]tcpip.Route{{ 889 Destination: subnet, 890 NIC: nicID, 891 }}) 892 893 stats := s.Stats().ICMP.V6.PacketsReceived 894 invalid := stats.Invalid 895 routerOnly := stats.RouterOnlyPacketsDroppedByHost 896 typStat := typ.statCounter(stats) 897 898 icmpH := header.ICMPv6(make([]byte, typ.size+len(typ.extraData))) 899 copy(icmpH[typ.size:], typ.extraData) 900 icmpH.SetType(typ.typ) 901 icmpH.SetCode(test.code) 902 icmpH.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 903 Header: icmpH[:typ.size], 904 Src: lladdr0, 905 Dst: lladdr1, 906 PayloadCsum: checksum.Checksum(typ.extraData /* initial */, 0), 907 PayloadLen: len(typ.extraData), 908 })) 909 910 // Rx count of the NDP message should initially be 0. 911 if got := typStat.Value(); got != 0 { 912 t.Errorf("got %s = %d, want = 0", typ.name, got) 913 } 914 915 // Invalid count should initially be 0. 916 if got := invalid.Value(); got != 0 { 917 t.Errorf("got invalid.Value() = %d, want = 0", got) 918 } 919 920 // Should initially not have dropped any packets. 921 if got := routerOnly.Value(); got != 0 { 922 t.Errorf("got routerOnly.Value() = %d, want = 0", got) 923 } 924 925 if t.Failed() { 926 t.FailNow() 927 } 928 929 handleIPv6Payload(icmpH, test.hopLimit, test.atomicFragment, ep) 930 931 // Rx count of the NDP packet should have increased. 932 if got := typStat.Value(); got != 1 { 933 t.Errorf("got %s = %d, want = 1", typ.name, got) 934 } 935 936 want := uint64(0) 937 if !test.valid { 938 // Invalid count should have increased. 939 want = 1 940 } 941 if got := invalid.Value(); got != want { 942 t.Errorf("got invalid.Value() = %d, want = %d", got, want) 943 } 944 945 want = 0 946 if test.valid && !isRouter && typ.routerOnly { 947 // Router only packets are expected to be dropped when operating 948 // as a host. 949 want = 1 950 } 951 if got := routerOnly.Value(); got != want { 952 t.Errorf("got routerOnly.Value() = %d, want = %d", got, want) 953 } 954 }) 955 } 956 }) 957 } 958 } 959 } 960 961 // TestNeighborAdvertisementValidation tests that the NIC validates received 962 // Neighbor Advertisements. 963 // 964 // In particular, if the IP Destination Address is a multicast address, and the 965 // Solicited flag is not zero, the Neighbor Advertisement is invalid and should 966 // be discarded. 967 func TestNeighborAdvertisementValidation(t *testing.T) { 968 tests := []struct { 969 name string 970 ipDstAddr tcpip.Address 971 solicitedFlag bool 972 valid bool 973 }{ 974 { 975 name: "Multicast IP destination address with Solicited flag set", 976 ipDstAddr: header.IPv6AllNodesMulticastAddress, 977 solicitedFlag: true, 978 valid: false, 979 }, 980 { 981 name: "Multicast IP destination address with Solicited flag unset", 982 ipDstAddr: header.IPv6AllNodesMulticastAddress, 983 solicitedFlag: false, 984 valid: true, 985 }, 986 { 987 name: "Unicast IP destination address with Solicited flag set", 988 ipDstAddr: lladdr0, 989 solicitedFlag: true, 990 valid: true, 991 }, 992 { 993 name: "Unicast IP destination address with Solicited flag unset", 994 ipDstAddr: lladdr0, 995 solicitedFlag: false, 996 valid: true, 997 }, 998 } 999 1000 for _, test := range tests { 1001 t.Run(test.name, func(t *testing.T) { 1002 c := newTestContext() 1003 defer c.cleanup() 1004 s := c.s 1005 1006 e := channel.New(0, header.IPv6MinimumMTU, linkAddr0) 1007 defer e.Close() 1008 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 1009 if err := s.CreateNIC(nicID, e); err != nil { 1010 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 1011 } 1012 protocolAddr := tcpip.ProtocolAddress{ 1013 Protocol: ProtocolNumber, 1014 AddressWithPrefix: lladdr0.WithPrefix(), 1015 } 1016 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 1017 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 1018 } 1019 1020 ndpNASize := header.ICMPv6NeighborAdvertMinimumSize 1021 hdr := prependable.New(header.IPv6MinimumSize + ndpNASize) 1022 pkt := header.ICMPv6(hdr.Prepend(ndpNASize)) 1023 pkt.SetType(header.ICMPv6NeighborAdvert) 1024 na := header.NDPNeighborAdvert(pkt.MessageBody()) 1025 na.SetTargetAddress(lladdr1) 1026 na.SetSolicitedFlag(test.solicitedFlag) 1027 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1028 Header: pkt, 1029 Src: lladdr1, 1030 Dst: test.ipDstAddr, 1031 })) 1032 payloadLength := hdr.UsedLength() 1033 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 1034 ip.Encode(&header.IPv6Fields{ 1035 PayloadLength: uint16(payloadLength), 1036 TransportProtocol: header.ICMPv6ProtocolNumber, 1037 HopLimit: 255, 1038 SrcAddr: lladdr1, 1039 DstAddr: test.ipDstAddr, 1040 }) 1041 1042 stats := s.Stats().ICMP.V6.PacketsReceived 1043 invalid := stats.Invalid 1044 rxNA := stats.NeighborAdvert 1045 1046 if got := rxNA.Value(); got != 0 { 1047 t.Fatalf("got rxNA = %d, want = 0", got) 1048 } 1049 if got := invalid.Value(); got != 0 { 1050 t.Fatalf("got invalid = %d, want = 0", got) 1051 } 1052 1053 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1054 Payload: buffer.MakeWithData(hdr.View()), 1055 }) 1056 e.InjectInbound(header.IPv6ProtocolNumber, pktBuf) 1057 pktBuf.DecRef() 1058 1059 if got := rxNA.Value(); got != 1 { 1060 t.Fatalf("got rxNA = %d, want = 1", got) 1061 } 1062 var wantInvalid uint64 = 1 1063 if test.valid { 1064 wantInvalid = 0 1065 } 1066 if got := invalid.Value(); got != wantInvalid { 1067 t.Fatalf("got invalid = %d, want = %d", got, wantInvalid) 1068 } 1069 // As per RFC 4861 section 7.2.5: 1070 // When a valid Neighbor Advertisement is received ... 1071 // If no entry exists, the advertisement SHOULD be silently discarded. 1072 // There is no need to create an entry if none exists, since the 1073 // recipient has apparently not initiated any communication with the 1074 // target. 1075 if neighbors, err := s.Neighbors(nicID, ProtocolNumber); err != nil { 1076 t.Fatalf("s.Neighbors(%d, %d): %s", nicID, ProtocolNumber, err) 1077 } else if len(neighbors) != 0 { 1078 t.Fatalf("got len(neighbors) = %d, want = 0; neighbors = %#v", len(neighbors), neighbors) 1079 } 1080 }) 1081 } 1082 } 1083 1084 // TestRouterAdvertValidation tests that when the NIC is configured to handle 1085 // NDP Router Advertisement packets, it validates the Router Advertisement 1086 // properly before handling them. 1087 func TestRouterAdvertValidation(t *testing.T) { 1088 tests := []struct { 1089 name string 1090 src tcpip.Address 1091 hopLimit uint8 1092 code header.ICMPv6Code 1093 ndpPayload []byte 1094 expectedSuccess bool 1095 }{ 1096 { 1097 "OK", 1098 lladdr0, 1099 255, 1100 0, 1101 []byte{ 1102 0, 0, 0, 0, 1103 0, 0, 0, 0, 1104 0, 0, 0, 0, 1105 }, 1106 true, 1107 }, 1108 { 1109 "NonLinkLocalSourceAddr", 1110 addr1, 1111 255, 1112 0, 1113 []byte{ 1114 0, 0, 0, 0, 1115 0, 0, 0, 0, 1116 0, 0, 0, 0, 1117 }, 1118 false, 1119 }, 1120 { 1121 "HopLimitNot255", 1122 lladdr0, 1123 254, 1124 0, 1125 []byte{ 1126 0, 0, 0, 0, 1127 0, 0, 0, 0, 1128 0, 0, 0, 0, 1129 }, 1130 false, 1131 }, 1132 { 1133 "NonZeroCode", 1134 lladdr0, 1135 255, 1136 1, 1137 []byte{ 1138 0, 0, 0, 0, 1139 0, 0, 0, 0, 1140 0, 0, 0, 0, 1141 }, 1142 false, 1143 }, 1144 { 1145 "NDPPayloadTooSmall", 1146 lladdr0, 1147 255, 1148 0, 1149 []byte{ 1150 0, 0, 0, 0, 1151 0, 0, 0, 0, 1152 0, 0, 0, 1153 }, 1154 false, 1155 }, 1156 { 1157 "OKWithOptions", 1158 lladdr0, 1159 255, 1160 0, 1161 []byte{ 1162 // RA payload 1163 0, 0, 0, 0, 1164 0, 0, 0, 0, 1165 0, 0, 0, 0, 1166 1167 // Option #1 (TargetLinkLayerAddress) 1168 2, 1, 0, 0, 0, 0, 0, 0, 1169 1170 // Option #2 (unrecognized) 1171 255, 1, 0, 0, 0, 0, 0, 0, 1172 1173 // Option #3 (PrefixInformation) 1174 3, 4, 0, 0, 0, 0, 0, 0, 1175 0, 0, 0, 0, 0, 0, 0, 0, 1176 0, 0, 0, 0, 0, 0, 0, 0, 1177 0, 0, 0, 0, 0, 0, 0, 0, 1178 }, 1179 true, 1180 }, 1181 { 1182 "OptionWithZeroLength", 1183 lladdr0, 1184 255, 1185 0, 1186 []byte{ 1187 // RA payload 1188 0, 0, 0, 0, 1189 0, 0, 0, 0, 1190 0, 0, 0, 0, 1191 1192 // Option #1 (TargetLinkLayerAddress) 1193 // Invalid as it has 0 length. 1194 2, 0, 0, 0, 0, 0, 0, 0, 1195 1196 // Option #2 (unrecognized) 1197 255, 1, 0, 0, 0, 0, 0, 0, 1198 1199 // Option #3 (PrefixInformation) 1200 3, 4, 0, 0, 0, 0, 0, 0, 1201 0, 0, 0, 0, 0, 0, 0, 0, 1202 0, 0, 0, 0, 0, 0, 0, 0, 1203 0, 0, 0, 0, 0, 0, 0, 0, 1204 }, 1205 false, 1206 }, 1207 } 1208 1209 for _, test := range tests { 1210 t.Run(test.name, func(t *testing.T) { 1211 c := newTestContext() 1212 defer c.cleanup() 1213 s := c.s 1214 1215 e := channel.New(10, 1280, linkAddr1) 1216 defer e.Close() 1217 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 1218 if err := s.CreateNIC(1, e); err != nil { 1219 t.Fatalf("CreateNIC(_) = %s", err) 1220 } 1221 1222 icmpSize := header.ICMPv6HeaderSize + len(test.ndpPayload) 1223 hdr := prependable.New(header.IPv6MinimumSize + icmpSize) 1224 pkt := header.ICMPv6(hdr.Prepend(icmpSize)) 1225 pkt.SetType(header.ICMPv6RouterAdvert) 1226 pkt.SetCode(test.code) 1227 copy(pkt.MessageBody(), test.ndpPayload) 1228 payloadLength := hdr.UsedLength() 1229 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1230 Header: pkt, 1231 Src: test.src, 1232 Dst: header.IPv6AllNodesMulticastAddress, 1233 })) 1234 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 1235 ip.Encode(&header.IPv6Fields{ 1236 PayloadLength: uint16(payloadLength), 1237 TransportProtocol: icmp.ProtocolNumber6, 1238 HopLimit: test.hopLimit, 1239 SrcAddr: test.src, 1240 DstAddr: header.IPv6AllNodesMulticastAddress, 1241 }) 1242 1243 stats := s.Stats().ICMP.V6.PacketsReceived 1244 invalid := stats.Invalid 1245 rxRA := stats.RouterAdvert 1246 1247 if got := invalid.Value(); got != 0 { 1248 t.Fatalf("got invalid = %d, want = 0", got) 1249 } 1250 if got := rxRA.Value(); got != 0 { 1251 t.Fatalf("got rxRA = %d, want = 0", got) 1252 } 1253 1254 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1255 Payload: buffer.MakeWithData(hdr.View()), 1256 }) 1257 e.InjectInbound(header.IPv6ProtocolNumber, pktBuf) 1258 pktBuf.DecRef() 1259 1260 if got := rxRA.Value(); got != 1 { 1261 t.Fatalf("got rxRA = %d, want = 1", got) 1262 } 1263 1264 if test.expectedSuccess { 1265 if got := invalid.Value(); got != 0 { 1266 t.Fatalf("got invalid = %d, want = 0", got) 1267 } 1268 } else { 1269 if got := invalid.Value(); got != 1 { 1270 t.Fatalf("got invalid = %d, want = 1", got) 1271 } 1272 } 1273 }) 1274 } 1275 } 1276 1277 // TestCheckDuplicateAddress checks that calls to CheckDuplicateAddress and DAD 1278 // performed when adding new addresses do not interfere with each other. 1279 func TestCheckDuplicateAddress(t *testing.T) { 1280 const nicID = 1 1281 1282 clock := faketime.NewManualClock() 1283 dadConfigs := stack.DADConfigurations{ 1284 DupAddrDetectTransmits: 1, 1285 RetransmitTimer: time.Second, 1286 } 1287 1288 s := stack.New(stack.Options{ 1289 Clock: clock, 1290 RandSource: rand.NewSource(time.Now().UnixNano()), 1291 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocolWithOptions(Options{ 1292 DADConfigs: dadConfigs, 1293 })}, 1294 }) 1295 defer func() { 1296 s.Close() 1297 s.Wait() 1298 }() 1299 1300 // This test is expected to send at max 2 DAD messages. We allow an extra 1301 // packet to be stored to catch unexpected packets. 1302 e := channel.New(3, header.IPv6MinimumMTU, linkAddr0) 1303 defer e.Close() 1304 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 1305 if err := s.CreateNIC(nicID, e); err != nil { 1306 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 1307 } 1308 1309 dadPacketsSent := 0 1310 snmc := header.SolicitedNodeAddr(lladdr0) 1311 remoteLinkAddr := header.EthernetAddressFromMulticastIPv6Address(snmc) 1312 checkDADMsg := func() { 1313 clock.RunImmediatelyScheduledJobs() 1314 p := e.Read() 1315 if p == nil { 1316 t.Fatalf("expected %d-th DAD message", dadPacketsSent) 1317 } 1318 defer p.DecRef() 1319 1320 if p.NetworkProtocolNumber != header.IPv6ProtocolNumber { 1321 t.Errorf("(i=%d) got p.NetworkProtocolNumber = %d, want = %d", dadPacketsSent, p.NetworkProtocolNumber, header.IPv6ProtocolNumber) 1322 } 1323 1324 if p.EgressRoute.RemoteLinkAddress != remoteLinkAddr { 1325 t.Errorf("(i=%d) got p.EgressRoute.RemoteLinkAddress = %s, want = %s", dadPacketsSent, p.EgressRoute.RemoteLinkAddress, remoteLinkAddr) 1326 } 1327 1328 payload := stack.PayloadSince(p.NetworkHeader()) 1329 defer payload.Release() 1330 checker.IPv6(t, payload, 1331 checker.SrcAddr(header.IPv6Any), 1332 checker.DstAddr(snmc), 1333 checker.TTL(header.NDPHopLimit), 1334 checker.NDPNS( 1335 checker.NDPNSTargetAddress(lladdr0), 1336 )) 1337 } 1338 protocolAddr := tcpip.ProtocolAddress{ 1339 Protocol: ProtocolNumber, 1340 AddressWithPrefix: lladdr0.WithPrefix(), 1341 } 1342 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 1343 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 1344 } 1345 checkDADMsg() 1346 1347 // Start DAD for the address we just added. 1348 // 1349 // Even though the stack will perform DAD before the added address transitions 1350 // from tentative to assigned, this DAD request should be independent of that. 1351 ch := make(chan stack.DADResult, 3) 1352 dadRequestsMade := 1 1353 dadPacketsSent++ 1354 if res, err := s.CheckDuplicateAddress(nicID, ProtocolNumber, lladdr0, func(r stack.DADResult) { 1355 ch <- r 1356 }); err != nil { 1357 t.Fatalf("s.CheckDuplicateAddress(%d, %d, %s, _): %s", nicID, ProtocolNumber, lladdr0, err) 1358 } else if res != stack.DADStarting { 1359 t.Fatalf("got s.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", nicID, ProtocolNumber, lladdr0, res, stack.DADStarting) 1360 } 1361 checkDADMsg() 1362 1363 // Remove the address and make sure our DAD request was not stopped. 1364 if err := s.RemoveAddress(nicID, lladdr0); err != nil { 1365 t.Fatalf("RemoveAddress(%d, %s): %s", nicID, lladdr0, err) 1366 } 1367 // Should not restart DAD since we already requested DAD above - the handler 1368 // should be called when the original request completes so we should not send 1369 // an extra DAD message here. 1370 dadRequestsMade++ 1371 if res, err := s.CheckDuplicateAddress(nicID, ProtocolNumber, lladdr0, func(r stack.DADResult) { 1372 ch <- r 1373 }); err != nil { 1374 t.Fatalf("s.CheckDuplicateAddress(%d, %d, %s, _): %s", nicID, ProtocolNumber, lladdr0, err) 1375 } else if res != stack.DADAlreadyRunning { 1376 t.Fatalf("got s.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", nicID, ProtocolNumber, lladdr0, res, stack.DADAlreadyRunning) 1377 } 1378 1379 // Wait for DAD to complete. 1380 clock.Advance(time.Duration(dadConfigs.DupAddrDetectTransmits) * dadConfigs.RetransmitTimer) 1381 for i := 0; i < dadRequestsMade; i++ { 1382 if diff := cmp.Diff(&stack.DADSucceeded{}, <-ch); diff != "" { 1383 t.Errorf("(i=%d) DAD result mismatch (-want +got):\n%s", i, diff) 1384 } 1385 } 1386 // Should have no more results. 1387 select { 1388 case r := <-ch: 1389 t.Errorf("unexpectedly got an extra DAD result; r = %#v", r) 1390 default: 1391 } 1392 1393 // Should have no more packets. 1394 if p := e.Read(); p != nil { 1395 t.Errorf("got unexpected packet = %#v", p) 1396 } 1397 }