github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/tcpip/network/ip_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 ip_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/google/netstack/tcpip"
    21  	"github.com/google/netstack/tcpip/buffer"
    22  	"github.com/google/netstack/tcpip/header"
    23  	"github.com/google/netstack/tcpip/link/loopback"
    24  	"github.com/google/netstack/tcpip/network/ipv4"
    25  	"github.com/google/netstack/tcpip/network/ipv6"
    26  	"github.com/google/netstack/tcpip/stack"
    27  	"github.com/google/netstack/tcpip/transport/tcp"
    28  	"github.com/google/netstack/tcpip/transport/udp"
    29  )
    30  
    31  const (
    32  	localIpv4Addr      = "\x0a\x00\x00\x01"
    33  	localIpv4PrefixLen = 24
    34  	remoteIpv4Addr     = "\x0a\x00\x00\x02"
    35  	ipv4SubnetAddr     = "\x0a\x00\x00\x00"
    36  	ipv4SubnetMask     = "\xff\xff\xff\x00"
    37  	ipv4Gateway        = "\x0a\x00\x00\x03"
    38  	localIpv6Addr      = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
    39  	localIpv6PrefixLen = 120
    40  	remoteIpv6Addr     = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
    41  	ipv6SubnetAddr     = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    42  	ipv6SubnetMask     = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00"
    43  	ipv6Gateway        = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"
    44  )
    45  
    46  // testObject implements two interfaces: LinkEndpoint and TransportDispatcher.
    47  // The former is used to pretend that it's a link endpoint so that we can
    48  // inspect packets written by the network endpoints. The latter is used to
    49  // pretend that it's the network stack so that it can inspect incoming packets
    50  // that have been handled by the network endpoints.
    51  //
    52  // Packets are checked by comparing their fields/values against the expected
    53  // values stored in the test object itself.
    54  type testObject struct {
    55  	t        *testing.T
    56  	protocol tcpip.TransportProtocolNumber
    57  	contents []byte
    58  	srcAddr  tcpip.Address
    59  	dstAddr  tcpip.Address
    60  	v4       bool
    61  	typ      stack.ControlType
    62  	extra    uint32
    63  
    64  	dataCalls    int
    65  	controlCalls int
    66  }
    67  
    68  // checkValues verifies that the transport protocol, data contents, src & dst
    69  // addresses of a packet match what's expected. If any field doesn't match, the
    70  // test fails.
    71  func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, vv buffer.VectorisedView, srcAddr, dstAddr tcpip.Address) {
    72  	v := vv.ToView()
    73  	if protocol != t.protocol {
    74  		t.t.Errorf("protocol = %v, want %v", protocol, t.protocol)
    75  	}
    76  
    77  	if srcAddr != t.srcAddr {
    78  		t.t.Errorf("srcAddr = %v, want %v", srcAddr, t.srcAddr)
    79  	}
    80  
    81  	if dstAddr != t.dstAddr {
    82  		t.t.Errorf("dstAddr = %v, want %v", dstAddr, t.dstAddr)
    83  	}
    84  
    85  	if len(v) != len(t.contents) {
    86  		t.t.Fatalf("len(payload) = %v, want %v", len(v), len(t.contents))
    87  	}
    88  
    89  	for i := range t.contents {
    90  		if t.contents[i] != v[i] {
    91  			t.t.Fatalf("payload[%v] = %v, want %v", i, v[i], t.contents[i])
    92  		}
    93  	}
    94  }
    95  
    96  // DeliverTransportPacket is called by network endpoints after parsing incoming
    97  // packets. This is used by the test object to verify that the results of the
    98  // parsing are expected.
    99  func (t *testObject) DeliverTransportPacket(r *stack.Route, protocol tcpip.TransportProtocolNumber, pkt tcpip.PacketBuffer) {
   100  	t.checkValues(protocol, pkt.Data, r.RemoteAddress, r.LocalAddress)
   101  	t.dataCalls++
   102  }
   103  
   104  // DeliverTransportControlPacket is called by network endpoints after parsing
   105  // incoming control (ICMP) packets. This is used by the test object to verify
   106  // that the results of the parsing are expected.
   107  func (t *testObject) DeliverTransportControlPacket(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, typ stack.ControlType, extra uint32, pkt tcpip.PacketBuffer) {
   108  	t.checkValues(trans, pkt.Data, remote, local)
   109  	if typ != t.typ {
   110  		t.t.Errorf("typ = %v, want %v", typ, t.typ)
   111  	}
   112  	if extra != t.extra {
   113  		t.t.Errorf("extra = %v, want %v", extra, t.extra)
   114  	}
   115  	t.controlCalls++
   116  }
   117  
   118  // Attach is only implemented to satisfy the LinkEndpoint interface.
   119  func (*testObject) Attach(stack.NetworkDispatcher) {}
   120  
   121  // IsAttached implements stack.LinkEndpoint.IsAttached.
   122  func (*testObject) IsAttached() bool {
   123  	return true
   124  }
   125  
   126  // MTU implements stack.LinkEndpoint.MTU. It just returns a constant that
   127  // matches the linux loopback MTU.
   128  func (*testObject) MTU() uint32 {
   129  	return 65536
   130  }
   131  
   132  // Capabilities implements stack.LinkEndpoint.Capabilities.
   133  func (*testObject) Capabilities() stack.LinkEndpointCapabilities {
   134  	return 0
   135  }
   136  
   137  // MaxHeaderLength is only implemented to satisfy the LinkEndpoint interface.
   138  func (*testObject) MaxHeaderLength() uint16 {
   139  	return 0
   140  }
   141  
   142  // LinkAddress returns the link address of this endpoint.
   143  func (*testObject) LinkAddress() tcpip.LinkAddress {
   144  	return ""
   145  }
   146  
   147  // Wait implements stack.LinkEndpoint.Wait.
   148  func (*testObject) Wait() {}
   149  
   150  // WritePacket is called by network endpoints after producing a packet and
   151  // writing it to the link endpoint. This is used by the test object to verify
   152  // that the produced packet is as expected.
   153  func (t *testObject) WritePacket(_ *stack.Route, _ *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) *tcpip.Error {
   154  	var prot tcpip.TransportProtocolNumber
   155  	var srcAddr tcpip.Address
   156  	var dstAddr tcpip.Address
   157  
   158  	if t.v4 {
   159  		h := header.IPv4(pkt.Header.View())
   160  		prot = tcpip.TransportProtocolNumber(h.Protocol())
   161  		srcAddr = h.SourceAddress()
   162  		dstAddr = h.DestinationAddress()
   163  
   164  	} else {
   165  		h := header.IPv6(pkt.Header.View())
   166  		prot = tcpip.TransportProtocolNumber(h.NextHeader())
   167  		srcAddr = h.SourceAddress()
   168  		dstAddr = h.DestinationAddress()
   169  	}
   170  	t.checkValues(prot, pkt.Data, srcAddr, dstAddr)
   171  	return nil
   172  }
   173  
   174  // WritePackets implements stack.LinkEndpoint.WritePackets.
   175  func (t *testObject) WritePackets(_ *stack.Route, _ *stack.GSO, hdr []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
   176  	panic("not implemented")
   177  }
   178  
   179  func (t *testObject) WriteRawPacket(_ buffer.VectorisedView) *tcpip.Error {
   180  	return tcpip.ErrNotSupported
   181  }
   182  
   183  func buildIPv4Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) {
   184  	s := stack.New(stack.Options{
   185  		NetworkProtocols:   []stack.NetworkProtocol{ipv4.NewProtocol()},
   186  		TransportProtocols: []stack.TransportProtocol{udp.NewProtocol(), tcp.NewProtocol()},
   187  	})
   188  	s.CreateNIC(1, loopback.New())
   189  	s.AddAddress(1, ipv4.ProtocolNumber, local)
   190  	s.SetRouteTable([]tcpip.Route{{
   191  		Destination: header.IPv4EmptySubnet,
   192  		Gateway:     ipv4Gateway,
   193  		NIC:         1,
   194  	}})
   195  
   196  	return s.FindRoute(1, local, remote, ipv4.ProtocolNumber, false /* multicastLoop */)
   197  }
   198  
   199  func buildIPv6Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) {
   200  	s := stack.New(stack.Options{
   201  		NetworkProtocols:   []stack.NetworkProtocol{ipv6.NewProtocol()},
   202  		TransportProtocols: []stack.TransportProtocol{udp.NewProtocol(), tcp.NewProtocol()},
   203  	})
   204  	s.CreateNIC(1, loopback.New())
   205  	s.AddAddress(1, ipv6.ProtocolNumber, local)
   206  	s.SetRouteTable([]tcpip.Route{{
   207  		Destination: header.IPv6EmptySubnet,
   208  		Gateway:     ipv6Gateway,
   209  		NIC:         1,
   210  	}})
   211  
   212  	return s.FindRoute(1, local, remote, ipv6.ProtocolNumber, false /* multicastLoop */)
   213  }
   214  
   215  func TestIPv4Send(t *testing.T) {
   216  	o := testObject{t: t, v4: true}
   217  	proto := ipv4.NewProtocol()
   218  	ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, nil, &o)
   219  	if err != nil {
   220  		t.Fatalf("NewEndpoint failed: %v", err)
   221  	}
   222  
   223  	// Allocate and initialize the payload view.
   224  	payload := buffer.NewView(100)
   225  	for i := 0; i < len(payload); i++ {
   226  		payload[i] = uint8(i)
   227  	}
   228  
   229  	// Allocate the header buffer.
   230  	hdr := buffer.NewPrependable(int(ep.MaxHeaderLength()))
   231  
   232  	// Issue the write.
   233  	o.protocol = 123
   234  	o.srcAddr = localIpv4Addr
   235  	o.dstAddr = remoteIpv4Addr
   236  	o.contents = payload
   237  
   238  	r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr)
   239  	if err != nil {
   240  		t.Fatalf("could not find route: %v", err)
   241  	}
   242  	if err := ep.WritePacket(&r, nil /* gso */, stack.NetworkHeaderParams{Protocol: 123, TTL: 123, TOS: stack.DefaultTOS}, stack.PacketOut, tcpip.PacketBuffer{
   243  		Header: hdr,
   244  		Data:   payload.ToVectorisedView(),
   245  	}); err != nil {
   246  		t.Fatalf("WritePacket failed: %v", err)
   247  	}
   248  }
   249  
   250  func TestIPv4Receive(t *testing.T) {
   251  	o := testObject{t: t, v4: true}
   252  	proto := ipv4.NewProtocol()
   253  	ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil)
   254  	if err != nil {
   255  		t.Fatalf("NewEndpoint failed: %v", err)
   256  	}
   257  
   258  	totalLen := header.IPv4MinimumSize + 30
   259  	view := buffer.NewView(totalLen)
   260  	ip := header.IPv4(view)
   261  	ip.Encode(&header.IPv4Fields{
   262  		IHL:         header.IPv4MinimumSize,
   263  		TotalLength: uint16(totalLen),
   264  		TTL:         20,
   265  		Protocol:    10,
   266  		SrcAddr:     remoteIpv4Addr,
   267  		DstAddr:     localIpv4Addr,
   268  	})
   269  
   270  	// Make payload be non-zero.
   271  	for i := header.IPv4MinimumSize; i < totalLen; i++ {
   272  		view[i] = uint8(i)
   273  	}
   274  
   275  	// Give packet to ipv4 endpoint, dispatcher will validate that it's ok.
   276  	o.protocol = 10
   277  	o.srcAddr = remoteIpv4Addr
   278  	o.dstAddr = localIpv4Addr
   279  	o.contents = view[header.IPv4MinimumSize:totalLen]
   280  
   281  	r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr)
   282  	if err != nil {
   283  		t.Fatalf("could not find route: %v", err)
   284  	}
   285  	ep.HandlePacket(&r, tcpip.PacketBuffer{
   286  		Data: view.ToVectorisedView(),
   287  	})
   288  	if o.dataCalls != 1 {
   289  		t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls)
   290  	}
   291  }
   292  
   293  func TestIPv4ReceiveControl(t *testing.T) {
   294  	const mtu = 0xbeef - header.IPv4MinimumSize
   295  	cases := []struct {
   296  		name           string
   297  		expectedCount  int
   298  		fragmentOffset uint16
   299  		code           uint8
   300  		expectedTyp    stack.ControlType
   301  		expectedExtra  uint32
   302  		trunc          int
   303  	}{
   304  		{"FragmentationNeeded", 1, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 0},
   305  		{"Truncated (10 bytes missing)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 10},
   306  		{"Truncated (missing IPv4 header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.IPv4MinimumSize + 8},
   307  		{"Truncated (missing 'extra info')", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 4 + header.IPv4MinimumSize + 8},
   308  		{"Truncated (missing ICMP header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.ICMPv4MinimumSize + header.IPv4MinimumSize + 8},
   309  		{"Port unreachable", 1, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0},
   310  		{"Non-zero fragment offset", 0, 100, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0},
   311  		{"Zero-length packet", 0, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv4MinimumSize + header.ICMPv4MinimumSize + 8},
   312  	}
   313  	r, err := buildIPv4Route(localIpv4Addr, "\x0a\x00\x00\xbb")
   314  	if err != nil {
   315  		t.Fatal(err)
   316  	}
   317  	for _, c := range cases {
   318  		t.Run(c.name, func(t *testing.T) {
   319  			o := testObject{t: t}
   320  			proto := ipv4.NewProtocol()
   321  			ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil)
   322  			if err != nil {
   323  				t.Fatalf("NewEndpoint failed: %v", err)
   324  			}
   325  			defer ep.Close()
   326  
   327  			const dataOffset = header.IPv4MinimumSize*2 + header.ICMPv4MinimumSize
   328  			view := buffer.NewView(dataOffset + 8)
   329  
   330  			// Create the outer IPv4 header.
   331  			ip := header.IPv4(view)
   332  			ip.Encode(&header.IPv4Fields{
   333  				IHL:         header.IPv4MinimumSize,
   334  				TotalLength: uint16(len(view) - c.trunc),
   335  				TTL:         20,
   336  				Protocol:    uint8(header.ICMPv4ProtocolNumber),
   337  				SrcAddr:     "\x0a\x00\x00\xbb",
   338  				DstAddr:     localIpv4Addr,
   339  			})
   340  
   341  			// Create the ICMP header.
   342  			icmp := header.ICMPv4(view[header.IPv4MinimumSize:])
   343  			icmp.SetType(header.ICMPv4DstUnreachable)
   344  			icmp.SetCode(c.code)
   345  			icmp.SetIdent(0xdead)
   346  			icmp.SetSequence(0xbeef)
   347  
   348  			// Create the inner IPv4 header.
   349  			ip = header.IPv4(view[header.IPv4MinimumSize+header.ICMPv4MinimumSize:])
   350  			ip.Encode(&header.IPv4Fields{
   351  				IHL:            header.IPv4MinimumSize,
   352  				TotalLength:    100,
   353  				TTL:            20,
   354  				Protocol:       10,
   355  				FragmentOffset: c.fragmentOffset,
   356  				SrcAddr:        localIpv4Addr,
   357  				DstAddr:        remoteIpv4Addr,
   358  			})
   359  
   360  			// Make payload be non-zero.
   361  			for i := dataOffset; i < len(view); i++ {
   362  				view[i] = uint8(i)
   363  			}
   364  
   365  			// Give packet to IPv4 endpoint, dispatcher will validate that
   366  			// it's ok.
   367  			o.protocol = 10
   368  			o.srcAddr = remoteIpv4Addr
   369  			o.dstAddr = localIpv4Addr
   370  			o.contents = view[dataOffset:]
   371  			o.typ = c.expectedTyp
   372  			o.extra = c.expectedExtra
   373  
   374  			vv := view[:len(view)-c.trunc].ToVectorisedView()
   375  			ep.HandlePacket(&r, tcpip.PacketBuffer{
   376  				Data: vv,
   377  			})
   378  			if want := c.expectedCount; o.controlCalls != want {
   379  				t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, o.controlCalls, want)
   380  			}
   381  		})
   382  	}
   383  }
   384  
   385  func TestIPv4FragmentationReceive(t *testing.T) {
   386  	o := testObject{t: t, v4: true}
   387  	proto := ipv4.NewProtocol()
   388  	ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil)
   389  	if err != nil {
   390  		t.Fatalf("NewEndpoint failed: %v", err)
   391  	}
   392  
   393  	totalLen := header.IPv4MinimumSize + 24
   394  
   395  	frag1 := buffer.NewView(totalLen)
   396  	ip1 := header.IPv4(frag1)
   397  	ip1.Encode(&header.IPv4Fields{
   398  		IHL:            header.IPv4MinimumSize,
   399  		TotalLength:    uint16(totalLen),
   400  		TTL:            20,
   401  		Protocol:       10,
   402  		FragmentOffset: 0,
   403  		Flags:          header.IPv4FlagMoreFragments,
   404  		SrcAddr:        remoteIpv4Addr,
   405  		DstAddr:        localIpv4Addr,
   406  	})
   407  	// Make payload be non-zero.
   408  	for i := header.IPv4MinimumSize; i < totalLen; i++ {
   409  		frag1[i] = uint8(i)
   410  	}
   411  
   412  	frag2 := buffer.NewView(totalLen)
   413  	ip2 := header.IPv4(frag2)
   414  	ip2.Encode(&header.IPv4Fields{
   415  		IHL:            header.IPv4MinimumSize,
   416  		TotalLength:    uint16(totalLen),
   417  		TTL:            20,
   418  		Protocol:       10,
   419  		FragmentOffset: 24,
   420  		SrcAddr:        remoteIpv4Addr,
   421  		DstAddr:        localIpv4Addr,
   422  	})
   423  	// Make payload be non-zero.
   424  	for i := header.IPv4MinimumSize; i < totalLen; i++ {
   425  		frag2[i] = uint8(i)
   426  	}
   427  
   428  	// Give packet to ipv4 endpoint, dispatcher will validate that it's ok.
   429  	o.protocol = 10
   430  	o.srcAddr = remoteIpv4Addr
   431  	o.dstAddr = localIpv4Addr
   432  	o.contents = append(frag1[header.IPv4MinimumSize:totalLen], frag2[header.IPv4MinimumSize:totalLen]...)
   433  
   434  	r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr)
   435  	if err != nil {
   436  		t.Fatalf("could not find route: %v", err)
   437  	}
   438  
   439  	// Send first segment.
   440  	ep.HandlePacket(&r, tcpip.PacketBuffer{
   441  		Data: frag1.ToVectorisedView(),
   442  	})
   443  	if o.dataCalls != 0 {
   444  		t.Fatalf("Bad number of data calls: got %x, want 0", o.dataCalls)
   445  	}
   446  
   447  	// Send second segment.
   448  	ep.HandlePacket(&r, tcpip.PacketBuffer{
   449  		Data: frag2.ToVectorisedView(),
   450  	})
   451  	if o.dataCalls != 1 {
   452  		t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls)
   453  	}
   454  }
   455  
   456  func TestIPv6Send(t *testing.T) {
   457  	o := testObject{t: t}
   458  	proto := ipv6.NewProtocol()
   459  	ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, nil, &o)
   460  	if err != nil {
   461  		t.Fatalf("NewEndpoint failed: %v", err)
   462  	}
   463  
   464  	// Allocate and initialize the payload view.
   465  	payload := buffer.NewView(100)
   466  	for i := 0; i < len(payload); i++ {
   467  		payload[i] = uint8(i)
   468  	}
   469  
   470  	// Allocate the header buffer.
   471  	hdr := buffer.NewPrependable(int(ep.MaxHeaderLength()))
   472  
   473  	// Issue the write.
   474  	o.protocol = 123
   475  	o.srcAddr = localIpv6Addr
   476  	o.dstAddr = remoteIpv6Addr
   477  	o.contents = payload
   478  
   479  	r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr)
   480  	if err != nil {
   481  		t.Fatalf("could not find route: %v", err)
   482  	}
   483  	if err := ep.WritePacket(&r, nil /* gso */, stack.NetworkHeaderParams{Protocol: 123, TTL: 123, TOS: stack.DefaultTOS}, stack.PacketOut, tcpip.PacketBuffer{
   484  		Header: hdr,
   485  		Data:   payload.ToVectorisedView(),
   486  	}); err != nil {
   487  		t.Fatalf("WritePacket failed: %v", err)
   488  	}
   489  }
   490  
   491  func TestIPv6Receive(t *testing.T) {
   492  	o := testObject{t: t}
   493  	proto := ipv6.NewProtocol()
   494  	ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, &o, nil)
   495  	if err != nil {
   496  		t.Fatalf("NewEndpoint failed: %v", err)
   497  	}
   498  
   499  	totalLen := header.IPv6MinimumSize + 30
   500  	view := buffer.NewView(totalLen)
   501  	ip := header.IPv6(view)
   502  	ip.Encode(&header.IPv6Fields{
   503  		PayloadLength: uint16(totalLen - header.IPv6MinimumSize),
   504  		NextHeader:    10,
   505  		HopLimit:      20,
   506  		SrcAddr:       remoteIpv6Addr,
   507  		DstAddr:       localIpv6Addr,
   508  	})
   509  
   510  	// Make payload be non-zero.
   511  	for i := header.IPv6MinimumSize; i < totalLen; i++ {
   512  		view[i] = uint8(i)
   513  	}
   514  
   515  	// Give packet to ipv6 endpoint, dispatcher will validate that it's ok.
   516  	o.protocol = 10
   517  	o.srcAddr = remoteIpv6Addr
   518  	o.dstAddr = localIpv6Addr
   519  	o.contents = view[header.IPv6MinimumSize:totalLen]
   520  
   521  	r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr)
   522  	if err != nil {
   523  		t.Fatalf("could not find route: %v", err)
   524  	}
   525  
   526  	ep.HandlePacket(&r, tcpip.PacketBuffer{
   527  		Data: view.ToVectorisedView(),
   528  	})
   529  	if o.dataCalls != 1 {
   530  		t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls)
   531  	}
   532  }
   533  
   534  func TestIPv6ReceiveControl(t *testing.T) {
   535  	newUint16 := func(v uint16) *uint16 { return &v }
   536  
   537  	const mtu = 0xffff
   538  	const outerSrcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa"
   539  	cases := []struct {
   540  		name           string
   541  		expectedCount  int
   542  		fragmentOffset *uint16
   543  		typ            header.ICMPv6Type
   544  		code           uint8
   545  		expectedTyp    stack.ControlType
   546  		expectedExtra  uint32
   547  		trunc          int
   548  	}{
   549  		{"PacketTooBig", 1, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 0},
   550  		{"Truncated (10 bytes missing)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 10},
   551  		{"Truncated (missing IPv6 header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.IPv6MinimumSize + 8},
   552  		{"Truncated PacketTooBig (missing 'extra info')", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 4 + header.IPv6MinimumSize + 8},
   553  		{"Truncated (missing ICMP header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.ICMPv6PacketTooBigMinimumSize + header.IPv6MinimumSize + 8},
   554  		{"Port unreachable", 1, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0},
   555  		{"Truncated DstUnreachable (missing 'extra info')", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 4 + header.IPv6MinimumSize + 8},
   556  		{"Fragmented, zero offset", 1, newUint16(0), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0},
   557  		{"Non-zero fragment offset", 0, newUint16(100), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0},
   558  		{"Zero-length packet", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv6MinimumSize + header.ICMPv6DstUnreachableMinimumSize + 8},
   559  	}
   560  	r, err := buildIPv6Route(
   561  		localIpv6Addr,
   562  		"\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa",
   563  	)
   564  	if err != nil {
   565  		t.Fatal(err)
   566  	}
   567  	for _, c := range cases {
   568  		t.Run(c.name, func(t *testing.T) {
   569  			o := testObject{t: t}
   570  			proto := ipv6.NewProtocol()
   571  			ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, &o, nil)
   572  			if err != nil {
   573  				t.Fatalf("NewEndpoint failed: %v", err)
   574  			}
   575  
   576  			defer ep.Close()
   577  
   578  			dataOffset := header.IPv6MinimumSize*2 + header.ICMPv6MinimumSize
   579  			if c.fragmentOffset != nil {
   580  				dataOffset += header.IPv6FragmentHeaderSize
   581  			}
   582  			view := buffer.NewView(dataOffset + 8)
   583  
   584  			// Create the outer IPv6 header.
   585  			ip := header.IPv6(view)
   586  			ip.Encode(&header.IPv6Fields{
   587  				PayloadLength: uint16(len(view) - header.IPv6MinimumSize - c.trunc),
   588  				NextHeader:    uint8(header.ICMPv6ProtocolNumber),
   589  				HopLimit:      20,
   590  				SrcAddr:       outerSrcAddr,
   591  				DstAddr:       localIpv6Addr,
   592  			})
   593  
   594  			// Create the ICMP header.
   595  			icmp := header.ICMPv6(view[header.IPv6MinimumSize:])
   596  			icmp.SetType(c.typ)
   597  			icmp.SetCode(c.code)
   598  			icmp.SetIdent(0xdead)
   599  			icmp.SetSequence(0xbeef)
   600  
   601  			// Create the inner IPv6 header.
   602  			ip = header.IPv6(view[header.IPv6MinimumSize+header.ICMPv6PayloadOffset:])
   603  			ip.Encode(&header.IPv6Fields{
   604  				PayloadLength: 100,
   605  				NextHeader:    10,
   606  				HopLimit:      20,
   607  				SrcAddr:       localIpv6Addr,
   608  				DstAddr:       remoteIpv6Addr,
   609  			})
   610  
   611  			// Build the fragmentation header if needed.
   612  			if c.fragmentOffset != nil {
   613  				ip.SetNextHeader(header.IPv6FragmentHeader)
   614  				frag := header.IPv6Fragment(view[2*header.IPv6MinimumSize+header.ICMPv6MinimumSize:])
   615  				frag.Encode(&header.IPv6FragmentFields{
   616  					NextHeader:     10,
   617  					FragmentOffset: *c.fragmentOffset,
   618  					M:              true,
   619  					Identification: 0x12345678,
   620  				})
   621  			}
   622  
   623  			// Make payload be non-zero.
   624  			for i := dataOffset; i < len(view); i++ {
   625  				view[i] = uint8(i)
   626  			}
   627  
   628  			// Give packet to IPv6 endpoint, dispatcher will validate that
   629  			// it's ok.
   630  			o.protocol = 10
   631  			o.srcAddr = remoteIpv6Addr
   632  			o.dstAddr = localIpv6Addr
   633  			o.contents = view[dataOffset:]
   634  			o.typ = c.expectedTyp
   635  			o.extra = c.expectedExtra
   636  
   637  			// Set ICMPv6 checksum.
   638  			icmp.SetChecksum(header.ICMPv6Checksum(icmp, outerSrcAddr, localIpv6Addr, buffer.VectorisedView{}))
   639  
   640  			ep.HandlePacket(&r, tcpip.PacketBuffer{
   641  				Data: view[:len(view)-c.trunc].ToVectorisedView(),
   642  			})
   643  			if want := c.expectedCount; o.controlCalls != want {
   644  				t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, o.controlCalls, want)
   645  			}
   646  		})
   647  	}
   648  }