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