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  }