gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/ipv6/ndp_test.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ipv6
    16  
    17  import (
    18  	"math/rand"
    19  	"strings"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"gvisor.dev/gvisor/pkg/buffer"
    25  	"gvisor.dev/gvisor/pkg/tcpip"
    26  	"gvisor.dev/gvisor/pkg/tcpip/checker"
    27  	"gvisor.dev/gvisor/pkg/tcpip/checksum"
    28  	"gvisor.dev/gvisor/pkg/tcpip/faketime"
    29  	"gvisor.dev/gvisor/pkg/tcpip/header"
    30  	"gvisor.dev/gvisor/pkg/tcpip/link/channel"
    31  	"gvisor.dev/gvisor/pkg/tcpip/prependable"
    32  	"gvisor.dev/gvisor/pkg/tcpip/stack"
    33  	"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
    34  )
    35  
    36  var _ NDPDispatcher = (*testNDPDispatcher)(nil)
    37  
    38  // testNDPDispatcher is an NDPDispatcher only allows default router discovery.
    39  type testNDPDispatcher struct {
    40  	addr tcpip.Address
    41  }
    42  
    43  func (*testNDPDispatcher) OnDuplicateAddressDetectionResult(tcpip.NICID, tcpip.Address, stack.DADResult) {
    44  }
    45  
    46  func (t *testNDPDispatcher) OnOffLinkRouteUpdated(_ tcpip.NICID, _ tcpip.Subnet, addr tcpip.Address, _ header.NDPRoutePreference) {
    47  	t.addr = addr
    48  }
    49  
    50  func (t *testNDPDispatcher) OnOffLinkRouteInvalidated(_ tcpip.NICID, _ tcpip.Subnet, addr tcpip.Address) {
    51  	t.addr = addr
    52  }
    53  
    54  func (*testNDPDispatcher) OnOnLinkPrefixDiscovered(tcpip.NICID, tcpip.Subnet) {
    55  }
    56  
    57  func (*testNDPDispatcher) OnOnLinkPrefixInvalidated(tcpip.NICID, tcpip.Subnet) {
    58  }
    59  
    60  func (*testNDPDispatcher) OnAutoGenAddress(tcpip.NICID, tcpip.AddressWithPrefix) stack.AddressDispatcher {
    61  	return nil
    62  }
    63  
    64  func (*testNDPDispatcher) OnAutoGenAddressDeprecated(tcpip.NICID, tcpip.AddressWithPrefix) {
    65  }
    66  
    67  func (*testNDPDispatcher) OnAutoGenAddressInvalidated(tcpip.NICID, tcpip.AddressWithPrefix) {
    68  }
    69  
    70  func (*testNDPDispatcher) OnRecursiveDNSServerOption(tcpip.NICID, []tcpip.Address, time.Duration) {
    71  }
    72  
    73  func (*testNDPDispatcher) OnDNSSearchListOption(tcpip.NICID, []string, time.Duration) {
    74  }
    75  
    76  func (*testNDPDispatcher) OnDHCPv6Configuration(tcpip.NICID, DHCPv6ConfigurationFromNDPRA) {
    77  }
    78  
    79  func TestStackNDPEndpointInvalidateDefaultRouter(t *testing.T) {
    80  	var ndpDisp testNDPDispatcher
    81  	s := stack.New(stack.Options{
    82  		NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocolWithOptions(Options{
    83  			NDPDisp: &ndpDisp,
    84  		})},
    85  	})
    86  	defer s.Close()
    87  
    88  	if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil {
    89  		t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
    90  	}
    91  
    92  	ep, err := s.GetNetworkEndpoint(nicID, ProtocolNumber)
    93  	if err != nil {
    94  		t.Fatalf("s.GetNetworkEndpoint(%d, %d): %s", nicID, ProtocolNumber, err)
    95  	}
    96  
    97  	ipv6EP := ep.(*endpoint)
    98  	ipv6EP.mu.Lock()
    99  	ipv6EP.mu.ndp.handleOffLinkRouteDiscovery(offLinkRoute{dest: header.IPv6EmptySubnet, router: lladdr1}, time.Hour, header.MediumRoutePreference)
   100  	ipv6EP.mu.Unlock()
   101  
   102  	if ndpDisp.addr != lladdr1 {
   103  		t.Fatalf("got ndpDisp.addr = %s, want = %s", ndpDisp.addr, lladdr1)
   104  	}
   105  
   106  	ndpDisp.addr = tcpip.Address{}
   107  	ndpEP := ep.(stack.NDPEndpoint)
   108  	ndpEP.InvalidateDefaultRouter(lladdr1)
   109  	if ndpDisp.addr != lladdr1 {
   110  		t.Fatalf("got ndpDisp.addr = %s, want = %s", ndpDisp.addr, lladdr1)
   111  	}
   112  }
   113  
   114  // TestNeighborSolicitationWithSourceLinkLayerOption tests that receiving a
   115  // valid NDP NS message with the Source Link Layer Address option results in a
   116  // new entry in the link address cache for the sender of the message.
   117  func TestNeighborSolicitationWithSourceLinkLayerOption(t *testing.T) {
   118  	const nicID = 1
   119  
   120  	tests := []struct {
   121  		name             string
   122  		optsBuf          []byte
   123  		expectedLinkAddr tcpip.LinkAddress
   124  	}{
   125  		{
   126  			name:             "Valid",
   127  			optsBuf:          []byte{1, 1, 2, 3, 4, 5, 6, 7},
   128  			expectedLinkAddr: "\x02\x03\x04\x05\x06\x07",
   129  		},
   130  		{
   131  			name:    "Too Small",
   132  			optsBuf: []byte{1, 1, 2, 3, 4, 5, 6},
   133  		},
   134  		{
   135  			name:    "Invalid Length",
   136  			optsBuf: []byte{1, 2, 2, 3, 4, 5, 6, 7},
   137  		},
   138  	}
   139  
   140  	for _, test := range tests {
   141  		t.Run(test.name, func(t *testing.T) {
   142  			c := newTestContext()
   143  			defer c.cleanup()
   144  			s := c.s
   145  
   146  			e := channel.New(0, 1280, linkAddr0)
   147  			defer e.Close()
   148  			e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
   149  			if err := s.CreateNIC(nicID, e); err != nil {
   150  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
   151  			}
   152  			protocolAddr := tcpip.ProtocolAddress{
   153  				Protocol:          ProtocolNumber,
   154  				AddressWithPrefix: lladdr0.WithPrefix(),
   155  			}
   156  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   157  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   158  			}
   159  
   160  			ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize + len(test.optsBuf)
   161  			hdr := prependable.New(header.IPv6MinimumSize + ndpNSSize)
   162  			pkt := header.ICMPv6(hdr.Prepend(ndpNSSize))
   163  			pkt.SetType(header.ICMPv6NeighborSolicit)
   164  			ns := header.NDPNeighborSolicit(pkt.MessageBody())
   165  			ns.SetTargetAddress(lladdr0)
   166  			opts := ns.Options()
   167  			copy(opts, test.optsBuf)
   168  			pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   169  				Header: pkt,
   170  				Src:    lladdr1,
   171  				Dst:    lladdr0,
   172  			}))
   173  			payloadLength := hdr.UsedLength()
   174  			ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   175  			ip.Encode(&header.IPv6Fields{
   176  				PayloadLength:     uint16(payloadLength),
   177  				TransportProtocol: header.ICMPv6ProtocolNumber,
   178  				HopLimit:          255,
   179  				SrcAddr:           lladdr1,
   180  				DstAddr:           lladdr0,
   181  			})
   182  
   183  			invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
   184  
   185  			// Invalid count should initially be 0.
   186  			if got := invalid.Value(); got != 0 {
   187  				t.Fatalf("got invalid = %d, want = 0", got)
   188  			}
   189  
   190  			pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
   191  				Payload: buffer.MakeWithData(hdr.View()),
   192  			})
   193  			e.InjectInbound(ProtocolNumber, pktBuf)
   194  			pktBuf.DecRef()
   195  
   196  			neighbors, err := s.Neighbors(nicID, ProtocolNumber)
   197  			if err != nil {
   198  				t.Fatalf("s.Neighbors(%d, %d): %s", nicID, ProtocolNumber, err)
   199  			}
   200  
   201  			neighborByAddr := make(map[tcpip.Address]stack.NeighborEntry)
   202  			for _, n := range neighbors {
   203  				if existing, ok := neighborByAddr[n.Addr]; ok {
   204  					if diff := cmp.Diff(existing, n); diff != "" {
   205  						t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry (-existing +got):\n%s", nicID, ProtocolNumber, diff)
   206  					}
   207  					t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry: %#v", nicID, ProtocolNumber, existing)
   208  				}
   209  				neighborByAddr[n.Addr] = n
   210  			}
   211  
   212  			if neigh, ok := neighborByAddr[lladdr1]; len(test.expectedLinkAddr) != 0 {
   213  				// Invalid count should not have increased.
   214  				if got := invalid.Value(); got != 0 {
   215  					t.Errorf("got invalid = %d, want = 0", got)
   216  				}
   217  
   218  				if !ok {
   219  					t.Fatalf("expected a neighbor entry for %q", lladdr1)
   220  				}
   221  				if neigh.LinkAddr != test.expectedLinkAddr {
   222  					t.Errorf("got link address = %s, want = %s", neigh.LinkAddr, test.expectedLinkAddr)
   223  				}
   224  				if neigh.State != stack.Stale {
   225  					t.Errorf("got NUD state = %s, want = %s", neigh.State, stack.Stale)
   226  				}
   227  			} else {
   228  				// Invalid count should have increased.
   229  				if got := invalid.Value(); got != 1 {
   230  					t.Errorf("got invalid = %d, want = 1", got)
   231  				}
   232  
   233  				if ok {
   234  					t.Fatalf("unexpectedly got neighbor entry: %#v", neigh)
   235  				}
   236  			}
   237  		})
   238  	}
   239  }
   240  
   241  func TestNeighborSolicitationResponse(t *testing.T) {
   242  	const nicID = 1
   243  	nicAddr := lladdr0
   244  	remoteAddr := lladdr1
   245  	nicAddrSNMC := header.SolicitedNodeAddr(nicAddr)
   246  	nicLinkAddr := linkAddr0
   247  	remoteLinkAddr0 := linkAddr1
   248  	remoteLinkAddr1 := linkAddr2
   249  
   250  	tests := []struct {
   251  		name                   string
   252  		nsOpts                 header.NDPOptionsSerializer
   253  		nsSrc                  tcpip.Address
   254  		nsDst                  tcpip.Address
   255  		nsInvalid              bool
   256  		naDstLinkAddr          tcpip.LinkAddress
   257  		naSolicited            bool
   258  		naSrc                  tcpip.Address
   259  		naDst                  tcpip.Address
   260  		performsLinkResolution bool
   261  		forwardingEnabled      bool
   262  	}{
   263  		{
   264  			name:          "Unspecified source to solicited-node multicast destination",
   265  			nsOpts:        nil,
   266  			nsSrc:         header.IPv6Any,
   267  			nsDst:         nicAddrSNMC,
   268  			nsInvalid:     false,
   269  			naDstLinkAddr: header.EthernetAddressFromMulticastIPv6Address(header.IPv6AllNodesMulticastAddress),
   270  			naSolicited:   false,
   271  			naSrc:         nicAddr,
   272  			naDst:         header.IPv6AllNodesMulticastAddress,
   273  		},
   274  		{
   275  			name: "Unspecified source with source ll option to multicast destination",
   276  			nsOpts: header.NDPOptionsSerializer{
   277  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]),
   278  			},
   279  			nsSrc:     header.IPv6Any,
   280  			nsDst:     nicAddrSNMC,
   281  			nsInvalid: true,
   282  		},
   283  		{
   284  			name:      "Unspecified source to unicast destination",
   285  			nsOpts:    nil,
   286  			nsSrc:     header.IPv6Any,
   287  			nsDst:     nicAddr,
   288  			nsInvalid: true,
   289  		},
   290  		{
   291  			name: "Unspecified source with source ll option to unicast destination",
   292  			nsOpts: header.NDPOptionsSerializer{
   293  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]),
   294  			},
   295  			nsSrc:     header.IPv6Any,
   296  			nsDst:     nicAddr,
   297  			nsInvalid: true,
   298  		},
   299  		{
   300  			name: "Specified source with 1 source ll to multicast destination",
   301  			nsOpts: header.NDPOptionsSerializer{
   302  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]),
   303  			},
   304  			nsSrc:         remoteAddr,
   305  			nsDst:         nicAddrSNMC,
   306  			nsInvalid:     false,
   307  			naDstLinkAddr: remoteLinkAddr0,
   308  			naSolicited:   true,
   309  			naSrc:         nicAddr,
   310  			naDst:         remoteAddr,
   311  		},
   312  		{
   313  			name: "Specified source with 1 source ll different from route to multicast destination",
   314  			nsOpts: header.NDPOptionsSerializer{
   315  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]),
   316  			},
   317  			nsSrc:         remoteAddr,
   318  			nsDst:         nicAddrSNMC,
   319  			nsInvalid:     false,
   320  			naDstLinkAddr: remoteLinkAddr1,
   321  			naSolicited:   true,
   322  			naSrc:         nicAddr,
   323  			naDst:         remoteAddr,
   324  		},
   325  		{
   326  			name:      "Specified source to multicast destination",
   327  			nsOpts:    nil,
   328  			nsSrc:     remoteAddr,
   329  			nsDst:     nicAddrSNMC,
   330  			nsInvalid: true,
   331  		},
   332  		{
   333  			name: "Specified source with 2 source ll to multicast destination",
   334  			nsOpts: header.NDPOptionsSerializer{
   335  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]),
   336  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]),
   337  			},
   338  			nsSrc:     remoteAddr,
   339  			nsDst:     nicAddrSNMC,
   340  			nsInvalid: true,
   341  		},
   342  
   343  		{
   344  			name:          "Specified source to unicast destination",
   345  			nsOpts:        nil,
   346  			nsSrc:         remoteAddr,
   347  			nsDst:         nicAddr,
   348  			nsInvalid:     false,
   349  			naDstLinkAddr: remoteLinkAddr0,
   350  			naSolicited:   true,
   351  			naSrc:         nicAddr,
   352  			naDst:         remoteAddr,
   353  			// Since we send a unicast solicitations to a node without an entry for
   354  			// the remote, the node needs to perform neighbor discovery to get the
   355  			// remote's link address to send the advertisement response.
   356  			performsLinkResolution: true,
   357  		},
   358  		{
   359  			name: "Specified source with 1 source ll to unicast destination",
   360  			nsOpts: header.NDPOptionsSerializer{
   361  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]),
   362  			},
   363  			nsSrc:         remoteAddr,
   364  			nsDst:         nicAddr,
   365  			nsInvalid:     false,
   366  			naDstLinkAddr: remoteLinkAddr0,
   367  			naSolicited:   true,
   368  			naSrc:         nicAddr,
   369  			naDst:         remoteAddr,
   370  		},
   371  		{
   372  			name: "Specified source with 1 source ll different from route to unicast destination",
   373  			nsOpts: header.NDPOptionsSerializer{
   374  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]),
   375  			},
   376  			nsSrc:         remoteAddr,
   377  			nsDst:         nicAddr,
   378  			nsInvalid:     false,
   379  			naDstLinkAddr: remoteLinkAddr1,
   380  			naSolicited:   true,
   381  			naSrc:         nicAddr,
   382  			naDst:         remoteAddr,
   383  		},
   384  		{
   385  			name: "Specified source with 2 source ll to unicast destination",
   386  			nsOpts: header.NDPOptionsSerializer{
   387  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]),
   388  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr1[:]),
   389  			},
   390  			nsSrc:     remoteAddr,
   391  			nsDst:     nicAddr,
   392  			nsInvalid: true,
   393  		},
   394  		{
   395  			name: "Specified source with 1 source ll to multicast destination with forwarding enabled",
   396  			nsOpts: header.NDPOptionsSerializer{
   397  				header.NDPSourceLinkLayerAddressOption(remoteLinkAddr0[:]),
   398  			},
   399  			nsSrc:             remoteAddr,
   400  			nsDst:             nicAddrSNMC,
   401  			nsInvalid:         false,
   402  			naDstLinkAddr:     remoteLinkAddr0,
   403  			naSolicited:       true,
   404  			naSrc:             nicAddr,
   405  			naDst:             remoteAddr,
   406  			forwardingEnabled: true,
   407  		},
   408  	}
   409  
   410  	for _, test := range tests {
   411  		t.Run(test.name, func(t *testing.T) {
   412  			c := newTestContext()
   413  			defer c.cleanup()
   414  			s := c.s
   415  
   416  			if err := s.SetForwardingDefaultAndAllNICs(header.IPv6ProtocolNumber, test.forwardingEnabled); err != nil {
   417  				t.Fatalf("SetForwardingDefaultAndAllNICs(%t): %s", test.forwardingEnabled, err)
   418  			}
   419  
   420  			e := channel.New(1, 1280, nicLinkAddr)
   421  			defer e.Close()
   422  			e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
   423  			if err := s.CreateNIC(nicID, e); err != nil {
   424  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
   425  			}
   426  			protocolAddr := tcpip.ProtocolAddress{
   427  				Protocol:          ProtocolNumber,
   428  				AddressWithPrefix: nicAddr.WithPrefix(),
   429  			}
   430  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   431  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   432  			}
   433  
   434  			s.SetRouteTable([]tcpip.Route{
   435  				{
   436  					Destination: header.IPv6EmptySubnet,
   437  					NIC:         1,
   438  				},
   439  			})
   440  
   441  			ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize + test.nsOpts.Length()
   442  			hdr := prependable.New(header.IPv6MinimumSize + ndpNSSize)
   443  			pkt := header.ICMPv6(hdr.Prepend(ndpNSSize))
   444  			pkt.SetType(header.ICMPv6NeighborSolicit)
   445  			ns := header.NDPNeighborSolicit(pkt.MessageBody())
   446  			ns.SetTargetAddress(nicAddr)
   447  			opts := ns.Options()
   448  			opts.Serialize(test.nsOpts)
   449  			pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   450  				Header: pkt,
   451  				Src:    test.nsSrc,
   452  				Dst:    test.nsDst,
   453  			}))
   454  			payloadLength := hdr.UsedLength()
   455  			ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   456  			ip.Encode(&header.IPv6Fields{
   457  				PayloadLength:     uint16(payloadLength),
   458  				TransportProtocol: header.ICMPv6ProtocolNumber,
   459  				HopLimit:          255,
   460  				SrcAddr:           test.nsSrc,
   461  				DstAddr:           test.nsDst,
   462  			})
   463  
   464  			invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
   465  
   466  			// Invalid count should initially be 0.
   467  			if got := invalid.Value(); got != 0 {
   468  				t.Fatalf("got invalid = %d, want = 0", got)
   469  			}
   470  
   471  			pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
   472  				Payload: buffer.MakeWithData(hdr.View()),
   473  			})
   474  			e.InjectInbound(ProtocolNumber, pktBuf)
   475  			pktBuf.DecRef()
   476  
   477  			if test.nsInvalid {
   478  				if got := invalid.Value(); got != 1 {
   479  					t.Fatalf("got invalid = %d, want = 1", got)
   480  				}
   481  
   482  				if p := e.Read(); p != nil {
   483  					t.Fatalf("unexpected response to an invalid NS = %+v", p)
   484  				}
   485  
   486  				// If we expected the NS to be invalid, we have nothing else to check.
   487  				return
   488  			}
   489  
   490  			if got := invalid.Value(); got != 0 {
   491  				t.Fatalf("got invalid = %d, want = 0", got)
   492  			}
   493  
   494  			if test.performsLinkResolution {
   495  				c.clock.RunImmediatelyScheduledJobs()
   496  				p := e.Read()
   497  				if p == nil {
   498  					t.Fatal("expected an NDP NS response")
   499  				}
   500  
   501  				respNSDst := header.SolicitedNodeAddr(test.nsSrc)
   502  				var want stack.RouteInfo
   503  				want.NetProto = ProtocolNumber
   504  				want.LocalLinkAddress = nicLinkAddr
   505  				want.RemoteLinkAddress = header.EthernetAddressFromMulticastIPv6Address(respNSDst)
   506  				if diff := cmp.Diff(want, p.EgressRoute, cmp.AllowUnexported(want)); diff != "" {
   507  					t.Errorf("route info mismatch (-want +got):\n%s", diff)
   508  				}
   509  
   510  				payload := stack.PayloadSince(p.NetworkHeader())
   511  				defer payload.Release()
   512  				checker.IPv6(t, payload,
   513  					checker.SrcAddr(nicAddr),
   514  					checker.DstAddr(respNSDst),
   515  					checker.TTL(header.NDPHopLimit),
   516  					checker.NDPNS(
   517  						checker.NDPNSTargetAddress(test.nsSrc),
   518  						checker.NDPNSOptions([]header.NDPOption{
   519  							header.NDPSourceLinkLayerAddressOption(nicLinkAddr),
   520  						}),
   521  					))
   522  				p.DecRef()
   523  
   524  				ser := header.NDPOptionsSerializer{
   525  					header.NDPTargetLinkLayerAddressOption(linkAddr1),
   526  				}
   527  				ndpNASize := header.ICMPv6NeighborAdvertMinimumSize + ser.Length()
   528  				hdr := prependable.New(header.IPv6MinimumSize + ndpNASize)
   529  				pkt := header.ICMPv6(hdr.Prepend(ndpNASize))
   530  				pkt.SetType(header.ICMPv6NeighborAdvert)
   531  				na := header.NDPNeighborAdvert(pkt.MessageBody())
   532  				na.SetSolicitedFlag(true)
   533  				na.SetOverrideFlag(true)
   534  				na.SetRouterFlag(test.forwardingEnabled)
   535  				na.SetTargetAddress(test.nsSrc)
   536  				na.Options().Serialize(ser)
   537  				pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   538  					Header: pkt,
   539  					Src:    test.nsSrc,
   540  					Dst:    nicAddr,
   541  				}))
   542  				payloadLength := hdr.UsedLength()
   543  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   544  				ip.Encode(&header.IPv6Fields{
   545  					PayloadLength:     uint16(payloadLength),
   546  					TransportProtocol: header.ICMPv6ProtocolNumber,
   547  					HopLimit:          header.NDPHopLimit,
   548  					SrcAddr:           test.nsSrc,
   549  					DstAddr:           nicAddr,
   550  				})
   551  				pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
   552  					Payload: buffer.MakeWithData(hdr.View()),
   553  				})
   554  				e.InjectInbound(ProtocolNumber, pktBuf)
   555  				pktBuf.DecRef()
   556  			}
   557  
   558  			c.clock.RunImmediatelyScheduledJobs()
   559  			p := e.Read()
   560  			if p == nil {
   561  				t.Fatal("expected an NDP NA response")
   562  			}
   563  			defer p.DecRef()
   564  
   565  			if p.EgressRoute.LocalAddress != test.naSrc {
   566  				t.Errorf("got p.EgressRoute.LocalAddress = %s, want = %s", p.EgressRoute.LocalAddress, test.naSrc)
   567  			}
   568  			if p.EgressRoute.LocalLinkAddress != nicLinkAddr {
   569  				t.Errorf("p.EgressRoute.LocalLinkAddress = %s, want = %s", p.EgressRoute.LocalLinkAddress, nicLinkAddr)
   570  			}
   571  			if p.EgressRoute.RemoteAddress != test.naDst {
   572  				t.Errorf("got p.EgressRoute.RemoteAddress = %s, want = %s", p.EgressRoute.RemoteAddress, test.naDst)
   573  			}
   574  			if p.EgressRoute.RemoteLinkAddress != test.naDstLinkAddr {
   575  				t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, test.naDstLinkAddr)
   576  			}
   577  
   578  			payload := stack.PayloadSince(p.NetworkHeader())
   579  			defer payload.Release()
   580  			checker.IPv6(t, payload,
   581  				checker.SrcAddr(test.naSrc),
   582  				checker.DstAddr(test.naDst),
   583  				checker.TTL(header.NDPHopLimit),
   584  				checker.NDPNA(
   585  					checker.NDPNASolicitedFlag(test.naSolicited),
   586  					checker.NDPNATargetAddress(nicAddr),
   587  					checker.NDPNAOptions([]header.NDPOption{
   588  						header.NDPTargetLinkLayerAddressOption(nicLinkAddr[:]),
   589  					}),
   590  				))
   591  		})
   592  	}
   593  }
   594  
   595  // TestNeighborAdvertisementWithTargetLinkLayerOption tests that receiving a
   596  // valid NDP NA message with the Target Link Layer Address option does not
   597  // result in a new entry in the neighbor cache for the target of the message.
   598  func TestNeighborAdvertisementWithTargetLinkLayerOption(t *testing.T) {
   599  	const nicID = 1
   600  
   601  	tests := []struct {
   602  		name    string
   603  		optsBuf []byte
   604  		isValid bool
   605  	}{
   606  		{
   607  			name:    "Valid",
   608  			optsBuf: []byte{2, 1, 2, 3, 4, 5, 6, 7},
   609  			isValid: true,
   610  		},
   611  		{
   612  			name:    "Too Small",
   613  			optsBuf: []byte{2, 1, 2, 3, 4, 5, 6},
   614  		},
   615  		{
   616  			name:    "Invalid Length",
   617  			optsBuf: []byte{2, 2, 2, 3, 4, 5, 6, 7},
   618  		},
   619  		{
   620  			name: "Multiple",
   621  			optsBuf: []byte{
   622  				2, 1, 2, 3, 4, 5, 6, 7,
   623  				2, 1, 2, 3, 4, 5, 6, 8,
   624  			},
   625  		},
   626  	}
   627  
   628  	for _, test := range tests {
   629  		t.Run(test.name, func(t *testing.T) {
   630  			c := newTestContext()
   631  			defer c.cleanup()
   632  			s := c.s
   633  
   634  			e := channel.New(0, 1280, linkAddr0)
   635  			defer e.Close()
   636  			e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
   637  			if err := s.CreateNIC(nicID, e); err != nil {
   638  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
   639  			}
   640  			protocolAddr := tcpip.ProtocolAddress{
   641  				Protocol:          ProtocolNumber,
   642  				AddressWithPrefix: lladdr0.WithPrefix(),
   643  			}
   644  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   645  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   646  			}
   647  
   648  			ndpNASize := header.ICMPv6NeighborAdvertMinimumSize + len(test.optsBuf)
   649  			hdr := prependable.New(header.IPv6MinimumSize + ndpNASize)
   650  			pkt := header.ICMPv6(hdr.Prepend(ndpNASize))
   651  			pkt.SetType(header.ICMPv6NeighborAdvert)
   652  			ns := header.NDPNeighborAdvert(pkt.MessageBody())
   653  			ns.SetTargetAddress(lladdr1)
   654  			opts := ns.Options()
   655  			copy(opts, test.optsBuf)
   656  			pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   657  				Header: pkt,
   658  				Src:    lladdr1,
   659  				Dst:    lladdr0,
   660  			}))
   661  			payloadLength := hdr.UsedLength()
   662  			ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   663  			ip.Encode(&header.IPv6Fields{
   664  				PayloadLength:     uint16(payloadLength),
   665  				TransportProtocol: header.ICMPv6ProtocolNumber,
   666  				HopLimit:          255,
   667  				SrcAddr:           lladdr1,
   668  				DstAddr:           lladdr0,
   669  			})
   670  
   671  			invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
   672  
   673  			// Invalid count should initially be 0.
   674  			if got := invalid.Value(); got != 0 {
   675  				t.Fatalf("got invalid = %d, want = 0", got)
   676  			}
   677  			pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
   678  				Payload: buffer.MakeWithData(hdr.View()),
   679  			})
   680  			e.InjectInbound(ProtocolNumber, pktBuf)
   681  			pktBuf.DecRef()
   682  
   683  			neighbors, err := s.Neighbors(nicID, ProtocolNumber)
   684  			if err != nil {
   685  				t.Fatalf("s.Neighbors(%d, %d): %s", nicID, ProtocolNumber, err)
   686  			}
   687  
   688  			neighborByAddr := make(map[tcpip.Address]stack.NeighborEntry)
   689  			for _, n := range neighbors {
   690  				if existing, ok := neighborByAddr[n.Addr]; ok {
   691  					if diff := cmp.Diff(existing, n); diff != "" {
   692  						t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry (-existing +got):\n%s", nicID, ProtocolNumber, diff)
   693  					}
   694  					t.Fatalf("s.Neighbors(%d, %d) returned unexpected duplicate neighbor entry: %#v", nicID, ProtocolNumber, existing)
   695  				}
   696  				neighborByAddr[n.Addr] = n
   697  			}
   698  
   699  			if neigh, ok := neighborByAddr[lladdr1]; ok {
   700  				t.Fatalf("unexpectedly got neighbor entry: %#v", neigh)
   701  			}
   702  
   703  			if test.isValid {
   704  				// Invalid count should not have increased.
   705  				if got := invalid.Value(); got != 0 {
   706  					t.Errorf("got invalid = %d, want = 0", got)
   707  				}
   708  			} else {
   709  				// Invalid count should have increased.
   710  				if got := invalid.Value(); got != 1 {
   711  					t.Errorf("got invalid = %d, want = 1", got)
   712  				}
   713  			}
   714  		})
   715  	}
   716  }
   717  
   718  func TestNDPValidation(t *testing.T) {
   719  	const nicID = 1
   720  
   721  	handleIPv6Payload := func(payload []byte, hopLimit uint8, atomicFragment bool, ep stack.NetworkEndpoint) {
   722  		var extHdrs header.IPv6ExtHdrSerializer
   723  		if atomicFragment {
   724  			extHdrs = append(extHdrs, &header.IPv6SerializableFragmentExtHdr{})
   725  		}
   726  		extHdrsLen := extHdrs.Length()
   727  
   728  		ip := make([]byte, header.IPv6MinimumSize+extHdrsLen)
   729  		header.IPv6(ip).Encode(&header.IPv6Fields{
   730  			PayloadLength:     uint16(len(payload) + extHdrsLen),
   731  			TransportProtocol: header.ICMPv6ProtocolNumber,
   732  			HopLimit:          hopLimit,
   733  			SrcAddr:           lladdr1,
   734  			DstAddr:           lladdr0,
   735  			ExtensionHeaders:  extHdrs,
   736  		})
   737  		buf := buffer.MakeWithData(ip)
   738  		buf.Append(buffer.NewViewWithData(payload))
   739  		pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   740  			Payload: buf,
   741  		})
   742  		ep.HandlePacket(pkt)
   743  		pkt.DecRef()
   744  	}
   745  
   746  	var tllData [header.NDPLinkLayerAddressSize]byte
   747  	header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{
   748  		header.NDPTargetLinkLayerAddressOption(linkAddr1),
   749  	})
   750  
   751  	var sllData [header.NDPLinkLayerAddressSize]byte
   752  	header.NDPOptions(sllData[:]).Serialize(header.NDPOptionsSerializer{
   753  		header.NDPSourceLinkLayerAddressOption(linkAddr1),
   754  	})
   755  
   756  	types := []struct {
   757  		name        string
   758  		typ         header.ICMPv6Type
   759  		size        int
   760  		extraData   []byte
   761  		statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter
   762  		routerOnly  bool
   763  	}{
   764  		{
   765  			name: "RouterSolicit",
   766  			typ:  header.ICMPv6RouterSolicit,
   767  			size: header.ICMPv6MinimumSize,
   768  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   769  				return stats.RouterSolicit
   770  			},
   771  			routerOnly: true,
   772  		},
   773  		{
   774  			name: "RouterAdvert",
   775  			typ:  header.ICMPv6RouterAdvert,
   776  			size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize,
   777  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   778  				return stats.RouterAdvert
   779  			},
   780  		},
   781  		{
   782  			name:      "NeighborSolicit",
   783  			typ:       header.ICMPv6NeighborSolicit,
   784  			size:      header.ICMPv6NeighborSolicitMinimumSize,
   785  			extraData: sllData[:],
   786  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   787  				return stats.NeighborSolicit
   788  			},
   789  		},
   790  		{
   791  			name:      "NeighborAdvert",
   792  			typ:       header.ICMPv6NeighborAdvert,
   793  			size:      header.ICMPv6NeighborAdvertMinimumSize,
   794  			extraData: tllData[:],
   795  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   796  				return stats.NeighborAdvert
   797  			},
   798  		},
   799  		{
   800  			name: "RedirectMsg",
   801  			typ:  header.ICMPv6RedirectMsg,
   802  			size: header.ICMPv6MinimumSize,
   803  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   804  				return stats.RedirectMsg
   805  			},
   806  		},
   807  	}
   808  
   809  	subTests := []struct {
   810  		name           string
   811  		atomicFragment bool
   812  		hopLimit       uint8
   813  		code           header.ICMPv6Code
   814  		valid          bool
   815  	}{
   816  		{
   817  			name:           "Valid",
   818  			atomicFragment: false,
   819  			hopLimit:       header.NDPHopLimit,
   820  			code:           0,
   821  			valid:          true,
   822  		},
   823  		{
   824  			name:           "Fragmented",
   825  			atomicFragment: true,
   826  			hopLimit:       header.NDPHopLimit,
   827  			code:           0,
   828  			valid:          false,
   829  		},
   830  		{
   831  			name:           "Invalid hop limit",
   832  			atomicFragment: false,
   833  			hopLimit:       header.NDPHopLimit - 1,
   834  			code:           0,
   835  			valid:          false,
   836  		},
   837  		{
   838  			name:           "Invalid ICMPv6 code",
   839  			atomicFragment: false,
   840  			hopLimit:       header.NDPHopLimit,
   841  			code:           1,
   842  			valid:          false,
   843  		},
   844  	}
   845  
   846  	subnet, err := tcpip.NewSubnet(lladdr1, tcpip.MaskFrom(strings.Repeat("\xff", lladdr0.Len())))
   847  	if err != nil {
   848  		t.Fatal(err)
   849  	}
   850  
   851  	for _, typ := range types {
   852  		for _, isRouter := range []bool{false, true} {
   853  			name := typ.name
   854  			if isRouter {
   855  				name += " (Router)"
   856  			}
   857  
   858  			t.Run(name, func(t *testing.T) {
   859  				for _, test := range subTests {
   860  					t.Run(test.name, func(t *testing.T) {
   861  						c := newTestContext()
   862  						defer c.cleanup()
   863  						s := c.s
   864  
   865  						if isRouter {
   866  							if err := s.SetForwardingDefaultAndAllNICs(ProtocolNumber, true); err != nil {
   867  								t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ProtocolNumber, err)
   868  							}
   869  						}
   870  
   871  						if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil {
   872  							t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
   873  						}
   874  
   875  						protocolAddr := tcpip.ProtocolAddress{
   876  							Protocol:          ProtocolNumber,
   877  							AddressWithPrefix: lladdr0.WithPrefix(),
   878  						}
   879  						if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   880  							t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   881  						}
   882  
   883  						ep, err := s.GetNetworkEndpoint(nicID, ProtocolNumber)
   884  						if err != nil {
   885  							t.Fatal("cannot find network endpoint instance for IPv6")
   886  						}
   887  
   888  						s.SetRouteTable([]tcpip.Route{{
   889  							Destination: subnet,
   890  							NIC:         nicID,
   891  						}})
   892  
   893  						stats := s.Stats().ICMP.V6.PacketsReceived
   894  						invalid := stats.Invalid
   895  						routerOnly := stats.RouterOnlyPacketsDroppedByHost
   896  						typStat := typ.statCounter(stats)
   897  
   898  						icmpH := header.ICMPv6(make([]byte, typ.size+len(typ.extraData)))
   899  						copy(icmpH[typ.size:], typ.extraData)
   900  						icmpH.SetType(typ.typ)
   901  						icmpH.SetCode(test.code)
   902  						icmpH.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   903  							Header:      icmpH[:typ.size],
   904  							Src:         lladdr0,
   905  							Dst:         lladdr1,
   906  							PayloadCsum: checksum.Checksum(typ.extraData /* initial */, 0),
   907  							PayloadLen:  len(typ.extraData),
   908  						}))
   909  
   910  						// Rx count of the NDP message should initially be 0.
   911  						if got := typStat.Value(); got != 0 {
   912  							t.Errorf("got %s = %d, want = 0", typ.name, got)
   913  						}
   914  
   915  						// Invalid count should initially be 0.
   916  						if got := invalid.Value(); got != 0 {
   917  							t.Errorf("got invalid.Value() = %d, want = 0", got)
   918  						}
   919  
   920  						// Should initially not have dropped any packets.
   921  						if got := routerOnly.Value(); got != 0 {
   922  							t.Errorf("got routerOnly.Value() = %d, want = 0", got)
   923  						}
   924  
   925  						if t.Failed() {
   926  							t.FailNow()
   927  						}
   928  
   929  						handleIPv6Payload(icmpH, test.hopLimit, test.atomicFragment, ep)
   930  
   931  						// Rx count of the NDP packet should have increased.
   932  						if got := typStat.Value(); got != 1 {
   933  							t.Errorf("got %s = %d, want = 1", typ.name, got)
   934  						}
   935  
   936  						want := uint64(0)
   937  						if !test.valid {
   938  							// Invalid count should have increased.
   939  							want = 1
   940  						}
   941  						if got := invalid.Value(); got != want {
   942  							t.Errorf("got invalid.Value() = %d, want = %d", got, want)
   943  						}
   944  
   945  						want = 0
   946  						if test.valid && !isRouter && typ.routerOnly {
   947  							// Router only packets are expected to be dropped when operating
   948  							// as a host.
   949  							want = 1
   950  						}
   951  						if got := routerOnly.Value(); got != want {
   952  							t.Errorf("got routerOnly.Value() = %d, want = %d", got, want)
   953  						}
   954  					})
   955  				}
   956  			})
   957  		}
   958  	}
   959  }
   960  
   961  // TestNeighborAdvertisementValidation tests that the NIC validates received
   962  // Neighbor Advertisements.
   963  //
   964  // In particular, if the IP Destination Address is a multicast address, and the
   965  // Solicited flag is not zero, the Neighbor Advertisement is invalid and should
   966  // be discarded.
   967  func TestNeighborAdvertisementValidation(t *testing.T) {
   968  	tests := []struct {
   969  		name          string
   970  		ipDstAddr     tcpip.Address
   971  		solicitedFlag bool
   972  		valid         bool
   973  	}{
   974  		{
   975  			name:          "Multicast IP destination address with Solicited flag set",
   976  			ipDstAddr:     header.IPv6AllNodesMulticastAddress,
   977  			solicitedFlag: true,
   978  			valid:         false,
   979  		},
   980  		{
   981  			name:          "Multicast IP destination address with Solicited flag unset",
   982  			ipDstAddr:     header.IPv6AllNodesMulticastAddress,
   983  			solicitedFlag: false,
   984  			valid:         true,
   985  		},
   986  		{
   987  			name:          "Unicast IP destination address with Solicited flag set",
   988  			ipDstAddr:     lladdr0,
   989  			solicitedFlag: true,
   990  			valid:         true,
   991  		},
   992  		{
   993  			name:          "Unicast IP destination address with Solicited flag unset",
   994  			ipDstAddr:     lladdr0,
   995  			solicitedFlag: false,
   996  			valid:         true,
   997  		},
   998  	}
   999  
  1000  	for _, test := range tests {
  1001  		t.Run(test.name, func(t *testing.T) {
  1002  			c := newTestContext()
  1003  			defer c.cleanup()
  1004  			s := c.s
  1005  
  1006  			e := channel.New(0, header.IPv6MinimumMTU, linkAddr0)
  1007  			defer e.Close()
  1008  			e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
  1009  			if err := s.CreateNIC(nicID, e); err != nil {
  1010  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  1011  			}
  1012  			protocolAddr := tcpip.ProtocolAddress{
  1013  				Protocol:          ProtocolNumber,
  1014  				AddressWithPrefix: lladdr0.WithPrefix(),
  1015  			}
  1016  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  1017  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  1018  			}
  1019  
  1020  			ndpNASize := header.ICMPv6NeighborAdvertMinimumSize
  1021  			hdr := prependable.New(header.IPv6MinimumSize + ndpNASize)
  1022  			pkt := header.ICMPv6(hdr.Prepend(ndpNASize))
  1023  			pkt.SetType(header.ICMPv6NeighborAdvert)
  1024  			na := header.NDPNeighborAdvert(pkt.MessageBody())
  1025  			na.SetTargetAddress(lladdr1)
  1026  			na.SetSolicitedFlag(test.solicitedFlag)
  1027  			pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  1028  				Header: pkt,
  1029  				Src:    lladdr1,
  1030  				Dst:    test.ipDstAddr,
  1031  			}))
  1032  			payloadLength := hdr.UsedLength()
  1033  			ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  1034  			ip.Encode(&header.IPv6Fields{
  1035  				PayloadLength:     uint16(payloadLength),
  1036  				TransportProtocol: header.ICMPv6ProtocolNumber,
  1037  				HopLimit:          255,
  1038  				SrcAddr:           lladdr1,
  1039  				DstAddr:           test.ipDstAddr,
  1040  			})
  1041  
  1042  			stats := s.Stats().ICMP.V6.PacketsReceived
  1043  			invalid := stats.Invalid
  1044  			rxNA := stats.NeighborAdvert
  1045  
  1046  			if got := rxNA.Value(); got != 0 {
  1047  				t.Fatalf("got rxNA = %d, want = 0", got)
  1048  			}
  1049  			if got := invalid.Value(); got != 0 {
  1050  				t.Fatalf("got invalid = %d, want = 0", got)
  1051  			}
  1052  
  1053  			pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
  1054  				Payload: buffer.MakeWithData(hdr.View()),
  1055  			})
  1056  			e.InjectInbound(header.IPv6ProtocolNumber, pktBuf)
  1057  			pktBuf.DecRef()
  1058  
  1059  			if got := rxNA.Value(); got != 1 {
  1060  				t.Fatalf("got rxNA = %d, want = 1", got)
  1061  			}
  1062  			var wantInvalid uint64 = 1
  1063  			if test.valid {
  1064  				wantInvalid = 0
  1065  			}
  1066  			if got := invalid.Value(); got != wantInvalid {
  1067  				t.Fatalf("got invalid = %d, want = %d", got, wantInvalid)
  1068  			}
  1069  			// As per RFC 4861 section 7.2.5:
  1070  			//   When a valid Neighbor Advertisement is received ...
  1071  			//   If no entry exists, the advertisement SHOULD be silently discarded.
  1072  			//   There is no need to create an entry if none exists, since the
  1073  			//   recipient has apparently not initiated any communication with the
  1074  			//   target.
  1075  			if neighbors, err := s.Neighbors(nicID, ProtocolNumber); err != nil {
  1076  				t.Fatalf("s.Neighbors(%d, %d): %s", nicID, ProtocolNumber, err)
  1077  			} else if len(neighbors) != 0 {
  1078  				t.Fatalf("got len(neighbors) = %d, want = 0; neighbors = %#v", len(neighbors), neighbors)
  1079  			}
  1080  		})
  1081  	}
  1082  }
  1083  
  1084  // TestRouterAdvertValidation tests that when the NIC is configured to handle
  1085  // NDP Router Advertisement packets, it validates the Router Advertisement
  1086  // properly before handling them.
  1087  func TestRouterAdvertValidation(t *testing.T) {
  1088  	tests := []struct {
  1089  		name            string
  1090  		src             tcpip.Address
  1091  		hopLimit        uint8
  1092  		code            header.ICMPv6Code
  1093  		ndpPayload      []byte
  1094  		expectedSuccess bool
  1095  	}{
  1096  		{
  1097  			"OK",
  1098  			lladdr0,
  1099  			255,
  1100  			0,
  1101  			[]byte{
  1102  				0, 0, 0, 0,
  1103  				0, 0, 0, 0,
  1104  				0, 0, 0, 0,
  1105  			},
  1106  			true,
  1107  		},
  1108  		{
  1109  			"NonLinkLocalSourceAddr",
  1110  			addr1,
  1111  			255,
  1112  			0,
  1113  			[]byte{
  1114  				0, 0, 0, 0,
  1115  				0, 0, 0, 0,
  1116  				0, 0, 0, 0,
  1117  			},
  1118  			false,
  1119  		},
  1120  		{
  1121  			"HopLimitNot255",
  1122  			lladdr0,
  1123  			254,
  1124  			0,
  1125  			[]byte{
  1126  				0, 0, 0, 0,
  1127  				0, 0, 0, 0,
  1128  				0, 0, 0, 0,
  1129  			},
  1130  			false,
  1131  		},
  1132  		{
  1133  			"NonZeroCode",
  1134  			lladdr0,
  1135  			255,
  1136  			1,
  1137  			[]byte{
  1138  				0, 0, 0, 0,
  1139  				0, 0, 0, 0,
  1140  				0, 0, 0, 0,
  1141  			},
  1142  			false,
  1143  		},
  1144  		{
  1145  			"NDPPayloadTooSmall",
  1146  			lladdr0,
  1147  			255,
  1148  			0,
  1149  			[]byte{
  1150  				0, 0, 0, 0,
  1151  				0, 0, 0, 0,
  1152  				0, 0, 0,
  1153  			},
  1154  			false,
  1155  		},
  1156  		{
  1157  			"OKWithOptions",
  1158  			lladdr0,
  1159  			255,
  1160  			0,
  1161  			[]byte{
  1162  				// RA payload
  1163  				0, 0, 0, 0,
  1164  				0, 0, 0, 0,
  1165  				0, 0, 0, 0,
  1166  
  1167  				// Option #1 (TargetLinkLayerAddress)
  1168  				2, 1, 0, 0, 0, 0, 0, 0,
  1169  
  1170  				// Option #2 (unrecognized)
  1171  				255, 1, 0, 0, 0, 0, 0, 0,
  1172  
  1173  				// Option #3 (PrefixInformation)
  1174  				3, 4, 0, 0, 0, 0, 0, 0,
  1175  				0, 0, 0, 0, 0, 0, 0, 0,
  1176  				0, 0, 0, 0, 0, 0, 0, 0,
  1177  				0, 0, 0, 0, 0, 0, 0, 0,
  1178  			},
  1179  			true,
  1180  		},
  1181  		{
  1182  			"OptionWithZeroLength",
  1183  			lladdr0,
  1184  			255,
  1185  			0,
  1186  			[]byte{
  1187  				// RA payload
  1188  				0, 0, 0, 0,
  1189  				0, 0, 0, 0,
  1190  				0, 0, 0, 0,
  1191  
  1192  				// Option #1 (TargetLinkLayerAddress)
  1193  				// Invalid as it has 0 length.
  1194  				2, 0, 0, 0, 0, 0, 0, 0,
  1195  
  1196  				// Option #2 (unrecognized)
  1197  				255, 1, 0, 0, 0, 0, 0, 0,
  1198  
  1199  				// Option #3 (PrefixInformation)
  1200  				3, 4, 0, 0, 0, 0, 0, 0,
  1201  				0, 0, 0, 0, 0, 0, 0, 0,
  1202  				0, 0, 0, 0, 0, 0, 0, 0,
  1203  				0, 0, 0, 0, 0, 0, 0, 0,
  1204  			},
  1205  			false,
  1206  		},
  1207  	}
  1208  
  1209  	for _, test := range tests {
  1210  		t.Run(test.name, func(t *testing.T) {
  1211  			c := newTestContext()
  1212  			defer c.cleanup()
  1213  			s := c.s
  1214  
  1215  			e := channel.New(10, 1280, linkAddr1)
  1216  			defer e.Close()
  1217  			e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
  1218  			if err := s.CreateNIC(1, e); err != nil {
  1219  				t.Fatalf("CreateNIC(_) = %s", err)
  1220  			}
  1221  
  1222  			icmpSize := header.ICMPv6HeaderSize + len(test.ndpPayload)
  1223  			hdr := prependable.New(header.IPv6MinimumSize + icmpSize)
  1224  			pkt := header.ICMPv6(hdr.Prepend(icmpSize))
  1225  			pkt.SetType(header.ICMPv6RouterAdvert)
  1226  			pkt.SetCode(test.code)
  1227  			copy(pkt.MessageBody(), test.ndpPayload)
  1228  			payloadLength := hdr.UsedLength()
  1229  			pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  1230  				Header: pkt,
  1231  				Src:    test.src,
  1232  				Dst:    header.IPv6AllNodesMulticastAddress,
  1233  			}))
  1234  			ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  1235  			ip.Encode(&header.IPv6Fields{
  1236  				PayloadLength:     uint16(payloadLength),
  1237  				TransportProtocol: icmp.ProtocolNumber6,
  1238  				HopLimit:          test.hopLimit,
  1239  				SrcAddr:           test.src,
  1240  				DstAddr:           header.IPv6AllNodesMulticastAddress,
  1241  			})
  1242  
  1243  			stats := s.Stats().ICMP.V6.PacketsReceived
  1244  			invalid := stats.Invalid
  1245  			rxRA := stats.RouterAdvert
  1246  
  1247  			if got := invalid.Value(); got != 0 {
  1248  				t.Fatalf("got invalid = %d, want = 0", got)
  1249  			}
  1250  			if got := rxRA.Value(); got != 0 {
  1251  				t.Fatalf("got rxRA = %d, want = 0", got)
  1252  			}
  1253  
  1254  			pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
  1255  				Payload: buffer.MakeWithData(hdr.View()),
  1256  			})
  1257  			e.InjectInbound(header.IPv6ProtocolNumber, pktBuf)
  1258  			pktBuf.DecRef()
  1259  
  1260  			if got := rxRA.Value(); got != 1 {
  1261  				t.Fatalf("got rxRA = %d, want = 1", got)
  1262  			}
  1263  
  1264  			if test.expectedSuccess {
  1265  				if got := invalid.Value(); got != 0 {
  1266  					t.Fatalf("got invalid = %d, want = 0", got)
  1267  				}
  1268  			} else {
  1269  				if got := invalid.Value(); got != 1 {
  1270  					t.Fatalf("got invalid = %d, want = 1", got)
  1271  				}
  1272  			}
  1273  		})
  1274  	}
  1275  }
  1276  
  1277  // TestCheckDuplicateAddress checks that calls to CheckDuplicateAddress and DAD
  1278  // performed when adding new addresses do not interfere with each other.
  1279  func TestCheckDuplicateAddress(t *testing.T) {
  1280  	const nicID = 1
  1281  
  1282  	clock := faketime.NewManualClock()
  1283  	dadConfigs := stack.DADConfigurations{
  1284  		DupAddrDetectTransmits: 1,
  1285  		RetransmitTimer:        time.Second,
  1286  	}
  1287  
  1288  	s := stack.New(stack.Options{
  1289  		Clock:      clock,
  1290  		RandSource: rand.NewSource(time.Now().UnixNano()),
  1291  		NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocolWithOptions(Options{
  1292  			DADConfigs: dadConfigs,
  1293  		})},
  1294  	})
  1295  	defer func() {
  1296  		s.Close()
  1297  		s.Wait()
  1298  	}()
  1299  
  1300  	// This test is expected to send at max 2 DAD messages. We allow an extra
  1301  	// packet to be stored to catch unexpected packets.
  1302  	e := channel.New(3, header.IPv6MinimumMTU, linkAddr0)
  1303  	defer e.Close()
  1304  	e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
  1305  	if err := s.CreateNIC(nicID, e); err != nil {
  1306  		t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  1307  	}
  1308  
  1309  	dadPacketsSent := 0
  1310  	snmc := header.SolicitedNodeAddr(lladdr0)
  1311  	remoteLinkAddr := header.EthernetAddressFromMulticastIPv6Address(snmc)
  1312  	checkDADMsg := func() {
  1313  		clock.RunImmediatelyScheduledJobs()
  1314  		p := e.Read()
  1315  		if p == nil {
  1316  			t.Fatalf("expected %d-th DAD message", dadPacketsSent)
  1317  		}
  1318  		defer p.DecRef()
  1319  
  1320  		if p.NetworkProtocolNumber != header.IPv6ProtocolNumber {
  1321  			t.Errorf("(i=%d) got p.NetworkProtocolNumber = %d, want = %d", dadPacketsSent, p.NetworkProtocolNumber, header.IPv6ProtocolNumber)
  1322  		}
  1323  
  1324  		if p.EgressRoute.RemoteLinkAddress != remoteLinkAddr {
  1325  			t.Errorf("(i=%d) got p.EgressRoute.RemoteLinkAddress = %s, want = %s", dadPacketsSent, p.EgressRoute.RemoteLinkAddress, remoteLinkAddr)
  1326  		}
  1327  
  1328  		payload := stack.PayloadSince(p.NetworkHeader())
  1329  		defer payload.Release()
  1330  		checker.IPv6(t, payload,
  1331  			checker.SrcAddr(header.IPv6Any),
  1332  			checker.DstAddr(snmc),
  1333  			checker.TTL(header.NDPHopLimit),
  1334  			checker.NDPNS(
  1335  				checker.NDPNSTargetAddress(lladdr0),
  1336  			))
  1337  	}
  1338  	protocolAddr := tcpip.ProtocolAddress{
  1339  		Protocol:          ProtocolNumber,
  1340  		AddressWithPrefix: lladdr0.WithPrefix(),
  1341  	}
  1342  	if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  1343  		t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  1344  	}
  1345  	checkDADMsg()
  1346  
  1347  	// Start DAD for the address we just added.
  1348  	//
  1349  	// Even though the stack will perform DAD before the added address transitions
  1350  	// from tentative to assigned, this DAD request should be independent of that.
  1351  	ch := make(chan stack.DADResult, 3)
  1352  	dadRequestsMade := 1
  1353  	dadPacketsSent++
  1354  	if res, err := s.CheckDuplicateAddress(nicID, ProtocolNumber, lladdr0, func(r stack.DADResult) {
  1355  		ch <- r
  1356  	}); err != nil {
  1357  		t.Fatalf("s.CheckDuplicateAddress(%d, %d, %s, _): %s", nicID, ProtocolNumber, lladdr0, err)
  1358  	} else if res != stack.DADStarting {
  1359  		t.Fatalf("got s.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", nicID, ProtocolNumber, lladdr0, res, stack.DADStarting)
  1360  	}
  1361  	checkDADMsg()
  1362  
  1363  	// Remove the address and make sure our DAD request was not stopped.
  1364  	if err := s.RemoveAddress(nicID, lladdr0); err != nil {
  1365  		t.Fatalf("RemoveAddress(%d, %s): %s", nicID, lladdr0, err)
  1366  	}
  1367  	// Should not restart DAD since we already requested DAD above - the handler
  1368  	// should be called when the original request completes so we should not send
  1369  	// an extra DAD message here.
  1370  	dadRequestsMade++
  1371  	if res, err := s.CheckDuplicateAddress(nicID, ProtocolNumber, lladdr0, func(r stack.DADResult) {
  1372  		ch <- r
  1373  	}); err != nil {
  1374  		t.Fatalf("s.CheckDuplicateAddress(%d, %d, %s, _): %s", nicID, ProtocolNumber, lladdr0, err)
  1375  	} else if res != stack.DADAlreadyRunning {
  1376  		t.Fatalf("got s.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", nicID, ProtocolNumber, lladdr0, res, stack.DADAlreadyRunning)
  1377  	}
  1378  
  1379  	// Wait for DAD to complete.
  1380  	clock.Advance(time.Duration(dadConfigs.DupAddrDetectTransmits) * dadConfigs.RetransmitTimer)
  1381  	for i := 0; i < dadRequestsMade; i++ {
  1382  		if diff := cmp.Diff(&stack.DADSucceeded{}, <-ch); diff != "" {
  1383  			t.Errorf("(i=%d) DAD result mismatch (-want +got):\n%s", i, diff)
  1384  		}
  1385  	}
  1386  	// Should have no more results.
  1387  	select {
  1388  	case r := <-ch:
  1389  		t.Errorf("unexpectedly got an extra DAD result; r = %#v", r)
  1390  	default:
  1391  	}
  1392  
  1393  	// Should have no more packets.
  1394  	if p := e.Read(); p != nil {
  1395  		t.Errorf("got unexpected packet = %#v", p)
  1396  	}
  1397  }