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