github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/network/arp/arp_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package arp_test
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"github.com/google/go-cmp/cmp"
    22  	"github.com/google/go-cmp/cmp/cmpopts"
    23  	"github.com/SagerNet/gvisor/pkg/tcpip"
    24  	"github.com/SagerNet/gvisor/pkg/tcpip/buffer"
    25  	"github.com/SagerNet/gvisor/pkg/tcpip/faketime"
    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/sniffer"
    29  	"github.com/SagerNet/gvisor/pkg/tcpip/network/arp"
    30  	"github.com/SagerNet/gvisor/pkg/tcpip/network/ipv4"
    31  	"github.com/SagerNet/gvisor/pkg/tcpip/stack"
    32  	"github.com/SagerNet/gvisor/pkg/tcpip/testutil"
    33  )
    34  
    35  const (
    36  	nicID = 1
    37  
    38  	stackLinkAddr  = tcpip.LinkAddress("\x0a\x0a\x0b\x0b\x0c\x0c")
    39  	remoteLinkAddr = tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06")
    40  )
    41  
    42  var (
    43  	stackAddr   = testutil.MustParse4("10.0.0.1")
    44  	remoteAddr  = testutil.MustParse4("10.0.0.2")
    45  	unknownAddr = testutil.MustParse4("10.0.0.3")
    46  )
    47  
    48  type eventType uint8
    49  
    50  const (
    51  	entryAdded eventType = iota
    52  	entryChanged
    53  	entryRemoved
    54  )
    55  
    56  func (t eventType) String() string {
    57  	switch t {
    58  	case entryAdded:
    59  		return "add"
    60  	case entryChanged:
    61  		return "change"
    62  	case entryRemoved:
    63  		return "remove"
    64  	default:
    65  		return fmt.Sprintf("unknown (%d)", t)
    66  	}
    67  }
    68  
    69  type eventInfo struct {
    70  	eventType eventType
    71  	nicID     tcpip.NICID
    72  	entry     stack.NeighborEntry
    73  }
    74  
    75  func (e eventInfo) String() string {
    76  	return fmt.Sprintf("%s event for NIC #%d, %#v", e.eventType, e.nicID, e.entry)
    77  }
    78  
    79  // arpDispatcher implements NUDDispatcher to validate the dispatching of
    80  // events upon certain NUD state machine events.
    81  type arpDispatcher struct {
    82  	// C is where events are queued
    83  	C chan eventInfo
    84  }
    85  
    86  var _ stack.NUDDispatcher = (*arpDispatcher)(nil)
    87  
    88  func (d *arpDispatcher) OnNeighborAdded(nicID tcpip.NICID, entry stack.NeighborEntry) {
    89  	e := eventInfo{
    90  		eventType: entryAdded,
    91  		nicID:     nicID,
    92  		entry:     entry,
    93  	}
    94  	d.C <- e
    95  }
    96  
    97  func (d *arpDispatcher) OnNeighborChanged(nicID tcpip.NICID, entry stack.NeighborEntry) {
    98  	e := eventInfo{
    99  		eventType: entryChanged,
   100  		nicID:     nicID,
   101  		entry:     entry,
   102  	}
   103  	d.C <- e
   104  }
   105  
   106  func (d *arpDispatcher) OnNeighborRemoved(nicID tcpip.NICID, entry stack.NeighborEntry) {
   107  	e := eventInfo{
   108  		eventType: entryRemoved,
   109  		nicID:     nicID,
   110  		entry:     entry,
   111  	}
   112  	d.C <- e
   113  }
   114  
   115  func (d *arpDispatcher) nextEvent() (eventInfo, bool) {
   116  	select {
   117  	case event := <-d.C:
   118  		return event, true
   119  	default:
   120  		return eventInfo{}, false
   121  	}
   122  }
   123  
   124  type testContext struct {
   125  	s       *stack.Stack
   126  	linkEP  *channel.Endpoint
   127  	nudDisp arpDispatcher
   128  }
   129  
   130  func makeTestContext(t *testing.T, eventDepth int, packetDepth int) testContext {
   131  	t.Helper()
   132  
   133  	tc := testContext{
   134  		nudDisp: arpDispatcher{
   135  			C: make(chan eventInfo, eventDepth),
   136  		},
   137  	}
   138  
   139  	tc.s = stack.New(stack.Options{
   140  		NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, arp.NewProtocol},
   141  		NUDDisp:          &tc.nudDisp,
   142  		Clock:            &faketime.NullClock{},
   143  	})
   144  
   145  	tc.linkEP = channel.New(packetDepth, header.IPv4MinimumMTU, stackLinkAddr)
   146  	tc.linkEP.LinkEPCapabilities |= stack.CapabilityResolutionRequired
   147  
   148  	wep := stack.LinkEndpoint(tc.linkEP)
   149  	if testing.Verbose() {
   150  		wep = sniffer.New(wep)
   151  	}
   152  	if err := tc.s.CreateNIC(nicID, wep); err != nil {
   153  		t.Fatalf("CreateNIC failed: %s", err)
   154  	}
   155  
   156  	if err := tc.s.AddAddress(nicID, ipv4.ProtocolNumber, stackAddr); err != nil {
   157  		t.Fatalf("AddAddress for ipv4 failed: %s", err)
   158  	}
   159  
   160  	tc.s.SetRouteTable([]tcpip.Route{{
   161  		Destination: header.IPv4EmptySubnet,
   162  		NIC:         nicID,
   163  	}})
   164  
   165  	return tc
   166  }
   167  
   168  func (c *testContext) cleanup() {
   169  	c.linkEP.Close()
   170  }
   171  
   172  func TestMalformedPacket(t *testing.T) {
   173  	c := makeTestContext(t, 0, 0)
   174  	defer c.cleanup()
   175  
   176  	v := make(buffer.View, header.ARPSize)
   177  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   178  		Data: v.ToVectorisedView(),
   179  	})
   180  
   181  	c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   182  
   183  	if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
   184  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   185  	}
   186  	if got := c.s.Stats().ARP.MalformedPacketsReceived.Value(); got != 1 {
   187  		t.Errorf("got c.s.Stats().ARP.MalformedPacketsReceived.Value() = %d, want = 1", got)
   188  	}
   189  }
   190  
   191  func TestDisabledEndpoint(t *testing.T) {
   192  	c := makeTestContext(t, 0, 0)
   193  	defer c.cleanup()
   194  
   195  	ep, err := c.s.GetNetworkEndpoint(nicID, header.ARPProtocolNumber)
   196  	if err != nil {
   197  		t.Fatalf("GetNetworkEndpoint(%d, header.ARPProtocolNumber) failed: %s", nicID, err)
   198  	}
   199  	ep.Disable()
   200  
   201  	v := make(buffer.View, header.ARPSize)
   202  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   203  		Data: v.ToVectorisedView(),
   204  	})
   205  
   206  	c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   207  
   208  	if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
   209  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   210  	}
   211  	if got := c.s.Stats().ARP.DisabledPacketsReceived.Value(); got != 1 {
   212  		t.Errorf("got c.s.Stats().ARP.DisabledPacketsReceived.Value() = %d, want = 1", got)
   213  	}
   214  }
   215  
   216  func TestDirectReply(t *testing.T) {
   217  	c := makeTestContext(t, 0, 0)
   218  	defer c.cleanup()
   219  
   220  	const senderMAC = "\x01\x02\x03\x04\x05\x06"
   221  	const senderIPv4 = "\x0a\x00\x00\x02"
   222  
   223  	v := make(buffer.View, header.ARPSize)
   224  	h := header.ARP(v)
   225  	h.SetIPv4OverEthernet()
   226  	h.SetOp(header.ARPReply)
   227  
   228  	copy(h.HardwareAddressSender(), senderMAC)
   229  	copy(h.ProtocolAddressSender(), senderIPv4)
   230  	copy(h.HardwareAddressTarget(), stackLinkAddr)
   231  	copy(h.ProtocolAddressTarget(), stackAddr)
   232  
   233  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   234  		Data: v.ToVectorisedView(),
   235  	})
   236  
   237  	c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   238  
   239  	if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
   240  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   241  	}
   242  	if got := c.s.Stats().ARP.RepliesReceived.Value(); got != 1 {
   243  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   244  	}
   245  }
   246  
   247  func TestDirectRequest(t *testing.T) {
   248  	c := makeTestContext(t, 1, 1)
   249  	defer c.cleanup()
   250  
   251  	tests := []struct {
   252  		name           string
   253  		senderAddr     tcpip.Address
   254  		senderLinkAddr tcpip.LinkAddress
   255  		targetAddr     tcpip.Address
   256  		isValid        bool
   257  	}{
   258  		{
   259  			name:           "Loopback",
   260  			senderAddr:     stackAddr,
   261  			senderLinkAddr: stackLinkAddr,
   262  			targetAddr:     stackAddr,
   263  			isValid:        true,
   264  		},
   265  		{
   266  			name:           "Remote",
   267  			senderAddr:     remoteAddr,
   268  			senderLinkAddr: remoteLinkAddr,
   269  			targetAddr:     stackAddr,
   270  			isValid:        true,
   271  		},
   272  		{
   273  			name:           "RemoteInvalidTarget",
   274  			senderAddr:     remoteAddr,
   275  			senderLinkAddr: remoteLinkAddr,
   276  			targetAddr:     unknownAddr,
   277  			isValid:        false,
   278  		},
   279  	}
   280  
   281  	for _, test := range tests {
   282  		t.Run(test.name, func(t *testing.T) {
   283  			packetsRecv := c.s.Stats().ARP.PacketsReceived.Value()
   284  			requestsRecv := c.s.Stats().ARP.RequestsReceived.Value()
   285  			requestsRecvUnknownAddr := c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value()
   286  			outgoingReplies := c.s.Stats().ARP.OutgoingRepliesSent.Value()
   287  
   288  			// Inject an incoming ARP request.
   289  			v := make(buffer.View, header.ARPSize)
   290  			h := header.ARP(v)
   291  			h.SetIPv4OverEthernet()
   292  			h.SetOp(header.ARPRequest)
   293  			copy(h.HardwareAddressSender(), test.senderLinkAddr)
   294  			copy(h.ProtocolAddressSender(), test.senderAddr)
   295  			copy(h.ProtocolAddressTarget(), test.targetAddr)
   296  			c.linkEP.InjectInbound(arp.ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
   297  				Data: v.ToVectorisedView(),
   298  			}))
   299  
   300  			if got, want := c.s.Stats().ARP.PacketsReceived.Value(), packetsRecv+1; got != want {
   301  				t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, want)
   302  			}
   303  			if got, want := c.s.Stats().ARP.RequestsReceived.Value(), requestsRecv+1; got != want {
   304  				t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, want)
   305  			}
   306  
   307  			if !test.isValid {
   308  				// No packets should be sent after receiving an invalid ARP request.
   309  				// There is no need to perform a blocking read here, since packets are
   310  				// sent in the same function that handles ARP requests.
   311  				if pkt, ok := c.linkEP.Read(); ok {
   312  					t.Errorf("unexpected packet sent with network protocol number %d", pkt.Proto)
   313  				}
   314  				if got, want := c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value(), requestsRecvUnknownAddr+1; got != want {
   315  					t.Errorf("got c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value() = %d, want = %d", got, want)
   316  				}
   317  				if got, want := c.s.Stats().ARP.OutgoingRepliesSent.Value(), outgoingReplies; got != want {
   318  					t.Errorf("got c.s.Stats().ARP.OutgoingRepliesSent.Value() = %d, want = %d", got, want)
   319  				}
   320  
   321  				return
   322  			}
   323  
   324  			if got, want := c.s.Stats().ARP.OutgoingRepliesSent.Value(), outgoingReplies+1; got != want {
   325  				t.Errorf("got c.s.Stats().ARP.OutgoingRepliesSent.Value() = %d, want = %d", got, want)
   326  			}
   327  
   328  			// Verify an ARP response was sent.
   329  			pi, ok := c.linkEP.Read()
   330  			if !ok {
   331  				t.Fatal("expected ARP response to be sent, got none")
   332  			}
   333  
   334  			if pi.Proto != arp.ProtocolNumber {
   335  				t.Fatalf("expected ARP response, got network protocol number %d", pi.Proto)
   336  			}
   337  			rep := header.ARP(pi.Pkt.NetworkHeader().View())
   338  			if !rep.IsValid() {
   339  				t.Fatalf("invalid ARP response: len = %d; response = %x", len(rep), rep)
   340  			}
   341  			if got, want := tcpip.LinkAddress(rep.HardwareAddressSender()), stackLinkAddr; got != want {
   342  				t.Errorf("got HardwareAddressSender() = %s, want = %s", got, want)
   343  			}
   344  			if got, want := tcpip.Address(rep.ProtocolAddressSender()), tcpip.Address(h.ProtocolAddressTarget()); got != want {
   345  				t.Errorf("got ProtocolAddressSender() = %s, want = %s", got, want)
   346  			}
   347  			if got, want := tcpip.LinkAddress(rep.HardwareAddressTarget()), tcpip.LinkAddress(h.HardwareAddressSender()); got != want {
   348  				t.Errorf("got HardwareAddressTarget() = %s, want = %s", got, want)
   349  			}
   350  			if got, want := tcpip.Address(rep.ProtocolAddressTarget()), tcpip.Address(h.ProtocolAddressSender()); got != want {
   351  				t.Errorf("got ProtocolAddressTarget() = %s, want = %s", got, want)
   352  			}
   353  
   354  			// Verify the sender was saved in the neighbor cache.
   355  			if got, ok := c.nudDisp.nextEvent(); ok {
   356  				want := eventInfo{
   357  					eventType: entryAdded,
   358  					nicID:     nicID,
   359  					entry: stack.NeighborEntry{
   360  						Addr:     test.senderAddr,
   361  						LinkAddr: test.senderLinkAddr,
   362  						State:    stack.Stale,
   363  					},
   364  				}
   365  				if diff := cmp.Diff(want, got, cmp.AllowUnexported(eventInfo{}), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAt")); diff != "" {
   366  					t.Errorf("got invalid event (-want +got):\n%s", diff)
   367  				}
   368  			} else {
   369  				t.Fatal("event didn't arrive")
   370  			}
   371  
   372  			neighbors, err := c.s.Neighbors(nicID, ipv4.ProtocolNumber)
   373  			if err != nil {
   374  				t.Fatalf("c.s.Neighbors(%d, %d): %s", nicID, ipv4.ProtocolNumber, err)
   375  			}
   376  
   377  			neighborByAddr := make(map[tcpip.Address]stack.NeighborEntry)
   378  			for _, n := range neighbors {
   379  				if existing, ok := neighborByAddr[n.Addr]; ok {
   380  					if diff := cmp.Diff(existing, n); diff != "" {
   381  						t.Fatalf("duplicate neighbor entry found (-existing +got):\n%s", diff)
   382  					}
   383  					t.Fatalf("exact neighbor entry duplicate found for addr=%s", n.Addr)
   384  				}
   385  				neighborByAddr[n.Addr] = n
   386  			}
   387  
   388  			neigh, ok := neighborByAddr[test.senderAddr]
   389  			if !ok {
   390  				t.Fatalf("expected neighbor entry with Addr = %s", test.senderAddr)
   391  			}
   392  			if got, want := neigh.LinkAddr, test.senderLinkAddr; got != want {
   393  				t.Errorf("got neighbor LinkAddr = %s, want = %s", got, want)
   394  			}
   395  			if got, want := neigh.State, stack.Stale; got != want {
   396  				t.Errorf("got neighbor State = %s, want = %s", got, want)
   397  			}
   398  
   399  			// No more events should be dispatched
   400  			for {
   401  				event, ok := c.nudDisp.nextEvent()
   402  				if !ok {
   403  					break
   404  				}
   405  				t.Errorf("unexpected %s", event)
   406  			}
   407  		})
   408  	}
   409  }
   410  
   411  var _ stack.LinkEndpoint = (*testLinkEndpoint)(nil)
   412  
   413  type testLinkEndpoint struct {
   414  	stack.LinkEndpoint
   415  
   416  	writeErr tcpip.Error
   417  }
   418  
   419  func (t *testLinkEndpoint) WritePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
   420  	if t.writeErr != nil {
   421  		return t.writeErr
   422  	}
   423  
   424  	return t.LinkEndpoint.WritePacket(r, protocol, pkt)
   425  }
   426  
   427  func TestLinkAddressRequest(t *testing.T) {
   428  	const nicID = 1
   429  
   430  	testAddr := tcpip.Address([]byte{1, 2, 3, 4})
   431  
   432  	tests := []struct {
   433  		name                                            string
   434  		nicAddr                                         tcpip.Address
   435  		localAddr                                       tcpip.Address
   436  		remoteLinkAddr                                  tcpip.LinkAddress
   437  		linkErr                                         tcpip.Error
   438  		expectedErr                                     tcpip.Error
   439  		expectedLocalAddr                               tcpip.Address
   440  		expectedRemoteLinkAddr                          tcpip.LinkAddress
   441  		expectedRequestsSent                            uint64
   442  		expectedRequestBadLocalAddressErrors            uint64
   443  		expectedRequestInterfaceHasNoLocalAddressErrors uint64
   444  		expectedRequestDroppedErrors                    uint64
   445  	}{
   446  		{
   447  			name:                                 "Unicast",
   448  			nicAddr:                              stackAddr,
   449  			localAddr:                            stackAddr,
   450  			remoteLinkAddr:                       remoteLinkAddr,
   451  			expectedLocalAddr:                    stackAddr,
   452  			expectedRemoteLinkAddr:               remoteLinkAddr,
   453  			expectedRequestsSent:                 1,
   454  			expectedRequestBadLocalAddressErrors: 0,
   455  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   456  			expectedRequestDroppedErrors:                    0,
   457  		},
   458  		{
   459  			name:                                 "Multicast",
   460  			nicAddr:                              stackAddr,
   461  			localAddr:                            stackAddr,
   462  			remoteLinkAddr:                       "",
   463  			expectedLocalAddr:                    stackAddr,
   464  			expectedRemoteLinkAddr:               header.EthernetBroadcastAddress,
   465  			expectedRequestsSent:                 1,
   466  			expectedRequestBadLocalAddressErrors: 0,
   467  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   468  			expectedRequestDroppedErrors:                    0,
   469  		},
   470  		{
   471  			name:                                 "Unicast with unspecified source",
   472  			nicAddr:                              stackAddr,
   473  			localAddr:                            "",
   474  			remoteLinkAddr:                       remoteLinkAddr,
   475  			expectedLocalAddr:                    stackAddr,
   476  			expectedRemoteLinkAddr:               remoteLinkAddr,
   477  			expectedRequestsSent:                 1,
   478  			expectedRequestBadLocalAddressErrors: 0,
   479  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   480  			expectedRequestDroppedErrors:                    0,
   481  		},
   482  		{
   483  			name:                                 "Multicast with unspecified source",
   484  			nicAddr:                              stackAddr,
   485  			localAddr:                            "",
   486  			remoteLinkAddr:                       "",
   487  			expectedLocalAddr:                    stackAddr,
   488  			expectedRemoteLinkAddr:               header.EthernetBroadcastAddress,
   489  			expectedRequestsSent:                 1,
   490  			expectedRequestBadLocalAddressErrors: 0,
   491  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   492  			expectedRequestDroppedErrors:                    0,
   493  		},
   494  		{
   495  			name:                                 "Unicast with unassigned address",
   496  			nicAddr:                              stackAddr,
   497  			localAddr:                            testAddr,
   498  			remoteLinkAddr:                       remoteLinkAddr,
   499  			expectedErr:                          &tcpip.ErrBadLocalAddress{},
   500  			expectedRequestsSent:                 0,
   501  			expectedRequestBadLocalAddressErrors: 1,
   502  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   503  			expectedRequestDroppedErrors:                    0,
   504  		},
   505  		{
   506  			name:                                 "Multicast with unassigned address",
   507  			nicAddr:                              stackAddr,
   508  			localAddr:                            testAddr,
   509  			remoteLinkAddr:                       "",
   510  			expectedErr:                          &tcpip.ErrBadLocalAddress{},
   511  			expectedRequestsSent:                 0,
   512  			expectedRequestBadLocalAddressErrors: 1,
   513  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   514  			expectedRequestDroppedErrors:                    0,
   515  		},
   516  		{
   517  			name:                                 "Unicast with no local address available",
   518  			nicAddr:                              "",
   519  			localAddr:                            "",
   520  			remoteLinkAddr:                       remoteLinkAddr,
   521  			expectedErr:                          &tcpip.ErrNetworkUnreachable{},
   522  			expectedRequestsSent:                 0,
   523  			expectedRequestBadLocalAddressErrors: 0,
   524  			expectedRequestInterfaceHasNoLocalAddressErrors: 1,
   525  			expectedRequestDroppedErrors:                    0,
   526  		},
   527  		{
   528  			name:                                 "Multicast with no local address available",
   529  			nicAddr:                              "",
   530  			localAddr:                            "",
   531  			remoteLinkAddr:                       "",
   532  			expectedErr:                          &tcpip.ErrNetworkUnreachable{},
   533  			expectedRequestsSent:                 0,
   534  			expectedRequestBadLocalAddressErrors: 0,
   535  			expectedRequestInterfaceHasNoLocalAddressErrors: 1,
   536  			expectedRequestDroppedErrors:                    0,
   537  		},
   538  		{
   539  			name:                                 "Link error",
   540  			nicAddr:                              stackAddr,
   541  			localAddr:                            stackAddr,
   542  			remoteLinkAddr:                       remoteLinkAddr,
   543  			linkErr:                              &tcpip.ErrInvalidEndpointState{},
   544  			expectedErr:                          &tcpip.ErrInvalidEndpointState{},
   545  			expectedRequestsSent:                 0,
   546  			expectedRequestBadLocalAddressErrors: 0,
   547  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   548  			expectedRequestDroppedErrors:                    1,
   549  		},
   550  	}
   551  
   552  	for _, test := range tests {
   553  		t.Run(test.name, func(t *testing.T) {
   554  			s := stack.New(stack.Options{
   555  				NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
   556  			})
   557  			linkEP := channel.New(1, header.IPv4MinimumMTU, stackLinkAddr)
   558  			if err := s.CreateNIC(nicID, &testLinkEndpoint{LinkEndpoint: linkEP, writeErr: test.linkErr}); err != nil {
   559  				t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   560  			}
   561  
   562  			ep, err := s.GetNetworkEndpoint(nicID, arp.ProtocolNumber)
   563  			if err != nil {
   564  				t.Fatalf("s.GetNetworkEndpoint(%d, %d): %s", nicID, arp.ProtocolNumber, err)
   565  			}
   566  			linkRes, ok := ep.(stack.LinkAddressResolver)
   567  			if !ok {
   568  				t.Fatalf("expected %T to implement stack.LinkAddressResolver", ep)
   569  			}
   570  
   571  			if len(test.nicAddr) != 0 {
   572  				if err := s.AddAddress(nicID, ipv4.ProtocolNumber, test.nicAddr); err != nil {
   573  					t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, ipv4.ProtocolNumber, test.nicAddr, err)
   574  				}
   575  			}
   576  
   577  			{
   578  				err := linkRes.LinkAddressRequest(remoteAddr, test.localAddr, test.remoteLinkAddr)
   579  				if diff := cmp.Diff(test.expectedErr, err); diff != "" {
   580  					t.Fatalf("unexpected error from p.LinkAddressRequest(%s, %s, %s, _), (-want, +got):\n%s", remoteAddr, test.localAddr, test.remoteLinkAddr, diff)
   581  				}
   582  			}
   583  
   584  			if got := s.Stats().ARP.OutgoingRequestsSent.Value(); got != test.expectedRequestsSent {
   585  				t.Errorf("got s.Stats().ARP.OutgoingRequestsSent.Value() = %d, want = %d", got, test.expectedRequestsSent)
   586  			}
   587  			if got := s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value(); got != test.expectedRequestInterfaceHasNoLocalAddressErrors {
   588  				t.Errorf("got s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value() = %d, want = %d", got, test.expectedRequestInterfaceHasNoLocalAddressErrors)
   589  			}
   590  			if got := s.Stats().ARP.OutgoingRequestBadLocalAddressErrors.Value(); got != test.expectedRequestBadLocalAddressErrors {
   591  				t.Errorf("got s.Stats().ARP.OutgoingRequestBadLocalAddressErrors.Value() = %d, want = %d", got, test.expectedRequestBadLocalAddressErrors)
   592  			}
   593  			if got := s.Stats().ARP.OutgoingRequestsDropped.Value(); got != test.expectedRequestDroppedErrors {
   594  				t.Errorf("got s.Stats().ARP.OutgoingRequestsDropped.Value() = %d, want = %d", got, test.expectedRequestDroppedErrors)
   595  			}
   596  
   597  			if test.expectedErr != nil {
   598  				return
   599  			}
   600  
   601  			pkt, ok := linkEP.Read()
   602  			if !ok {
   603  				t.Fatal("expected to send a link address request")
   604  			}
   605  
   606  			if pkt.Route.RemoteLinkAddress != test.expectedRemoteLinkAddr {
   607  				t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", pkt.Route.RemoteLinkAddress, test.expectedRemoteLinkAddr)
   608  			}
   609  
   610  			rep := header.ARP(stack.PayloadSince(pkt.Pkt.NetworkHeader()))
   611  			if got := rep.Op(); got != header.ARPRequest {
   612  				t.Errorf("got Op = %d, want = %d", got, header.ARPRequest)
   613  			}
   614  			if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
   615  				t.Errorf("got HardwareAddressSender = %s, want = %s", got, stackLinkAddr)
   616  			}
   617  			if got := tcpip.Address(rep.ProtocolAddressSender()); got != test.expectedLocalAddr {
   618  				t.Errorf("got ProtocolAddressSender = %s, want = %s", got, test.expectedLocalAddr)
   619  			}
   620  			if got, want := tcpip.LinkAddress(rep.HardwareAddressTarget()), tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00"); got != want {
   621  				t.Errorf("got HardwareAddressTarget = %s, want = %s", got, want)
   622  			}
   623  			if got := tcpip.Address(rep.ProtocolAddressTarget()); got != remoteAddr {
   624  				t.Errorf("got ProtocolAddressTarget = %s, want = %s", got, remoteAddr)
   625  			}
   626  		})
   627  	}
   628  }
   629  
   630  func TestDADARPRequestPacket(t *testing.T) {
   631  	clock := faketime.NewManualClock()
   632  	s := stack.New(stack.Options{
   633  		NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocolWithOptions(arp.Options{
   634  			DADConfigs: stack.DADConfigurations{
   635  				DupAddrDetectTransmits: 1,
   636  			},
   637  		}), ipv4.NewProtocol},
   638  		Clock: clock,
   639  	})
   640  	e := channel.New(1, header.IPv4MinimumMTU, stackLinkAddr)
   641  	if err := s.CreateNIC(nicID, e); err != nil {
   642  		t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   643  	}
   644  
   645  	if res, err := s.CheckDuplicateAddress(nicID, header.IPv4ProtocolNumber, remoteAddr, func(stack.DADResult) {}); err != nil {
   646  		t.Fatalf("s.CheckDuplicateAddress(%d, %d, %s, _): %s", nicID, header.IPv4ProtocolNumber, remoteAddr, err)
   647  	} else if res != stack.DADStarting {
   648  		t.Fatalf("got s.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", nicID, header.IPv4ProtocolNumber, remoteAddr, res, stack.DADStarting)
   649  	}
   650  
   651  	clock.RunImmediatelyScheduledJobs()
   652  	pkt, ok := e.Read()
   653  	if !ok {
   654  		t.Fatal("expected to send an ARP request")
   655  	}
   656  
   657  	if pkt.Route.RemoteLinkAddress != header.EthernetBroadcastAddress {
   658  		t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", pkt.Route.RemoteLinkAddress, header.EthernetBroadcastAddress)
   659  	}
   660  
   661  	req := header.ARP(stack.PayloadSince(pkt.Pkt.NetworkHeader()))
   662  	if !req.IsValid() {
   663  		t.Errorf("got req.IsValid() = false, want = true")
   664  	}
   665  	if got := req.Op(); got != header.ARPRequest {
   666  		t.Errorf("got req.Op() = %d, want = %d", got, header.ARPRequest)
   667  	}
   668  	if got := tcpip.LinkAddress(req.HardwareAddressSender()); got != stackLinkAddr {
   669  		t.Errorf("got req.HardwareAddressSender() = %s, want = %s", got, stackLinkAddr)
   670  	}
   671  	if got := tcpip.Address(req.ProtocolAddressSender()); got != header.IPv4Any {
   672  		t.Errorf("got req.ProtocolAddressSender() = %s, want = %s", got, header.IPv4Any)
   673  	}
   674  	if got, want := tcpip.LinkAddress(req.HardwareAddressTarget()), tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00"); got != want {
   675  		t.Errorf("got req.HardwareAddressTarget() = %s, want = %s", got, want)
   676  	}
   677  	if got := tcpip.Address(req.ProtocolAddressTarget()); got != remoteAddr {
   678  		t.Errorf("got req.ProtocolAddressTarget() = %s, want = %s", got, remoteAddr)
   679  	}
   680  }