gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/tests/integration/loopback_test.go (about) 1 // Copyright 2020 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 loopback_test 16 17 import ( 18 "bytes" 19 "testing" 20 "time" 21 22 "github.com/google/go-cmp/cmp" 23 "gvisor.dev/gvisor/pkg/buffer" 24 "gvisor.dev/gvisor/pkg/tcpip" 25 "gvisor.dev/gvisor/pkg/tcpip/checker" 26 "gvisor.dev/gvisor/pkg/tcpip/header" 27 "gvisor.dev/gvisor/pkg/tcpip/link/channel" 28 "gvisor.dev/gvisor/pkg/tcpip/link/loopback" 29 "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" 30 "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" 31 "gvisor.dev/gvisor/pkg/tcpip/stack" 32 "gvisor.dev/gvisor/pkg/tcpip/tests/utils" 33 "gvisor.dev/gvisor/pkg/tcpip/testutil" 34 "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" 35 "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" 36 "gvisor.dev/gvisor/pkg/tcpip/transport/udp" 37 "gvisor.dev/gvisor/pkg/waiter" 38 ) 39 40 var _ ipv6.NDPDispatcher = (*ndpDispatcher)(nil) 41 42 type ndpDispatcher struct{} 43 44 func (*ndpDispatcher) OnDuplicateAddressDetectionResult(tcpip.NICID, tcpip.Address, stack.DADResult) { 45 } 46 47 func (*ndpDispatcher) OnOffLinkRouteUpdated(tcpip.NICID, tcpip.Subnet, tcpip.Address, header.NDPRoutePreference) { 48 } 49 50 func (*ndpDispatcher) OnOffLinkRouteInvalidated(tcpip.NICID, tcpip.Subnet, tcpip.Address) {} 51 52 func (*ndpDispatcher) OnOnLinkPrefixDiscovered(tcpip.NICID, tcpip.Subnet) { 53 } 54 55 func (*ndpDispatcher) OnOnLinkPrefixInvalidated(tcpip.NICID, tcpip.Subnet) {} 56 57 func (*ndpDispatcher) OnAutoGenAddress(tcpip.NICID, tcpip.AddressWithPrefix) stack.AddressDispatcher { 58 return nil 59 } 60 61 func (*ndpDispatcher) OnAutoGenAddressDeprecated(tcpip.NICID, tcpip.AddressWithPrefix) {} 62 63 func (*ndpDispatcher) OnAutoGenAddressInvalidated(tcpip.NICID, tcpip.AddressWithPrefix) {} 64 65 func (*ndpDispatcher) OnRecursiveDNSServerOption(tcpip.NICID, []tcpip.Address, time.Duration) {} 66 67 func (*ndpDispatcher) OnDNSSearchListOption(tcpip.NICID, []string, time.Duration) {} 68 69 func (*ndpDispatcher) OnDHCPv6Configuration(tcpip.NICID, ipv6.DHCPv6ConfigurationFromNDPRA) {} 70 71 // TestInitialLoopbackAddresses tests that the loopback interface does not 72 // auto-generate a link-local address when it is brought up. 73 func TestInitialLoopbackAddresses(t *testing.T) { 74 const nicID = 1 75 76 s := stack.New(stack.Options{ 77 NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocolWithOptions(ipv6.Options{ 78 NDPDisp: &ndpDispatcher{}, 79 AutoGenLinkLocal: true, 80 OpaqueIIDOpts: ipv6.OpaqueInterfaceIdentifierOptions{ 81 NICNameFromID: func(nicID tcpip.NICID, nicName string) string { 82 t.Fatalf("should not attempt to get name for NIC with ID = %d; nicName = %s", nicID, nicName) 83 return "" 84 }, 85 }, 86 })}, 87 }) 88 defer s.Destroy() 89 90 if err := s.CreateNIC(nicID, loopback.New()); err != nil { 91 t.Fatalf("CreateNIC(%d, _): %s", nicID, err) 92 } 93 94 nicsInfo := s.NICInfo() 95 if nicInfo, ok := nicsInfo[nicID]; !ok { 96 t.Fatalf("did not find NIC with ID = %d in s.NICInfo() = %#v", nicID, nicsInfo) 97 } else if got := len(nicInfo.ProtocolAddresses); got != 0 { 98 t.Fatalf("got len(nicInfo.ProtocolAddresses) = %d, want = 0; nicInfo.ProtocolAddresses = %#v", got, nicInfo.ProtocolAddresses) 99 } 100 } 101 102 // TestLoopbackAcceptAllInSubnetUDP tests that a loopback interface considers 103 // itself bound to all addresses in the subnet of an assigned address and UDP 104 // traffic is sent/received correctly. 105 func TestLoopbackAcceptAllInSubnetUDP(t *testing.T) { 106 const ( 107 nicID = 1 108 localPort = 80 109 ) 110 111 data := []byte{1, 2, 3, 4} 112 113 ipv4ProtocolAddress := tcpip.ProtocolAddress{ 114 Protocol: header.IPv4ProtocolNumber, 115 AddressWithPrefix: utils.Ipv4Addr, 116 } 117 addrCopy := ipv4ProtocolAddress.AddressWithPrefix.Address 118 ipv4Bytes := addrCopy.AsSlice() 119 ipv4Bytes[len(ipv4Bytes)-1]++ 120 otherIPv4Address := tcpip.AddrFromSlice(ipv4Bytes) 121 122 ipv6ProtocolAddress := tcpip.ProtocolAddress{ 123 Protocol: header.IPv6ProtocolNumber, 124 AddressWithPrefix: utils.Ipv6Addr, 125 } 126 addrCopy = utils.Ipv6Addr.Address 127 ipv6Bytes := addrCopy.AsSlice() 128 ipv6Bytes[len(ipv6Bytes)-1]++ 129 otherIPv6Address := tcpip.AddrFromSlice(ipv6Bytes) 130 131 tests := []struct { 132 name string 133 addAddress tcpip.ProtocolAddress 134 bindAddr tcpip.Address 135 dstAddr tcpip.Address 136 expectRx bool 137 }{ 138 { 139 name: "IPv4 bind to wildcard and send to assigned address", 140 addAddress: ipv4ProtocolAddress, 141 dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address, 142 expectRx: true, 143 }, 144 { 145 name: "IPv4 bind to wildcard and send to other subnet-local address", 146 addAddress: ipv4ProtocolAddress, 147 dstAddr: otherIPv4Address, 148 expectRx: true, 149 }, 150 { 151 name: "IPv4 bind to wildcard send to other address", 152 addAddress: ipv4ProtocolAddress, 153 dstAddr: utils.RemoteIPv4Addr, 154 expectRx: false, 155 }, 156 { 157 name: "IPv4 bind to other subnet-local address and send to assigned address", 158 addAddress: ipv4ProtocolAddress, 159 bindAddr: otherIPv4Address, 160 dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address, 161 expectRx: false, 162 }, 163 { 164 name: "IPv4 bind and send to other subnet-local address", 165 addAddress: ipv4ProtocolAddress, 166 bindAddr: otherIPv4Address, 167 dstAddr: otherIPv4Address, 168 expectRx: true, 169 }, 170 { 171 name: "IPv4 bind to assigned address and send to other subnet-local address", 172 addAddress: ipv4ProtocolAddress, 173 bindAddr: ipv4ProtocolAddress.AddressWithPrefix.Address, 174 dstAddr: otherIPv4Address, 175 expectRx: false, 176 }, 177 178 { 179 name: "IPv6 bind and send to assigned address", 180 addAddress: ipv6ProtocolAddress, 181 bindAddr: utils.Ipv6Addr.Address, 182 dstAddr: utils.Ipv6Addr.Address, 183 expectRx: true, 184 }, 185 { 186 name: "IPv6 bind to wildcard and send to other subnet-local address", 187 addAddress: ipv6ProtocolAddress, 188 dstAddr: otherIPv6Address, 189 expectRx: false, 190 }, 191 } 192 193 for _, test := range tests { 194 t.Run(test.name, func(t *testing.T) { 195 s := stack.New(stack.Options{ 196 NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol}, 197 TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol}, 198 }) 199 defer s.Destroy() 200 if err := s.CreateNIC(nicID, loopback.New()); err != nil { 201 t.Fatalf("CreateNIC(%d, _): %s", nicID, err) 202 } 203 if err := s.AddProtocolAddress(nicID, test.addAddress, stack.AddressProperties{}); err != nil { 204 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, test.addAddress, err) 205 } 206 s.SetRouteTable([]tcpip.Route{ 207 { 208 Destination: header.IPv4EmptySubnet, 209 NIC: nicID, 210 }, 211 { 212 Destination: header.IPv6EmptySubnet, 213 NIC: nicID, 214 }, 215 }) 216 217 var wq waiter.Queue 218 rep, err := s.NewEndpoint(udp.ProtocolNumber, test.addAddress.Protocol, &wq) 219 if err != nil { 220 t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err) 221 } 222 defer rep.Close() 223 224 bindAddr := tcpip.FullAddress{Addr: test.bindAddr, Port: localPort} 225 if err := rep.Bind(bindAddr); err != nil { 226 t.Fatalf("rep.Bind(%+v): %s", bindAddr, err) 227 } 228 229 sep, err := s.NewEndpoint(udp.ProtocolNumber, test.addAddress.Protocol, &wq) 230 if err != nil { 231 t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err) 232 } 233 defer sep.Close() 234 235 wopts := tcpip.WriteOptions{ 236 To: &tcpip.FullAddress{ 237 Addr: test.dstAddr, 238 Port: localPort, 239 }, 240 } 241 var r bytes.Reader 242 r.Reset(data) 243 n, err := sep.Write(&r, wopts) 244 if err != nil { 245 t.Fatalf("sep.Write(_, _): %s", err) 246 } 247 if want := int64(len(data)); n != want { 248 t.Fatalf("got sep.Write(_, _) = (%d, nil), want = (%d, nil)", n, want) 249 } 250 251 var buf bytes.Buffer 252 opts := tcpip.ReadOptions{NeedRemoteAddr: true} 253 if res, err := rep.Read(&buf, opts); test.expectRx { 254 if err != nil { 255 t.Fatalf("rep.Read(_, %#v): %s", opts, err) 256 } 257 if diff := cmp.Diff(tcpip.ReadResult{ 258 Count: buf.Len(), 259 Total: buf.Len(), 260 RemoteAddr: tcpip.FullAddress{ 261 Addr: test.addAddress.AddressWithPrefix.Address, 262 }, 263 }, res, 264 checker.IgnoreCmpPath("ControlMessages", "RemoteAddr.NIC", "RemoteAddr.Port"), 265 ); diff != "" { 266 t.Errorf("rep.Read: unexpected result (-want +got):\n%s", diff) 267 } 268 if diff := cmp.Diff(data, buf.Bytes()); diff != "" { 269 t.Errorf("got UDP payload mismatch (-want +got):\n%s", diff) 270 } 271 } else if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 272 t.Fatalf("got rep.Read = (%v, %s) [with data %x], want = (_, %s)", res, err, buf.Bytes(), &tcpip.ErrWouldBlock{}) 273 } 274 }) 275 } 276 } 277 278 // TestLoopbackSubnetLifetimeBoundToAddr tests that the lifetime of an address 279 // in a loopback interface's associated subnet is bound to the permanently bound 280 // address. 281 func TestLoopbackSubnetLifetimeBoundToAddr(t *testing.T) { 282 const nicID = 1 283 284 protoAddr := tcpip.ProtocolAddress{ 285 Protocol: ipv4.ProtocolNumber, 286 AddressWithPrefix: utils.Ipv4Addr, 287 } 288 addrCopy := utils.Ipv4Addr.Address 289 addrBytes := addrCopy.AsSlice() 290 addrBytes[len(addrBytes)-1]++ 291 otherAddr := tcpip.AddrFromSlice(addrBytes) 292 293 s := stack.New(stack.Options{ 294 NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol}, 295 }) 296 defer s.Destroy() 297 if err := s.CreateNIC(nicID, loopback.New()); err != nil { 298 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 299 } 300 if err := s.AddProtocolAddress(nicID, protoAddr, stack.AddressProperties{}); err != nil { 301 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, protoAddr, err) 302 } 303 s.SetRouteTable([]tcpip.Route{ 304 { 305 Destination: header.IPv4EmptySubnet, 306 NIC: nicID, 307 }, 308 }) 309 310 r, err := s.FindRoute(nicID, otherAddr, utils.RemoteIPv4Addr, ipv4.ProtocolNumber, false /* multicastLoop */) 311 if err != nil { 312 t.Fatalf("s.FindRoute(%d, %s, %s, %d, false): %s", nicID, otherAddr, utils.RemoteIPv4Addr, ipv4.ProtocolNumber, err) 313 } 314 defer r.Release() 315 316 params := stack.NetworkHeaderParams{ 317 Protocol: 111, 318 TTL: 64, 319 TOS: stack.DefaultTOS, 320 } 321 data := []byte{1, 2, 3, 4} 322 if err := r.WritePacket(params, stack.NewPacketBuffer(stack.PacketBufferOptions{ 323 ReserveHeaderBytes: int(r.MaxHeaderLength()), 324 Payload: buffer.MakeWithData(data), 325 })); err != nil { 326 t.Fatalf("r.WritePacket(%#v, _): %s", params, err) 327 } 328 329 // Removing the address should make the endpoint invalid. 330 if err := s.RemoveAddress(nicID, protoAddr.AddressWithPrefix.Address); err != nil { 331 t.Fatalf("s.RemoveAddress(%d, %s): %s", nicID, protoAddr.AddressWithPrefix.Address, err) 332 } 333 { 334 err := r.WritePacket(params, stack.NewPacketBuffer(stack.PacketBufferOptions{ 335 ReserveHeaderBytes: int(r.MaxHeaderLength()), 336 Payload: buffer.MakeWithData(data), 337 })) 338 if _, ok := err.(*tcpip.ErrInvalidEndpointState); !ok { 339 t.Fatalf("got r.WritePacket(%#v, _) = %s, want = %s", params, err, &tcpip.ErrInvalidEndpointState{}) 340 } 341 } 342 } 343 344 // TestLoopbackAcceptAllInSubnetTCP tests that a loopback interface considers 345 // itself bound to all addresses in the subnet of an assigned address and TCP 346 // traffic is sent/received correctly. 347 func TestLoopbackAcceptAllInSubnetTCP(t *testing.T) { 348 const ( 349 nicID = 1 350 localPort = 80 351 ) 352 353 ipv4ProtocolAddress := tcpip.ProtocolAddress{ 354 Protocol: header.IPv4ProtocolNumber, 355 AddressWithPrefix: utils.Ipv4Addr, 356 } 357 ipv4ProtocolAddress.AddressWithPrefix.PrefixLen = 8 358 addrCopy := ipv4ProtocolAddress.AddressWithPrefix.Address 359 ipv4Bytes := addrCopy.AsSlice() 360 ipv4Bytes[len(ipv4Bytes)-1]++ 361 otherIPv4Address := tcpip.AddrFromSlice(ipv4Bytes) 362 363 ipv6ProtocolAddress := tcpip.ProtocolAddress{ 364 Protocol: header.IPv6ProtocolNumber, 365 AddressWithPrefix: utils.Ipv6Addr, 366 } 367 addrCopy = utils.Ipv6Addr.Address 368 ipv6Bytes := addrCopy.AsSlice() 369 ipv6Bytes[len(ipv6Bytes)-1]++ 370 otherIPv6Address := tcpip.AddrFromSlice(ipv6Bytes) 371 372 tests := []struct { 373 name string 374 addAddress tcpip.ProtocolAddress 375 bindAddr tcpip.Address 376 dstAddr tcpip.Address 377 expectAccept bool 378 }{ 379 { 380 name: "IPv4 bind to wildcard and send to assigned address", 381 addAddress: ipv4ProtocolAddress, 382 dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address, 383 expectAccept: true, 384 }, 385 { 386 name: "IPv4 bind to wildcard and send to other subnet-local address", 387 addAddress: ipv4ProtocolAddress, 388 dstAddr: otherIPv4Address, 389 expectAccept: true, 390 }, 391 { 392 name: "IPv4 bind to wildcard send to other address", 393 addAddress: ipv4ProtocolAddress, 394 dstAddr: utils.RemoteIPv4Addr, 395 expectAccept: false, 396 }, 397 { 398 name: "IPv4 bind to other subnet-local address and send to assigned address", 399 addAddress: ipv4ProtocolAddress, 400 bindAddr: otherIPv4Address, 401 dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address, 402 expectAccept: false, 403 }, 404 { 405 name: "IPv4 bind and send to other subnet-local address", 406 addAddress: ipv4ProtocolAddress, 407 bindAddr: otherIPv4Address, 408 dstAddr: otherIPv4Address, 409 expectAccept: true, 410 }, 411 { 412 name: "IPv4 bind to assigned address and send to other subnet-local address", 413 addAddress: ipv4ProtocolAddress, 414 bindAddr: ipv4ProtocolAddress.AddressWithPrefix.Address, 415 dstAddr: otherIPv4Address, 416 expectAccept: false, 417 }, 418 419 { 420 name: "IPv6 bind and send to assigned address", 421 addAddress: ipv6ProtocolAddress, 422 bindAddr: utils.Ipv6Addr.Address, 423 dstAddr: utils.Ipv6Addr.Address, 424 expectAccept: true, 425 }, 426 { 427 name: "IPv6 bind to wildcard and send to other subnet-local address", 428 addAddress: ipv6ProtocolAddress, 429 dstAddr: otherIPv6Address, 430 expectAccept: false, 431 }, 432 } 433 434 for _, test := range tests { 435 t.Run(test.name, func(t *testing.T) { 436 s := stack.New(stack.Options{ 437 NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol}, 438 TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol}, 439 }) 440 defer s.Destroy() 441 if err := s.CreateNIC(nicID, loopback.New()); err != nil { 442 t.Fatalf("CreateNIC(%d, _): %s", nicID, err) 443 } 444 if err := s.AddProtocolAddress(nicID, test.addAddress, stack.AddressProperties{}); err != nil { 445 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, test.addAddress, err) 446 } 447 s.SetRouteTable([]tcpip.Route{ 448 { 449 Destination: header.IPv4EmptySubnet, 450 NIC: nicID, 451 }, 452 { 453 Destination: header.IPv6EmptySubnet, 454 NIC: nicID, 455 }, 456 }) 457 458 var wq waiter.Queue 459 we, ch := waiter.NewChannelEntry(waiter.ReadableEvents) 460 wq.EventRegister(&we) 461 defer wq.EventUnregister(&we) 462 listeningEndpoint, err := s.NewEndpoint(tcp.ProtocolNumber, test.addAddress.Protocol, &wq) 463 if err != nil { 464 t.Fatalf("NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, test.addAddress.Protocol, err) 465 } 466 defer listeningEndpoint.Close() 467 468 bindAddr := tcpip.FullAddress{Addr: test.bindAddr, Port: localPort} 469 if err := listeningEndpoint.Bind(bindAddr); err != nil { 470 t.Fatalf("listeningEndpoint.Bind(%#v): %s", bindAddr, err) 471 } 472 473 if err := listeningEndpoint.Listen(1); err != nil { 474 t.Fatalf("listeningEndpoint.Listen(1): %s", err) 475 } 476 477 connectingEndpoint, err := s.NewEndpoint(tcp.ProtocolNumber, test.addAddress.Protocol, &wq) 478 if err != nil { 479 t.Fatalf("s.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, test.addAddress.Protocol, err) 480 } 481 defer connectingEndpoint.Close() 482 483 connectAddr := tcpip.FullAddress{ 484 Addr: test.dstAddr, 485 Port: localPort, 486 } 487 { 488 err := connectingEndpoint.Connect(connectAddr) 489 if _, ok := err.(*tcpip.ErrConnectStarted); !ok { 490 t.Fatalf("connectingEndpoint.Connect(%#v): %s", connectAddr, err) 491 } 492 } 493 494 if !test.expectAccept { 495 _, _, err := listeningEndpoint.Accept(nil) 496 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 497 t.Fatalf("got listeningEndpoint.Accept(nil) = %s, want = %s", err, &tcpip.ErrWouldBlock{}) 498 } 499 return 500 } 501 502 // Wait for the listening endpoint to be "readable". That is, wait for a 503 // new connection. 504 <-ch 505 var addr tcpip.FullAddress 506 if _, _, err := listeningEndpoint.Accept(&addr); err != nil { 507 t.Fatalf("listeningEndpoint.Accept(nil): %s", err) 508 } 509 if addr.Addr != test.addAddress.AddressWithPrefix.Address { 510 t.Errorf("got addr.Addr = %s, want = %s", addr.Addr, test.addAddress.AddressWithPrefix.Address) 511 } 512 }) 513 } 514 } 515 516 func TestExternalLoopbackTraffic(t *testing.T) { 517 const ( 518 nicID1 = 1 519 nicID2 = 2 520 521 numPackets = 1 522 ttl = 64 523 ) 524 ipv4Loopback := testutil.MustParse4("127.0.0.1") 525 526 loopbackSourcedICMPv4 := func(e *channel.Endpoint) { 527 utils.RxICMPv4EchoRequest(e, ipv4Loopback, utils.Ipv4Addr.Address, ttl) 528 } 529 530 loopbackSourcedICMPv6 := func(e *channel.Endpoint) { 531 utils.RxICMPv6EchoRequest(e, header.IPv6Loopback, utils.Ipv6Addr.Address, ttl) 532 } 533 534 loopbackDestinedICMPv4 := func(e *channel.Endpoint) { 535 utils.RxICMPv4EchoRequest(e, utils.RemoteIPv4Addr, ipv4Loopback, ttl) 536 } 537 538 loopbackDestinedICMPv6 := func(e *channel.Endpoint) { 539 utils.RxICMPv6EchoRequest(e, utils.RemoteIPv6Addr, header.IPv6Loopback, ttl) 540 } 541 542 invalidSrcAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter { 543 return s.InvalidSourceAddressesReceived 544 } 545 546 invalidDestAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter { 547 return s.InvalidDestinationAddressesReceived 548 } 549 550 tests := []struct { 551 name string 552 allowExternalLoopback bool 553 forwarding bool 554 rxICMP func(*channel.Endpoint) 555 invalidAddressStat func(tcpip.IPStats) *tcpip.StatCounter 556 shouldAccept bool 557 }{ 558 { 559 name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback disabled", 560 allowExternalLoopback: true, 561 forwarding: false, 562 rxICMP: loopbackSourcedICMPv4, 563 invalidAddressStat: invalidSrcAddrStat, 564 shouldAccept: true, 565 }, 566 { 567 name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback enabled", 568 allowExternalLoopback: false, 569 forwarding: false, 570 rxICMP: loopbackSourcedICMPv4, 571 invalidAddressStat: invalidSrcAddrStat, 572 shouldAccept: false, 573 }, 574 { 575 name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback disabled", 576 allowExternalLoopback: true, 577 forwarding: true, 578 rxICMP: loopbackSourcedICMPv4, 579 invalidAddressStat: invalidSrcAddrStat, 580 shouldAccept: true, 581 }, 582 { 583 name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback enabled", 584 allowExternalLoopback: false, 585 forwarding: true, 586 rxICMP: loopbackSourcedICMPv4, 587 invalidAddressStat: invalidSrcAddrStat, 588 shouldAccept: false, 589 }, 590 { 591 name: "IPv4 external loopback destined traffic without forwarding and drop external loopback disabled", 592 allowExternalLoopback: true, 593 forwarding: false, 594 rxICMP: loopbackDestinedICMPv4, 595 invalidAddressStat: invalidDestAddrStat, 596 shouldAccept: false, 597 }, 598 { 599 name: "IPv4 external loopback destined traffic without forwarding and drop external loopback enabled", 600 allowExternalLoopback: false, 601 forwarding: false, 602 rxICMP: loopbackDestinedICMPv4, 603 invalidAddressStat: invalidDestAddrStat, 604 shouldAccept: false, 605 }, 606 { 607 name: "IPv4 external loopback destined traffic with forwarding and drop external loopback disabled", 608 allowExternalLoopback: true, 609 forwarding: true, 610 rxICMP: loopbackDestinedICMPv4, 611 invalidAddressStat: invalidDestAddrStat, 612 shouldAccept: true, 613 }, 614 { 615 name: "IPv4 external loopback destined traffic with forwarding and drop external loopback enabled", 616 allowExternalLoopback: false, 617 forwarding: true, 618 rxICMP: loopbackDestinedICMPv4, 619 invalidAddressStat: invalidDestAddrStat, 620 shouldAccept: false, 621 }, 622 623 { 624 name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback disabled", 625 allowExternalLoopback: true, 626 forwarding: false, 627 rxICMP: loopbackSourcedICMPv6, 628 invalidAddressStat: invalidSrcAddrStat, 629 shouldAccept: true, 630 }, 631 { 632 name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback enabled", 633 allowExternalLoopback: false, 634 forwarding: false, 635 rxICMP: loopbackSourcedICMPv6, 636 invalidAddressStat: invalidSrcAddrStat, 637 shouldAccept: false, 638 }, 639 { 640 name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback disabled", 641 allowExternalLoopback: true, 642 forwarding: true, 643 rxICMP: loopbackSourcedICMPv6, 644 invalidAddressStat: invalidSrcAddrStat, 645 shouldAccept: true, 646 }, 647 { 648 name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback enabled", 649 allowExternalLoopback: false, 650 forwarding: true, 651 rxICMP: loopbackSourcedICMPv6, 652 invalidAddressStat: invalidSrcAddrStat, 653 shouldAccept: false, 654 }, 655 { 656 name: "IPv6 external loopback destined traffic without forwarding and drop external loopback disabled", 657 allowExternalLoopback: true, 658 forwarding: false, 659 rxICMP: loopbackDestinedICMPv6, 660 invalidAddressStat: invalidDestAddrStat, 661 shouldAccept: false, 662 }, 663 { 664 name: "IPv6 external loopback destined traffic without forwarding and drop external loopback enabled", 665 allowExternalLoopback: false, 666 forwarding: false, 667 rxICMP: loopbackDestinedICMPv6, 668 invalidAddressStat: invalidDestAddrStat, 669 shouldAccept: false, 670 }, 671 { 672 name: "IPv6 external loopback destined traffic with forwarding and drop external loopback disabled", 673 allowExternalLoopback: true, 674 forwarding: true, 675 rxICMP: loopbackDestinedICMPv6, 676 invalidAddressStat: invalidDestAddrStat, 677 shouldAccept: true, 678 }, 679 { 680 name: "IPv6 external loopback destined traffic with forwarding and drop external loopback enabled", 681 allowExternalLoopback: false, 682 forwarding: true, 683 rxICMP: loopbackDestinedICMPv6, 684 invalidAddressStat: invalidDestAddrStat, 685 shouldAccept: false, 686 }, 687 } 688 689 for _, test := range tests { 690 t.Run(test.name, func(t *testing.T) { 691 s := stack.New(stack.Options{ 692 NetworkProtocols: []stack.NetworkProtocolFactory{ 693 ipv4.NewProtocolWithOptions(ipv4.Options{ 694 AllowExternalLoopbackTraffic: test.allowExternalLoopback, 695 }), 696 ipv6.NewProtocolWithOptions(ipv6.Options{ 697 AllowExternalLoopbackTraffic: test.allowExternalLoopback, 698 }), 699 }, 700 TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4, icmp.NewProtocol6}, 701 }) 702 defer s.Destroy() 703 e := channel.New(1, header.IPv6MinimumMTU, "") 704 if err := s.CreateNIC(nicID1, e); err != nil { 705 t.Fatalf("CreateNIC(%d, _): %s", nicID1, err) 706 } 707 v4Addr := tcpip.ProtocolAddress{ 708 Protocol: ipv4.ProtocolNumber, 709 AddressWithPrefix: utils.Ipv4Addr, 710 } 711 if err := s.AddProtocolAddress(nicID1, v4Addr, stack.AddressProperties{}); err != nil { 712 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID1, v4Addr, err) 713 } 714 v6Addr := tcpip.ProtocolAddress{ 715 Protocol: ipv6.ProtocolNumber, 716 AddressWithPrefix: utils.Ipv6Addr, 717 } 718 if err := s.AddProtocolAddress(nicID1, v6Addr, stack.AddressProperties{}); err != nil { 719 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID1, v6Addr, err) 720 } 721 722 if err := s.CreateNIC(nicID2, loopback.New()); err != nil { 723 t.Fatalf("CreateNIC(%d, _): %s", nicID2, err) 724 } 725 protocolAddrV4 := tcpip.ProtocolAddress{ 726 Protocol: ipv4.ProtocolNumber, 727 AddressWithPrefix: tcpip.AddressWithPrefix{ 728 Address: ipv4Loopback, 729 PrefixLen: 8, 730 }, 731 } 732 if err := s.AddProtocolAddress(nicID2, protocolAddrV4, stack.AddressProperties{}); err != nil { 733 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID2, protocolAddrV4, err) 734 } 735 protocolAddrV6 := tcpip.ProtocolAddress{ 736 Protocol: ipv6.ProtocolNumber, 737 AddressWithPrefix: header.IPv6Loopback.WithPrefix(), 738 } 739 if err := s.AddProtocolAddress(nicID2, protocolAddrV6, stack.AddressProperties{}); err != nil { 740 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID2, protocolAddrV6, err) 741 } 742 743 if test.forwarding { 744 if err := s.SetForwardingDefaultAndAllNICs(ipv4.ProtocolNumber, true); err != nil { 745 t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ipv4.ProtocolNumber, err) 746 } 747 if err := s.SetForwardingDefaultAndAllNICs(ipv6.ProtocolNumber, true); err != nil { 748 t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ipv6.ProtocolNumber, err) 749 } 750 } 751 752 s.SetRouteTable([]tcpip.Route{ 753 { 754 Destination: header.IPv4EmptySubnet, 755 NIC: nicID1, 756 }, 757 { 758 Destination: header.IPv6EmptySubnet, 759 NIC: nicID1, 760 }, 761 { 762 Destination: ipv4Loopback.WithPrefix().Subnet(), 763 NIC: nicID2, 764 }, 765 { 766 Destination: header.IPv6Loopback.WithPrefix().Subnet(), 767 NIC: nicID2, 768 }, 769 }) 770 771 stats := s.Stats().IP 772 invalidAddressStat := test.invalidAddressStat(stats) 773 deliveredPacketsStat := stats.PacketsDelivered 774 if got := invalidAddressStat.Value(); got != 0 { 775 t.Fatalf("got invalidAddressStat.Value() = %d, want = 0", got) 776 } 777 if got := deliveredPacketsStat.Value(); got != 0 { 778 t.Fatalf("got deliveredPacketsStat.Value() = %d, want = 0", got) 779 } 780 test.rxICMP(e) 781 var expectedInvalidPackets uint64 782 if !test.shouldAccept { 783 expectedInvalidPackets = numPackets 784 } 785 if got := invalidAddressStat.Value(); got != expectedInvalidPackets { 786 t.Fatalf("got invalidAddressStat.Value() = %d, want = %d", got, expectedInvalidPackets) 787 } 788 if got, want := deliveredPacketsStat.Value(), numPackets-expectedInvalidPackets; got != want { 789 t.Fatalf("got deliveredPacketsStat.Value() = %d, want = %d", got, want) 790 } 791 }) 792 } 793 }