gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/ipv6/icmp_test.go (about) 1 // Copyright 2018 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 "bytes" 19 "net" 20 "reflect" 21 "strings" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 "golang.org/x/time/rate" 26 "gvisor.dev/gvisor/pkg/buffer" 27 "gvisor.dev/gvisor/pkg/refs" 28 "gvisor.dev/gvisor/pkg/tcpip" 29 "gvisor.dev/gvisor/pkg/tcpip/checker" 30 "gvisor.dev/gvisor/pkg/tcpip/checksum" 31 "gvisor.dev/gvisor/pkg/tcpip/faketime" 32 "gvisor.dev/gvisor/pkg/tcpip/header" 33 "gvisor.dev/gvisor/pkg/tcpip/link/channel" 34 "gvisor.dev/gvisor/pkg/tcpip/link/sniffer" 35 "gvisor.dev/gvisor/pkg/tcpip/prependable" 36 "gvisor.dev/gvisor/pkg/tcpip/stack" 37 "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" 38 "gvisor.dev/gvisor/pkg/tcpip/transport/udp" 39 "gvisor.dev/gvisor/pkg/waiter" 40 ) 41 42 const ( 43 nicID = 1 44 45 linkAddr0 = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06") 46 linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e") 47 linkAddr2 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0f") 48 49 defaultChannelSize = 1 50 defaultMTU = 65536 51 52 arbitraryHopLimit = 42 53 ) 54 55 var ( 56 lladdr0 = header.LinkLocalAddr(linkAddr0) 57 lladdr1 = header.LinkLocalAddr(linkAddr1) 58 ) 59 60 type stubLinkEndpoint struct { 61 stack.LinkEndpoint 62 } 63 64 func (*stubLinkEndpoint) MTU() uint32 { 65 return defaultMTU 66 } 67 68 func (*stubLinkEndpoint) Capabilities() stack.LinkEndpointCapabilities { 69 // Indicate that resolution for link layer addresses is required to send 70 // packets over this link. This is needed so the NIC knows to allocate a 71 // neighbor table. 72 return stack.CapabilityResolutionRequired 73 } 74 75 func (*stubLinkEndpoint) MaxHeaderLength() uint16 { 76 return 0 77 } 78 79 func (*stubLinkEndpoint) LinkAddress() tcpip.LinkAddress { 80 return "" 81 } 82 83 func (*stubLinkEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) { 84 return pkts.Len(), nil 85 } 86 87 func (*stubLinkEndpoint) Attach(stack.NetworkDispatcher) {} 88 89 func (*stubLinkEndpoint) AddHeader(*stack.PacketBuffer) {} 90 91 func (*stubLinkEndpoint) Wait() {} 92 93 type stubDispatcher struct { 94 stack.TransportDispatcher 95 } 96 97 func (*stubDispatcher) DeliverTransportPacket(tcpip.TransportProtocolNumber, *stack.PacketBuffer) stack.TransportPacketDisposition { 98 return stack.TransportPacketHandled 99 } 100 101 func (*stubDispatcher) DeliverRawPacket(tcpip.TransportProtocolNumber, *stack.PacketBuffer) { 102 // No-op. 103 } 104 105 var _ stack.NetworkInterface = (*testInterface)(nil) 106 107 type testInterface struct { 108 stack.LinkEndpoint 109 110 probeCount int 111 confirmationCount int 112 113 nicID tcpip.NICID 114 } 115 116 func (*testInterface) ID() tcpip.NICID { 117 return nicID 118 } 119 120 func (*testInterface) IsLoopback() bool { 121 return false 122 } 123 124 func (*testInterface) Name() string { 125 return "" 126 } 127 128 func (*testInterface) Enabled() bool { 129 return true 130 } 131 132 func (*testInterface) Promiscuous() bool { 133 return false 134 } 135 136 func (*testInterface) Spoofing() bool { 137 return false 138 } 139 140 func (t *testInterface) WritePacket(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Error { 141 pkt.EgressRoute = r.Fields() 142 var pkts stack.PacketBufferList 143 pkts.PushBack(pkt) 144 _, err := t.LinkEndpoint.WritePackets(pkts) 145 return err 146 } 147 148 func (t *testInterface) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, pkt *stack.PacketBuffer) tcpip.Error { 149 pkt.EgressRoute.NetProto = pkt.NetworkProtocolNumber 150 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 151 var pkts stack.PacketBufferList 152 pkts.PushBack(pkt) 153 _, err := t.LinkEndpoint.WritePackets(pkts) 154 return err 155 } 156 157 func (t *testInterface) HandleNeighborProbe(tcpip.NetworkProtocolNumber, tcpip.Address, tcpip.LinkAddress) tcpip.Error { 158 t.probeCount++ 159 return nil 160 } 161 162 func (t *testInterface) HandleNeighborConfirmation(tcpip.NetworkProtocolNumber, tcpip.Address, tcpip.LinkAddress, stack.ReachabilityConfirmationFlags) tcpip.Error { 163 t.confirmationCount++ 164 return nil 165 } 166 167 func (*testInterface) PrimaryAddress(tcpip.NetworkProtocolNumber) (tcpip.AddressWithPrefix, tcpip.Error) { 168 return tcpip.AddressWithPrefix{}, nil 169 } 170 171 func (*testInterface) CheckLocalAddress(tcpip.NetworkProtocolNumber, tcpip.Address) bool { 172 return false 173 } 174 175 func handleICMPInIPv6(ep stack.NetworkEndpoint, src, dst tcpip.Address, icmp header.ICMPv6, hopLimit uint8, includeRouterAlert bool) { 176 var extensionHeaders header.IPv6ExtHdrSerializer 177 if includeRouterAlert { 178 extensionHeaders = header.IPv6ExtHdrSerializer{ 179 header.IPv6SerializableHopByHopExtHdr{ 180 &header.IPv6RouterAlertOption{Value: header.IPv6RouterAlertMLD}, 181 }, 182 } 183 } 184 ip := make([]byte, header.IPv6MinimumSize+extensionHeaders.Length()) 185 header.IPv6(ip).Encode(&header.IPv6Fields{ 186 PayloadLength: uint16(len(icmp)), 187 TransportProtocol: header.ICMPv6ProtocolNumber, 188 HopLimit: hopLimit, 189 SrcAddr: src, 190 DstAddr: dst, 191 ExtensionHeaders: extensionHeaders, 192 }) 193 194 buf := buffer.MakeWithData(ip) 195 buf.Append(buffer.NewViewWithData([]byte(icmp))) 196 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 197 Payload: buf, 198 }) 199 ep.HandlePacket(pkt) 200 pkt.DecRef() 201 } 202 203 type testContext struct { 204 s *stack.Stack 205 clock *faketime.ManualClock 206 } 207 208 func newTestContext() testContext { 209 clock := faketime.NewManualClock() 210 s := stack.New(stack.Options{ 211 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 212 TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6, udp.NewProtocol}, 213 Clock: clock, 214 }) 215 return testContext{s: s, clock: clock} 216 } 217 218 func (c *testContext) cleanup() { 219 c.s.Close() 220 c.s.Wait() 221 // Stack.Wait() closes all devices and transports synchronously, but it 222 // does not guarantee that all packets will reach refcount zero until 223 // after an asynchronous followup from neighborEntry.notifyCompletionLocked(). 224 c.clock.RunImmediatelyScheduledJobs() 225 refs.DoRepeatedLeakCheck() 226 } 227 228 func TestICMPCounts(t *testing.T) { 229 c := newTestContext() 230 defer c.cleanup() 231 s := c.s 232 233 if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil { 234 t.Fatalf("CreateNIC(_, _) = %s", err) 235 } 236 { 237 subnet, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr1.Len()))) 238 if err != nil { 239 t.Fatal(err) 240 } 241 s.SetRouteTable( 242 []tcpip.Route{{ 243 Destination: subnet, 244 NIC: nicID, 245 }}, 246 ) 247 } 248 249 netProto := s.NetworkProtocolInstance(ProtocolNumber) 250 if netProto == nil { 251 t.Fatalf("cannot find protocol instance for network protocol %d", ProtocolNumber) 252 } 253 ep := netProto.NewEndpoint(&testInterface{}, &stubDispatcher{}) 254 defer ep.Close() 255 256 if err := ep.Enable(); err != nil { 257 t.Fatalf("ep.Enable(): %s", err) 258 } 259 260 addressableEndpoint, ok := ep.(stack.AddressableEndpoint) 261 if !ok { 262 t.Fatalf("expected network endpoint to implement stack.AddressableEndpoint") 263 } 264 addr := lladdr0.WithPrefix() 265 if ep, err := addressableEndpoint.AddAndAcquirePermanentAddress(addr, stack.AddressProperties{}); err != nil { 266 t.Fatalf("addressableEndpoint.AddAndAcquirePermanentAddress(%s, {}): %s", addr, err) 267 } else { 268 ep.DecRef() 269 } 270 271 var tllData [header.NDPLinkLayerAddressSize]byte 272 header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{ 273 header.NDPTargetLinkLayerAddressOption(linkAddr1), 274 }) 275 276 types := []struct { 277 typ header.ICMPv6Type 278 hopLimit uint8 279 includeRouterAlert bool 280 size int 281 extraData []byte 282 }{ 283 { 284 typ: header.ICMPv6DstUnreachable, 285 hopLimit: arbitraryHopLimit, 286 size: header.ICMPv6DstUnreachableMinimumSize, 287 }, 288 { 289 typ: header.ICMPv6PacketTooBig, 290 hopLimit: arbitraryHopLimit, 291 size: header.ICMPv6PacketTooBigMinimumSize, 292 }, 293 { 294 typ: header.ICMPv6TimeExceeded, 295 hopLimit: arbitraryHopLimit, 296 size: header.ICMPv6MinimumSize, 297 }, 298 { 299 typ: header.ICMPv6ParamProblem, 300 hopLimit: arbitraryHopLimit, 301 size: header.ICMPv6MinimumSize, 302 }, 303 { 304 typ: header.ICMPv6EchoRequest, 305 hopLimit: arbitraryHopLimit, 306 size: header.ICMPv6EchoMinimumSize, 307 }, 308 { 309 typ: header.ICMPv6EchoReply, 310 hopLimit: arbitraryHopLimit, 311 size: header.ICMPv6EchoMinimumSize, 312 }, 313 { 314 typ: header.ICMPv6RouterSolicit, 315 hopLimit: header.NDPHopLimit, 316 size: header.ICMPv6MinimumSize, 317 }, 318 { 319 typ: header.ICMPv6RouterAdvert, 320 hopLimit: header.NDPHopLimit, 321 size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize, 322 }, 323 { 324 typ: header.ICMPv6NeighborSolicit, 325 hopLimit: header.NDPHopLimit, 326 size: header.ICMPv6NeighborSolicitMinimumSize, 327 }, 328 { 329 typ: header.ICMPv6NeighborAdvert, 330 hopLimit: header.NDPHopLimit, 331 size: header.ICMPv6NeighborAdvertMinimumSize, 332 extraData: tllData[:], 333 }, 334 { 335 typ: header.ICMPv6RedirectMsg, 336 hopLimit: header.NDPHopLimit, 337 size: header.ICMPv6MinimumSize, 338 }, 339 { 340 typ: header.ICMPv6MulticastListenerQuery, 341 hopLimit: header.MLDHopLimit, 342 includeRouterAlert: true, 343 size: header.MLDMinimumSize + header.ICMPv6HeaderSize, 344 }, 345 { 346 typ: header.ICMPv6MulticastListenerReport, 347 hopLimit: header.MLDHopLimit, 348 includeRouterAlert: true, 349 size: header.MLDMinimumSize + header.ICMPv6HeaderSize, 350 }, 351 { 352 typ: header.ICMPv6MulticastListenerV2Report, 353 hopLimit: header.MLDHopLimit, 354 includeRouterAlert: true, 355 size: header.MLDv2ReportMinimumSize + header.ICMPv6HeaderSize, 356 }, 357 { 358 typ: header.ICMPv6MulticastListenerDone, 359 hopLimit: header.MLDHopLimit, 360 includeRouterAlert: true, 361 size: header.MLDMinimumSize + header.ICMPv6HeaderSize, 362 }, 363 { 364 typ: 255, /* Unrecognized */ 365 size: 50, 366 }, 367 } 368 369 for _, typ := range types { 370 icmp := header.ICMPv6(make([]byte, typ.size+len(typ.extraData))) 371 copy(icmp[typ.size:], typ.extraData) 372 icmp.SetType(typ.typ) 373 icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 374 Header: icmp[:typ.size], 375 Src: lladdr0, 376 Dst: lladdr1, 377 PayloadCsum: checksum.Checksum(typ.extraData, 0 /* initial */), 378 PayloadLen: len(typ.extraData), 379 })) 380 handleICMPInIPv6(ep, lladdr1, lladdr0, icmp, typ.hopLimit, typ.includeRouterAlert) 381 } 382 383 // Construct an empty ICMP packet so that 384 // Stats().ICMP.ICMPv6ReceivedPacketStats.Invalid is incremented. 385 handleICMPInIPv6(ep, lladdr1, lladdr0, header.ICMPv6(make([]byte, header.IPv6MinimumSize)), arbitraryHopLimit, false) 386 387 icmpv6Stats := s.Stats().ICMP.V6.PacketsReceived 388 visitStats(reflect.ValueOf(&icmpv6Stats).Elem(), func(name string, s *tcpip.StatCounter) { 389 if got, want := s.Value(), uint64(1); got != want { 390 t.Errorf("got %s = %d, want = %d", name, got, want) 391 } 392 }) 393 if t.Failed() { 394 t.Logf("stats:\n%+v", s.Stats()) 395 } 396 } 397 398 func visitStats(v reflect.Value, f func(string, *tcpip.StatCounter)) { 399 t := v.Type() 400 for i := 0; i < v.NumField(); i++ { 401 v := v.Field(i) 402 if s, ok := v.Interface().(*tcpip.StatCounter); ok { 403 f(t.Field(i).Name, s) 404 } else { 405 visitStats(v, f) 406 } 407 } 408 } 409 410 type multiStackTestContext struct { 411 s0 *stack.Stack 412 s1 *stack.Stack 413 414 linkEP0 *channel.Endpoint 415 linkEP1 *channel.Endpoint 416 417 clock *faketime.ManualClock 418 } 419 420 type endpointWithResolutionCapability struct { 421 stack.LinkEndpoint 422 } 423 424 func (e endpointWithResolutionCapability) Capabilities() stack.LinkEndpointCapabilities { 425 return e.LinkEndpoint.Capabilities() | stack.CapabilityResolutionRequired 426 } 427 428 func newMultiStackTestContext(t *testing.T) multiStackTestContext { 429 clock := faketime.NewManualClock() 430 s0 := stack.New(stack.Options{ 431 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 432 TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6}, 433 Clock: clock, 434 }) 435 s1 := stack.New(stack.Options{ 436 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 437 TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6}, 438 Clock: clock, 439 }) 440 c := multiStackTestContext{ 441 s0: s0, 442 s1: s1, 443 clock: clock, 444 } 445 446 c.linkEP0 = channel.New(defaultChannelSize, defaultMTU, linkAddr0) 447 448 wrappedEP0 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP0}) 449 if testing.Verbose() { 450 wrappedEP0 = sniffer.New(wrappedEP0) 451 } 452 if err := c.s0.CreateNIC(nicID, wrappedEP0); err != nil { 453 t.Fatalf("CreateNIC s0: %v", err) 454 } 455 llProtocolAddr0 := tcpip.ProtocolAddress{ 456 Protocol: ProtocolNumber, 457 AddressWithPrefix: lladdr0.WithPrefix(), 458 } 459 if err := c.s0.AddProtocolAddress(nicID, llProtocolAddr0, stack.AddressProperties{}); err != nil { 460 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, llProtocolAddr0, err) 461 } 462 463 c.linkEP1 = channel.New(defaultChannelSize, defaultMTU, linkAddr1) 464 wrappedEP1 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP1}) 465 if err := c.s1.CreateNIC(nicID, wrappedEP1); err != nil { 466 t.Fatalf("CreateNIC failed: %v", err) 467 } 468 llProtocolAddr1 := tcpip.ProtocolAddress{ 469 Protocol: ProtocolNumber, 470 AddressWithPrefix: lladdr1.WithPrefix(), 471 } 472 if err := c.s1.AddProtocolAddress(nicID, llProtocolAddr1, stack.AddressProperties{}); err != nil { 473 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, llProtocolAddr1, err) 474 } 475 476 subnet0, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr1.Len()))) 477 if err != nil { 478 t.Fatal(err) 479 } 480 c.s0.SetRouteTable( 481 []tcpip.Route{{ 482 Destination: subnet0, 483 NIC: nicID, 484 }}, 485 ) 486 subnet1, err := tcpip.NewSubnet(lladdr0, tcpip.MaskFrom(strings.Repeat("\xff", lladdr0.Len()))) 487 if err != nil { 488 t.Fatal(err) 489 } 490 c.s1.SetRouteTable( 491 []tcpip.Route{{ 492 Destination: subnet1, 493 NIC: nicID, 494 }}, 495 ) 496 497 t.Cleanup(func() { 498 if err := c.s0.RemoveNIC(nicID); err != nil { 499 t.Errorf("c.s0.RemoveNIC(%d): %s", nicID, err) 500 } 501 if err := c.s1.RemoveNIC(nicID); err != nil { 502 t.Errorf("c.s1.RemoveNIC(%d): %s", nicID, err) 503 } 504 505 c.linkEP0.Close() 506 c.linkEP1.Close() 507 }) 508 509 return c 510 } 511 512 func (c *multiStackTestContext) cleanup() { 513 c.s0.Close() 514 c.s1.Close() 515 c.s0.Wait() 516 c.s1.Wait() 517 } 518 519 type routeArgs struct { 520 src, dst *channel.Endpoint 521 typ header.ICMPv6Type 522 remoteLinkAddr tcpip.LinkAddress 523 } 524 525 func routeICMPv6Packet(t *testing.T, clock *faketime.ManualClock, args routeArgs, fn func(*testing.T, header.ICMPv6)) { 526 t.Helper() 527 528 clock.RunImmediatelyScheduledJobs() 529 pi := args.src.Read() 530 if pi == nil { 531 t.Fatal("packet didn't arrive") 532 } 533 defer pi.DecRef() 534 535 { 536 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 537 Payload: pi.ToBuffer(), 538 }) 539 args.dst.InjectInbound(pi.NetworkProtocolNumber, pkt) 540 pkt.DecRef() 541 } 542 543 if pi.NetworkProtocolNumber != ProtocolNumber { 544 t.Errorf("unexpected protocol number %d", pi.NetworkProtocolNumber) 545 return 546 } 547 548 if len(args.remoteLinkAddr) != 0 && pi.EgressRoute.RemoteLinkAddress != args.remoteLinkAddr { 549 t.Errorf("got remote link address = %s, want = %s", pi.EgressRoute.RemoteLinkAddress, args.remoteLinkAddr) 550 } 551 552 // Pull the full payload since network header. Needed for header.IPv6 to 553 // extract its payload. 554 payload := stack.PayloadSince(pi.NetworkHeader()) 555 defer payload.Release() 556 ipv6 := header.IPv6(payload.AsSlice()) 557 transProto := tcpip.TransportProtocolNumber(ipv6.NextHeader()) 558 if transProto != header.ICMPv6ProtocolNumber { 559 t.Errorf("unexpected transport protocol number %d", transProto) 560 return 561 } 562 icmpv6 := header.ICMPv6(ipv6.Payload()) 563 if got, want := icmpv6.Type(), args.typ; got != want { 564 t.Errorf("got ICMPv6 type = %d, want = %d", got, want) 565 return 566 } 567 if fn != nil { 568 fn(t, icmpv6) 569 } 570 } 571 572 func TestLinkResolution(t *testing.T) { 573 c := newMultiStackTestContext(t) 574 575 r, err := c.s0.FindRoute(nicID, lladdr0, lladdr1, ProtocolNumber, false /* multicastLoop */) 576 if err != nil { 577 t.Fatalf("FindRoute(%d, %s, %s, _, false) = (_, %s), want = (_, nil)", nicID, lladdr0, lladdr1, err) 578 } 579 defer r.Release() 580 581 hdr := prependable.New(int(r.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6EchoMinimumSize) 582 pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6EchoMinimumSize)) 583 pkt.SetType(header.ICMPv6EchoRequest) 584 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 585 Header: pkt, 586 Src: r.LocalAddress(), 587 Dst: r.RemoteAddress(), 588 })) 589 590 // We can't send our payload directly over the route because that 591 // doesn't provoke NDP discovery. 592 var wq waiter.Queue 593 ep, err := c.s0.NewEndpoint(header.ICMPv6ProtocolNumber, ProtocolNumber, &wq) 594 defer ep.Close() 595 if err != nil { 596 t.Fatalf("NewEndpoint(_) = (_, %s), want = (_, nil)", err) 597 } 598 599 { 600 var r bytes.Reader 601 r.Reset(hdr.View()) 602 if _, err := ep.Write(&r, tcpip.WriteOptions{To: &tcpip.FullAddress{NIC: nicID, Addr: lladdr1}}); err != nil { 603 t.Fatalf("ep.Write(_): %s", err) 604 } 605 } 606 for _, args := range []routeArgs{ 607 {src: c.linkEP0, dst: c.linkEP1, typ: header.ICMPv6NeighborSolicit, remoteLinkAddr: header.EthernetAddressFromMulticastIPv6Address(header.SolicitedNodeAddr(lladdr1))}, 608 {src: c.linkEP1, dst: c.linkEP0, typ: header.ICMPv6NeighborAdvert}, 609 } { 610 routeICMPv6Packet(t, c.clock, args, func(t *testing.T, icmpv6 header.ICMPv6) { 611 if got, want := tcpip.AddrFromSlice(icmpv6[8:][:16]), lladdr1; got != want { 612 t.Errorf("%d: got target = %s, want = %s", icmpv6.Type(), got, want) 613 } 614 }) 615 } 616 617 for _, args := range []routeArgs{ 618 {src: c.linkEP0, dst: c.linkEP1, typ: header.ICMPv6EchoRequest}, 619 {src: c.linkEP1, dst: c.linkEP0, typ: header.ICMPv6EchoReply}, 620 } { 621 routeICMPv6Packet(t, c.clock, args, nil) 622 } 623 } 624 625 func TestICMPChecksumValidationSimple(t *testing.T) { 626 var tllData [header.NDPLinkLayerAddressSize]byte 627 header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{ 628 header.NDPTargetLinkLayerAddressOption(linkAddr1), 629 }) 630 631 types := []struct { 632 name string 633 typ header.ICMPv6Type 634 size int 635 extraData []byte 636 statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter 637 routerOnly bool 638 }{ 639 { 640 name: "DstUnreachable", 641 typ: header.ICMPv6DstUnreachable, 642 size: header.ICMPv6DstUnreachableMinimumSize, 643 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 644 return stats.DstUnreachable 645 }, 646 }, 647 { 648 name: "PacketTooBig", 649 typ: header.ICMPv6PacketTooBig, 650 size: header.ICMPv6PacketTooBigMinimumSize, 651 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 652 return stats.PacketTooBig 653 }, 654 }, 655 { 656 name: "TimeExceeded", 657 typ: header.ICMPv6TimeExceeded, 658 size: header.ICMPv6MinimumSize, 659 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 660 return stats.TimeExceeded 661 }, 662 }, 663 { 664 name: "ParamProblem", 665 typ: header.ICMPv6ParamProblem, 666 size: header.ICMPv6MinimumSize, 667 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 668 return stats.ParamProblem 669 }, 670 }, 671 { 672 name: "EchoRequest", 673 typ: header.ICMPv6EchoRequest, 674 size: header.ICMPv6EchoMinimumSize, 675 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 676 return stats.EchoRequest 677 }, 678 }, 679 { 680 name: "EchoReply", 681 typ: header.ICMPv6EchoReply, 682 size: header.ICMPv6EchoMinimumSize, 683 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 684 return stats.EchoReply 685 }, 686 }, 687 { 688 name: "RouterSolicit", 689 typ: header.ICMPv6RouterSolicit, 690 size: header.ICMPv6MinimumSize, 691 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 692 return stats.RouterSolicit 693 }, 694 // Hosts MUST silently discard any received Router Solicitation messages. 695 routerOnly: true, 696 }, 697 { 698 name: "RouterAdvert", 699 typ: header.ICMPv6RouterAdvert, 700 size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize, 701 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 702 return stats.RouterAdvert 703 }, 704 }, 705 { 706 name: "NeighborSolicit", 707 typ: header.ICMPv6NeighborSolicit, 708 size: header.ICMPv6NeighborSolicitMinimumSize, 709 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 710 return stats.NeighborSolicit 711 }, 712 }, 713 { 714 name: "NeighborAdvert", 715 typ: header.ICMPv6NeighborAdvert, 716 size: header.ICMPv6NeighborAdvertMinimumSize, 717 extraData: tllData[:], 718 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 719 return stats.NeighborAdvert 720 }, 721 }, 722 { 723 name: "RedirectMsg", 724 typ: header.ICMPv6RedirectMsg, 725 size: header.ICMPv6MinimumSize, 726 statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 727 return stats.RedirectMsg 728 }, 729 }, 730 } 731 732 for _, typ := range types { 733 for _, isRouter := range []bool{false, true} { 734 name := typ.name 735 if isRouter { 736 name += " (Router)" 737 } 738 t.Run(name, func(t *testing.T) { 739 c := newTestContext() 740 defer c.cleanup() 741 s := c.s 742 743 if isRouter { 744 if err := s.SetForwardingDefaultAndAllNICs(ProtocolNumber, true); err != nil { 745 t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ProtocolNumber, err) 746 } 747 } 748 749 e := channel.New(0, 1280, linkAddr0) 750 // Indicate that resolution for link layer addresses is required to 751 // send packets over this link. This is needed so the NIC knows to 752 // allocate a neighbor table. 753 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 754 if err := s.CreateNIC(nicID, e); err != nil { 755 t.Fatalf("CreateNIC(_, _) = %s", err) 756 } 757 758 protocolAddr := tcpip.ProtocolAddress{ 759 Protocol: ProtocolNumber, 760 AddressWithPrefix: lladdr0.WithPrefix(), 761 } 762 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 763 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 764 } 765 { 766 subnet, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr1.Len()))) 767 if err != nil { 768 t.Fatal(err) 769 } 770 s.SetRouteTable( 771 []tcpip.Route{{ 772 Destination: subnet, 773 NIC: nicID, 774 }}, 775 ) 776 } 777 778 handleIPv6Payload := func(checksum bool) { 779 icmp := header.ICMPv6(make([]byte, typ.size+len(typ.extraData))) 780 copy(icmp[typ.size:], typ.extraData) 781 icmp.SetType(typ.typ) 782 if checksum { 783 icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 784 Header: icmp, 785 Src: lladdr1, 786 Dst: lladdr0, 787 })) 788 } 789 ip := header.IPv6(make([]byte, header.IPv6MinimumSize)) 790 ip.Encode(&header.IPv6Fields{ 791 PayloadLength: uint16(len(icmp)), 792 TransportProtocol: header.ICMPv6ProtocolNumber, 793 HopLimit: header.NDPHopLimit, 794 SrcAddr: lladdr1, 795 DstAddr: lladdr0, 796 }) 797 buf := buffer.MakeWithData(append(ip, icmp...)) 798 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 799 Payload: buf, 800 }) 801 e.InjectInbound(ProtocolNumber, pkt) 802 pkt.DecRef() 803 } 804 805 stats := s.Stats().ICMP.V6.PacketsReceived 806 invalid := stats.Invalid 807 routerOnly := stats.RouterOnlyPacketsDroppedByHost 808 typStat := typ.statCounter(stats) 809 810 // Initial stat counts should be 0. 811 if got := invalid.Value(); got != 0 { 812 t.Fatalf("got invalid = %d, want = 0", got) 813 } 814 if got := routerOnly.Value(); got != 0 { 815 t.Fatalf("got RouterOnlyPacketsReceivedByHost = %d, want = 0", got) 816 } 817 if got := typStat.Value(); got != 0 { 818 t.Fatalf("got %s = %d, want = 0", typ.name, got) 819 } 820 821 // Without setting checksum, the incoming packet should 822 // be invalid. 823 handleIPv6Payload(false) 824 if got := invalid.Value(); got != 1 { 825 t.Fatalf("got invalid = %d, want = 1", got) 826 } 827 // Router only count should not have increased. 828 if got := routerOnly.Value(); got != 0 { 829 t.Fatalf("got RouterOnlyPacketsReceivedByHost = %d, want = 0", got) 830 } 831 // Rx count of type typ.typ should not have increased. 832 if got := typStat.Value(); got != 0 { 833 t.Fatalf("got %s = %d, want = 0", typ.name, got) 834 } 835 836 // When checksum is set, it should be received. 837 handleIPv6Payload(true) 838 if got := typStat.Value(); got != 1 { 839 t.Fatalf("got %s = %d, want = 1", typ.name, got) 840 } 841 // Invalid count should not have increased again. 842 if got := invalid.Value(); got != 1 { 843 t.Fatalf("got invalid = %d, want = 1", got) 844 } 845 if !isRouter && typ.routerOnly { 846 // Router only count should have increased. 847 if got := routerOnly.Value(); got != 1 { 848 t.Fatalf("got RouterOnlyPacketsReceivedByHost = %d, want = 1", got) 849 } 850 } 851 }) 852 } 853 } 854 } 855 856 func TestICMPChecksumValidationWithPayload(t *testing.T) { 857 const simpleBodySize = 64 858 simpleBody := func(view []byte) { 859 for i := 0; i < simpleBodySize; i++ { 860 view[i] = uint8(i) 861 } 862 } 863 864 const errorICMPBodySize = header.IPv6MinimumSize + simpleBodySize 865 errorICMPBody := func(view []byte) { 866 ip := header.IPv6(view) 867 ip.Encode(&header.IPv6Fields{ 868 PayloadLength: simpleBodySize, 869 TransportProtocol: 10, 870 HopLimit: 20, 871 SrcAddr: lladdr0, 872 DstAddr: lladdr1, 873 }) 874 simpleBody(view[header.IPv6MinimumSize:]) 875 } 876 877 types := []struct { 878 name string 879 typ header.ICMPv6Type 880 size int 881 statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter 882 payloadSize int 883 payload func([]byte) 884 }{ 885 { 886 "DstUnreachable", 887 header.ICMPv6DstUnreachable, 888 header.ICMPv6DstUnreachableMinimumSize, 889 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 890 return stats.DstUnreachable 891 }, 892 errorICMPBodySize, 893 errorICMPBody, 894 }, 895 { 896 "PacketTooBig", 897 header.ICMPv6PacketTooBig, 898 header.ICMPv6PacketTooBigMinimumSize, 899 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 900 return stats.PacketTooBig 901 }, 902 errorICMPBodySize, 903 errorICMPBody, 904 }, 905 { 906 "TimeExceeded", 907 header.ICMPv6TimeExceeded, 908 header.ICMPv6MinimumSize, 909 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 910 return stats.TimeExceeded 911 }, 912 errorICMPBodySize, 913 errorICMPBody, 914 }, 915 { 916 "ParamProblem", 917 header.ICMPv6ParamProblem, 918 header.ICMPv6MinimumSize, 919 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 920 return stats.ParamProblem 921 }, 922 errorICMPBodySize, 923 errorICMPBody, 924 }, 925 { 926 "EchoRequest", 927 header.ICMPv6EchoRequest, 928 header.ICMPv6EchoMinimumSize, 929 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 930 return stats.EchoRequest 931 }, 932 simpleBodySize, 933 simpleBody, 934 }, 935 { 936 "EchoReply", 937 header.ICMPv6EchoReply, 938 header.ICMPv6EchoMinimumSize, 939 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 940 return stats.EchoReply 941 }, 942 simpleBodySize, 943 simpleBody, 944 }, 945 } 946 947 for _, typ := range types { 948 t.Run(typ.name, func(t *testing.T) { 949 c := newTestContext() 950 defer c.cleanup() 951 s := c.s 952 953 e := channel.New(10, 1280, linkAddr0) 954 defer e.Close() 955 if err := s.CreateNIC(nicID, e); err != nil { 956 t.Fatalf("CreateNIC(_, _) = %s", err) 957 } 958 959 protocolAddr := tcpip.ProtocolAddress{ 960 Protocol: ProtocolNumber, 961 AddressWithPrefix: lladdr0.WithPrefix(), 962 } 963 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 964 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 965 } 966 { 967 subnet, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr1.Len()))) 968 if err != nil { 969 t.Fatal(err) 970 } 971 s.SetRouteTable( 972 []tcpip.Route{{ 973 Destination: subnet, 974 NIC: nicID, 975 }}, 976 ) 977 } 978 979 handleIPv6Payload := func(typ header.ICMPv6Type, size, payloadSize int, payloadFn func([]byte), checksum bool) { 980 icmpSize := size + payloadSize 981 hdr := prependable.New(header.IPv6MinimumSize + icmpSize) 982 icmpHdr := header.ICMPv6(hdr.Prepend(icmpSize)) 983 icmpHdr.SetType(typ) 984 payloadFn(icmpHdr.Payload()) 985 986 if checksum { 987 icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 988 Header: icmpHdr, 989 Src: lladdr1, 990 Dst: lladdr0, 991 })) 992 } 993 994 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 995 ip.Encode(&header.IPv6Fields{ 996 PayloadLength: uint16(icmpSize), 997 TransportProtocol: header.ICMPv6ProtocolNumber, 998 HopLimit: header.NDPHopLimit, 999 SrcAddr: lladdr1, 1000 DstAddr: lladdr0, 1001 }) 1002 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1003 Payload: buffer.MakeWithData(hdr.View()), 1004 }) 1005 e.InjectInbound(ProtocolNumber, pkt) 1006 pkt.DecRef() 1007 } 1008 1009 stats := s.Stats().ICMP.V6.PacketsReceived 1010 invalid := stats.Invalid 1011 typStat := typ.statCounter(stats) 1012 1013 // Initial stat counts should be 0. 1014 if got := invalid.Value(); got != 0 { 1015 t.Fatalf("got invalid = %d, want = 0", got) 1016 } 1017 if got := typStat.Value(); got != 0 { 1018 t.Fatalf("got = %d, want = 0", got) 1019 } 1020 1021 // Without setting checksum, the incoming packet should 1022 // be invalid. 1023 handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, false) 1024 if got := invalid.Value(); got != 1 { 1025 t.Fatalf("got invalid = %d, want = 1", got) 1026 } 1027 // Rx count of type typ.typ should not have increased. 1028 if got := typStat.Value(); got != 0 { 1029 t.Fatalf("got = %d, want = 0", got) 1030 } 1031 1032 // When checksum is set, it should be received. 1033 handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, true) 1034 if got := typStat.Value(); got != 1 { 1035 t.Fatalf("got = %d, want = 0", got) 1036 } 1037 // Invalid count should not have increased again. 1038 if got := invalid.Value(); got != 1 { 1039 t.Fatalf("got invalid = %d, want = 1", got) 1040 } 1041 }) 1042 } 1043 } 1044 1045 func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) { 1046 const simpleBodySize = 64 1047 simpleBody := func(view []byte) { 1048 for i := 0; i < simpleBodySize; i++ { 1049 view[i] = uint8(i) 1050 } 1051 } 1052 1053 const errorICMPBodySize = header.IPv6MinimumSize + simpleBodySize 1054 errorICMPBody := func(view []byte) { 1055 ip := header.IPv6(view) 1056 ip.Encode(&header.IPv6Fields{ 1057 PayloadLength: simpleBodySize, 1058 TransportProtocol: 10, 1059 HopLimit: 20, 1060 SrcAddr: lladdr0, 1061 DstAddr: lladdr1, 1062 }) 1063 simpleBody(view[header.IPv6MinimumSize:]) 1064 } 1065 1066 types := []struct { 1067 name string 1068 typ header.ICMPv6Type 1069 size int 1070 statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter 1071 payloadSize int 1072 payload func([]byte) 1073 }{ 1074 { 1075 "DstUnreachable", 1076 header.ICMPv6DstUnreachable, 1077 header.ICMPv6DstUnreachableMinimumSize, 1078 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 1079 return stats.DstUnreachable 1080 }, 1081 errorICMPBodySize, 1082 errorICMPBody, 1083 }, 1084 { 1085 "PacketTooBig", 1086 header.ICMPv6PacketTooBig, 1087 header.ICMPv6PacketTooBigMinimumSize, 1088 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 1089 return stats.PacketTooBig 1090 }, 1091 errorICMPBodySize, 1092 errorICMPBody, 1093 }, 1094 { 1095 "TimeExceeded", 1096 header.ICMPv6TimeExceeded, 1097 header.ICMPv6MinimumSize, 1098 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 1099 return stats.TimeExceeded 1100 }, 1101 errorICMPBodySize, 1102 errorICMPBody, 1103 }, 1104 { 1105 "ParamProblem", 1106 header.ICMPv6ParamProblem, 1107 header.ICMPv6MinimumSize, 1108 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 1109 return stats.ParamProblem 1110 }, 1111 errorICMPBodySize, 1112 errorICMPBody, 1113 }, 1114 { 1115 "EchoRequest", 1116 header.ICMPv6EchoRequest, 1117 header.ICMPv6EchoMinimumSize, 1118 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 1119 return stats.EchoRequest 1120 }, 1121 simpleBodySize, 1122 simpleBody, 1123 }, 1124 { 1125 "EchoReply", 1126 header.ICMPv6EchoReply, 1127 header.ICMPv6EchoMinimumSize, 1128 func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 1129 return stats.EchoReply 1130 }, 1131 simpleBodySize, 1132 simpleBody, 1133 }, 1134 } 1135 1136 for _, typ := range types { 1137 t.Run(typ.name, func(t *testing.T) { 1138 c := newTestContext() 1139 defer c.cleanup() 1140 s := c.s 1141 1142 e := channel.New(10, 1280, linkAddr0) 1143 defer e.Close() 1144 if err := s.CreateNIC(nicID, e); err != nil { 1145 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 1146 } 1147 1148 protocolAddr := tcpip.ProtocolAddress{ 1149 Protocol: ProtocolNumber, 1150 AddressWithPrefix: lladdr0.WithPrefix(), 1151 } 1152 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 1153 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 1154 } 1155 { 1156 subnet, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr1.Len()))) 1157 if err != nil { 1158 t.Fatal(err) 1159 } 1160 s.SetRouteTable( 1161 []tcpip.Route{{ 1162 Destination: subnet, 1163 NIC: nicID, 1164 }}, 1165 ) 1166 } 1167 1168 handleIPv6Payload := func(typ header.ICMPv6Type, size, payloadSize int, payloadFn func([]byte), xsum bool) { 1169 hdr := prependable.New(header.IPv6MinimumSize + size) 1170 icmpHdr := header.ICMPv6(hdr.Prepend(size)) 1171 icmpHdr.SetType(typ) 1172 1173 payload := make([]byte, payloadSize) 1174 payloadFn(payload) 1175 1176 if xsum { 1177 icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1178 Header: icmpHdr, 1179 Src: lladdr1, 1180 Dst: lladdr0, 1181 PayloadCsum: checksum.Checksum(payload, 0 /* initial */), 1182 PayloadLen: len(payload), 1183 })) 1184 } 1185 1186 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 1187 ip.Encode(&header.IPv6Fields{ 1188 PayloadLength: uint16(size + payloadSize), 1189 TransportProtocol: header.ICMPv6ProtocolNumber, 1190 HopLimit: header.NDPHopLimit, 1191 SrcAddr: lladdr1, 1192 DstAddr: lladdr0, 1193 }) 1194 buf := buffer.MakeWithData(append(hdr.View(), payload...)) 1195 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1196 Payload: buf, 1197 }) 1198 e.InjectInbound(ProtocolNumber, pkt) 1199 pkt.DecRef() 1200 } 1201 1202 stats := s.Stats().ICMP.V6.PacketsReceived 1203 invalid := stats.Invalid 1204 typStat := typ.statCounter(stats) 1205 1206 // Initial stat counts should be 0. 1207 if got := invalid.Value(); got != 0 { 1208 t.Fatalf("got invalid = %d, want = 0", got) 1209 } 1210 if got := typStat.Value(); got != 0 { 1211 t.Fatalf("got = %d, want = 0", got) 1212 } 1213 1214 // Without setting checksum, the incoming packet should 1215 // be invalid. 1216 handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, false) 1217 if got := invalid.Value(); got != 1 { 1218 t.Fatalf("got invalid = %d, want = 1", got) 1219 } 1220 // Rx count of type typ.typ should not have increased. 1221 if got := typStat.Value(); got != 0 { 1222 t.Fatalf("got = %d, want = 0", got) 1223 } 1224 1225 // When checksum is set, it should be received. 1226 handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, true) 1227 if got := typStat.Value(); got != 1 { 1228 t.Fatalf("got = %d, want = 0", got) 1229 } 1230 // Invalid count should not have increased again. 1231 if got := invalid.Value(); got != 1 { 1232 t.Fatalf("got invalid = %d, want = 1", got) 1233 } 1234 }) 1235 } 1236 } 1237 1238 func TestLinkAddressRequest(t *testing.T) { 1239 const nicID = 1 1240 1241 snaddr := header.SolicitedNodeAddr(lladdr0) 1242 mcaddr := header.EthernetAddressFromMulticastIPv6Address(snaddr) 1243 1244 tests := []struct { 1245 name string 1246 nicAddr tcpip.Address 1247 localAddr tcpip.Address 1248 remoteLinkAddr tcpip.LinkAddress 1249 1250 expectedErr tcpip.Error 1251 expectedRemoteAddr tcpip.Address 1252 expectedRemoteLinkAddr tcpip.LinkAddress 1253 }{ 1254 { 1255 name: "Unicast", 1256 nicAddr: lladdr1, 1257 localAddr: lladdr1, 1258 remoteLinkAddr: linkAddr1, 1259 expectedRemoteAddr: lladdr0, 1260 expectedRemoteLinkAddr: linkAddr1, 1261 }, 1262 { 1263 name: "Multicast", 1264 nicAddr: lladdr1, 1265 localAddr: lladdr1, 1266 remoteLinkAddr: "", 1267 expectedRemoteAddr: snaddr, 1268 expectedRemoteLinkAddr: mcaddr, 1269 }, 1270 { 1271 name: "Unicast with unspecified source", 1272 nicAddr: lladdr1, 1273 remoteLinkAddr: linkAddr1, 1274 expectedRemoteAddr: lladdr0, 1275 expectedRemoteLinkAddr: linkAddr1, 1276 }, 1277 { 1278 name: "Multicast with unspecified source", 1279 nicAddr: lladdr1, 1280 remoteLinkAddr: "", 1281 expectedRemoteAddr: snaddr, 1282 expectedRemoteLinkAddr: mcaddr, 1283 }, 1284 { 1285 name: "Unicast with unassigned address", 1286 localAddr: lladdr1, 1287 remoteLinkAddr: linkAddr1, 1288 expectedErr: &tcpip.ErrBadLocalAddress{}, 1289 }, 1290 { 1291 name: "Multicast with unassigned address", 1292 localAddr: lladdr1, 1293 remoteLinkAddr: "", 1294 expectedErr: &tcpip.ErrBadLocalAddress{}, 1295 }, 1296 { 1297 name: "Unicast with no local address available", 1298 remoteLinkAddr: linkAddr1, 1299 expectedErr: &tcpip.ErrNetworkUnreachable{}, 1300 }, 1301 { 1302 name: "Multicast with no local address available", 1303 remoteLinkAddr: "", 1304 expectedErr: &tcpip.ErrNetworkUnreachable{}, 1305 }, 1306 } 1307 1308 for _, test := range tests { 1309 t.Run(test.name, func(t *testing.T) { 1310 c := newTestContext() 1311 defer c.cleanup() 1312 s := c.s 1313 1314 linkEP := channel.New(defaultChannelSize, defaultMTU, linkAddr0) 1315 if err := s.CreateNIC(nicID, linkEP); err != nil { 1316 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 1317 } 1318 1319 ep, err := s.GetNetworkEndpoint(nicID, ProtocolNumber) 1320 if err != nil { 1321 t.Fatalf("s.GetNetworkEndpoint(%d, %d): %s", nicID, ProtocolNumber, err) 1322 } 1323 linkRes, ok := ep.(stack.LinkAddressResolver) 1324 if !ok { 1325 t.Fatalf("expected %T to implement stack.LinkAddressResolver", ep) 1326 } 1327 1328 if test.nicAddr.Len() != 0 { 1329 protocolAddr := tcpip.ProtocolAddress{ 1330 Protocol: ProtocolNumber, 1331 AddressWithPrefix: test.nicAddr.WithPrefix(), 1332 } 1333 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 1334 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 1335 } 1336 } 1337 1338 { 1339 err := linkRes.LinkAddressRequest(lladdr0, test.localAddr, test.remoteLinkAddr) 1340 if diff := cmp.Diff(test.expectedErr, err); diff != "" { 1341 t.Fatalf("unexpected error from p.LinkAddressRequest(%s, %s, %s, _), (-want, +got):\n%s", lladdr0, test.localAddr, test.remoteLinkAddr, diff) 1342 } 1343 } 1344 1345 if test.expectedErr != nil { 1346 return 1347 } 1348 1349 pkt := linkEP.Read() 1350 if pkt == nil { 1351 t.Fatal("expected to send a link address request") 1352 } 1353 defer pkt.DecRef() 1354 1355 var want stack.RouteInfo 1356 want.NetProto = ProtocolNumber 1357 want.LocalLinkAddress = linkAddr0 1358 want.RemoteLinkAddress = test.expectedRemoteLinkAddr 1359 if diff := cmp.Diff(want, pkt.EgressRoute, cmp.AllowUnexported(want)); diff != "" { 1360 t.Errorf("route info mismatch (-want +got):\n%s", diff) 1361 } 1362 payload := stack.PayloadSince(pkt.NetworkHeader()) 1363 defer payload.Release() 1364 checker.IPv6(t, payload, 1365 checker.SrcAddr(lladdr1), 1366 checker.DstAddr(test.expectedRemoteAddr), 1367 checker.TTL(header.NDPHopLimit), 1368 checker.NDPNS( 1369 checker.NDPNSTargetAddress(lladdr0), 1370 checker.NDPNSOptions([]header.NDPOption{header.NDPSourceLinkLayerAddressOption(linkAddr0)}), 1371 )) 1372 }) 1373 } 1374 } 1375 1376 func TestPacketQueing(t *testing.T) { 1377 const nicID = 1 1378 1379 var ( 1380 host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06") 1381 host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09") 1382 1383 host1IPv6Addr = tcpip.ProtocolAddress{ 1384 Protocol: ProtocolNumber, 1385 AddressWithPrefix: tcpip.AddressWithPrefix{ 1386 Address: tcpip.AddrFromSlice(net.ParseIP("a::1").To16()), 1387 PrefixLen: 64, 1388 }, 1389 } 1390 host2IPv6Addr = tcpip.ProtocolAddress{ 1391 Protocol: ProtocolNumber, 1392 AddressWithPrefix: tcpip.AddressWithPrefix{ 1393 Address: tcpip.AddrFromSlice(net.ParseIP("a::2").To16()), 1394 PrefixLen: 64, 1395 }, 1396 } 1397 ) 1398 1399 tests := []struct { 1400 name string 1401 rxPkt func(*channel.Endpoint) 1402 checkResp func(*testing.T, *channel.Endpoint) 1403 }{ 1404 { 1405 name: "ICMP Error", 1406 rxPkt: func(e *channel.Endpoint) { 1407 hdr := prependable.New(header.IPv6MinimumSize + header.UDPMinimumSize) 1408 u := header.UDP(hdr.Prepend(header.UDPMinimumSize)) 1409 u.Encode(&header.UDPFields{ 1410 SrcPort: 5555, 1411 DstPort: 80, 1412 Length: header.UDPMinimumSize, 1413 }) 1414 sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, header.UDPMinimumSize) 1415 sum = checksum.Checksum(nil, sum) 1416 u.SetChecksum(^u.CalculateChecksum(sum)) 1417 payloadLength := hdr.UsedLength() 1418 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 1419 ip.Encode(&header.IPv6Fields{ 1420 PayloadLength: uint16(payloadLength), 1421 TransportProtocol: udp.ProtocolNumber, 1422 HopLimit: DefaultTTL, 1423 SrcAddr: host2IPv6Addr.AddressWithPrefix.Address, 1424 DstAddr: host1IPv6Addr.AddressWithPrefix.Address, 1425 }) 1426 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1427 Payload: buffer.MakeWithData(hdr.View()), 1428 }) 1429 e.InjectInbound(ProtocolNumber, pkt) 1430 pkt.DecRef() 1431 }, 1432 checkResp: func(t *testing.T, e *channel.Endpoint) { 1433 p := e.Read() 1434 if p == nil { 1435 t.Fatalf("timed out waiting for packet") 1436 } 1437 defer p.DecRef() 1438 if p.NetworkProtocolNumber != ProtocolNumber { 1439 t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, ProtocolNumber) 1440 } 1441 if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { 1442 t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) 1443 } 1444 payload := stack.PayloadSince(p.NetworkHeader()) 1445 defer payload.Release() 1446 checker.IPv6(t, payload, 1447 checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), 1448 checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address), 1449 checker.ICMPv6( 1450 checker.ICMPv6Type(header.ICMPv6DstUnreachable), 1451 checker.ICMPv6Code(header.ICMPv6PortUnreachable))) 1452 }, 1453 }, 1454 1455 { 1456 name: "Ping", 1457 rxPkt: func(e *channel.Endpoint) { 1458 totalLen := header.IPv6MinimumSize + header.ICMPv6MinimumSize 1459 hdr := prependable.New(totalLen) 1460 pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize)) 1461 pkt.SetType(header.ICMPv6EchoRequest) 1462 pkt.SetCode(0) 1463 pkt.SetChecksum(0) 1464 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1465 Header: pkt, 1466 Src: host2IPv6Addr.AddressWithPrefix.Address, 1467 Dst: host1IPv6Addr.AddressWithPrefix.Address, 1468 })) 1469 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 1470 ip.Encode(&header.IPv6Fields{ 1471 PayloadLength: header.ICMPv6MinimumSize, 1472 TransportProtocol: icmp.ProtocolNumber6, 1473 HopLimit: DefaultTTL, 1474 SrcAddr: host2IPv6Addr.AddressWithPrefix.Address, 1475 DstAddr: host1IPv6Addr.AddressWithPrefix.Address, 1476 }) 1477 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1478 Payload: buffer.MakeWithData(hdr.View()), 1479 }) 1480 e.InjectInbound(header.IPv6ProtocolNumber, pktBuf) 1481 pktBuf.DecRef() 1482 }, 1483 checkResp: func(t *testing.T, e *channel.Endpoint) { 1484 p := e.Read() 1485 if p == nil { 1486 t.Fatalf("timed out waiting for packet") 1487 } 1488 defer p.DecRef() 1489 if p.NetworkProtocolNumber != ProtocolNumber { 1490 t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, ProtocolNumber) 1491 } 1492 if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { 1493 t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) 1494 } 1495 payload := stack.PayloadSince(p.NetworkHeader()) 1496 defer payload.Release() 1497 checker.IPv6(t, payload, 1498 checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), 1499 checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address), 1500 checker.ICMPv6( 1501 checker.ICMPv6Type(header.ICMPv6EchoReply), 1502 checker.ICMPv6Code(header.ICMPv6UnusedCode))) 1503 }, 1504 }, 1505 } 1506 1507 for _, test := range tests { 1508 t.Run(test.name, func(t *testing.T) { 1509 c := newTestContext() 1510 defer c.cleanup() 1511 s := c.s 1512 1513 // Make sure ICMP rate limiting doesn't get in our way. 1514 s.SetICMPLimit(rate.Inf) 1515 1516 e := channel.New(1, header.IPv6MinimumMTU, host1NICLinkAddr) 1517 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 1518 if err := s.CreateNIC(nicID, e); err != nil { 1519 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 1520 } 1521 if err := s.AddProtocolAddress(nicID, host1IPv6Addr, stack.AddressProperties{}); err != nil { 1522 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, host1IPv6Addr, err) 1523 } 1524 1525 s.SetRouteTable([]tcpip.Route{ 1526 { 1527 Destination: host1IPv6Addr.AddressWithPrefix.Subnet(), 1528 NIC: nicID, 1529 }, 1530 }) 1531 1532 // Receive a packet to trigger link resolution before a response is sent. 1533 test.rxPkt(e) 1534 1535 // Wait for a neighbor solicitation since link address resolution should 1536 // be performed. 1537 { 1538 c.clock.RunImmediatelyScheduledJobs() 1539 p := e.Read() 1540 if p == nil { 1541 t.Fatalf("timed out waiting for packet") 1542 } 1543 if p.NetworkProtocolNumber != ProtocolNumber { 1544 t.Errorf("got Proto = %d, want = %d", p.NetworkProtocolNumber, ProtocolNumber) 1545 } 1546 snmc := header.SolicitedNodeAddr(host2IPv6Addr.AddressWithPrefix.Address) 1547 if want := header.EthernetAddressFromMulticastIPv6Address(snmc); p.EgressRoute.RemoteLinkAddress != want { 1548 t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, want) 1549 } 1550 payload := stack.PayloadSince(p.NetworkHeader()) 1551 defer payload.Release() 1552 checker.IPv6(t, payload, 1553 checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), 1554 checker.DstAddr(snmc), 1555 checker.TTL(header.NDPHopLimit), 1556 checker.NDPNS( 1557 checker.NDPNSTargetAddress(host2IPv6Addr.AddressWithPrefix.Address), 1558 checker.NDPNSOptions([]header.NDPOption{header.NDPSourceLinkLayerAddressOption(host1NICLinkAddr)}), 1559 )) 1560 p.DecRef() 1561 } 1562 1563 // Send a neighbor advertisement to complete link address resolution. 1564 { 1565 naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize 1566 hdr := prependable.New(header.IPv6MinimumSize + naSize) 1567 pkt := header.ICMPv6(hdr.Prepend(naSize)) 1568 pkt.SetType(header.ICMPv6NeighborAdvert) 1569 na := header.NDPNeighborAdvert(pkt.MessageBody()) 1570 na.SetSolicitedFlag(true) 1571 na.SetOverrideFlag(true) 1572 na.SetTargetAddress(host2IPv6Addr.AddressWithPrefix.Address) 1573 na.Options().Serialize(header.NDPOptionsSerializer{ 1574 header.NDPTargetLinkLayerAddressOption(host2NICLinkAddr), 1575 }) 1576 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1577 Header: pkt, 1578 Src: host2IPv6Addr.AddressWithPrefix.Address, 1579 Dst: host1IPv6Addr.AddressWithPrefix.Address, 1580 })) 1581 payloadLength := hdr.UsedLength() 1582 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 1583 ip.Encode(&header.IPv6Fields{ 1584 PayloadLength: uint16(payloadLength), 1585 TransportProtocol: icmp.ProtocolNumber6, 1586 HopLimit: header.NDPHopLimit, 1587 SrcAddr: host2IPv6Addr.AddressWithPrefix.Address, 1588 DstAddr: host1IPv6Addr.AddressWithPrefix.Address, 1589 }) 1590 pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1591 Payload: buffer.MakeWithData(hdr.View()), 1592 }) 1593 e.InjectInbound(ProtocolNumber, pktBuf) 1594 pktBuf.DecRef() 1595 } 1596 1597 // Expect the response now that the link address has resolved. 1598 c.clock.RunImmediatelyScheduledJobs() 1599 test.checkResp(t, e) 1600 1601 // Since link resolution was already performed, it shouldn't be performed 1602 // again. 1603 test.rxPkt(e) 1604 test.checkResp(t, e) 1605 }) 1606 } 1607 } 1608 1609 func TestCallsToNeighborCache(t *testing.T) { 1610 tests := []struct { 1611 name string 1612 createPacket func() header.ICMPv6 1613 multicast bool 1614 source tcpip.Address 1615 destination tcpip.Address 1616 wantProbeCount int 1617 wantConfirmationCount int 1618 }{ 1619 { 1620 name: "Unicast Neighbor Solicitation without source link-layer address option", 1621 createPacket: func() header.ICMPv6 { 1622 nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize 1623 icmp := header.ICMPv6(make([]byte, nsSize)) 1624 icmp.SetType(header.ICMPv6NeighborSolicit) 1625 ns := header.NDPNeighborSolicit(icmp.MessageBody()) 1626 ns.SetTargetAddress(lladdr0) 1627 return icmp 1628 }, 1629 source: lladdr1, 1630 destination: lladdr0, 1631 // "The source link-layer address option SHOULD be included in unicast 1632 // solicitations." - RFC 4861 section 4.3 1633 // 1634 // A Neighbor Advertisement needs to be sent in response, but the 1635 // Neighbor Cache shouldn't be updated since we have no useful 1636 // information about the sender. 1637 wantProbeCount: 0, 1638 }, 1639 { 1640 name: "Unicast Neighbor Solicitation with source link-layer address option", 1641 createPacket: func() header.ICMPv6 { 1642 nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize 1643 icmp := header.ICMPv6(make([]byte, nsSize)) 1644 icmp.SetType(header.ICMPv6NeighborSolicit) 1645 ns := header.NDPNeighborSolicit(icmp.MessageBody()) 1646 ns.SetTargetAddress(lladdr0) 1647 ns.Options().Serialize(header.NDPOptionsSerializer{ 1648 header.NDPSourceLinkLayerAddressOption(linkAddr1), 1649 }) 1650 return icmp 1651 }, 1652 source: lladdr1, 1653 destination: lladdr0, 1654 wantProbeCount: 1, 1655 }, 1656 { 1657 name: "Multicast Neighbor Solicitation without source link-layer address option", 1658 createPacket: func() header.ICMPv6 { 1659 nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize 1660 icmp := header.ICMPv6(make([]byte, nsSize)) 1661 icmp.SetType(header.ICMPv6NeighborSolicit) 1662 ns := header.NDPNeighborSolicit(icmp.MessageBody()) 1663 ns.SetTargetAddress(lladdr0) 1664 return icmp 1665 }, 1666 source: lladdr1, 1667 destination: header.SolicitedNodeAddr(lladdr0), 1668 // "The source link-layer address option MUST be included in multicast 1669 // solicitations." - RFC 4861 section 4.3 1670 wantProbeCount: 0, 1671 }, 1672 { 1673 name: "Multicast Neighbor Solicitation with source link-layer address option", 1674 createPacket: func() header.ICMPv6 { 1675 nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize 1676 icmp := header.ICMPv6(make([]byte, nsSize)) 1677 icmp.SetType(header.ICMPv6NeighborSolicit) 1678 ns := header.NDPNeighborSolicit(icmp.MessageBody()) 1679 ns.SetTargetAddress(lladdr0) 1680 ns.Options().Serialize(header.NDPOptionsSerializer{ 1681 header.NDPSourceLinkLayerAddressOption(linkAddr1), 1682 }) 1683 return icmp 1684 }, 1685 source: lladdr1, 1686 destination: header.SolicitedNodeAddr(lladdr0), 1687 wantProbeCount: 1, 1688 }, 1689 { 1690 name: "Unicast Neighbor Advertisement without target link-layer address option", 1691 createPacket: func() header.ICMPv6 { 1692 naSize := header.ICMPv6NeighborAdvertMinimumSize 1693 icmp := header.ICMPv6(make([]byte, naSize)) 1694 icmp.SetType(header.ICMPv6NeighborAdvert) 1695 na := header.NDPNeighborAdvert(icmp.MessageBody()) 1696 na.SetSolicitedFlag(true) 1697 na.SetOverrideFlag(false) 1698 na.SetTargetAddress(lladdr1) 1699 return icmp 1700 }, 1701 source: lladdr1, 1702 destination: lladdr0, 1703 // "When responding to unicast solicitations, the target link-layer 1704 // address option can be omitted since the sender of the solicitation has 1705 // the correct link-layer address; otherwise, it would not be able to 1706 // send the unicast solicitation in the first place." 1707 // - RFC 4861 section 4.4 1708 wantConfirmationCount: 1, 1709 }, 1710 { 1711 name: "Unicast Neighbor Advertisement with target link-layer address option", 1712 createPacket: func() header.ICMPv6 { 1713 naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize 1714 icmp := header.ICMPv6(make([]byte, naSize)) 1715 icmp.SetType(header.ICMPv6NeighborAdvert) 1716 na := header.NDPNeighborAdvert(icmp.MessageBody()) 1717 na.SetSolicitedFlag(true) 1718 na.SetOverrideFlag(false) 1719 na.SetTargetAddress(lladdr1) 1720 na.Options().Serialize(header.NDPOptionsSerializer{ 1721 header.NDPTargetLinkLayerAddressOption(linkAddr1), 1722 }) 1723 return icmp 1724 }, 1725 source: lladdr1, 1726 destination: lladdr0, 1727 wantConfirmationCount: 1, 1728 }, 1729 { 1730 name: "Multicast Neighbor Advertisement without target link-layer address option", 1731 createPacket: func() header.ICMPv6 { 1732 naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize 1733 icmp := header.ICMPv6(make([]byte, naSize)) 1734 icmp.SetType(header.ICMPv6NeighborAdvert) 1735 na := header.NDPNeighborAdvert(icmp.MessageBody()) 1736 na.SetSolicitedFlag(false) 1737 na.SetOverrideFlag(false) 1738 na.SetTargetAddress(lladdr1) 1739 return icmp 1740 }, 1741 source: lladdr1, 1742 destination: header.IPv6AllNodesMulticastAddress, 1743 // "Target link-layer address MUST be included for multicast solicitations 1744 // in order to avoid infinite Neighbor Solicitation "recursion" when the 1745 // peer node does not have a cache entry to return a Neighbor 1746 // Advertisements message." - RFC 4861 section 4.4 1747 wantConfirmationCount: 0, 1748 }, 1749 { 1750 name: "Multicast Neighbor Advertisement with target link-layer address option", 1751 createPacket: func() header.ICMPv6 { 1752 naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize 1753 icmp := header.ICMPv6(make([]byte, naSize)) 1754 icmp.SetType(header.ICMPv6NeighborAdvert) 1755 na := header.NDPNeighborAdvert(icmp.MessageBody()) 1756 na.SetSolicitedFlag(false) 1757 na.SetOverrideFlag(false) 1758 na.SetTargetAddress(lladdr1) 1759 na.Options().Serialize(header.NDPOptionsSerializer{ 1760 header.NDPTargetLinkLayerAddressOption(linkAddr1), 1761 }) 1762 return icmp 1763 }, 1764 source: lladdr1, 1765 destination: header.IPv6AllNodesMulticastAddress, 1766 wantConfirmationCount: 1, 1767 }, 1768 } 1769 1770 for _, test := range tests { 1771 t.Run(test.name, func(t *testing.T) { 1772 c := newTestContext() 1773 defer c.cleanup() 1774 s := c.s 1775 1776 { 1777 if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil { 1778 t.Fatalf("CreateNIC(_, _) = %s", err) 1779 } 1780 protocolAddr := tcpip.ProtocolAddress{ 1781 Protocol: ProtocolNumber, 1782 AddressWithPrefix: lladdr0.WithPrefix(), 1783 } 1784 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 1785 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 1786 } 1787 } 1788 { 1789 subnet, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr1.Len()))) 1790 if err != nil { 1791 t.Fatal(err) 1792 } 1793 s.SetRouteTable( 1794 []tcpip.Route{{ 1795 Destination: subnet, 1796 NIC: nicID, 1797 }}, 1798 ) 1799 } 1800 1801 netProto := s.NetworkProtocolInstance(ProtocolNumber) 1802 if netProto == nil { 1803 t.Fatalf("cannot find protocol instance for network protocol %d", ProtocolNumber) 1804 } 1805 1806 testInterface := testInterface{LinkEndpoint: channel.New(0, header.IPv6MinimumMTU, linkAddr0)} 1807 ep := netProto.NewEndpoint(&testInterface, &stubDispatcher{}) 1808 defer ep.Close() 1809 1810 if err := ep.Enable(); err != nil { 1811 t.Fatalf("ep.Enable(): %s", err) 1812 } 1813 1814 addressableEndpoint, ok := ep.(stack.AddressableEndpoint) 1815 if !ok { 1816 t.Fatalf("expected network endpoint to implement stack.AddressableEndpoint") 1817 } 1818 addr := lladdr0.WithPrefix() 1819 if ep, err := addressableEndpoint.AddAndAcquirePermanentAddress(addr, stack.AddressProperties{}); err != nil { 1820 t.Fatalf("addressableEndpoint.AddAndAcquirePermanentAddress(%s, {}): %s", addr, err) 1821 } else { 1822 ep.DecRef() 1823 } 1824 1825 icmp := test.createPacket() 1826 icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1827 Header: icmp, 1828 Src: test.source, 1829 Dst: test.destination, 1830 })) 1831 handleICMPInIPv6(ep, test.source, test.destination, icmp, header.NDPHopLimit, false) 1832 1833 // Confirm the endpoint calls the correct NUDHandler method. 1834 if testInterface.probeCount != test.wantProbeCount { 1835 t.Errorf("got testInterface.probeCount = %d, want = %d", testInterface.probeCount, test.wantProbeCount) 1836 } 1837 if testInterface.confirmationCount != test.wantConfirmationCount { 1838 t.Errorf("got testInterface.confirmationCount = %d, want = %d", testInterface.confirmationCount, test.wantConfirmationCount) 1839 } 1840 }) 1841 } 1842 }