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

     1  // Copyright 2021 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 ipv4_test
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/hex"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"math"
    23  	"net"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/google/go-cmp/cmp"
    28  	"github.com/google/go-cmp/cmp/cmpopts"
    29  	"gvisor.dev/gvisor/pkg/buffer"
    30  	"gvisor.dev/gvisor/pkg/refs"
    31  	"gvisor.dev/gvisor/pkg/sync"
    32  	"gvisor.dev/gvisor/pkg/tcpip"
    33  	"gvisor.dev/gvisor/pkg/tcpip/checker"
    34  	"gvisor.dev/gvisor/pkg/tcpip/checksum"
    35  	"gvisor.dev/gvisor/pkg/tcpip/faketime"
    36  	"gvisor.dev/gvisor/pkg/tcpip/header"
    37  	"gvisor.dev/gvisor/pkg/tcpip/link/channel"
    38  	"gvisor.dev/gvisor/pkg/tcpip/link/sniffer"
    39  	"gvisor.dev/gvisor/pkg/tcpip/network/arp"
    40  	iptestutil "gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil"
    41  	"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
    42  	"gvisor.dev/gvisor/pkg/tcpip/prependable"
    43  	"gvisor.dev/gvisor/pkg/tcpip/stack"
    44  	"gvisor.dev/gvisor/pkg/tcpip/testutil"
    45  	"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
    46  	"gvisor.dev/gvisor/pkg/tcpip/transport/raw"
    47  	"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
    48  	"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
    49  	"gvisor.dev/gvisor/pkg/waiter"
    50  )
    51  
    52  const (
    53  	extraHeaderReserve = 50
    54  	defaultMTU         = 65536
    55  )
    56  
    57  type testContext struct {
    58  	s     *stack.Stack
    59  	clock *faketime.ManualClock
    60  }
    61  
    62  var _ stack.MulticastForwardingEventDispatcher = (*fakeMulticastEventDispatcher)(nil)
    63  
    64  type fakeMulticastEventDispatcher struct{}
    65  
    66  func (m *fakeMulticastEventDispatcher) OnMissingRoute(context stack.MulticastPacketContext) {}
    67  
    68  func (m *fakeMulticastEventDispatcher) OnUnexpectedInputInterface(context stack.MulticastPacketContext, expectedInputInterface tcpip.NICID) {
    69  }
    70  
    71  func newTestContext() testContext {
    72  	clock := faketime.NewManualClock()
    73  	s := stack.New(stack.Options{
    74  		NetworkProtocols:   []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
    75  		TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
    76  		Clock:              clock,
    77  		RawFactory:         raw.EndpointFactory{},
    78  	})
    79  	return testContext{s: s, clock: clock}
    80  }
    81  
    82  func (ctx testContext) cleanup() {
    83  	ctx.s.Close()
    84  	ctx.s.Wait()
    85  	refs.DoRepeatedLeakCheck()
    86  }
    87  
    88  func TestExcludeBroadcast(t *testing.T) {
    89  	ctx := newTestContext()
    90  	defer ctx.cleanup()
    91  	s := ctx.s
    92  
    93  	ch := channel.New(256, defaultMTU, "")
    94  	defer ch.Close()
    95  	ep := stack.LinkEndpoint(ch)
    96  	if testing.Verbose() {
    97  		ep = sniffer.New(ep)
    98  	}
    99  	if err := s.CreateNIC(1, ep); err != nil {
   100  		t.Fatalf("CreateNIC failed: %v", err)
   101  	}
   102  
   103  	s.SetRouteTable([]tcpip.Route{{
   104  		Destination: header.IPv4EmptySubnet,
   105  		NIC:         1,
   106  	}})
   107  
   108  	randomAddr := tcpip.FullAddress{NIC: 1, Addr: tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x01")), Port: 53}
   109  
   110  	var wq waiter.Queue
   111  	t.Run("WithoutPrimaryAddress", func(t *testing.T) {
   112  		ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq)
   113  		if err != nil {
   114  			t.Fatal(err)
   115  		}
   116  		defer ep.Close()
   117  
   118  		// Cannot connect using a broadcast address as the source.
   119  		{
   120  			err := ep.Connect(randomAddr)
   121  			if _, ok := err.(*tcpip.ErrHostUnreachable); !ok {
   122  				t.Errorf("got ep.Connect(...) = %v, want = %v", err, &tcpip.ErrHostUnreachable{})
   123  			}
   124  		}
   125  
   126  		// However, we can bind to a broadcast address to listen.
   127  		if err := ep.Bind(tcpip.FullAddress{Addr: header.IPv4Broadcast, Port: 53, NIC: 1}); err != nil {
   128  			t.Errorf("Bind failed: %v", err)
   129  		}
   130  	})
   131  
   132  	t.Run("WithPrimaryAddress", func(t *testing.T) {
   133  		ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq)
   134  		if err != nil {
   135  			t.Fatal(err)
   136  		}
   137  		defer ep.Close()
   138  
   139  		// Add a valid primary endpoint address, now we can connect.
   140  		protocolAddr := tcpip.ProtocolAddress{
   141  			Protocol:          ipv4.ProtocolNumber,
   142  			AddressWithPrefix: tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x02")).WithPrefix(),
   143  		}
   144  		if err := s.AddProtocolAddress(1, protocolAddr, stack.AddressProperties{}); err != nil {
   145  			t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", 1, protocolAddr, err)
   146  		}
   147  		if err := ep.Connect(randomAddr); err != nil {
   148  			t.Errorf("Connect failed: %v", err)
   149  		}
   150  	})
   151  }
   152  
   153  const (
   154  	incomingNICID = 1
   155  	outgoingNICID = 2
   156  )
   157  
   158  var (
   159  	incomingIPv4Addr = tcpip.AddressWithPrefix{
   160  		Address:   testutil.MustParse4("10.0.0.1"),
   161  		PrefixLen: 8,
   162  	}
   163  	outgoingIPv4Addr = tcpip.AddressWithPrefix{
   164  		Address:   testutil.MustParse4("11.0.0.1"),
   165  		PrefixLen: 8,
   166  	}
   167  	defaultEndpointConfigs = map[tcpip.NICID]tcpip.AddressWithPrefix{
   168  		incomingNICID: incomingIPv4Addr,
   169  		outgoingNICID: outgoingIPv4Addr,
   170  	}
   171  	multicastIPv4Addr = testutil.MustParse4("225.0.0.0")
   172  	remoteIPv4Addr1   = testutil.MustParse4("10.0.0.2")
   173  	remoteIPv4Addr2   = testutil.MustParse4("11.0.0.2")
   174  )
   175  
   176  func TestAddMulticastRouteIPv4Errors(t *testing.T) {
   177  	incomingEpSubnet := incomingIPv4Addr.Subnet()
   178  	wantErr := &tcpip.ErrBadAddress{}
   179  
   180  	tests := []struct {
   181  		name    string
   182  		srcAddr tcpip.Address
   183  	}{
   184  		{
   185  			name:    "subnet-local broadcast source",
   186  			srcAddr: incomingEpSubnet.Broadcast().To4(),
   187  		},
   188  		{
   189  			name:    "broadcast source",
   190  			srcAddr: header.IPv4Broadcast,
   191  		},
   192  	}
   193  
   194  	for _, test := range tests {
   195  		t.Run(test.name, func(t *testing.T) {
   196  			ctx := newTestContext()
   197  			defer ctx.cleanup()
   198  			s := ctx.s
   199  
   200  			for nicID, addr := range defaultEndpointConfigs {
   201  				ep := channel.New(1, ipv4.MaxTotalSize, "")
   202  				defer ep.Close()
   203  
   204  				if err := s.CreateNIC(nicID, ep); err != nil {
   205  					t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   206  				}
   207  				addr := tcpip.ProtocolAddress{
   208  					Protocol:          header.IPv4ProtocolNumber,
   209  					AddressWithPrefix: addr,
   210  				}
   211  				if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
   212  					t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err)
   213  				}
   214  			}
   215  
   216  			if _, err := s.EnableMulticastForwardingForProtocol(ipv4.ProtocolNumber, &fakeMulticastEventDispatcher{}); err != nil {
   217  				t.Fatalf("s.EnableMulticastForwardingForProtocol(%d, _): (_, %s)", ipv4.ProtocolNumber, err)
   218  			}
   219  
   220  			outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{{ID: outgoingNICID, MinTTL: 1}}
   221  
   222  			addresses := stack.UnicastSourceAndMulticastDestination{
   223  				Source:      test.srcAddr,
   224  				Destination: multicastIPv4Addr,
   225  			}
   226  
   227  			route := stack.MulticastRoute{
   228  				ExpectedInputInterface: outgoingNICID,
   229  				OutgoingInterfaces:     outgoingInterfaces,
   230  			}
   231  
   232  			err := s.AddMulticastRoute(ipv4.ProtocolNumber, addresses, route)
   233  
   234  			if !cmp.Equal(err, wantErr, cmpopts.EquateErrors()) {
   235  				t.Errorf("got s.AddMulticastRoute(%d, %#v, %#v) = %s, want %s", ipv4.ProtocolNumber, addresses, route, err, wantErr)
   236  			}
   237  		})
   238  	}
   239  }
   240  
   241  type icmpError struct {
   242  	icmpType header.ICMPv4Type
   243  	icmpCode header.ICMPv4Code
   244  }
   245  
   246  type packetOptions struct {
   247  	ipFlags       uint8
   248  	payloadLength int
   249  	options       header.IPv4Options
   250  }
   251  
   252  func newICMPEchoPacket(t *testing.T, srcAddr, dstAddr tcpip.Address, ttl uint8, options packetOptions) (*stack.PacketBuffer, []byte) {
   253  	const (
   254  		arbitraryICMPHeaderSequence = 123
   255  		randomIdent                 = 42
   256  	)
   257  
   258  	t.Helper()
   259  	ipHeaderLength := header.IPv4MinimumSize + len(options.options)
   260  	if ipHeaderLength > header.IPv4MaximumHeaderSize {
   261  		t.Fatalf("ipHeaderLength = %d, want <= %d ", ipHeaderLength, header.IPv4MaximumHeaderSize)
   262  	}
   263  	totalLength := ipHeaderLength + header.ICMPv4MinimumSize + options.payloadLength
   264  	hdr := prependable.New(totalLength)
   265  	hdr.Prepend(options.payloadLength)
   266  	icmpH := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
   267  	icmpH.SetIdent(randomIdent)
   268  	icmpH.SetSequence(arbitraryICMPHeaderSequence)
   269  	icmpH.SetType(header.ICMPv4Echo)
   270  	icmpH.SetCode(header.ICMPv4UnusedCode)
   271  	icmpH.SetChecksum(0)
   272  	icmpH.SetChecksum(^checksum.Checksum(icmpH, 0))
   273  	ip := header.IPv4(hdr.Prepend(ipHeaderLength))
   274  	ip.Encode(&header.IPv4Fields{
   275  		TotalLength: uint16(totalLength),
   276  		Protocol:    uint8(header.ICMPv4ProtocolNumber),
   277  		TTL:         ttl,
   278  		SrcAddr:     srcAddr,
   279  		DstAddr:     dstAddr,
   280  		Flags:       options.ipFlags,
   281  	})
   282  	if len(options.options) != 0 {
   283  		ip.SetHeaderLength(uint8(ipHeaderLength))
   284  		// Copy options manually. We do not use Encode for options so we can
   285  		// verify malformed options with handcrafted payloads.
   286  		if want, got := copy(ip.Options(), options.options), len(options.options); want != got {
   287  			t.Fatalf("got copy(ip.Options(), test.options) = %d, want = %d", got, want)
   288  		}
   289  	}
   290  	ip.SetChecksum(0)
   291  	ip.SetChecksum(^ip.CalculateChecksum())
   292  
   293  	expectedICMPPayloadLength := func() int {
   294  		maxICMPPacketLength := header.IPv4MinimumProcessableDatagramSize
   295  		maxICMPPayloadLength := maxICMPPacketLength - header.ICMPv4MinimumSize - header.IPv4MinimumSize
   296  		if len(hdr.View()) > maxICMPPayloadLength {
   297  			return maxICMPPayloadLength
   298  		}
   299  		return len(hdr.View())
   300  	}
   301  
   302  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   303  		Payload: buffer.MakeWithData(hdr.View()),
   304  	})
   305  	pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber
   306  
   307  	return pkt, hdr.View()[:expectedICMPPayloadLength()]
   308  }
   309  
   310  func max(a, b int) int {
   311  	if a > b {
   312  		return a
   313  	}
   314  	return b
   315  }
   316  
   317  func checkFragements(t *testing.T, ep *channel.Endpoint, expectedFragments []fragmentInfo, requestPkt *stack.PacketBuffer) {
   318  	t.Helper()
   319  	var fragmentedPackets []*stack.PacketBuffer
   320  	for i := 0; i < len(expectedFragments); i++ {
   321  		reply := ep.Read()
   322  		if reply == nil {
   323  			t.Fatal("Expected ICMP Echo fragment through outgoing NIC")
   324  		}
   325  		fragmentedPackets = append(fragmentedPackets, reply)
   326  	}
   327  
   328  	// The forwarded packet's TTL will have been decremented.
   329  	ipHeader := header.IPv4(requestPkt.NetworkHeader().Slice())
   330  	ipHeader.SetTTL(ipHeader.TTL() - 1)
   331  
   332  	// Forwarded packets have available header bytes equalling the sum of the
   333  	// maximum IP header size and the maximum size allocated for link layer
   334  	// headers. In this case, no size is allocated for link layer headers.
   335  	expectedAvailableHeaderBytes := header.IPv4MaximumHeaderSize
   336  	if err := compareFragments(fragmentedPackets, requestPkt, defaultMTU, expectedFragments, header.ICMPv4ProtocolNumber, true /* withIPHeader */, expectedAvailableHeaderBytes); err != nil {
   337  		t.Error(err)
   338  	}
   339  	for _, pkt := range fragmentedPackets {
   340  		pkt.DecRef()
   341  	}
   342  }
   343  
   344  func TestForwarding(t *testing.T) {
   345  	const randomTimeOffset = 0x10203040
   346  
   347  	unreachableIPv4Addr := testutil.MustParse4("12.0.0.2")
   348  	linkLocalIPv4Addr := testutil.MustParse4("169.254.0.0")
   349  
   350  	tests := []struct {
   351  		name                             string
   352  		TTL                              uint8
   353  		srcAddr                          tcpip.Address
   354  		dstAddr                          tcpip.Address
   355  		options                          header.IPv4Options
   356  		forwardedOptions                 header.IPv4Options
   357  		icmpError                        *icmpError
   358  		expectedPacketUnrouteableErrors  uint64
   359  		expectedInitializingSourceErrors uint64
   360  		expectedLinkLocalSourceErrors    uint64
   361  		expectedLinkLocalDestErrors      uint64
   362  		expectedMalformedPacketErrors    uint64
   363  		expectedExhaustedTTLErrors       uint64
   364  		expectPacketForwarded            bool
   365  	}{
   366  		{
   367  			name:    "TTL of zero",
   368  			TTL:     0,
   369  			srcAddr: remoteIPv4Addr1,
   370  			dstAddr: remoteIPv4Addr2,
   371  			icmpError: &icmpError{
   372  				icmpType: header.ICMPv4TimeExceeded,
   373  				icmpCode: header.ICMPv4TTLExceeded,
   374  			},
   375  			expectedExhaustedTTLErrors: 1,
   376  			expectPacketForwarded:      false,
   377  		},
   378  		{
   379  			name:                  "TTL of one",
   380  			TTL:                   1,
   381  			srcAddr:               remoteIPv4Addr1,
   382  			dstAddr:               remoteIPv4Addr2,
   383  			expectPacketForwarded: true,
   384  		},
   385  		{
   386  			name:                  "TTL of two",
   387  			TTL:                   2,
   388  			srcAddr:               remoteIPv4Addr1,
   389  			dstAddr:               remoteIPv4Addr2,
   390  			expectPacketForwarded: true,
   391  		},
   392  		{
   393  			name:                  "Max TTL",
   394  			TTL:                   math.MaxUint8,
   395  			srcAddr:               remoteIPv4Addr1,
   396  			dstAddr:               remoteIPv4Addr2,
   397  			expectPacketForwarded: true,
   398  		},
   399  		{
   400  			name:                  "four EOL options",
   401  			TTL:                   2,
   402  			srcAddr:               remoteIPv4Addr1,
   403  			dstAddr:               remoteIPv4Addr2,
   404  			options:               header.IPv4Options{0, 0, 0, 0},
   405  			forwardedOptions:      header.IPv4Options{0, 0, 0, 0},
   406  			expectPacketForwarded: true,
   407  		},
   408  		{
   409  			name:    "TS type 1 full",
   410  			TTL:     2,
   411  			srcAddr: remoteIPv4Addr1,
   412  			dstAddr: remoteIPv4Addr2,
   413  			options: header.IPv4Options{
   414  				68, 12, 13, 0xF1,
   415  				192, 168, 1, 12,
   416  				1, 2, 3, 4,
   417  			},
   418  			icmpError: &icmpError{
   419  				icmpType: header.ICMPv4ParamProblem,
   420  				icmpCode: header.ICMPv4UnusedCode,
   421  			},
   422  			expectedMalformedPacketErrors: 1,
   423  		},
   424  		{
   425  			name:    "TS type 0",
   426  			TTL:     2,
   427  			srcAddr: remoteIPv4Addr1,
   428  			dstAddr: remoteIPv4Addr2,
   429  			options: header.IPv4Options{
   430  				68, 24, 21, 0x00,
   431  				1, 2, 3, 4,
   432  				5, 6, 7, 8,
   433  				9, 10, 11, 12,
   434  				13, 14, 15, 16,
   435  				0, 0, 0, 0,
   436  			},
   437  			forwardedOptions: header.IPv4Options{
   438  				68, 24, 25, 0x00,
   439  				1, 2, 3, 4,
   440  				5, 6, 7, 8,
   441  				9, 10, 11, 12,
   442  				13, 14, 15, 16,
   443  				0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock
   444  			},
   445  			expectPacketForwarded: true,
   446  		},
   447  		{
   448  			name:    "end of options list",
   449  			TTL:     2,
   450  			srcAddr: remoteIPv4Addr1,
   451  			dstAddr: remoteIPv4Addr2,
   452  			options: header.IPv4Options{
   453  				68, 12, 13, 0x11,
   454  				192, 168, 1, 12,
   455  				1, 2, 3, 4,
   456  				0, 10, 3, 99, // EOL followed by junk
   457  				1, 2, 3, 4,
   458  			},
   459  			forwardedOptions: header.IPv4Options{
   460  				68, 12, 13, 0x21,
   461  				192, 168, 1, 12,
   462  				1, 2, 3, 4,
   463  				0,       // End of Options hides following bytes.
   464  				0, 0, 0, // 7 bytes unknown option removed.
   465  				0, 0, 0, 0,
   466  			},
   467  			expectPacketForwarded: true,
   468  		},
   469  		{
   470  			name:    "Network unreachable",
   471  			TTL:     2,
   472  			srcAddr: remoteIPv4Addr1,
   473  			dstAddr: unreachableIPv4Addr,
   474  			icmpError: &icmpError{
   475  				icmpType: header.ICMPv4DstUnreachable,
   476  				icmpCode: header.ICMPv4NetUnreachable,
   477  			},
   478  			expectedPacketUnrouteableErrors: 1,
   479  			expectPacketForwarded:           false,
   480  		},
   481  		{
   482  			name:                        "Link local destination",
   483  			TTL:                         2,
   484  			srcAddr:                     remoteIPv4Addr1,
   485  			dstAddr:                     linkLocalIPv4Addr,
   486  			expectedLinkLocalDestErrors: 1,
   487  			expectPacketForwarded:       false,
   488  		},
   489  		{
   490  			name:                          "Link local source",
   491  			TTL:                           2,
   492  			srcAddr:                       linkLocalIPv4Addr,
   493  			dstAddr:                       remoteIPv4Addr2,
   494  			expectedLinkLocalSourceErrors: 1,
   495  			expectPacketForwarded:         false,
   496  		},
   497  		{
   498  			name:                             "unspecified source",
   499  			TTL:                              2,
   500  			srcAddr:                          header.IPv4Any,
   501  			dstAddr:                          remoteIPv4Addr2,
   502  			expectedInitializingSourceErrors: 1,
   503  			expectPacketForwarded:            false,
   504  		},
   505  		{
   506  			name:                             "initializing source",
   507  			TTL:                              2,
   508  			srcAddr:                          tcpip.AddrFromSlice(net.ParseIP("0.0.0.255").To4()),
   509  			dstAddr:                          remoteIPv4Addr2,
   510  			expectedInitializingSourceErrors: 1,
   511  			expectPacketForwarded:            false,
   512  		},
   513  	}
   514  	for _, test := range tests {
   515  		t.Run(test.name, func(t *testing.T) {
   516  			ctx := newTestContext()
   517  			defer ctx.cleanup()
   518  			s := ctx.s
   519  			clock := ctx.clock
   520  
   521  			// Advance the clock by some unimportant amount to make
   522  			// it give a more recognisable signature than 00,00,00,00.
   523  			clock.Advance(time.Millisecond * randomTimeOffset)
   524  
   525  			endpoints := make(map[tcpip.NICID]*channel.Endpoint)
   526  			for nicID, addr := range defaultEndpointConfigs {
   527  				ep := channel.New(1, ipv4.MaxTotalSize, "")
   528  				defer ep.Close()
   529  
   530  				if err := s.CreateNIC(nicID, ep); err != nil {
   531  					t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   532  				}
   533  				addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr}
   534  				if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
   535  					t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err)
   536  				}
   537  				endpoints[nicID] = ep
   538  			}
   539  
   540  			s.SetRouteTable([]tcpip.Route{
   541  				{
   542  					Destination: incomingIPv4Addr.Subnet(),
   543  					NIC:         incomingNICID,
   544  				},
   545  				{
   546  					Destination: outgoingIPv4Addr.Subnet(),
   547  					NIC:         outgoingNICID,
   548  				},
   549  			})
   550  
   551  			if err := s.SetForwardingDefaultAndAllNICs(header.IPv4ProtocolNumber, true); err != nil {
   552  				t.Fatalf("s.SetForwardingDefaultAndAllNICs(%d, true): %s", header.IPv4ProtocolNumber, err)
   553  			}
   554  
   555  			requestPkt, expectedICMPErrorPayload := newICMPEchoPacket(t, test.srcAddr, test.dstAddr, test.TTL, packetOptions{options: test.options})
   556  			defer requestPkt.DecRef()
   557  
   558  			incomingEndpoint, ok := endpoints[incomingNICID]
   559  			if !ok {
   560  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID)
   561  			}
   562  			incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt)
   563  			reply := incomingEndpoint.Read()
   564  
   565  			if test.icmpError != nil {
   566  				if reply == nil {
   567  					t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.icmpError.icmpType)
   568  				}
   569  
   570  				payload := stack.PayloadSince(reply.NetworkHeader())
   571  				defer payload.Release()
   572  				checker.IPv4(t, payload,
   573  					checker.SrcAddr(incomingIPv4Addr.Address),
   574  					checker.DstAddr(test.srcAddr),
   575  					checker.TTL(ipv4.DefaultTTL),
   576  					checker.ICMPv4(
   577  						checker.ICMPv4Checksum(),
   578  						checker.ICMPv4Type(test.icmpError.icmpType),
   579  						checker.ICMPv4Code(test.icmpError.icmpCode),
   580  						checker.ICMPv4Payload(expectedICMPErrorPayload),
   581  					),
   582  				)
   583  				reply.DecRef()
   584  			} else if reply != nil {
   585  				t.Fatalf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply)
   586  			}
   587  
   588  			outgoingEndpoint, ok := endpoints[outgoingNICID]
   589  			if !ok {
   590  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID)
   591  			}
   592  
   593  			if test.expectPacketForwarded {
   594  				reply := outgoingEndpoint.Read()
   595  				if reply == nil {
   596  					t.Fatal("Expected ICMP Echo packet through outgoing NIC")
   597  				}
   598  
   599  				payload := stack.PayloadSince(reply.NetworkHeader())
   600  				defer payload.Release()
   601  				checker.IPv4(t, payload,
   602  					checker.SrcAddr(test.srcAddr),
   603  					checker.DstAddr(test.dstAddr),
   604  					checker.TTL(test.TTL-1),
   605  					checker.IPv4Options(test.forwardedOptions),
   606  					checker.ICMPv4(
   607  						checker.ICMPv4Checksum(),
   608  						checker.ICMPv4Type(header.ICMPv4Echo),
   609  						checker.ICMPv4Code(header.ICMPv4UnusedCode),
   610  						checker.ICMPv4Payload(nil),
   611  					),
   612  				)
   613  				reply.DecRef()
   614  			} else {
   615  				if reply := outgoingEndpoint.Read(); reply != nil {
   616  					t.Fatalf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply)
   617  				}
   618  			}
   619  
   620  			if got, want := s.Stats().IP.Forwarding.InitializingSource.Value(), test.expectedInitializingSourceErrors; got != want {
   621  				t.Errorf("s.Stats().IP.Forwarding.InitializingSource.Value() = %d, want = %d", got, want)
   622  			}
   623  
   624  			if got, want := s.Stats().IP.Forwarding.LinkLocalSource.Value(), test.expectedLinkLocalSourceErrors; got != want {
   625  				t.Errorf("s.Stats().IP.Forwarding.LinkLocalSource.Value() = %d, want = %d", got, want)
   626  			}
   627  
   628  			if got, want := s.Stats().IP.Forwarding.LinkLocalDestination.Value(), test.expectedLinkLocalDestErrors; got != want {
   629  				t.Errorf("s.Stats().IP.Forwarding.LinkLocalDestination.Value() = %d, want = %d", got, want)
   630  			}
   631  
   632  			if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.expectedMalformedPacketErrors; got != want {
   633  				t.Errorf("s.Stats().IP.MalformedPacketsReceived.Value() = %d, want = %d", got, want)
   634  			}
   635  
   636  			if got, want := s.Stats().IP.Forwarding.ExhaustedTTL.Value(), test.expectedExhaustedTTLErrors; got != want {
   637  				t.Errorf("s.Stats().IP.Forwarding.ExhaustedTTL.Value() = %d, want = %d", got, want)
   638  			}
   639  
   640  			if got, want := s.Stats().IP.Forwarding.Unrouteable.Value(), test.expectedPacketUnrouteableErrors; got != want {
   641  				t.Errorf("s.Stats().IP.Forwarding.Unrouteable.Value() = %d, want = %d", got, want)
   642  			}
   643  
   644  			expectedTotalErrors := test.expectedLinkLocalSourceErrors + test.expectedLinkLocalDestErrors + test.expectedMalformedPacketErrors + test.expectedExhaustedTTLErrors + test.expectedPacketUnrouteableErrors + test.expectedInitializingSourceErrors
   645  			if got, want := s.Stats().IP.Forwarding.Errors.Value(), expectedTotalErrors; got != want {
   646  				t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want)
   647  			}
   648  		})
   649  	}
   650  }
   651  
   652  func TestFragmentForwarding(t *testing.T) {
   653  	const (
   654  		defaultMTU           = 1000
   655  		defaultPayloadLength = defaultMTU + 4
   656  		packetTTL            = 2
   657  	)
   658  
   659  	tests := []struct {
   660  		name                       string
   661  		ipFlags                    uint8
   662  		icmpError                  *icmpError
   663  		expectedPacketTooBigErrors uint64
   664  		expectedFragmentsForwarded []fragmentInfo
   665  	}{
   666  		{
   667  			name:    "Fragmentation needed and DF set",
   668  			ipFlags: header.IPv4FlagDontFragment,
   669  			// We've picked this MTU because it is:
   670  			//
   671  			// 1) Greater than the minimum MTU that IPv4 hosts are required to process
   672  			// (576 bytes). As per RFC 1812, Section 4.3.2.3:
   673  			//
   674  			//   The ICMP datagram SHOULD contain as much of the original datagram as
   675  			//   possible without the length of the ICMP datagram exceeding 576 bytes.
   676  			//
   677  			// Therefore, setting an MTU greater than 576 bytes ensures that we can fit a
   678  			// complete ICMP packet on the incoming endpoint (and make assertions about
   679  			// it).
   680  			//
   681  			// 2) Less than `ipv4.MaxTotalSize`, which lets us build an IPv4 packet whose
   682  			// size exceeds the MTU.
   683  			icmpError: &icmpError{
   684  				icmpType: header.ICMPv4DstUnreachable,
   685  				icmpCode: header.ICMPv4FragmentationNeeded,
   686  			},
   687  			expectedFragmentsForwarded: []fragmentInfo{},
   688  			expectedPacketTooBigErrors: 1,
   689  		},
   690  		{
   691  			name: "Fragmentation needed and DF not set",
   692  			expectedFragmentsForwarded: []fragmentInfo{
   693  				// The first fragment has a length of the greatest multiple of 8 which is
   694  				// less than or equal to to `mtu - header.IPv4MinimumSize`.
   695  				{offset: 0, payloadSize: uint16(976), more: true},
   696  				// The next fragment holds the rest of the packet.
   697  				{offset: uint16(976), payloadSize: 36, more: false},
   698  			},
   699  		},
   700  	}
   701  	for _, test := range tests {
   702  		t.Run(test.name, func(t *testing.T) {
   703  			ctx := newTestContext()
   704  			defer ctx.cleanup()
   705  			s := ctx.s
   706  
   707  			endpoints := make(map[tcpip.NICID]*channel.Endpoint)
   708  			for nicID, addr := range defaultEndpointConfigs {
   709  				// For the input interface, we expect at most a single packet in
   710  				// response to our ICMP Echo Request.
   711  				expectedEmittedPacketCount := 1
   712  
   713  				if nicID == outgoingNICID {
   714  					expectedEmittedPacketCount = max(1, len(test.expectedFragmentsForwarded))
   715  				}
   716  
   717  				ep := channel.New(expectedEmittedPacketCount, defaultMTU, "")
   718  				defer ep.Close()
   719  
   720  				if err := s.CreateNIC(nicID, ep); err != nil {
   721  					t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   722  				}
   723  				addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr}
   724  				if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
   725  					t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err)
   726  				}
   727  				endpoints[nicID] = ep
   728  			}
   729  
   730  			s.SetRouteTable([]tcpip.Route{
   731  				{
   732  					Destination: incomingIPv4Addr.Subnet(),
   733  					NIC:         incomingNICID,
   734  				},
   735  				{
   736  					Destination: outgoingIPv4Addr.Subnet(),
   737  					NIC:         outgoingNICID,
   738  				},
   739  			})
   740  
   741  			if err := s.SetForwardingDefaultAndAllNICs(header.IPv4ProtocolNumber, true); err != nil {
   742  				t.Fatalf("s.SetForwardingDefaultAndAllNICs(%d, true): %s", header.IPv4ProtocolNumber, err)
   743  			}
   744  
   745  			requestPkt, expectedICMPErrorPayload := newICMPEchoPacket(t, remoteIPv4Addr1, remoteIPv4Addr2, packetTTL, packetOptions{ipFlags: test.ipFlags, payloadLength: defaultPayloadLength})
   746  			defer requestPkt.DecRef()
   747  
   748  			incomingEndpoint, ok := endpoints[incomingNICID]
   749  			if !ok {
   750  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID)
   751  			}
   752  			incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt)
   753  			reply := incomingEndpoint.Read()
   754  
   755  			if test.icmpError != nil {
   756  				if reply == nil {
   757  					t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.icmpError.icmpType)
   758  				}
   759  
   760  				payload := stack.PayloadSince(reply.NetworkHeader())
   761  				defer payload.Release()
   762  				checker.IPv4(t, payload,
   763  					checker.SrcAddr(incomingIPv4Addr.Address),
   764  					checker.DstAddr(remoteIPv4Addr1),
   765  					checker.TTL(ipv4.DefaultTTL),
   766  					checker.ICMPv4(
   767  						checker.ICMPv4Checksum(),
   768  						checker.ICMPv4Type(test.icmpError.icmpType),
   769  						checker.ICMPv4Code(test.icmpError.icmpCode),
   770  						checker.ICMPv4Payload(expectedICMPErrorPayload),
   771  					),
   772  				)
   773  				reply.DecRef()
   774  			} else if reply != nil {
   775  				t.Fatalf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply)
   776  			}
   777  
   778  			outgoingEndpoint, ok := endpoints[outgoingNICID]
   779  			if !ok {
   780  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID)
   781  			}
   782  
   783  			if len(test.expectedFragmentsForwarded) > 0 {
   784  				checkFragements(t, outgoingEndpoint, test.expectedFragmentsForwarded, requestPkt)
   785  			} else {
   786  				if reply := outgoingEndpoint.Read(); reply != nil {
   787  					t.Errorf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply)
   788  				}
   789  			}
   790  
   791  			if got, want := s.Stats().IP.Forwarding.PacketTooBig.Value(), test.expectedPacketTooBigErrors; got != want {
   792  				t.Errorf("s.Stats().IP.Forwarding.PacketTooBig.Value() = %d, want = %d", got, want)
   793  			}
   794  
   795  			if got, want := s.Stats().IP.Forwarding.Errors.Value(), test.expectedPacketTooBigErrors; got != want {
   796  				t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want)
   797  			}
   798  		})
   799  	}
   800  }
   801  
   802  func TestMulticastFragmentForwarding(t *testing.T) {
   803  	const (
   804  		defaultMTU           = 1000
   805  		defaultPayloadLength = defaultMTU + 4
   806  		packetTTL            = 2
   807  		multicastRouteMinTTL = 2
   808  	)
   809  
   810  	tests := []struct {
   811  		name                       string
   812  		ipFlags                    uint8
   813  		icmpError                  *icmpError
   814  		expectedPacketTooBigErrors uint64
   815  		expectedFragmentsForwarded []fragmentInfo
   816  	}{
   817  		{
   818  			name:    "Fragmentation needed and DF set",
   819  			ipFlags: header.IPv4FlagDontFragment,
   820  			// We've picked this MTU because it is:
   821  			//
   822  			// 1) Greater than the minimum MTU that IPv4 hosts are required to process
   823  			// (576 bytes). As per RFC 1812, Section 4.3.2.3:
   824  			//
   825  			//   The ICMP datagram SHOULD contain as much of the original datagram as
   826  			//   possible without the length of the ICMP datagram exceeding 576 bytes.
   827  			//
   828  			// Therefore, setting an MTU greater than 576 bytes ensures that we can fit a
   829  			// complete ICMP packet on the incoming endpoint (and make assertions about
   830  			// it).
   831  			//
   832  			// 2) Less than `ipv4.MaxTotalSize`, which lets us build an IPv4 packet whose
   833  			// size exceeds the MTU.
   834  			icmpError: &icmpError{
   835  				icmpType: header.ICMPv4DstUnreachable,
   836  				icmpCode: header.ICMPv4FragmentationNeeded,
   837  			},
   838  			expectedFragmentsForwarded: []fragmentInfo{},
   839  			expectedPacketTooBigErrors: 1,
   840  		},
   841  		{
   842  			name: "Fragmentation needed and DF not set",
   843  			expectedFragmentsForwarded: []fragmentInfo{
   844  				// The first fragment has a length of the greatest multiple of 8 which is
   845  				// less than or equal to to `mtu - header.IPv4MinimumSize`.
   846  				{offset: 0, payloadSize: uint16(976), more: true},
   847  				// The next fragment holds the rest of the packet.
   848  				{offset: uint16(976), payloadSize: 36, more: false},
   849  			},
   850  		},
   851  	}
   852  	for _, test := range tests {
   853  		t.Run(test.name, func(t *testing.T) {
   854  			ctx := newTestContext()
   855  			defer ctx.cleanup()
   856  			s := ctx.s
   857  
   858  			if _, err := s.EnableMulticastForwardingForProtocol(ipv4.ProtocolNumber, &fakeMulticastEventDispatcher{}); err != nil {
   859  				t.Fatalf("s.EnableMulticastForwardingForProtocol(%d, _): (_, %s)", ipv4.ProtocolNumber, err)
   860  			}
   861  
   862  			endpoints := make(map[tcpip.NICID]*channel.Endpoint)
   863  			for nicID, addr := range defaultEndpointConfigs {
   864  				// For the input interface, we expect at most a single packet in
   865  				// response to our ICMP Echo Request.
   866  				expectedEmittedPacketCount := 1
   867  
   868  				if nicID == outgoingNICID {
   869  					expectedEmittedPacketCount = max(1, len(test.expectedFragmentsForwarded))
   870  				}
   871  
   872  				ep := channel.New(expectedEmittedPacketCount, defaultMTU, "")
   873  				defer ep.Close()
   874  
   875  				if err := s.CreateNIC(nicID, ep); err != nil {
   876  					t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   877  				}
   878  				addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr}
   879  				if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
   880  					t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err)
   881  				}
   882  				s.SetNICMulticastForwarding(nicID, ipv4.ProtocolNumber, true /* enabled */)
   883  				endpoints[nicID] = ep
   884  			}
   885  
   886  			// Add a route that could theoretically be used to send an ICMP error.
   887  			// Note that such an error should never be sent for multicast.
   888  			s.SetRouteTable([]tcpip.Route{
   889  				{
   890  					Destination: header.IPv4EmptySubnet,
   891  					NIC:         outgoingNICID,
   892  				},
   893  			})
   894  
   895  			outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{
   896  				{ID: outgoingNICID, MinTTL: multicastRouteMinTTL},
   897  			}
   898  			addresses := stack.UnicastSourceAndMulticastDestination{
   899  				Source:      remoteIPv4Addr1,
   900  				Destination: multicastIPv4Addr,
   901  			}
   902  
   903  			route := stack.MulticastRoute{
   904  				ExpectedInputInterface: incomingNICID,
   905  				OutgoingInterfaces:     outgoingInterfaces,
   906  			}
   907  
   908  			if err := s.AddMulticastRoute(ipv4.ProtocolNumber, addresses, route); err != nil {
   909  				t.Fatalf("s.AddMulticastRoute(%d, %#v, %#v): %s", ipv4.ProtocolNumber, addresses, route, err)
   910  			}
   911  
   912  			requestPkt, _ := newICMPEchoPacket(t, remoteIPv4Addr1, multicastIPv4Addr, packetTTL, packetOptions{ipFlags: test.ipFlags, payloadLength: defaultPayloadLength})
   913  			defer requestPkt.DecRef()
   914  
   915  			incomingEndpoint, ok := endpoints[incomingNICID]
   916  			if !ok {
   917  				t.Fatalf("got endpoints[%d] = (_, false), want (_, true)", incomingNICID)
   918  			}
   919  			incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt)
   920  			reply := incomingEndpoint.Read()
   921  
   922  			if reply != nil {
   923  				// An ICMP error should never be sent in response to a multicast packet.
   924  				t.Errorf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply)
   925  			}
   926  
   927  			outgoingEndpoint, ok := endpoints[outgoingNICID]
   928  			if !ok {
   929  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID)
   930  			}
   931  
   932  			if len(test.expectedFragmentsForwarded) > 0 {
   933  				checkFragements(t, outgoingEndpoint, test.expectedFragmentsForwarded, requestPkt)
   934  			} else {
   935  				if reply := outgoingEndpoint.Read(); reply != nil {
   936  					t.Errorf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply)
   937  				}
   938  			}
   939  
   940  			if got, want := s.Stats().IP.Forwarding.PacketTooBig.Value(), test.expectedPacketTooBigErrors; got != want {
   941  				t.Errorf("s.Stats().IP.Forwarding.PacketTooBig.Value() = %d, want = %d", got, want)
   942  			}
   943  
   944  			if got, want := s.Stats().IP.Forwarding.Errors.Value(), test.expectedPacketTooBigErrors; got != want {
   945  				t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want)
   946  			}
   947  		})
   948  	}
   949  }
   950  
   951  func TestMulticastForwardingOptions(t *testing.T) {
   952  	const (
   953  		randomTimeOffset     = 0x10203040
   954  		packetTTL            = 2
   955  		multicastRouteMinTTL = 2
   956  	)
   957  
   958  	tests := []struct {
   959  		name                          string
   960  		options                       header.IPv4Options
   961  		forwardedOptions              header.IPv4Options
   962  		expectedMalformedPacketErrors uint64
   963  		expectPacketForwarded         bool
   964  	}{
   965  		{
   966  			name:                  "four EOL options",
   967  			options:               header.IPv4Options{0, 0, 0, 0},
   968  			forwardedOptions:      header.IPv4Options{0, 0, 0, 0},
   969  			expectPacketForwarded: true,
   970  		},
   971  		{
   972  			name: "TS type 1 full",
   973  			options: header.IPv4Options{
   974  				68, 12, 13, 0xF1,
   975  				192, 168, 1, 12,
   976  				1, 2, 3, 4,
   977  			},
   978  			expectedMalformedPacketErrors: 1,
   979  		},
   980  		{
   981  			name: "TS type 0",
   982  			options: header.IPv4Options{
   983  				68, 24, 21, 0x00,
   984  				1, 2, 3, 4,
   985  				5, 6, 7, 8,
   986  				9, 10, 11, 12,
   987  				13, 14, 15, 16,
   988  				0, 0, 0, 0,
   989  			},
   990  			forwardedOptions: header.IPv4Options{
   991  				68, 24, 25, 0x00,
   992  				1, 2, 3, 4,
   993  				5, 6, 7, 8,
   994  				9, 10, 11, 12,
   995  				13, 14, 15, 16,
   996  				0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock
   997  			},
   998  			expectPacketForwarded: true,
   999  		},
  1000  		{
  1001  			name: "end of options list",
  1002  			options: header.IPv4Options{
  1003  				68, 12, 13, 0x11,
  1004  				192, 168, 1, 12,
  1005  				1, 2, 3, 4,
  1006  				0, 10, 3, 99, // EOL followed by junk
  1007  				1, 2, 3, 4,
  1008  			},
  1009  			forwardedOptions: header.IPv4Options{
  1010  				68, 12, 13, 0x21,
  1011  				192, 168, 1, 12,
  1012  				1, 2, 3, 4,
  1013  				0,       // End of Options hides following bytes.
  1014  				0, 0, 0, // 7 bytes unknown option removed.
  1015  				0, 0, 0, 0,
  1016  			},
  1017  			expectPacketForwarded: true,
  1018  		},
  1019  	}
  1020  	for _, test := range tests {
  1021  		t.Run(test.name, func(t *testing.T) {
  1022  			ctx := newTestContext()
  1023  			defer ctx.cleanup()
  1024  			s := ctx.s
  1025  			clock := ctx.clock
  1026  
  1027  			// Advance the clock by some unimportant amount to make
  1028  			// it give a more recognisable signature than 00,00,00,00.
  1029  			clock.Advance(time.Millisecond * randomTimeOffset)
  1030  
  1031  			if _, err := s.EnableMulticastForwardingForProtocol(ipv4.ProtocolNumber, &fakeMulticastEventDispatcher{}); err != nil {
  1032  				t.Fatalf("s.EnableMulticastForwardingForProtocol(%d, _): (_, %s)", ipv4.ProtocolNumber, err)
  1033  			}
  1034  
  1035  			endpoints := make(map[tcpip.NICID]*channel.Endpoint)
  1036  			for nicID, addr := range defaultEndpointConfigs {
  1037  				ep := channel.New(1, ipv4.MaxTotalSize, "")
  1038  				defer ep.Close()
  1039  
  1040  				if err := s.CreateNIC(nicID, ep); err != nil {
  1041  					t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  1042  				}
  1043  				addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr}
  1044  				if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
  1045  					t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err)
  1046  				}
  1047  				s.SetNICMulticastForwarding(nicID, ipv4.ProtocolNumber, true /* enabled */)
  1048  				endpoints[nicID] = ep
  1049  			}
  1050  
  1051  			// Add a route that could theoretically be used to send an ICMP error.
  1052  			// Note that such an error should never be sent for multicast.
  1053  			s.SetRouteTable([]tcpip.Route{
  1054  				{
  1055  					Destination: header.IPv4EmptySubnet,
  1056  					NIC:         outgoingNICID,
  1057  				},
  1058  			})
  1059  
  1060  			outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{
  1061  				{ID: outgoingNICID, MinTTL: multicastRouteMinTTL},
  1062  			}
  1063  			addresses := stack.UnicastSourceAndMulticastDestination{
  1064  				Source:      remoteIPv4Addr1,
  1065  				Destination: multicastIPv4Addr,
  1066  			}
  1067  
  1068  			route := stack.MulticastRoute{
  1069  				ExpectedInputInterface: incomingNICID,
  1070  				OutgoingInterfaces:     outgoingInterfaces,
  1071  			}
  1072  
  1073  			if err := s.AddMulticastRoute(ipv4.ProtocolNumber, addresses, route); err != nil {
  1074  				t.Fatalf("s.AddMulticastRoute(%d, %#v, %#v): %s", ipv4.ProtocolNumber, addresses, route, err)
  1075  			}
  1076  
  1077  			requestPkt, _ := newICMPEchoPacket(t, remoteIPv4Addr1, multicastIPv4Addr, packetTTL, packetOptions{options: test.options})
  1078  			defer requestPkt.DecRef()
  1079  
  1080  			incomingEndpoint, ok := endpoints[incomingNICID]
  1081  			if !ok {
  1082  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID)
  1083  			}
  1084  			incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt)
  1085  			reply := incomingEndpoint.Read()
  1086  
  1087  			if reply != nil {
  1088  				// An ICMP error should never be sent in response to a multicast packet.
  1089  				t.Errorf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply)
  1090  			}
  1091  
  1092  			outgoingEndpoint, ok := endpoints[outgoingNICID]
  1093  			if !ok {
  1094  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID)
  1095  			}
  1096  
  1097  			if test.expectPacketForwarded {
  1098  				reply := outgoingEndpoint.Read()
  1099  				if reply == nil {
  1100  					t.Fatal("Expected ICMP Echo packet through outgoing NIC")
  1101  				}
  1102  
  1103  				payload := stack.PayloadSince(reply.NetworkHeader())
  1104  				defer payload.Release()
  1105  				checker.IPv4(t, payload,
  1106  					checker.SrcAddr(remoteIPv4Addr1),
  1107  					checker.DstAddr(multicastIPv4Addr),
  1108  					checker.TTL(packetTTL-1),
  1109  					checker.IPv4Options(test.forwardedOptions),
  1110  					checker.ICMPv4(
  1111  						checker.ICMPv4Checksum(),
  1112  						checker.ICMPv4Type(header.ICMPv4Echo),
  1113  						checker.ICMPv4Code(header.ICMPv4UnusedCode),
  1114  						checker.ICMPv4Payload(nil),
  1115  					),
  1116  				)
  1117  				reply.DecRef()
  1118  			} else {
  1119  				if reply := outgoingEndpoint.Read(); reply != nil {
  1120  					t.Fatalf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply)
  1121  				}
  1122  			}
  1123  
  1124  			if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.expectedMalformedPacketErrors; got != want {
  1125  				t.Errorf("s.Stats().IP.MalformedPacketsReceived.Value() = %d, want = %d", got, want)
  1126  			}
  1127  
  1128  			if got, want := s.Stats().IP.Forwarding.Errors.Value(), test.expectedMalformedPacketErrors; got != want {
  1129  				t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want)
  1130  			}
  1131  		})
  1132  	}
  1133  }
  1134  
  1135  // TestIPv4Sanity sends IP/ICMP packets with various problems to the stack and
  1136  // checks the response.
  1137  func TestIPv4Sanity(t *testing.T) {
  1138  	const (
  1139  		ttl            = 255
  1140  		nicID          = 1
  1141  		randomSequence = 123
  1142  		randomIdent    = 42
  1143  		// In some cases Linux sets the error pointer to the start of the option
  1144  		// (offset 0) instead of the actual wrong value, which is the length byte
  1145  		// (offset 1). For compatibility we must do the same. Use this constant
  1146  		// to indicate where this happens.
  1147  		pointerOffsetForInvalidLength = 0
  1148  		randomTimeOffset              = 0x10203040
  1149  	)
  1150  	var (
  1151  		ipv4Addr = tcpip.AddressWithPrefix{
  1152  			Address:   tcpip.AddrFromSlice(net.ParseIP("192.168.1.58").To4()),
  1153  			PrefixLen: 24,
  1154  		}
  1155  		remoteIPv4Addr = tcpip.AddrFromSlice(net.ParseIP("10.0.0.1").To4())
  1156  	)
  1157  
  1158  	tests := []struct {
  1159  		name                string
  1160  		headerLength        uint8 // value of 0 means "use correct size"
  1161  		badHeaderChecksum   bool
  1162  		maxTotalLength      uint16
  1163  		transportProtocol   uint8
  1164  		TTL                 uint8
  1165  		options             header.IPv4Options
  1166  		replyOptions        header.IPv4Options // reply should look like this
  1167  		shouldFail          bool
  1168  		expectErrorICMP     bool
  1169  		ICMPType            header.ICMPv4Type
  1170  		ICMPCode            header.ICMPv4Code
  1171  		paramProblemPointer uint8
  1172  	}{
  1173  		{
  1174  			name:              "valid no options",
  1175  			maxTotalLength:    ipv4.MaxTotalSize,
  1176  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1177  			TTL:               ttl,
  1178  		},
  1179  		{
  1180  			name:              "bad header checksum",
  1181  			maxTotalLength:    ipv4.MaxTotalSize,
  1182  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1183  			TTL:               ttl,
  1184  			badHeaderChecksum: true,
  1185  			shouldFail:        true,
  1186  		},
  1187  		// The TTL tests check that we are not rejecting an incoming packet
  1188  		// with a zero or one TTL, which has been a point of confusion in the
  1189  		// past as RFC 791 says: "If this field contains the value zero, then the
  1190  		// datagram must be destroyed". However RFC 1122 section 3.2.1.7 clarifies
  1191  		// for the case of the destination host, stating as follows.
  1192  		//
  1193  		//      A host MUST NOT send a datagram with a Time-to-Live (TTL)
  1194  		//      value of zero.
  1195  		//
  1196  		//      A host MUST NOT discard a datagram just because it was
  1197  		//      received with TTL less than 2.
  1198  		{
  1199  			name:              "zero TTL",
  1200  			maxTotalLength:    ipv4.MaxTotalSize,
  1201  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1202  			TTL:               0,
  1203  		},
  1204  		{
  1205  			name:              "one TTL",
  1206  			maxTotalLength:    ipv4.MaxTotalSize,
  1207  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1208  			TTL:               1,
  1209  		},
  1210  		{
  1211  			name:              "End options",
  1212  			maxTotalLength:    ipv4.MaxTotalSize,
  1213  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1214  			TTL:               ttl,
  1215  			options:           header.IPv4Options{0, 0, 0, 0},
  1216  			replyOptions:      header.IPv4Options{0, 0, 0, 0},
  1217  		},
  1218  		{
  1219  			name:              "NOP options",
  1220  			maxTotalLength:    ipv4.MaxTotalSize,
  1221  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1222  			TTL:               ttl,
  1223  			options:           header.IPv4Options{1, 1, 1, 1},
  1224  			replyOptions:      header.IPv4Options{1, 1, 1, 1},
  1225  		},
  1226  		{
  1227  			name:              "NOP and End options",
  1228  			maxTotalLength:    ipv4.MaxTotalSize,
  1229  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1230  			TTL:               ttl,
  1231  			options:           header.IPv4Options{1, 1, 0, 0},
  1232  			replyOptions:      header.IPv4Options{1, 1, 0, 0},
  1233  		},
  1234  		{
  1235  			name:              "bad header length",
  1236  			headerLength:      header.IPv4MinimumSize - 1,
  1237  			maxTotalLength:    ipv4.MaxTotalSize,
  1238  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1239  			TTL:               ttl,
  1240  			shouldFail:        true,
  1241  		},
  1242  		{
  1243  			name:              "bad total length (0)",
  1244  			maxTotalLength:    0,
  1245  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1246  			TTL:               ttl,
  1247  			shouldFail:        true,
  1248  		},
  1249  		{
  1250  			name:              "bad total length (ip - 1)",
  1251  			maxTotalLength:    uint16(header.IPv4MinimumSize - 1),
  1252  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1253  			TTL:               ttl,
  1254  			shouldFail:        true,
  1255  		},
  1256  		{
  1257  			name:              "bad total length (ip + icmp - 1)",
  1258  			maxTotalLength:    uint16(header.IPv4MinimumSize + header.ICMPv4MinimumSize - 1),
  1259  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1260  			TTL:               ttl,
  1261  			shouldFail:        true,
  1262  		},
  1263  		{
  1264  			name:              "bad protocol",
  1265  			maxTotalLength:    ipv4.MaxTotalSize,
  1266  			transportProtocol: 99,
  1267  			TTL:               ttl,
  1268  			shouldFail:        true,
  1269  			expectErrorICMP:   true,
  1270  			ICMPType:          header.ICMPv4DstUnreachable,
  1271  			ICMPCode:          header.ICMPv4ProtoUnreachable,
  1272  		},
  1273  		{
  1274  			name:              "timestamp option overflow",
  1275  			maxTotalLength:    ipv4.MaxTotalSize,
  1276  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1277  			TTL:               ttl,
  1278  			options: header.IPv4Options{
  1279  				68, 12, 13, 0x11,
  1280  				192, 168, 1, 12,
  1281  				1, 2, 3, 4,
  1282  			},
  1283  			replyOptions: header.IPv4Options{
  1284  				68, 12, 13, 0x21,
  1285  				192, 168, 1, 12,
  1286  				1, 2, 3, 4,
  1287  			},
  1288  		},
  1289  		{
  1290  			name:              "timestamp option overflow full",
  1291  			maxTotalLength:    ipv4.MaxTotalSize,
  1292  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1293  			TTL:               ttl,
  1294  			options: header.IPv4Options{
  1295  				68, 12, 13, 0xF1,
  1296  				//            ^   Counter full (15/0xF)
  1297  				192, 168, 1, 12,
  1298  				1, 2, 3, 4,
  1299  			},
  1300  			shouldFail:          true,
  1301  			expectErrorICMP:     true,
  1302  			ICMPType:            header.ICMPv4ParamProblem,
  1303  			ICMPCode:            header.ICMPv4UnusedCode,
  1304  			paramProblemPointer: header.IPv4MinimumSize + 3,
  1305  			replyOptions:        header.IPv4Options{},
  1306  		},
  1307  		{
  1308  			name:              "unknown option",
  1309  			maxTotalLength:    ipv4.MaxTotalSize,
  1310  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1311  			TTL:               ttl,
  1312  			options:           header.IPv4Options{10, 4, 9, 0},
  1313  			//                        ^^
  1314  			// The unknown option should be stripped out of the reply.
  1315  			replyOptions: header.IPv4Options{},
  1316  		},
  1317  		{
  1318  			name:              "bad option - no length",
  1319  			maxTotalLength:    ipv4.MaxTotalSize,
  1320  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1321  			TTL:               ttl,
  1322  			options: header.IPv4Options{
  1323  				1, 1, 1, 68,
  1324  				//        ^-start of timestamp.. but no length..
  1325  			},
  1326  			shouldFail:          true,
  1327  			expectErrorICMP:     true,
  1328  			ICMPType:            header.ICMPv4ParamProblem,
  1329  			ICMPCode:            header.ICMPv4UnusedCode,
  1330  			paramProblemPointer: header.IPv4MinimumSize + 3,
  1331  		},
  1332  		{
  1333  			name:              "bad option - length 0",
  1334  			maxTotalLength:    ipv4.MaxTotalSize,
  1335  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1336  			TTL:               ttl,
  1337  			options: header.IPv4Options{
  1338  				68, 0, 9, 0,
  1339  				//  ^
  1340  				1, 2, 3, 4,
  1341  			},
  1342  			shouldFail:          true,
  1343  			expectErrorICMP:     true,
  1344  			ICMPType:            header.ICMPv4ParamProblem,
  1345  			ICMPCode:            header.ICMPv4UnusedCode,
  1346  			paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength,
  1347  		},
  1348  		{
  1349  			name:              "bad option - length 1",
  1350  			maxTotalLength:    ipv4.MaxTotalSize,
  1351  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1352  			TTL:               ttl,
  1353  			options: header.IPv4Options{
  1354  				68, 1, 9, 0,
  1355  				//  ^
  1356  				1, 2, 3, 4,
  1357  			},
  1358  			shouldFail:          true,
  1359  			expectErrorICMP:     true,
  1360  			ICMPType:            header.ICMPv4ParamProblem,
  1361  			ICMPCode:            header.ICMPv4UnusedCode,
  1362  			paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength,
  1363  		},
  1364  		{
  1365  			name:              "bad option - length big",
  1366  			maxTotalLength:    ipv4.MaxTotalSize,
  1367  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1368  			TTL:               ttl,
  1369  			options: header.IPv4Options{
  1370  				68, 9, 9, 0,
  1371  				//  ^
  1372  				// There are only 8 bytes allocated to options so 9 bytes of timestamp
  1373  				// space is not possible. (Second byte)
  1374  				1, 2, 3, 4,
  1375  			},
  1376  			shouldFail:          true,
  1377  			expectErrorICMP:     true,
  1378  			ICMPType:            header.ICMPv4ParamProblem,
  1379  			ICMPCode:            header.ICMPv4UnusedCode,
  1380  			paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength,
  1381  		},
  1382  		{
  1383  			// This tests for some linux compatible behaviour.
  1384  			// The ICMP pointer returned is 22 for Linux but the
  1385  			// error is actually in spot 21.
  1386  			name:              "bad option - length bad",
  1387  			maxTotalLength:    ipv4.MaxTotalSize,
  1388  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1389  			TTL:               ttl,
  1390  			// Timestamps are in multiples of 4 or 8 but never 7.
  1391  			// The option space should be padded out.
  1392  			options: header.IPv4Options{
  1393  				68, 7, 5, 0,
  1394  				//  ^  ^ Linux points here which is wrong.
  1395  				//  | Not a multiple of 4
  1396  				1, 2, 3, 0,
  1397  			},
  1398  			shouldFail:          true,
  1399  			expectErrorICMP:     true,
  1400  			ICMPType:            header.ICMPv4ParamProblem,
  1401  			ICMPCode:            header.ICMPv4UnusedCode,
  1402  			paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptTSPointerOffset,
  1403  		},
  1404  		{
  1405  			name:              "multiple type 0 with room",
  1406  			maxTotalLength:    ipv4.MaxTotalSize,
  1407  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1408  			TTL:               ttl,
  1409  			options: header.IPv4Options{
  1410  				68, 24, 21, 0x00,
  1411  				1, 2, 3, 4,
  1412  				5, 6, 7, 8,
  1413  				9, 10, 11, 12,
  1414  				13, 14, 15, 16,
  1415  				0, 0, 0, 0,
  1416  			},
  1417  			replyOptions: header.IPv4Options{
  1418  				68, 24, 25, 0x00,
  1419  				1, 2, 3, 4,
  1420  				5, 6, 7, 8,
  1421  				9, 10, 11, 12,
  1422  				13, 14, 15, 16,
  1423  				0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock
  1424  			},
  1425  		},
  1426  		{
  1427  			// The timestamp area is full so add to the overflow count.
  1428  			name:              "multiple type 1 timestamps",
  1429  			maxTotalLength:    ipv4.MaxTotalSize,
  1430  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1431  			TTL:               ttl,
  1432  			options: header.IPv4Options{
  1433  				68, 20, 21, 0x11,
  1434  				//            ^
  1435  				192, 168, 1, 12,
  1436  				1, 2, 3, 4,
  1437  				192, 168, 1, 13,
  1438  				5, 6, 7, 8,
  1439  			},
  1440  			// Overflow count is the top nibble of the 4th byte.
  1441  			replyOptions: header.IPv4Options{
  1442  				68, 20, 21, 0x21,
  1443  				//            ^
  1444  				192, 168, 1, 12,
  1445  				1, 2, 3, 4,
  1446  				192, 168, 1, 13,
  1447  				5, 6, 7, 8,
  1448  			},
  1449  		},
  1450  		{
  1451  			name:              "multiple type 1 timestamps with room",
  1452  			maxTotalLength:    ipv4.MaxTotalSize,
  1453  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1454  			TTL:               ttl,
  1455  			options: header.IPv4Options{
  1456  				68, 28, 21, 0x01,
  1457  				192, 168, 1, 12,
  1458  				1, 2, 3, 4,
  1459  				192, 168, 1, 13,
  1460  				5, 6, 7, 8,
  1461  				0, 0, 0, 0,
  1462  				0, 0, 0, 0,
  1463  			},
  1464  			replyOptions: header.IPv4Options{
  1465  				68, 28, 29, 0x01,
  1466  				192, 168, 1, 12,
  1467  				1, 2, 3, 4,
  1468  				192, 168, 1, 13,
  1469  				5, 6, 7, 8,
  1470  				192, 168, 1, 58, // New IP Address.
  1471  				0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock
  1472  			},
  1473  		},
  1474  		{
  1475  			// Timestamp pointer uses one based counting so 0 is invalid.
  1476  			name:              "timestamp pointer invalid",
  1477  			maxTotalLength:    ipv4.MaxTotalSize,
  1478  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1479  			TTL:               ttl,
  1480  			options: header.IPv4Options{
  1481  				68, 8, 0, 0x00,
  1482  				//      ^ 0 instead of 5 or more.
  1483  				0, 0, 0, 0,
  1484  			},
  1485  			shouldFail:          true,
  1486  			expectErrorICMP:     true,
  1487  			ICMPType:            header.ICMPv4ParamProblem,
  1488  			ICMPCode:            header.ICMPv4UnusedCode,
  1489  			paramProblemPointer: header.IPv4MinimumSize + 2,
  1490  		},
  1491  		{
  1492  			// Timestamp pointer cannot be less than 5. It must point past the header
  1493  			// which is 4 bytes. (1 based counting)
  1494  			name:              "timestamp pointer too small by 1",
  1495  			maxTotalLength:    ipv4.MaxTotalSize,
  1496  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1497  			TTL:               ttl,
  1498  			options: header.IPv4Options{
  1499  				68, 8, header.IPv4OptionTimestampHdrLength, 0x00,
  1500  				//          ^ header is 4 bytes, so 4 should fail.
  1501  				0, 0, 0, 0,
  1502  			},
  1503  			shouldFail:          true,
  1504  			expectErrorICMP:     true,
  1505  			ICMPType:            header.ICMPv4ParamProblem,
  1506  			ICMPCode:            header.ICMPv4UnusedCode,
  1507  			paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptTSPointerOffset,
  1508  		},
  1509  		{
  1510  			name:              "valid timestamp pointer",
  1511  			maxTotalLength:    ipv4.MaxTotalSize,
  1512  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1513  			TTL:               ttl,
  1514  			options: header.IPv4Options{
  1515  				68, 8, header.IPv4OptionTimestampHdrLength + 1, 0x00,
  1516  				//          ^ header is 4 bytes, so 5 should succeed.
  1517  				0, 0, 0, 0,
  1518  			},
  1519  			replyOptions: header.IPv4Options{
  1520  				68, 8, 9, 0x00,
  1521  				0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock
  1522  			},
  1523  		},
  1524  		{
  1525  			// Needs 8 bytes for a type 1 timestamp but there are only 4 free.
  1526  			name:              "bad timer element alignment",
  1527  			maxTotalLength:    ipv4.MaxTotalSize,
  1528  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1529  			TTL:               ttl,
  1530  			options: header.IPv4Options{
  1531  				68, 20, 17, 0x01,
  1532  				//  ^^  ^^   20 byte area, next free spot at 17.
  1533  				192, 168, 1, 12,
  1534  				1, 2, 3, 4,
  1535  				0, 0, 0, 0,
  1536  				0, 0, 0, 0,
  1537  			},
  1538  			shouldFail:          true,
  1539  			expectErrorICMP:     true,
  1540  			ICMPType:            header.ICMPv4ParamProblem,
  1541  			ICMPCode:            header.ICMPv4UnusedCode,
  1542  			paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptTSPointerOffset,
  1543  		},
  1544  		// End of option list with illegal option after it, which should be ignored.
  1545  		{
  1546  			name:              "end of options list",
  1547  			maxTotalLength:    ipv4.MaxTotalSize,
  1548  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1549  			TTL:               ttl,
  1550  			options: header.IPv4Options{
  1551  				68, 12, 13, 0x11,
  1552  				192, 168, 1, 12,
  1553  				1, 2, 3, 4,
  1554  				0, 10, 3, 99, // EOL followed by junk
  1555  			},
  1556  			replyOptions: header.IPv4Options{
  1557  				68, 12, 13, 0x21,
  1558  				192, 168, 1, 12,
  1559  				1, 2, 3, 4,
  1560  				0,       // End of Options hides following bytes.
  1561  				0, 0, 0, // 3 bytes unknown option removed.
  1562  			},
  1563  		},
  1564  		{
  1565  			// Timestamp with a size much too small.
  1566  			name:              "timestamp truncated",
  1567  			maxTotalLength:    ipv4.MaxTotalSize,
  1568  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1569  			TTL:               ttl,
  1570  			options: header.IPv4Options{
  1571  				68, 1, 0, 0,
  1572  				//  ^ Smallest possible is 8. Linux points at the 68.
  1573  			},
  1574  			shouldFail:          true,
  1575  			expectErrorICMP:     true,
  1576  			ICMPType:            header.ICMPv4ParamProblem,
  1577  			ICMPCode:            header.ICMPv4UnusedCode,
  1578  			paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength,
  1579  		},
  1580  		{
  1581  			name:              "single record route with room",
  1582  			maxTotalLength:    ipv4.MaxTotalSize,
  1583  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1584  			TTL:               ttl,
  1585  			options: header.IPv4Options{
  1586  				7, 7, 4, //  3 byte header
  1587  				0, 0, 0, 0,
  1588  				0,
  1589  			},
  1590  			replyOptions: header.IPv4Options{
  1591  				7, 7, 8, // 3 byte header
  1592  				192, 168, 1, 58, // New IP Address.
  1593  				0, // padding to multiple of 4 bytes.
  1594  			},
  1595  		},
  1596  		{
  1597  			name:              "multiple record route with room",
  1598  			maxTotalLength:    ipv4.MaxTotalSize,
  1599  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1600  			TTL:               ttl,
  1601  			options: header.IPv4Options{
  1602  				7, 23, 20, //  3 byte header
  1603  				1, 2, 3, 4,
  1604  				5, 6, 7, 8,
  1605  				9, 10, 11, 12,
  1606  				13, 14, 15, 16,
  1607  				0, 0, 0, 0,
  1608  				0,
  1609  			},
  1610  			replyOptions: header.IPv4Options{
  1611  				7, 23, 24,
  1612  				1, 2, 3, 4,
  1613  				5, 6, 7, 8,
  1614  				9, 10, 11, 12,
  1615  				13, 14, 15, 16,
  1616  				192, 168, 1, 58, // New IP Address.
  1617  				0, // padding to multiple of 4 bytes.
  1618  			},
  1619  		},
  1620  		{
  1621  			name:              "single record route with no room",
  1622  			maxTotalLength:    ipv4.MaxTotalSize,
  1623  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1624  			TTL:               ttl,
  1625  			options: header.IPv4Options{
  1626  				7, 7, 8, // 3 byte header
  1627  				1, 2, 3, 4,
  1628  				0,
  1629  			},
  1630  			replyOptions: header.IPv4Options{
  1631  				7, 7, 8, // 3 byte header
  1632  				1, 2, 3, 4,
  1633  				0, // padding to multiple of 4 bytes.
  1634  			},
  1635  		},
  1636  		{
  1637  			// Unlike timestamp, this should just succeed.
  1638  			name:              "multiple record route with no room",
  1639  			maxTotalLength:    ipv4.MaxTotalSize,
  1640  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1641  			TTL:               ttl,
  1642  			options: header.IPv4Options{
  1643  				7, 23, 24, // 3 byte header
  1644  				1, 2, 3, 4,
  1645  				5, 6, 7, 8,
  1646  				9, 10, 11, 12,
  1647  				13, 14, 15, 16,
  1648  				17, 18, 19, 20,
  1649  				0,
  1650  			},
  1651  			replyOptions: header.IPv4Options{
  1652  				7, 23, 24,
  1653  				1, 2, 3, 4,
  1654  				5, 6, 7, 8,
  1655  				9, 10, 11, 12,
  1656  				13, 14, 15, 16,
  1657  				17, 18, 19, 20,
  1658  				0, // padding to multiple of 4 bytes.
  1659  			},
  1660  		},
  1661  		{
  1662  			// Pointer uses one based counting so 0 is invalid.
  1663  			name:              "record route pointer zero",
  1664  			maxTotalLength:    ipv4.MaxTotalSize,
  1665  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1666  			TTL:               ttl,
  1667  			options: header.IPv4Options{
  1668  				7, 8, 0, // 3 byte header
  1669  				0, 0, 0, 0,
  1670  				0,
  1671  			},
  1672  			shouldFail:          true,
  1673  			expectErrorICMP:     true,
  1674  			ICMPType:            header.ICMPv4ParamProblem,
  1675  			ICMPCode:            header.ICMPv4UnusedCode,
  1676  			paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptRRPointerOffset,
  1677  		},
  1678  		{
  1679  			// Pointer must be 4 or more as it must point past the 3 byte header
  1680  			// using 1 based counting. 3 should fail.
  1681  			name:              "record route pointer too small by 1",
  1682  			maxTotalLength:    ipv4.MaxTotalSize,
  1683  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1684  			TTL:               ttl,
  1685  			options: header.IPv4Options{
  1686  				7, 8, header.IPv4OptionRecordRouteHdrLength, // 3 byte header
  1687  				0, 0, 0, 0,
  1688  				0,
  1689  			},
  1690  			shouldFail:          true,
  1691  			expectErrorICMP:     true,
  1692  			ICMPType:            header.ICMPv4ParamProblem,
  1693  			ICMPCode:            header.ICMPv4UnusedCode,
  1694  			paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptRRPointerOffset,
  1695  		},
  1696  		{
  1697  			// Pointer must be 4 or more as it must point past the 3 byte header
  1698  			// using 1 based counting. Check 4 passes. (Duplicates "single
  1699  			// record route with room")
  1700  			name:              "valid record route pointer",
  1701  			maxTotalLength:    ipv4.MaxTotalSize,
  1702  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1703  			TTL:               ttl,
  1704  			options: header.IPv4Options{
  1705  				7, 7, header.IPv4OptionRecordRouteHdrLength + 1, // 3 byte header
  1706  				0, 0, 0, 0,
  1707  				0,
  1708  			},
  1709  			replyOptions: header.IPv4Options{
  1710  				7, 7, 8, // 3 byte header
  1711  				192, 168, 1, 58, // New IP Address.
  1712  				0, // padding to multiple of 4 bytes.
  1713  			},
  1714  		},
  1715  		{
  1716  			// Confirm Linux bug for bug compatibility.
  1717  			// Linux returns slot 22 but the error is in slot 21.
  1718  			name:              "multiple record route with not enough room",
  1719  			maxTotalLength:    ipv4.MaxTotalSize,
  1720  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1721  			TTL:               ttl,
  1722  			options: header.IPv4Options{
  1723  				7, 8, 8, // 3 byte header
  1724  				// ^  ^ Linux points here. We must too.
  1725  				// | Not enough room. 1 byte free, need 4.
  1726  				1, 2, 3, 4,
  1727  				0,
  1728  			},
  1729  			shouldFail:          true,
  1730  			expectErrorICMP:     true,
  1731  			ICMPType:            header.ICMPv4ParamProblem,
  1732  			ICMPCode:            header.ICMPv4UnusedCode,
  1733  			paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptRRPointerOffset,
  1734  		},
  1735  		{
  1736  			name:              "duplicate record route",
  1737  			maxTotalLength:    ipv4.MaxTotalSize,
  1738  			transportProtocol: uint8(header.ICMPv4ProtocolNumber),
  1739  			TTL:               ttl,
  1740  			options: header.IPv4Options{
  1741  				7, 7, 8, // 3 byte header
  1742  				1, 2, 3, 4,
  1743  				7, 7, 8, // 3 byte header
  1744  				1, 2, 3, 4,
  1745  				0, 0, // pad
  1746  			},
  1747  			shouldFail:          true,
  1748  			expectErrorICMP:     true,
  1749  			ICMPType:            header.ICMPv4ParamProblem,
  1750  			ICMPCode:            header.ICMPv4UnusedCode,
  1751  			paramProblemPointer: header.IPv4MinimumSize + 7,
  1752  		},
  1753  	}
  1754  
  1755  	for _, test := range tests {
  1756  		t.Run(test.name, func(t *testing.T) {
  1757  			ctx := newTestContext()
  1758  			defer ctx.cleanup()
  1759  			s := ctx.s
  1760  			clock := ctx.clock
  1761  
  1762  			// Advance the clock by some unimportant amount to make
  1763  			// it give a more recognisable signature than 00,00,00,00.
  1764  			clock.Advance(time.Millisecond * randomTimeOffset)
  1765  
  1766  			// We expect at most a single packet in response to our ICMP Echo Request.
  1767  			e := channel.New(1, ipv4.MaxTotalSize, "")
  1768  			defer e.Close()
  1769  			if err := s.CreateNIC(nicID, e); err != nil {
  1770  				t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
  1771  			}
  1772  			ipv4ProtoAddr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: ipv4Addr}
  1773  			if err := s.AddProtocolAddress(nicID, ipv4ProtoAddr, stack.AddressProperties{}); err != nil {
  1774  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, ipv4ProtoAddr, err)
  1775  			}
  1776  
  1777  			// Default routes for IPv4 so ICMP can find a route to the remote
  1778  			// node when attempting to send the ICMP Echo Reply.
  1779  			s.SetRouteTable([]tcpip.Route{
  1780  				{
  1781  					Destination: header.IPv4EmptySubnet,
  1782  					NIC:         nicID,
  1783  				},
  1784  			})
  1785  
  1786  			if len(test.options)%4 != 0 {
  1787  				t.Fatalf("options must be aligned to 32 bits, invalid test options: %x (len=%d)", test.options, len(test.options))
  1788  			}
  1789  			ipHeaderLength := header.IPv4MinimumSize + len(test.options)
  1790  			if ipHeaderLength > header.IPv4MaximumHeaderSize {
  1791  				t.Fatalf("IP header length too large: got = %d, want <= %d ", ipHeaderLength, header.IPv4MaximumHeaderSize)
  1792  			}
  1793  			totalLen := uint16(ipHeaderLength + header.ICMPv4MinimumSize)
  1794  			hdr := prependable.New(int(totalLen))
  1795  			icmpH := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
  1796  
  1797  			// Specify ident/seq to make sure we get the same in the response.
  1798  			icmpH.SetIdent(randomIdent)
  1799  			icmpH.SetSequence(randomSequence)
  1800  			icmpH.SetType(header.ICMPv4Echo)
  1801  			icmpH.SetCode(header.ICMPv4UnusedCode)
  1802  			icmpH.SetChecksum(0)
  1803  			icmpH.SetChecksum(^checksum.Checksum(icmpH, 0))
  1804  			ip := header.IPv4(hdr.Prepend(ipHeaderLength))
  1805  			if test.maxTotalLength < totalLen {
  1806  				totalLen = test.maxTotalLength
  1807  			}
  1808  			ip.Encode(&header.IPv4Fields{
  1809  				TotalLength: totalLen,
  1810  				Protocol:    test.transportProtocol,
  1811  				TTL:         test.TTL,
  1812  				SrcAddr:     remoteIPv4Addr,
  1813  				DstAddr:     ipv4Addr.Address,
  1814  			})
  1815  			if test.headerLength != 0 {
  1816  				ip.SetHeaderLength(test.headerLength)
  1817  			} else {
  1818  				// Set the calculated header length, since we may manually add options.
  1819  				ip.SetHeaderLength(uint8(ipHeaderLength))
  1820  			}
  1821  			if len(test.options) != 0 {
  1822  				// Copy options manually. We do not use Encode for options so we can
  1823  				// verify malformed options with handcrafted payloads.
  1824  				if want, got := copy(ip.Options(), test.options), len(test.options); want != got {
  1825  					t.Fatalf("got copy(ip.Options(), test.options) = %d, want = %d", got, want)
  1826  				}
  1827  			}
  1828  			ip.SetChecksum(0)
  1829  			ipHeaderChecksum := ip.CalculateChecksum()
  1830  			if test.badHeaderChecksum {
  1831  				ipHeaderChecksum += 42
  1832  			}
  1833  			ip.SetChecksum(^ipHeaderChecksum)
  1834  			requestPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  1835  				Payload: buffer.MakeWithData(hdr.View()),
  1836  			})
  1837  			defer requestPkt.DecRef()
  1838  			e.InjectInbound(header.IPv4ProtocolNumber, requestPkt)
  1839  			reply := e.Read()
  1840  			if reply == nil {
  1841  				if test.shouldFail {
  1842  					if test.expectErrorICMP {
  1843  						t.Fatalf("ICMP error response (type %d, code %d) missing", test.ICMPType, test.ICMPCode)
  1844  					}
  1845  					return // Expected silent failure.
  1846  				}
  1847  				t.Fatal("expected ICMP echo reply missing")
  1848  			}
  1849  			defer reply.DecRef()
  1850  
  1851  			// We didn't expect a packet. Register our surprise but carry on to
  1852  			// provide more information about what we got.
  1853  			if test.shouldFail && !test.expectErrorICMP {
  1854  				t.Error("unexpected packet response")
  1855  			}
  1856  
  1857  			// Check the route that brought the packet to us.
  1858  			if reply.EgressRoute.LocalAddress != ipv4Addr.Address {
  1859  				t.Errorf("got pkt.Route.LocalAddress = %s, want = %s", reply.EgressRoute.LocalAddress, ipv4Addr.Address)
  1860  			}
  1861  			if reply.EgressRoute.RemoteAddress != remoteIPv4Addr {
  1862  				t.Errorf("got pkt.Route.RemoteAddress = %s, want = %s", reply.EgressRoute.RemoteAddress, remoteIPv4Addr)
  1863  			}
  1864  
  1865  			// Make sure it's all in one buffer for checker.
  1866  			replyIPHeader := stack.PayloadSince(reply.NetworkHeader())
  1867  			defer replyIPHeader.Release()
  1868  
  1869  			// At this stage we only know it's probably an IP+ICMP header so verify
  1870  			// that much.
  1871  			checker.IPv4(t, replyIPHeader,
  1872  				checker.SrcAddr(ipv4Addr.Address),
  1873  				checker.DstAddr(remoteIPv4Addr),
  1874  				checker.ICMPv4(
  1875  					checker.ICMPv4Checksum(),
  1876  				),
  1877  			)
  1878  
  1879  			// Don't proceed any further if the checker found problems.
  1880  			if t.Failed() {
  1881  				t.FailNow()
  1882  			}
  1883  
  1884  			// OK it's ICMP. We can safely look at the type now.
  1885  			replyICMPHeader := header.ICMPv4(header.IPv4(replyIPHeader.AsSlice()).Payload())
  1886  			switch replyICMPHeader.Type() {
  1887  			case header.ICMPv4ParamProblem:
  1888  				if !test.shouldFail {
  1889  					t.Fatalf("got Parameter Problem with pointer %d, wanted Echo Reply", replyICMPHeader.Pointer())
  1890  				}
  1891  				if !test.expectErrorICMP {
  1892  					t.Fatalf("got Parameter Problem with pointer %d, wanted no response", replyICMPHeader.Pointer())
  1893  				}
  1894  				checker.IPv4(t, replyIPHeader,
  1895  					checker.IPFullLength(uint16(header.IPv4MinimumSize+header.ICMPv4MinimumSize+requestPkt.Size())),
  1896  					checker.IPv4HeaderLength(header.IPv4MinimumSize),
  1897  					checker.ICMPv4(
  1898  						checker.ICMPv4Type(test.ICMPType),
  1899  						checker.ICMPv4Code(test.ICMPCode),
  1900  						checker.ICMPv4Pointer(test.paramProblemPointer),
  1901  						checker.ICMPv4Payload(hdr.View()),
  1902  					),
  1903  				)
  1904  				return
  1905  			case header.ICMPv4DstUnreachable:
  1906  				if !test.shouldFail {
  1907  					t.Fatalf("got ICMP error packet type %d, code %d, wanted Echo Reply",
  1908  						header.ICMPv4DstUnreachable, replyICMPHeader.Code())
  1909  				}
  1910  				if !test.expectErrorICMP {
  1911  					t.Fatalf("got ICMP error packet type %d, code %d, wanted no response",
  1912  						header.ICMPv4DstUnreachable, replyICMPHeader.Code())
  1913  				}
  1914  				checker.IPv4(t, replyIPHeader,
  1915  					checker.IPFullLength(uint16(header.IPv4MinimumSize+header.ICMPv4MinimumSize+requestPkt.Size())),
  1916  					checker.IPv4HeaderLength(header.IPv4MinimumSize),
  1917  					checker.ICMPv4(
  1918  						checker.ICMPv4Type(test.ICMPType),
  1919  						checker.ICMPv4Code(test.ICMPCode),
  1920  						checker.ICMPv4Payload(hdr.View()),
  1921  					),
  1922  				)
  1923  				return
  1924  			case header.ICMPv4EchoReply:
  1925  				if test.shouldFail {
  1926  					if !test.expectErrorICMP {
  1927  						t.Error("got Echo Reply packet, want no response")
  1928  					} else {
  1929  						t.Errorf("got Echo Reply, want ICMP error type %d, code %d", test.ICMPType, test.ICMPCode)
  1930  					}
  1931  				}
  1932  				// If the IP options change size then the packet will change size, so
  1933  				// some IP header fields will need to be adjusted for the checks.
  1934  				sizeChange := len(test.replyOptions) - len(test.options)
  1935  
  1936  				checker.IPv4(t, replyIPHeader,
  1937  					checker.IPv4HeaderLength(ipHeaderLength+sizeChange),
  1938  					checker.IPv4Options(test.replyOptions),
  1939  					checker.IPFullLength(uint16(requestPkt.Size()+sizeChange)),
  1940  					checker.ICMPv4(
  1941  						checker.ICMPv4Checksum(),
  1942  						checker.ICMPv4Code(header.ICMPv4UnusedCode),
  1943  						checker.ICMPv4Seq(randomSequence),
  1944  						checker.ICMPv4Ident(randomIdent),
  1945  					),
  1946  				)
  1947  			default:
  1948  				t.Fatalf("unexpected ICMP response, got type %d, want = %d, %d or %d",
  1949  					replyICMPHeader.Type(), header.ICMPv4EchoReply, header.ICMPv4DstUnreachable, header.ICMPv4ParamProblem)
  1950  			}
  1951  		})
  1952  	}
  1953  }
  1954  
  1955  // compareFragments compares the contents of a set of fragmented packets against
  1956  // the contents of a source packet.
  1957  //
  1958  // If withIPHeader is set to true, we will validate the fragmented packets' IP
  1959  // headers against the source packet's IP header. If set to false, we validate
  1960  // the fragmented packets' IP headers against each other.
  1961  func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketBuffer, mtu uint32, wantFragments []fragmentInfo, proto tcpip.TransportProtocolNumber, withIPHeader bool, expectedAvailableHeaderBytes int) error {
  1962  	// Make a complete array of the sourcePacket packet.
  1963  	var source header.IPv4
  1964  	buf := sourcePacket.ToBuffer()
  1965  	defer buf.Release()
  1966  
  1967  	// If the packet to be fragmented contains an IPv4 header, use that header for
  1968  	// validating fragment headers. Else, use the header of the first fragment.
  1969  	if withIPHeader {
  1970  		source = header.IPv4(buf.Flatten())
  1971  	} else {
  1972  		source = header.IPv4(packets[0].NetworkHeader().Slice())
  1973  		source = append(source, buf.Flatten()...)
  1974  	}
  1975  
  1976  	// Make a copy of the IP header, which will be modified in some fields to make
  1977  	// an expected header.
  1978  	sourceCopy := header.IPv4(append([]byte{}, source[:source.HeaderLength()]...))
  1979  	sourceCopy.SetChecksum(0)
  1980  	sourceCopy.SetFlagsFragmentOffset(0, 0)
  1981  	sourceCopy.SetTotalLength(0)
  1982  	// Build up an array of the bytes sent.
  1983  	var reassembledPayload buffer.Buffer
  1984  	defer reassembledPayload.Release()
  1985  	for i, packet := range packets {
  1986  		// Confirm that the packet is valid.
  1987  		allBytes := packet.ToBuffer()
  1988  		defer allBytes.Release()
  1989  		fragmentIPHeader := header.IPv4(allBytes.Flatten())
  1990  		if !fragmentIPHeader.IsValid(len(fragmentIPHeader)) {
  1991  			return fmt.Errorf("fragment #%d: IP packet is invalid:\n%s", i, hex.Dump(fragmentIPHeader))
  1992  		}
  1993  		if got := len(fragmentIPHeader); got > int(mtu) {
  1994  			return fmt.Errorf("fragment #%d: got len(fragmentIPHeader) = %d, want <= %d", i, got, mtu)
  1995  		}
  1996  		if got := fragmentIPHeader.TransportProtocol(); got != proto {
  1997  			return fmt.Errorf("fragment #%d: got fragmentIPHeader.TransportProtocol() = %d, want = %d", i, got, uint8(proto))
  1998  		}
  1999  		if got, want := packet.NetworkProtocolNumber, sourcePacket.NetworkProtocolNumber; got != want {
  2000  			return fmt.Errorf("fragment #%d: got fragment.NetworkProtocolNumber = %d, want = %d", i, got, want)
  2001  		}
  2002  		if got := packet.AvailableHeaderBytes(); got != expectedAvailableHeaderBytes {
  2003  			return fmt.Errorf("fragment #%d: got packet.AvailableHeaderBytes() = %d, want = %d", i, got, expectedAvailableHeaderBytes)
  2004  		}
  2005  		if got, want := fragmentIPHeader.CalculateChecksum(), uint16(0xffff); got != want {
  2006  			return fmt.Errorf("fragment #%d: got ip.CalculateChecksum() = %#x, want = %#x", i, got, want)
  2007  		}
  2008  		if wantFragments[i].more {
  2009  			sourceCopy.SetFlagsFragmentOffset(sourceCopy.Flags()|header.IPv4FlagMoreFragments, wantFragments[i].offset)
  2010  		} else {
  2011  			sourceCopy.SetFlagsFragmentOffset(sourceCopy.Flags()&^header.IPv4FlagMoreFragments, wantFragments[i].offset)
  2012  		}
  2013  		reassembledPayload.Append(packet.TransportHeader().View())
  2014  		reassembledPayload.Append(packet.Data().AsRange().ToView())
  2015  		// Clear out the checksum and length from the ip because we can't compare
  2016  		// it.
  2017  		sourceCopy.SetTotalLength(wantFragments[i].payloadSize + header.IPv4MinimumSize)
  2018  		sourceCopy.SetChecksum(0)
  2019  		sourceCopy.SetChecksum(^sourceCopy.CalculateChecksum())
  2020  
  2021  		// If we are validating against the original IP header, we should exclude the
  2022  		// ID field, which will only be set fo fragmented packets.
  2023  		if withIPHeader {
  2024  			fragmentIPHeader.SetID(0)
  2025  			fragmentIPHeader.SetChecksum(0)
  2026  			fragmentIPHeader.SetChecksum(^fragmentIPHeader.CalculateChecksum())
  2027  		}
  2028  		if diff := cmp.Diff(fragmentIPHeader[:fragmentIPHeader.HeaderLength()], sourceCopy[:sourceCopy.HeaderLength()]); diff != "" {
  2029  			return fmt.Errorf("fragment #%d: fragmentIPHeader mismatch (-want +got):\n%s", i, diff)
  2030  		}
  2031  	}
  2032  
  2033  	expected := []byte(source[source.HeaderLength():])
  2034  	if diff := cmp.Diff(expected, reassembledPayload.Flatten()); diff != "" {
  2035  		return fmt.Errorf("reassembledPayload mismatch (-want +got):\n%s", diff)
  2036  	}
  2037  
  2038  	return nil
  2039  }
  2040  
  2041  type fragmentInfo struct {
  2042  	offset      uint16
  2043  	more        bool
  2044  	payloadSize uint16
  2045  }
  2046  
  2047  var fragmentationTests = []struct {
  2048  	description           string
  2049  	mtu                   uint32
  2050  	transportHeaderLength int
  2051  	payloadSize           int
  2052  	wantFragments         []fragmentInfo
  2053  }{
  2054  	{
  2055  		description:           "No fragmentation",
  2056  		mtu:                   1280,
  2057  		transportHeaderLength: 0,
  2058  		payloadSize:           1000,
  2059  		wantFragments: []fragmentInfo{
  2060  			{offset: 0, payloadSize: 1000, more: false},
  2061  		},
  2062  	},
  2063  	{
  2064  		description:           "Fragmented",
  2065  		mtu:                   1280,
  2066  		transportHeaderLength: 0,
  2067  		payloadSize:           2000,
  2068  		wantFragments: []fragmentInfo{
  2069  			{offset: 0, payloadSize: 1256, more: true},
  2070  			{offset: 1256, payloadSize: 744, more: false},
  2071  		},
  2072  	},
  2073  	{
  2074  		description:           "Fragmented with the minimum mtu",
  2075  		mtu:                   header.IPv4MinimumMTU,
  2076  		transportHeaderLength: 0,
  2077  		payloadSize:           100,
  2078  		wantFragments: []fragmentInfo{
  2079  			{offset: 0, payloadSize: 48, more: true},
  2080  			{offset: 48, payloadSize: 48, more: true},
  2081  			{offset: 96, payloadSize: 4, more: false},
  2082  		},
  2083  	},
  2084  	{
  2085  		description:           "Fragmented with mtu not a multiple of 8",
  2086  		mtu:                   header.IPv4MinimumMTU + 1,
  2087  		transportHeaderLength: 0,
  2088  		payloadSize:           100,
  2089  		wantFragments: []fragmentInfo{
  2090  			{offset: 0, payloadSize: 48, more: true},
  2091  			{offset: 48, payloadSize: 48, more: true},
  2092  			{offset: 96, payloadSize: 4, more: false},
  2093  		},
  2094  	},
  2095  	{
  2096  		description:           "No fragmentation with big header",
  2097  		mtu:                   2000,
  2098  		transportHeaderLength: 100,
  2099  		payloadSize:           1000,
  2100  		wantFragments: []fragmentInfo{
  2101  			{offset: 0, payloadSize: 1100, more: false},
  2102  		},
  2103  	},
  2104  	{
  2105  		description:           "Fragmented with big header",
  2106  		mtu:                   1280,
  2107  		transportHeaderLength: 100,
  2108  		payloadSize:           1200,
  2109  		wantFragments: []fragmentInfo{
  2110  			{offset: 0, payloadSize: 1256, more: true},
  2111  			{offset: 1256, payloadSize: 44, more: false},
  2112  		},
  2113  	},
  2114  	{
  2115  		description:           "Fragmented with MTU smaller than header",
  2116  		mtu:                   300,
  2117  		transportHeaderLength: 1000,
  2118  		payloadSize:           500,
  2119  		wantFragments: []fragmentInfo{
  2120  			{offset: 0, payloadSize: 280, more: true},
  2121  			{offset: 280, payloadSize: 280, more: true},
  2122  			{offset: 560, payloadSize: 280, more: true},
  2123  			{offset: 840, payloadSize: 280, more: true},
  2124  			{offset: 1120, payloadSize: 280, more: true},
  2125  			{offset: 1400, payloadSize: 100, more: false},
  2126  		},
  2127  	},
  2128  }
  2129  
  2130  func TestFragmentationWritePacket(t *testing.T) {
  2131  	const ttl = 42
  2132  
  2133  	for _, ft := range fragmentationTests {
  2134  		t.Run(ft.description, func(t *testing.T) {
  2135  			ctx := newTestContext()
  2136  			defer ctx.cleanup()
  2137  
  2138  			ep := iptestutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32)
  2139  			defer ep.Close()
  2140  			r := buildRoute(t, ctx, ep)
  2141  			defer r.Release()
  2142  			pkt := iptestutil.MakeRandPkt(ft.transportHeaderLength, extraHeaderReserve+header.IPv4MinimumSize, []int{ft.payloadSize}, header.IPv4ProtocolNumber)
  2143  			defer pkt.DecRef()
  2144  			source := pkt.Clone()
  2145  			defer source.DecRef()
  2146  			err := r.WritePacket(stack.NetworkHeaderParams{
  2147  				Protocol: tcp.ProtocolNumber,
  2148  				TTL:      ttl,
  2149  				TOS:      stack.DefaultTOS,
  2150  			}, pkt)
  2151  			if err != nil {
  2152  				t.Fatalf("r.WritePacket(...): %s", err)
  2153  			}
  2154  			if got := len(ep.WrittenPackets); got != len(ft.wantFragments) {
  2155  				t.Errorf("got len(ep.WrittenPackets) = %d, want = %d", got, len(ft.wantFragments))
  2156  			}
  2157  			if got := int(r.Stats().IP.PacketsSent.Value()); got != len(ft.wantFragments) {
  2158  				t.Errorf("got c.Route.Stats().IP.PacketsSent.Value() = %d, want = %d", got, len(ft.wantFragments))
  2159  			}
  2160  			if got := r.Stats().IP.OutgoingPacketErrors.Value(); got != 0 {
  2161  				t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = 0", got)
  2162  			}
  2163  			if err := compareFragments(ep.WrittenPackets, source, ft.mtu, ft.wantFragments, tcp.ProtocolNumber, false /* withIPHeader */, extraHeaderReserve); err != nil {
  2164  				t.Error(err)
  2165  			}
  2166  		})
  2167  	}
  2168  }
  2169  
  2170  // TestFragmentationErrors checks that errors are returned from WritePacket
  2171  // correctly.
  2172  func TestFragmentationErrors(t *testing.T) {
  2173  	const ttl = 42
  2174  
  2175  	tests := []struct {
  2176  		description           string
  2177  		mtu                   uint32
  2178  		transportHeaderLength int
  2179  		payloadSize           int
  2180  		allowPackets          int
  2181  		outgoingErrors        int
  2182  		mockError             tcpip.Error
  2183  		wantError             tcpip.Error
  2184  	}{
  2185  		{
  2186  			description:           "No frag",
  2187  			mtu:                   2000,
  2188  			payloadSize:           1000,
  2189  			transportHeaderLength: 0,
  2190  			allowPackets:          0,
  2191  			outgoingErrors:        1,
  2192  			mockError:             &tcpip.ErrAborted{},
  2193  			wantError:             &tcpip.ErrAborted{},
  2194  		},
  2195  		{
  2196  			description:           "Error on first frag",
  2197  			mtu:                   500,
  2198  			payloadSize:           1000,
  2199  			transportHeaderLength: 0,
  2200  			allowPackets:          0,
  2201  			outgoingErrors:        3,
  2202  			mockError:             &tcpip.ErrAborted{},
  2203  			wantError:             &tcpip.ErrAborted{},
  2204  		},
  2205  		{
  2206  			description:           "Error on second frag",
  2207  			mtu:                   500,
  2208  			payloadSize:           1000,
  2209  			transportHeaderLength: 0,
  2210  			allowPackets:          1,
  2211  			outgoingErrors:        2,
  2212  			mockError:             &tcpip.ErrAborted{},
  2213  			wantError:             &tcpip.ErrAborted{},
  2214  		},
  2215  		{
  2216  			description:           "Error on first frag MTU smaller than header",
  2217  			mtu:                   500,
  2218  			transportHeaderLength: 1000,
  2219  			payloadSize:           500,
  2220  			allowPackets:          0,
  2221  			outgoingErrors:        4,
  2222  			mockError:             &tcpip.ErrAborted{},
  2223  			wantError:             &tcpip.ErrAborted{},
  2224  		},
  2225  		{
  2226  			description:           "Error when MTU is smaller than IPv4 minimum MTU",
  2227  			mtu:                   header.IPv4MinimumMTU - 1,
  2228  			transportHeaderLength: 0,
  2229  			payloadSize:           500,
  2230  			allowPackets:          0,
  2231  			outgoingErrors:        1,
  2232  			mockError:             nil,
  2233  			wantError:             &tcpip.ErrInvalidEndpointState{},
  2234  		},
  2235  	}
  2236  
  2237  	for _, ft := range tests {
  2238  		t.Run(ft.description, func(t *testing.T) {
  2239  			ctx := newTestContext()
  2240  			defer ctx.cleanup()
  2241  
  2242  			ep := iptestutil.NewMockLinkEndpoint(ft.mtu, ft.mockError, ft.allowPackets)
  2243  			defer ep.Close()
  2244  			r := buildRoute(t, ctx, ep)
  2245  			defer r.Release()
  2246  			pkt := iptestutil.MakeRandPkt(ft.transportHeaderLength, extraHeaderReserve+header.IPv4MinimumSize, []int{ft.payloadSize}, header.IPv4ProtocolNumber)
  2247  			defer pkt.DecRef()
  2248  			err := r.WritePacket(stack.NetworkHeaderParams{
  2249  				Protocol: tcp.ProtocolNumber,
  2250  				TTL:      ttl,
  2251  				TOS:      stack.DefaultTOS,
  2252  			}, pkt)
  2253  			if diff := cmp.Diff(ft.wantError, err); diff != "" {
  2254  				t.Fatalf("unexpected error from r.WritePacket(_, _, _), (-want, +got):\n%s", diff)
  2255  			}
  2256  			if got := int(r.Stats().IP.PacketsSent.Value()); got != ft.allowPackets {
  2257  				t.Errorf("got r.Stats().IP.PacketsSent.Value() = %d, want = %d", got, ft.allowPackets)
  2258  			}
  2259  			if got := int(r.Stats().IP.OutgoingPacketErrors.Value()); got != ft.outgoingErrors {
  2260  				t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = %d", got, ft.outgoingErrors)
  2261  			}
  2262  		})
  2263  	}
  2264  }
  2265  
  2266  func TestInvalidFragments(t *testing.T) {
  2267  	const (
  2268  		nicID    = 1
  2269  		linkAddr = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e")
  2270  		tos      = 0
  2271  		ident    = 1
  2272  		ttl      = 48
  2273  		protocol = 6
  2274  	)
  2275  
  2276  	var (
  2277  		addr1 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x01"))
  2278  		addr2 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x02"))
  2279  	)
  2280  
  2281  	payloadGen := func(payloadLen int) []byte {
  2282  		payload := make([]byte, payloadLen)
  2283  		for i := 0; i < len(payload); i++ {
  2284  			payload[i] = 0x30
  2285  		}
  2286  		return payload
  2287  	}
  2288  
  2289  	type fragmentData struct {
  2290  		ipv4fields header.IPv4Fields
  2291  		// 0 means insert the correct IHL. Non 0 means override the correct IHL.
  2292  		overrideIHL  int // For 0 use 1 as it is an int and will be divided by 4.
  2293  		payload      []byte
  2294  		autoChecksum bool // If true, the Checksum field will be overwritten.
  2295  	}
  2296  
  2297  	tests := []struct {
  2298  		name                   string
  2299  		fragments              []fragmentData
  2300  		wantMalformedIPPackets uint64
  2301  		wantMalformedFragments uint64
  2302  	}{
  2303  		{
  2304  			name: "IHL and TotalLength zero, FragmentOffset non-zero",
  2305  			fragments: []fragmentData{
  2306  				{
  2307  					ipv4fields: header.IPv4Fields{
  2308  						TOS:            tos,
  2309  						TotalLength:    0,
  2310  						ID:             ident,
  2311  						Flags:          header.IPv4FlagDontFragment | header.IPv4FlagMoreFragments,
  2312  						FragmentOffset: 59776,
  2313  						TTL:            ttl,
  2314  						Protocol:       protocol,
  2315  						SrcAddr:        addr1,
  2316  						DstAddr:        addr2,
  2317  					},
  2318  					overrideIHL:  1, // See note above.
  2319  					payload:      payloadGen(12),
  2320  					autoChecksum: true,
  2321  				},
  2322  			},
  2323  			wantMalformedIPPackets: 1,
  2324  			wantMalformedFragments: 0,
  2325  		},
  2326  		{
  2327  			name: "IHL and TotalLength zero, FragmentOffset zero",
  2328  			fragments: []fragmentData{
  2329  				{
  2330  					ipv4fields: header.IPv4Fields{
  2331  						TOS:            tos,
  2332  						TotalLength:    0,
  2333  						ID:             ident,
  2334  						Flags:          header.IPv4FlagMoreFragments,
  2335  						FragmentOffset: 0,
  2336  						TTL:            ttl,
  2337  						Protocol:       protocol,
  2338  						SrcAddr:        addr1,
  2339  						DstAddr:        addr2,
  2340  					},
  2341  					overrideIHL:  1, // See note above.
  2342  					payload:      payloadGen(12),
  2343  					autoChecksum: true,
  2344  				},
  2345  			},
  2346  			wantMalformedIPPackets: 1,
  2347  			wantMalformedFragments: 0,
  2348  		},
  2349  		{
  2350  			// Payload 17 octets and Fragment offset 65520
  2351  			// Leading to the fragment end to be past 65536.
  2352  			name: "fragment ends past 65536",
  2353  			fragments: []fragmentData{
  2354  				{
  2355  					ipv4fields: header.IPv4Fields{
  2356  						TOS:            tos,
  2357  						TotalLength:    header.IPv4MinimumSize + 17,
  2358  						ID:             ident,
  2359  						Flags:          0,
  2360  						FragmentOffset: 65520,
  2361  						TTL:            ttl,
  2362  						Protocol:       protocol,
  2363  						SrcAddr:        addr1,
  2364  						DstAddr:        addr2,
  2365  					},
  2366  					payload:      payloadGen(17),
  2367  					autoChecksum: true,
  2368  				},
  2369  			},
  2370  			wantMalformedIPPackets: 1,
  2371  			wantMalformedFragments: 1,
  2372  		},
  2373  		{
  2374  			// Payload 16 octets and fragment offset 65520
  2375  			// Leading to the fragment end to be exactly 65536.
  2376  			name: "fragment ends exactly at 65536",
  2377  			fragments: []fragmentData{
  2378  				{
  2379  					ipv4fields: header.IPv4Fields{
  2380  						TOS:            tos,
  2381  						TotalLength:    header.IPv4MinimumSize + 16,
  2382  						ID:             ident,
  2383  						Flags:          0,
  2384  						FragmentOffset: 65520,
  2385  						TTL:            ttl,
  2386  						Protocol:       protocol,
  2387  						SrcAddr:        addr1,
  2388  						DstAddr:        addr2,
  2389  					},
  2390  					payload:      payloadGen(16),
  2391  					autoChecksum: true,
  2392  				},
  2393  			},
  2394  			wantMalformedIPPackets: 0,
  2395  			wantMalformedFragments: 0,
  2396  		},
  2397  		{
  2398  			name: "IHL less than IPv4 minimum size",
  2399  			fragments: []fragmentData{
  2400  				{
  2401  					ipv4fields: header.IPv4Fields{
  2402  						TOS:            tos,
  2403  						TotalLength:    header.IPv4MinimumSize + 28,
  2404  						ID:             ident,
  2405  						Flags:          0,
  2406  						FragmentOffset: 1944,
  2407  						TTL:            ttl,
  2408  						Protocol:       protocol,
  2409  						SrcAddr:        addr1,
  2410  						DstAddr:        addr2,
  2411  					},
  2412  					payload:      payloadGen(28),
  2413  					overrideIHL:  header.IPv4MinimumSize - 12,
  2414  					autoChecksum: true,
  2415  				},
  2416  				{
  2417  					ipv4fields: header.IPv4Fields{
  2418  						TOS:            tos,
  2419  						TotalLength:    header.IPv4MinimumSize - 12,
  2420  						ID:             ident,
  2421  						Flags:          header.IPv4FlagMoreFragments,
  2422  						FragmentOffset: 0,
  2423  						TTL:            ttl,
  2424  						Protocol:       protocol,
  2425  						SrcAddr:        addr1,
  2426  						DstAddr:        addr2,
  2427  					},
  2428  					payload:      payloadGen(28),
  2429  					overrideIHL:  header.IPv4MinimumSize - 12,
  2430  					autoChecksum: true,
  2431  				},
  2432  			},
  2433  			wantMalformedIPPackets: 2,
  2434  			wantMalformedFragments: 0,
  2435  		},
  2436  		{
  2437  			name: "fragment with short TotalLength and extra payload",
  2438  			fragments: []fragmentData{
  2439  				{
  2440  					ipv4fields: header.IPv4Fields{
  2441  						TOS:            tos,
  2442  						TotalLength:    header.IPv4MinimumSize + 28,
  2443  						ID:             ident,
  2444  						Flags:          0,
  2445  						FragmentOffset: 28816,
  2446  						TTL:            ttl,
  2447  						Protocol:       protocol,
  2448  						SrcAddr:        addr1,
  2449  						DstAddr:        addr2,
  2450  					},
  2451  					payload:      payloadGen(28),
  2452  					overrideIHL:  header.IPv4MinimumSize + 4,
  2453  					autoChecksum: true,
  2454  				},
  2455  				{
  2456  					ipv4fields: header.IPv4Fields{
  2457  						TOS:            tos,
  2458  						TotalLength:    header.IPv4MinimumSize + 4,
  2459  						ID:             ident,
  2460  						Flags:          header.IPv4FlagMoreFragments,
  2461  						FragmentOffset: 0,
  2462  						TTL:            ttl,
  2463  						Protocol:       protocol,
  2464  						SrcAddr:        addr1,
  2465  						DstAddr:        addr2,
  2466  					},
  2467  					payload:      payloadGen(28),
  2468  					overrideIHL:  header.IPv4MinimumSize + 4,
  2469  					autoChecksum: true,
  2470  				},
  2471  			},
  2472  			wantMalformedIPPackets: 1,
  2473  			wantMalformedFragments: 1,
  2474  		},
  2475  		{
  2476  			name: "multiple fragments with More Fragments flag set to false",
  2477  			fragments: []fragmentData{
  2478  				{
  2479  					ipv4fields: header.IPv4Fields{
  2480  						TOS:            tos,
  2481  						TotalLength:    header.IPv4MinimumSize + 8,
  2482  						ID:             ident,
  2483  						Flags:          0,
  2484  						FragmentOffset: 128,
  2485  						TTL:            ttl,
  2486  						Protocol:       protocol,
  2487  						SrcAddr:        addr1,
  2488  						DstAddr:        addr2,
  2489  					},
  2490  					payload:      payloadGen(8),
  2491  					autoChecksum: true,
  2492  				},
  2493  				{
  2494  					ipv4fields: header.IPv4Fields{
  2495  						TOS:            tos,
  2496  						TotalLength:    header.IPv4MinimumSize + 8,
  2497  						ID:             ident,
  2498  						Flags:          0,
  2499  						FragmentOffset: 8,
  2500  						TTL:            ttl,
  2501  						Protocol:       protocol,
  2502  						SrcAddr:        addr1,
  2503  						DstAddr:        addr2,
  2504  					},
  2505  					payload:      payloadGen(8),
  2506  					autoChecksum: true,
  2507  				},
  2508  				{
  2509  					ipv4fields: header.IPv4Fields{
  2510  						TOS:            tos,
  2511  						TotalLength:    header.IPv4MinimumSize + 8,
  2512  						ID:             ident,
  2513  						Flags:          header.IPv4FlagMoreFragments,
  2514  						FragmentOffset: 0,
  2515  						TTL:            ttl,
  2516  						Protocol:       protocol,
  2517  						SrcAddr:        addr1,
  2518  						DstAddr:        addr2,
  2519  					},
  2520  					payload:      payloadGen(8),
  2521  					autoChecksum: true,
  2522  				},
  2523  			},
  2524  			wantMalformedIPPackets: 1,
  2525  			wantMalformedFragments: 1,
  2526  		},
  2527  	}
  2528  
  2529  	for _, test := range tests {
  2530  		t.Run(test.name, func(t *testing.T) {
  2531  			ctx := newTestContext()
  2532  			defer ctx.cleanup()
  2533  			s := ctx.s
  2534  
  2535  			e := channel.New(0, 1500, linkAddr)
  2536  			defer e.Close()
  2537  			if err := s.CreateNIC(nicID, e); err != nil {
  2538  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  2539  			}
  2540  			protocolAddr := tcpip.ProtocolAddress{
  2541  				Protocol:          ipv4.ProtocolNumber,
  2542  				AddressWithPrefix: addr2.WithPrefix(),
  2543  			}
  2544  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  2545  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  2546  			}
  2547  
  2548  			for _, f := range test.fragments {
  2549  				pktSize := header.IPv4MinimumSize + len(f.payload)
  2550  				hdr := prependable.New(pktSize)
  2551  
  2552  				ip := header.IPv4(hdr.Prepend(pktSize))
  2553  				ip.Encode(&f.ipv4fields)
  2554  				if want, got := len(f.payload), copy(ip[header.IPv4MinimumSize:], f.payload); want != got {
  2555  					t.Fatalf("copied %d bytes, expected %d bytes.", got, want)
  2556  				}
  2557  				// Encode sets this up correctly. If we want a different value for
  2558  				// testing then we need to overwrite the good value.
  2559  				if f.overrideIHL != 0 {
  2560  					ip.SetHeaderLength(uint8(f.overrideIHL))
  2561  					// If we are asked to add options (type not specified) then pad
  2562  					// with 0 (EOL). RFC 791 page 23 says "The padding is zero".
  2563  					for i := header.IPv4MinimumSize; i < f.overrideIHL; i++ {
  2564  						ip[i] = byte(header.IPv4OptionListEndType)
  2565  					}
  2566  				}
  2567  
  2568  				if f.autoChecksum {
  2569  					ip.SetChecksum(0)
  2570  					ip.SetChecksum(^ip.CalculateChecksum())
  2571  				}
  2572  
  2573  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  2574  					Payload: buffer.MakeWithData(hdr.View()),
  2575  				})
  2576  				e.InjectInbound(header.IPv4ProtocolNumber, pkt)
  2577  				pkt.DecRef()
  2578  			}
  2579  
  2580  			if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.wantMalformedIPPackets; got != want {
  2581  				t.Errorf("incorrect Stats.IP.MalformedPacketsReceived, got: %d, want: %d", got, want)
  2582  			}
  2583  			if got, want := s.Stats().IP.MalformedFragmentsReceived.Value(), test.wantMalformedFragments; got != want {
  2584  				t.Errorf("incorrect Stats.IP.MalformedFragmentsReceived, got: %d, want: %d", got, want)
  2585  			}
  2586  		})
  2587  	}
  2588  }
  2589  
  2590  func TestFragmentReassemblyTimeout(t *testing.T) {
  2591  	const (
  2592  		nicID    = 1
  2593  		linkAddr = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e")
  2594  		tos      = 0
  2595  		ident    = 1
  2596  		ttl      = 48
  2597  		protocol = 99
  2598  		data     = "TEST_FRAGMENT_REASSEMBLY_TIMEOUT"
  2599  	)
  2600  
  2601  	var (
  2602  		addr1 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x01"))
  2603  		addr2 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x02"))
  2604  	)
  2605  
  2606  	type fragmentData struct {
  2607  		ipv4fields header.IPv4Fields
  2608  		payload    []byte
  2609  	}
  2610  
  2611  	tests := []struct {
  2612  		name       string
  2613  		fragments  []fragmentData
  2614  		expectICMP bool
  2615  	}{
  2616  		{
  2617  			name: "first fragment only",
  2618  			fragments: []fragmentData{
  2619  				{
  2620  					ipv4fields: header.IPv4Fields{
  2621  						TOS:            tos,
  2622  						TotalLength:    header.IPv4MinimumSize + 16,
  2623  						ID:             ident,
  2624  						Flags:          header.IPv4FlagMoreFragments,
  2625  						FragmentOffset: 0,
  2626  						TTL:            ttl,
  2627  						Protocol:       protocol,
  2628  						SrcAddr:        addr1,
  2629  						DstAddr:        addr2,
  2630  					},
  2631  					payload: []byte(data)[:16],
  2632  				},
  2633  			},
  2634  			expectICMP: true,
  2635  		},
  2636  		{
  2637  			name: "two first fragments",
  2638  			fragments: []fragmentData{
  2639  				{
  2640  					ipv4fields: header.IPv4Fields{
  2641  						TOS:            tos,
  2642  						TotalLength:    header.IPv4MinimumSize + 16,
  2643  						ID:             ident,
  2644  						Flags:          header.IPv4FlagMoreFragments,
  2645  						FragmentOffset: 0,
  2646  						TTL:            ttl,
  2647  						Protocol:       protocol,
  2648  						SrcAddr:        addr1,
  2649  						DstAddr:        addr2,
  2650  					},
  2651  					payload: []byte(data)[:16],
  2652  				},
  2653  				{
  2654  					ipv4fields: header.IPv4Fields{
  2655  						TOS:            tos,
  2656  						TotalLength:    header.IPv4MinimumSize + 16,
  2657  						ID:             ident,
  2658  						Flags:          header.IPv4FlagMoreFragments,
  2659  						FragmentOffset: 0,
  2660  						TTL:            ttl,
  2661  						Protocol:       protocol,
  2662  						SrcAddr:        addr1,
  2663  						DstAddr:        addr2,
  2664  					},
  2665  					payload: []byte(data)[:16],
  2666  				},
  2667  			},
  2668  			expectICMP: true,
  2669  		},
  2670  		{
  2671  			name: "second fragment only",
  2672  			fragments: []fragmentData{
  2673  				{
  2674  					ipv4fields: header.IPv4Fields{
  2675  						TOS:            tos,
  2676  						TotalLength:    uint16(header.IPv4MinimumSize + len(data) - 16),
  2677  						ID:             ident,
  2678  						Flags:          0,
  2679  						FragmentOffset: 8,
  2680  						TTL:            ttl,
  2681  						Protocol:       protocol,
  2682  						SrcAddr:        addr1,
  2683  						DstAddr:        addr2,
  2684  					},
  2685  					payload: []byte(data)[16:],
  2686  				},
  2687  			},
  2688  			expectICMP: false,
  2689  		},
  2690  		{
  2691  			name: "two fragments with a gap",
  2692  			fragments: []fragmentData{
  2693  				{
  2694  					ipv4fields: header.IPv4Fields{
  2695  						TOS:            tos,
  2696  						TotalLength:    header.IPv4MinimumSize + 8,
  2697  						ID:             ident,
  2698  						Flags:          header.IPv4FlagMoreFragments,
  2699  						FragmentOffset: 0,
  2700  						TTL:            ttl,
  2701  						Protocol:       protocol,
  2702  						SrcAddr:        addr1,
  2703  						DstAddr:        addr2,
  2704  					},
  2705  					payload: []byte(data)[:8],
  2706  				},
  2707  				{
  2708  					ipv4fields: header.IPv4Fields{
  2709  						TOS:            tos,
  2710  						TotalLength:    uint16(header.IPv4MinimumSize + len(data) - 16),
  2711  						ID:             ident,
  2712  						Flags:          0,
  2713  						FragmentOffset: 16,
  2714  						TTL:            ttl,
  2715  						Protocol:       protocol,
  2716  						SrcAddr:        addr1,
  2717  						DstAddr:        addr2,
  2718  					},
  2719  					payload: []byte(data)[16:],
  2720  				},
  2721  			},
  2722  			expectICMP: true,
  2723  		},
  2724  		{
  2725  			name: "two fragments with a gap in reverse order",
  2726  			fragments: []fragmentData{
  2727  				{
  2728  					ipv4fields: header.IPv4Fields{
  2729  						TOS:            tos,
  2730  						TotalLength:    uint16(header.IPv4MinimumSize + len(data) - 16),
  2731  						ID:             ident,
  2732  						Flags:          0,
  2733  						FragmentOffset: 16,
  2734  						TTL:            ttl,
  2735  						Protocol:       protocol,
  2736  						SrcAddr:        addr1,
  2737  						DstAddr:        addr2,
  2738  					},
  2739  					payload: []byte(data)[16:],
  2740  				},
  2741  				{
  2742  					ipv4fields: header.IPv4Fields{
  2743  						TOS:            tos,
  2744  						TotalLength:    header.IPv4MinimumSize + 8,
  2745  						ID:             ident,
  2746  						Flags:          header.IPv4FlagMoreFragments,
  2747  						FragmentOffset: 0,
  2748  						TTL:            ttl,
  2749  						Protocol:       protocol,
  2750  						SrcAddr:        addr1,
  2751  						DstAddr:        addr2,
  2752  					},
  2753  					payload: []byte(data)[:8],
  2754  				},
  2755  			},
  2756  			expectICMP: true,
  2757  		},
  2758  	}
  2759  
  2760  	for _, test := range tests {
  2761  		t.Run(test.name, func(t *testing.T) {
  2762  			ctx := newTestContext()
  2763  			defer ctx.cleanup()
  2764  			s := ctx.s
  2765  			clock := ctx.clock
  2766  
  2767  			e := channel.New(1, 1500, linkAddr)
  2768  			defer e.Close()
  2769  			if err := s.CreateNIC(nicID, e); err != nil {
  2770  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  2771  			}
  2772  			protocolAddr := tcpip.ProtocolAddress{
  2773  				Protocol:          ipv4.ProtocolNumber,
  2774  				AddressWithPrefix: addr2.WithPrefix(),
  2775  			}
  2776  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  2777  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  2778  			}
  2779  			s.SetRouteTable([]tcpip.Route{{
  2780  				Destination: header.IPv4EmptySubnet,
  2781  				NIC:         nicID,
  2782  			}})
  2783  
  2784  			var firstFragmentSent buffer.Buffer
  2785  			for _, f := range test.fragments {
  2786  				pktSize := header.IPv4MinimumSize
  2787  				hdr := prependable.New(pktSize)
  2788  
  2789  				ip := header.IPv4(hdr.Prepend(pktSize))
  2790  				ip.Encode(&f.ipv4fields)
  2791  
  2792  				ip.SetChecksum(0)
  2793  				ip.SetChecksum(^ip.CalculateChecksum())
  2794  
  2795  				buf := buffer.MakeWithData(hdr.View())
  2796  				buf.Append(buffer.NewViewWithData(f.payload))
  2797  
  2798  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  2799  					Payload: buf,
  2800  				})
  2801  
  2802  				if firstFragmentSent.Size() == 0 && ip.FragmentOffset() == 0 {
  2803  					firstFragmentSent = buffer.MakeWithView(stack.PayloadSince(pkt.NetworkHeader()))
  2804  					defer firstFragmentSent.Release()
  2805  				}
  2806  
  2807  				e.InjectInbound(header.IPv4ProtocolNumber, pkt)
  2808  				pkt.DecRef()
  2809  			}
  2810  
  2811  			clock.Advance(ipv4.ReassembleTimeout)
  2812  
  2813  			reply := e.Read()
  2814  			if !test.expectICMP {
  2815  				if reply != nil {
  2816  					t.Fatalf("unexpected ICMP error message received: %#v", reply)
  2817  				}
  2818  				return
  2819  			}
  2820  			if reply == nil {
  2821  				t.Fatal("expected ICMP error message missing")
  2822  			}
  2823  			if firstFragmentSent.Size() == 0 {
  2824  				t.Fatalf("unexpected ICMP error message received: %#v", reply)
  2825  			}
  2826  
  2827  			payload := stack.PayloadSince(reply.NetworkHeader())
  2828  			defer payload.Release()
  2829  			checker.IPv4(t, payload,
  2830  				checker.SrcAddr(addr2),
  2831  				checker.DstAddr(addr1),
  2832  				checker.IPFullLength(uint16(header.IPv4MinimumSize+header.ICMPv4MinimumSize+firstFragmentSent.Size())),
  2833  				checker.IPv4HeaderLength(header.IPv4MinimumSize),
  2834  				checker.ICMPv4(
  2835  					checker.ICMPv4Type(header.ICMPv4TimeExceeded),
  2836  					checker.ICMPv4Code(header.ICMPv4ReassemblyTimeout),
  2837  					checker.ICMPv4Checksum(),
  2838  					checker.ICMPv4Payload(firstFragmentSent.Flatten()),
  2839  				),
  2840  			)
  2841  			reply.DecRef()
  2842  		})
  2843  	}
  2844  }
  2845  
  2846  // TestReceiveFragments feeds fragments in through the incoming packet path to
  2847  // test reassembly
  2848  func TestReceiveFragments(t *testing.T) {
  2849  	const (
  2850  		nicID = 1
  2851  	)
  2852  
  2853  	var (
  2854  		addr1 = tcpip.AddrFromSlice([]byte("\x0c\xa8\x00\x01")) // 192.168.0.1
  2855  		addr2 = tcpip.AddrFromSlice([]byte("\x0c\xa8\x00\x02")) // 192.168.0.2
  2856  		addr3 = tcpip.AddrFromSlice([]byte("\x0c\xa8\x00\x03")) // 192.168.0.3
  2857  	)
  2858  
  2859  	// Build and return a UDP header containing payload.
  2860  	udpGen := func(payloadLen int, multiplier uint8, src, dst tcpip.Address) []byte {
  2861  		payload := make([]byte, payloadLen)
  2862  		for i := 0; i < len(payload); i++ {
  2863  			payload[i] = uint8(i) * multiplier
  2864  		}
  2865  
  2866  		udpLength := header.UDPMinimumSize + len(payload)
  2867  
  2868  		hdr := prependable.New(udpLength)
  2869  		u := header.UDP(hdr.Prepend(udpLength))
  2870  		u.Encode(&header.UDPFields{
  2871  			SrcPort: 5555,
  2872  			DstPort: 80,
  2873  			Length:  uint16(udpLength),
  2874  		})
  2875  		copy(u.Payload(), payload)
  2876  		sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(udpLength))
  2877  		sum = checksum.Checksum(payload, sum)
  2878  		u.SetChecksum(^u.CalculateChecksum(sum))
  2879  		return hdr.View()
  2880  	}
  2881  
  2882  	// UDP header plus a payload of 0..256
  2883  	ipv4Payload1Addr1ToAddr2 := udpGen(256, 1, addr1, addr2)
  2884  	udpPayload1Addr1ToAddr2 := ipv4Payload1Addr1ToAddr2[header.UDPMinimumSize:]
  2885  	ipv4Payload1Addr3ToAddr2 := udpGen(256, 1, addr3, addr2)
  2886  	udpPayload1Addr3ToAddr2 := ipv4Payload1Addr3ToAddr2[header.UDPMinimumSize:]
  2887  	// UDP header plus a payload of 0..256 in increments of 2.
  2888  	ipv4Payload2Addr1ToAddr2 := udpGen(128, 2, addr1, addr2)
  2889  	udpPayload2Addr1ToAddr2 := ipv4Payload2Addr1ToAddr2[header.UDPMinimumSize:]
  2890  	// UDP header plus a payload of 0..256 in increments of 3.
  2891  	// Used to test cases where the fragment blocks are not a multiple of
  2892  	// the fragment block size of 8 (RFC 791 section 3.1 page 14).
  2893  	ipv4Payload3Addr1ToAddr2 := udpGen(127, 3, addr1, addr2)
  2894  	udpPayload3Addr1ToAddr2 := ipv4Payload3Addr1ToAddr2[header.UDPMinimumSize:]
  2895  	// Used to test the max reassembled IPv4 payload length.
  2896  	ipv4Payload4Addr1ToAddr2 := udpGen(header.UDPMaximumSize-header.UDPMinimumSize, 4, addr1, addr2)
  2897  	udpPayload4Addr1ToAddr2 := ipv4Payload4Addr1ToAddr2[header.UDPMinimumSize:]
  2898  
  2899  	type fragmentData struct {
  2900  		srcAddr        tcpip.Address
  2901  		dstAddr        tcpip.Address
  2902  		id             uint16
  2903  		flags          uint8
  2904  		fragmentOffset uint16
  2905  		payload        []byte
  2906  	}
  2907  
  2908  	tests := []struct {
  2909  		name             string
  2910  		fragments        []fragmentData
  2911  		expectedPayloads [][]byte
  2912  	}{
  2913  		{
  2914  			name: "No fragmentation",
  2915  			fragments: []fragmentData{
  2916  				{
  2917  					srcAddr:        addr1,
  2918  					dstAddr:        addr2,
  2919  					id:             1,
  2920  					flags:          0,
  2921  					fragmentOffset: 0,
  2922  					payload:        ipv4Payload1Addr1ToAddr2,
  2923  				},
  2924  			},
  2925  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  2926  		},
  2927  		{
  2928  			name: "No fragmentation with size not a multiple of fragment block size",
  2929  			fragments: []fragmentData{
  2930  				{
  2931  					srcAddr:        addr1,
  2932  					dstAddr:        addr2,
  2933  					id:             1,
  2934  					flags:          0,
  2935  					fragmentOffset: 0,
  2936  					payload:        ipv4Payload3Addr1ToAddr2,
  2937  				},
  2938  			},
  2939  			expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2},
  2940  		},
  2941  		{
  2942  			name: "More fragments without payload",
  2943  			fragments: []fragmentData{
  2944  				{
  2945  					srcAddr:        addr1,
  2946  					dstAddr:        addr2,
  2947  					id:             1,
  2948  					flags:          header.IPv4FlagMoreFragments,
  2949  					fragmentOffset: 0,
  2950  					payload:        ipv4Payload1Addr1ToAddr2,
  2951  				},
  2952  			},
  2953  			expectedPayloads: nil,
  2954  		},
  2955  		{
  2956  			name: "Non-zero fragment offset without payload",
  2957  			fragments: []fragmentData{
  2958  				{
  2959  					srcAddr:        addr1,
  2960  					dstAddr:        addr2,
  2961  					id:             1,
  2962  					flags:          0,
  2963  					fragmentOffset: 8,
  2964  					payload:        ipv4Payload1Addr1ToAddr2,
  2965  				},
  2966  			},
  2967  			expectedPayloads: nil,
  2968  		},
  2969  		{
  2970  			name: "Two fragments",
  2971  			fragments: []fragmentData{
  2972  				{
  2973  					srcAddr:        addr1,
  2974  					dstAddr:        addr2,
  2975  					id:             1,
  2976  					flags:          header.IPv4FlagMoreFragments,
  2977  					fragmentOffset: 0,
  2978  					payload:        ipv4Payload1Addr1ToAddr2[:64],
  2979  				},
  2980  				{
  2981  					srcAddr:        addr1,
  2982  					dstAddr:        addr2,
  2983  					id:             1,
  2984  					flags:          0,
  2985  					fragmentOffset: 64,
  2986  					payload:        ipv4Payload1Addr1ToAddr2[64:],
  2987  				},
  2988  			},
  2989  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  2990  		},
  2991  		{
  2992  			name: "Two fragments out of order",
  2993  			fragments: []fragmentData{
  2994  				{
  2995  					srcAddr:        addr1,
  2996  					dstAddr:        addr2,
  2997  					id:             1,
  2998  					flags:          0,
  2999  					fragmentOffset: 64,
  3000  					payload:        ipv4Payload1Addr1ToAddr2[64:],
  3001  				},
  3002  				{
  3003  					srcAddr:        addr1,
  3004  					dstAddr:        addr2,
  3005  					id:             1,
  3006  					flags:          header.IPv4FlagMoreFragments,
  3007  					fragmentOffset: 0,
  3008  					payload:        ipv4Payload1Addr1ToAddr2[:64],
  3009  				},
  3010  			},
  3011  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  3012  		},
  3013  		{
  3014  			name: "Two fragments with last fragment size not a multiple of fragment block size",
  3015  			fragments: []fragmentData{
  3016  				{
  3017  					srcAddr:        addr1,
  3018  					dstAddr:        addr2,
  3019  					id:             1,
  3020  					flags:          header.IPv4FlagMoreFragments,
  3021  					fragmentOffset: 0,
  3022  					payload:        ipv4Payload3Addr1ToAddr2[:64],
  3023  				},
  3024  				{
  3025  					srcAddr:        addr1,
  3026  					dstAddr:        addr2,
  3027  					id:             1,
  3028  					flags:          0,
  3029  					fragmentOffset: 64,
  3030  					payload:        ipv4Payload3Addr1ToAddr2[64:],
  3031  				},
  3032  			},
  3033  			expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2},
  3034  		},
  3035  		{
  3036  			name: "Two fragments with first fragment size not a multiple of fragment block size",
  3037  			fragments: []fragmentData{
  3038  				{
  3039  					srcAddr:        addr1,
  3040  					dstAddr:        addr2,
  3041  					id:             1,
  3042  					flags:          header.IPv4FlagMoreFragments,
  3043  					fragmentOffset: 0,
  3044  					payload:        ipv4Payload3Addr1ToAddr2[:63],
  3045  				},
  3046  				{
  3047  					srcAddr:        addr1,
  3048  					dstAddr:        addr2,
  3049  					id:             1,
  3050  					flags:          0,
  3051  					fragmentOffset: 63,
  3052  					payload:        ipv4Payload3Addr1ToAddr2[63:],
  3053  				},
  3054  			},
  3055  			expectedPayloads: nil,
  3056  		},
  3057  		{
  3058  			name: "Second fragment has MoreFlags set",
  3059  			fragments: []fragmentData{
  3060  				{
  3061  					srcAddr:        addr1,
  3062  					dstAddr:        addr2,
  3063  					id:             1,
  3064  					flags:          header.IPv4FlagMoreFragments,
  3065  					fragmentOffset: 0,
  3066  					payload:        ipv4Payload1Addr1ToAddr2[:64],
  3067  				},
  3068  				{
  3069  					srcAddr:        addr1,
  3070  					dstAddr:        addr2,
  3071  					id:             1,
  3072  					flags:          header.IPv4FlagMoreFragments,
  3073  					fragmentOffset: 64,
  3074  					payload:        ipv4Payload1Addr1ToAddr2[64:],
  3075  				},
  3076  			},
  3077  			expectedPayloads: nil,
  3078  		},
  3079  		{
  3080  			name: "Two fragments with different IDs",
  3081  			fragments: []fragmentData{
  3082  				{
  3083  					srcAddr:        addr1,
  3084  					dstAddr:        addr2,
  3085  					id:             1,
  3086  					flags:          header.IPv4FlagMoreFragments,
  3087  					fragmentOffset: 0,
  3088  					payload:        ipv4Payload1Addr1ToAddr2[:64],
  3089  				},
  3090  				{
  3091  					srcAddr:        addr1,
  3092  					dstAddr:        addr2,
  3093  					id:             2,
  3094  					flags:          0,
  3095  					fragmentOffset: 64,
  3096  					payload:        ipv4Payload1Addr1ToAddr2[64:],
  3097  				},
  3098  			},
  3099  			expectedPayloads: nil,
  3100  		},
  3101  		{
  3102  			name: "Two interleaved fragmented packets",
  3103  			fragments: []fragmentData{
  3104  				{
  3105  					srcAddr:        addr1,
  3106  					dstAddr:        addr2,
  3107  					id:             1,
  3108  					flags:          header.IPv4FlagMoreFragments,
  3109  					fragmentOffset: 0,
  3110  					payload:        ipv4Payload1Addr1ToAddr2[:64],
  3111  				},
  3112  				{
  3113  					srcAddr:        addr1,
  3114  					dstAddr:        addr2,
  3115  					id:             2,
  3116  					flags:          header.IPv4FlagMoreFragments,
  3117  					fragmentOffset: 0,
  3118  					payload:        ipv4Payload2Addr1ToAddr2[:64],
  3119  				},
  3120  				{
  3121  					srcAddr:        addr1,
  3122  					dstAddr:        addr2,
  3123  					id:             1,
  3124  					flags:          0,
  3125  					fragmentOffset: 64,
  3126  					payload:        ipv4Payload1Addr1ToAddr2[64:],
  3127  				},
  3128  				{
  3129  					srcAddr:        addr1,
  3130  					dstAddr:        addr2,
  3131  					id:             2,
  3132  					flags:          0,
  3133  					fragmentOffset: 64,
  3134  					payload:        ipv4Payload2Addr1ToAddr2[64:],
  3135  				},
  3136  			},
  3137  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload2Addr1ToAddr2},
  3138  		},
  3139  		{
  3140  			name: "Two interleaved fragmented packets from different sources but with same ID",
  3141  			fragments: []fragmentData{
  3142  				{
  3143  					srcAddr:        addr1,
  3144  					dstAddr:        addr2,
  3145  					id:             1,
  3146  					flags:          header.IPv4FlagMoreFragments,
  3147  					fragmentOffset: 0,
  3148  					payload:        ipv4Payload1Addr1ToAddr2[:64],
  3149  				},
  3150  				{
  3151  					srcAddr:        addr3,
  3152  					dstAddr:        addr2,
  3153  					id:             1,
  3154  					flags:          header.IPv4FlagMoreFragments,
  3155  					fragmentOffset: 0,
  3156  					payload:        ipv4Payload1Addr3ToAddr2[:32],
  3157  				},
  3158  				{
  3159  					srcAddr:        addr1,
  3160  					dstAddr:        addr2,
  3161  					id:             1,
  3162  					flags:          0,
  3163  					fragmentOffset: 64,
  3164  					payload:        ipv4Payload1Addr1ToAddr2[64:],
  3165  				},
  3166  				{
  3167  					srcAddr:        addr3,
  3168  					dstAddr:        addr2,
  3169  					id:             1,
  3170  					flags:          0,
  3171  					fragmentOffset: 32,
  3172  					payload:        ipv4Payload1Addr3ToAddr2[32:],
  3173  				},
  3174  			},
  3175  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload1Addr3ToAddr2},
  3176  		},
  3177  		{
  3178  			name: "Fragment without followup",
  3179  			fragments: []fragmentData{
  3180  				{
  3181  					srcAddr:        addr1,
  3182  					dstAddr:        addr2,
  3183  					id:             1,
  3184  					flags:          header.IPv4FlagMoreFragments,
  3185  					fragmentOffset: 0,
  3186  					payload:        ipv4Payload1Addr1ToAddr2[:64],
  3187  				},
  3188  			},
  3189  			expectedPayloads: nil,
  3190  		},
  3191  		{
  3192  			name: "Two fragments reassembled into a maximum UDP packet",
  3193  			fragments: []fragmentData{
  3194  				{
  3195  					srcAddr:        addr1,
  3196  					dstAddr:        addr2,
  3197  					id:             1,
  3198  					flags:          header.IPv4FlagMoreFragments,
  3199  					fragmentOffset: 0,
  3200  					payload:        ipv4Payload4Addr1ToAddr2[:65512],
  3201  				},
  3202  				{
  3203  					srcAddr:        addr1,
  3204  					dstAddr:        addr2,
  3205  					id:             1,
  3206  					flags:          0,
  3207  					fragmentOffset: 65512,
  3208  					payload:        ipv4Payload4Addr1ToAddr2[65512:],
  3209  				},
  3210  			},
  3211  			expectedPayloads: [][]byte{udpPayload4Addr1ToAddr2},
  3212  		},
  3213  		{
  3214  			name: "Two fragments with MF flag reassembled into a maximum UDP packet",
  3215  			fragments: []fragmentData{
  3216  				{
  3217  					srcAddr:        addr1,
  3218  					dstAddr:        addr2,
  3219  					id:             1,
  3220  					flags:          header.IPv4FlagMoreFragments,
  3221  					fragmentOffset: 0,
  3222  					payload:        ipv4Payload4Addr1ToAddr2[:65512],
  3223  				},
  3224  				{
  3225  					srcAddr:        addr1,
  3226  					dstAddr:        addr2,
  3227  					id:             1,
  3228  					flags:          header.IPv4FlagMoreFragments,
  3229  					fragmentOffset: 65512,
  3230  					payload:        ipv4Payload4Addr1ToAddr2[65512:],
  3231  				},
  3232  			},
  3233  			expectedPayloads: nil,
  3234  		},
  3235  	}
  3236  
  3237  	for _, test := range tests {
  3238  		t.Run(test.name, func(t *testing.T) {
  3239  			ctx := newTestContext()
  3240  			defer ctx.cleanup()
  3241  			s := ctx.s
  3242  
  3243  			e := channel.New(0, 1280, "\xf0\x00")
  3244  			defer e.Close()
  3245  			if err := s.CreateNIC(nicID, e); err != nil {
  3246  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  3247  			}
  3248  			protocolAddr := tcpip.ProtocolAddress{
  3249  				Protocol:          header.IPv4ProtocolNumber,
  3250  				AddressWithPrefix: addr2.WithPrefix(),
  3251  			}
  3252  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  3253  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  3254  			}
  3255  
  3256  			wq := waiter.Queue{}
  3257  			we, ch := waiter.NewChannelEntry(waiter.ReadableEvents)
  3258  			wq.EventRegister(&we)
  3259  			defer wq.EventUnregister(&we)
  3260  			defer close(ch)
  3261  			ep, err := s.NewEndpoint(udp.ProtocolNumber, header.IPv4ProtocolNumber, &wq)
  3262  			if err != nil {
  3263  				t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, header.IPv4ProtocolNumber, err)
  3264  			}
  3265  			defer ep.Close()
  3266  
  3267  			bindAddr := tcpip.FullAddress{Addr: addr2, Port: 80}
  3268  			if err := ep.Bind(bindAddr); err != nil {
  3269  				t.Fatalf("Bind(%+v): %s", bindAddr, err)
  3270  			}
  3271  
  3272  			// Bring up a raw endpoint so we can examine network headers.
  3273  			epRaw, err := s.NewRawEndpoint(udp.ProtocolNumber, header.IPv4ProtocolNumber, &wq, true /* associated */)
  3274  			if err != nil {
  3275  				t.Fatalf("NewRawEndpoint(%d, %d, _, true): %s", udp.ProtocolNumber, header.IPv4ProtocolNumber, err)
  3276  			}
  3277  			defer epRaw.Close()
  3278  
  3279  			// Prepare and send the fragments.
  3280  			for _, frag := range test.fragments {
  3281  				hdr := prependable.New(header.IPv4MinimumSize)
  3282  
  3283  				// Serialize IPv4 fixed header.
  3284  				ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
  3285  				ip.Encode(&header.IPv4Fields{
  3286  					TotalLength:    header.IPv4MinimumSize + uint16(len(frag.payload)),
  3287  					ID:             frag.id,
  3288  					Flags:          frag.flags,
  3289  					FragmentOffset: frag.fragmentOffset,
  3290  					TTL:            64,
  3291  					Protocol:       uint8(header.UDPProtocolNumber),
  3292  					SrcAddr:        frag.srcAddr,
  3293  					DstAddr:        frag.dstAddr,
  3294  				})
  3295  				ip.SetChecksum(^ip.CalculateChecksum())
  3296  
  3297  				buf := buffer.MakeWithData(hdr.View())
  3298  				buf.Append(buffer.NewViewWithData(frag.payload))
  3299  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3300  					Payload: buf,
  3301  				})
  3302  				e.InjectInbound(header.IPv4ProtocolNumber, pkt)
  3303  				pkt.DecRef()
  3304  			}
  3305  
  3306  			if got, want := s.Stats().UDP.PacketsReceived.Value(), uint64(len(test.expectedPayloads)); got != want {
  3307  				t.Errorf("got UDP Rx Packets = %d, want = %d", got, want)
  3308  			}
  3309  
  3310  			for i, expectedPayload := range test.expectedPayloads {
  3311  				// Check UDP payload delivered by UDP endpoint.
  3312  				var buf bytes.Buffer
  3313  				result, err := ep.Read(&buf, tcpip.ReadOptions{})
  3314  				if err != nil {
  3315  					t.Fatalf("(i=%d) ep.Read: %s", i, err)
  3316  				}
  3317  				if diff := cmp.Diff(tcpip.ReadResult{
  3318  					Count: len(expectedPayload),
  3319  					Total: len(expectedPayload),
  3320  				}, result, checker.IgnoreCmpPath("ControlMessages")); diff != "" {
  3321  					t.Errorf("(i=%d) ep.Read: unexpected result (-want +got):\n%s", i, diff)
  3322  				}
  3323  				if diff := cmp.Diff(expectedPayload, buf.Bytes()); diff != "" {
  3324  					t.Errorf("(i=%d) ep.Read: UDP payload mismatch (-want +got):\n%s", i, diff)
  3325  				}
  3326  
  3327  				// Check IPv4 header in packet delivered by raw endpoint.
  3328  				buf.Reset()
  3329  				_, err = epRaw.Read(&buf, tcpip.ReadOptions{})
  3330  				if err != nil {
  3331  					t.Fatalf("(i=%d) epRaw.Read: %s", i, err)
  3332  				}
  3333  				// Reassambly does not take care of checksum. Here we write our own
  3334  				// check routine instead of using checker.IPv4.
  3335  				ip := header.IPv4(buf.Bytes())
  3336  				for _, check := range []checker.NetworkChecker{
  3337  					checker.FragmentFlags(0),
  3338  					checker.FragmentOffset(0),
  3339  					checker.IPFullLength(uint16(header.IPv4MinimumSize + header.UDPMinimumSize + len(expectedPayload))),
  3340  				} {
  3341  					check(t, []header.Network{ip})
  3342  				}
  3343  			}
  3344  
  3345  			res, err := ep.Read(ioutil.Discard, tcpip.ReadOptions{})
  3346  			if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
  3347  				t.Fatalf("(last) got Read = (%#v, %v), want = (_, %s)", res, err, &tcpip.ErrWouldBlock{})
  3348  			}
  3349  		})
  3350  	}
  3351  }
  3352  
  3353  func TestWriteStats(t *testing.T) {
  3354  	const nPackets = 3
  3355  
  3356  	tests := []struct {
  3357  		name                     string
  3358  		setup                    func(*testing.T, *stack.Stack)
  3359  		allowPackets             int
  3360  		expectSent               int
  3361  		expectOutputDropped      int
  3362  		expectPostroutingDropped int
  3363  		expectWritten            int
  3364  	}{
  3365  		{
  3366  			name: "Accept all",
  3367  			// No setup needed, tables accept everything by default.
  3368  			setup:                    func(*testing.T, *stack.Stack) {},
  3369  			allowPackets:             math.MaxInt32,
  3370  			expectSent:               nPackets,
  3371  			expectOutputDropped:      0,
  3372  			expectPostroutingDropped: 0,
  3373  			expectWritten:            nPackets,
  3374  		}, {
  3375  			name: "Accept all with error",
  3376  			// No setup needed, tables accept everything by default.
  3377  			setup:                    func(*testing.T, *stack.Stack) {},
  3378  			allowPackets:             nPackets - 1,
  3379  			expectSent:               nPackets - 1,
  3380  			expectOutputDropped:      0,
  3381  			expectPostroutingDropped: 0,
  3382  			expectWritten:            nPackets - 1,
  3383  		}, {
  3384  			name: "Drop all with Output chain",
  3385  			setup: func(t *testing.T, stk *stack.Stack) {
  3386  				// Install Output DROP rule.
  3387  				ipt := stk.IPTables()
  3388  				filter := ipt.GetTable(stack.FilterID, false /* ipv6 */)
  3389  				ruleIdx := filter.BuiltinChains[stack.Output]
  3390  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  3391  				ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */)
  3392  			},
  3393  			allowPackets:             math.MaxInt32,
  3394  			expectSent:               0,
  3395  			expectOutputDropped:      nPackets,
  3396  			expectPostroutingDropped: 0,
  3397  			expectWritten:            nPackets,
  3398  		}, {
  3399  			name: "Drop all with Postrouting chain",
  3400  			setup: func(t *testing.T, stk *stack.Stack) {
  3401  				ipt := stk.IPTables()
  3402  				filter := ipt.GetTable(stack.NATID, false /* ipv6 */)
  3403  				ruleIdx := filter.BuiltinChains[stack.Postrouting]
  3404  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  3405  				ipt.ForceReplaceTable(stack.NATID, filter, false /* ipv6 */)
  3406  			},
  3407  			allowPackets:             math.MaxInt32,
  3408  			expectSent:               0,
  3409  			expectOutputDropped:      0,
  3410  			expectPostroutingDropped: nPackets,
  3411  			expectWritten:            nPackets,
  3412  		}, {
  3413  			name: "Drop some with Output chain",
  3414  			setup: func(t *testing.T, stk *stack.Stack) {
  3415  				// Install Output DROP rule that matches only 1
  3416  				// of the 3 packets.
  3417  				ipt := stk.IPTables()
  3418  				filter := ipt.GetTable(stack.FilterID, false /* ipv6 */)
  3419  				// We'll match and DROP the last packet.
  3420  				ruleIdx := filter.BuiltinChains[stack.Output]
  3421  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  3422  				filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}}
  3423  				// Make sure the next rule is ACCEPT.
  3424  				filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
  3425  				ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */)
  3426  			},
  3427  			allowPackets:             math.MaxInt32,
  3428  			expectSent:               nPackets - 1,
  3429  			expectOutputDropped:      1,
  3430  			expectPostroutingDropped: 0,
  3431  			expectWritten:            nPackets,
  3432  		}, {
  3433  			name: "Drop some with Postrouting chain",
  3434  			setup: func(t *testing.T, stk *stack.Stack) {
  3435  				// Install Postrouting DROP rule that matches only 1
  3436  				// of the 3 packets.
  3437  				ipt := stk.IPTables()
  3438  				filter := ipt.GetTable(stack.NATID, false /* ipv6 */)
  3439  				// We'll match and DROP the last packet.
  3440  				ruleIdx := filter.BuiltinChains[stack.Postrouting]
  3441  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  3442  				filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}}
  3443  				// Make sure the next rule is ACCEPT.
  3444  				filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
  3445  				ipt.ForceReplaceTable(stack.NATID, filter, false /* ipv6 */)
  3446  			},
  3447  			allowPackets:             math.MaxInt32,
  3448  			expectSent:               nPackets - 1,
  3449  			expectOutputDropped:      0,
  3450  			expectPostroutingDropped: 1,
  3451  			expectWritten:            nPackets,
  3452  		},
  3453  	}
  3454  
  3455  	for _, test := range tests {
  3456  		t.Run(test.name, func(t *testing.T) {
  3457  			ctx := newTestContext()
  3458  			defer ctx.cleanup()
  3459  
  3460  			ep := iptestutil.NewMockLinkEndpoint(header.IPv4MinimumMTU, &tcpip.ErrInvalidEndpointState{}, test.allowPackets)
  3461  			defer ep.Close()
  3462  			rt := buildRoute(t, ctx, ep)
  3463  			defer rt.Release()
  3464  
  3465  			test.setup(t, rt.Stack())
  3466  			nWritten := 0
  3467  			for i := 0; i < nPackets; i++ {
  3468  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3469  					ReserveHeaderBytes: header.UDPMinimumSize + int(rt.MaxHeaderLength()),
  3470  					Payload:            buffer.Buffer{},
  3471  				})
  3472  				defer pkt.DecRef()
  3473  				pkt.TransportHeader().Push(header.UDPMinimumSize)
  3474  				if err := rt.WritePacket(stack.NetworkHeaderParams{}, pkt); err != nil {
  3475  					break
  3476  				}
  3477  				nWritten++
  3478  			}
  3479  
  3480  			if got := int(rt.Stats().IP.PacketsSent.Value()); got != test.expectSent {
  3481  				t.Errorf("got rt.Stats().IP.PacketsSent.Value() = %d, want = %d", got, test.expectSent)
  3482  			}
  3483  			if got := int(rt.Stats().IP.IPTablesOutputDropped.Value()); got != test.expectOutputDropped {
  3484  				t.Errorf("got rt.Stats().IP.IPTablesOutputDropped.Value() = %d, want = %d", got, test.expectOutputDropped)
  3485  			}
  3486  			if got := int(rt.Stats().IP.IPTablesPostroutingDropped.Value()); got != test.expectPostroutingDropped {
  3487  				t.Errorf("got rt.Stats().IP.IPTablesPostroutingDropped.Value() = %d, want = %d", got, test.expectPostroutingDropped)
  3488  			}
  3489  			if nWritten != test.expectWritten {
  3490  				t.Errorf("got nWritten = %d, want = %d", nWritten, test.expectWritten)
  3491  			}
  3492  		})
  3493  	}
  3494  }
  3495  
  3496  func buildRoute(t *testing.T, c testContext, ep stack.LinkEndpoint) *stack.Route {
  3497  	s := c.s
  3498  	if err := s.CreateNIC(1, ep); err != nil {
  3499  		t.Fatalf("CreateNIC(1, _) failed: %s", err)
  3500  	}
  3501  	var (
  3502  		src = tcpip.AddrFromSlice([]byte("\x10\x00\x00\x01"))
  3503  		dst = tcpip.AddrFromSlice([]byte("\x10\x00\x00\x02"))
  3504  	)
  3505  	protocolAddr := tcpip.ProtocolAddress{
  3506  		Protocol:          ipv4.ProtocolNumber,
  3507  		AddressWithPrefix: src.WithPrefix(),
  3508  	}
  3509  	if err := s.AddProtocolAddress(1, protocolAddr, stack.AddressProperties{}); err != nil {
  3510  		t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", 1, protocolAddr, err)
  3511  	}
  3512  	{
  3513  		mask := tcpip.MaskFromBytes(header.IPv4Broadcast.AsSlice())
  3514  		subnet, err := tcpip.NewSubnet(dst, mask)
  3515  		if err != nil {
  3516  			t.Fatalf("NewSubnet(%s, %s) failed: %v", dst, mask, err)
  3517  		}
  3518  		s.SetRouteTable([]tcpip.Route{{
  3519  			Destination: subnet,
  3520  			NIC:         1,
  3521  		}})
  3522  	}
  3523  	rt, err := s.FindRoute(1, src, dst, ipv4.ProtocolNumber, false /* multicastLoop */)
  3524  	if err != nil {
  3525  		t.Fatalf("FindRoute(1, %s, %s, %d, false) = %s", src, dst, ipv4.ProtocolNumber, err)
  3526  	}
  3527  	return rt
  3528  }
  3529  
  3530  // limitedMatcher is an iptables matcher that matches after a certain number of
  3531  // packets are checked against it.
  3532  type limitedMatcher struct {
  3533  	limit int
  3534  }
  3535  
  3536  // Name implements Matcher.Name.
  3537  func (*limitedMatcher) Name() string {
  3538  	return "limitedMatcher"
  3539  }
  3540  
  3541  // Match implements Matcher.Match.
  3542  func (lm *limitedMatcher) Match(stack.Hook, *stack.PacketBuffer, string, string) (bool, bool) {
  3543  	if lm.limit == 0 {
  3544  		return true, false
  3545  	}
  3546  	lm.limit--
  3547  	return false, false
  3548  }
  3549  
  3550  func TestPacketQueuing(t *testing.T) {
  3551  	const nicID = 1
  3552  
  3553  	var (
  3554  		host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06")
  3555  		host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09")
  3556  
  3557  		host1IPv4Addr = tcpip.ProtocolAddress{
  3558  			Protocol: ipv4.ProtocolNumber,
  3559  			AddressWithPrefix: tcpip.AddressWithPrefix{
  3560  				Address:   tcpip.AddrFromSlice(net.ParseIP("192.168.0.1").To4()),
  3561  				PrefixLen: 24,
  3562  			},
  3563  		}
  3564  		host2IPv4Addr = tcpip.ProtocolAddress{
  3565  			Protocol: ipv4.ProtocolNumber,
  3566  			AddressWithPrefix: tcpip.AddressWithPrefix{
  3567  				Address:   tcpip.AddrFromSlice(net.ParseIP("192.168.0.2").To4()),
  3568  				PrefixLen: 8,
  3569  			},
  3570  		}
  3571  	)
  3572  
  3573  	tests := []struct {
  3574  		name      string
  3575  		rxPkt     func(*channel.Endpoint)
  3576  		checkResp func(*testing.T, *channel.Endpoint)
  3577  	}{
  3578  		{
  3579  			name: "ICMP Error",
  3580  			rxPkt: func(e *channel.Endpoint) {
  3581  				hdr := prependable.New(header.IPv4MinimumSize + header.UDPMinimumSize)
  3582  				u := header.UDP(hdr.Prepend(header.UDPMinimumSize))
  3583  				u.Encode(&header.UDPFields{
  3584  					SrcPort: 5555,
  3585  					DstPort: 80,
  3586  					Length:  header.UDPMinimumSize,
  3587  				})
  3588  				sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv4Addr.AddressWithPrefix.Address, host1IPv4Addr.AddressWithPrefix.Address, header.UDPMinimumSize)
  3589  				sum = checksum.Checksum(nil, sum)
  3590  				u.SetChecksum(^u.CalculateChecksum(sum))
  3591  				ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
  3592  				ip.Encode(&header.IPv4Fields{
  3593  					TotalLength: header.IPv4MinimumSize + header.UDPMinimumSize,
  3594  					TTL:         ipv4.DefaultTTL,
  3595  					Protocol:    uint8(udp.ProtocolNumber),
  3596  					SrcAddr:     host2IPv4Addr.AddressWithPrefix.Address,
  3597  					DstAddr:     host1IPv4Addr.AddressWithPrefix.Address,
  3598  				})
  3599  				ip.SetChecksum(^ip.CalculateChecksum())
  3600  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3601  					Payload: buffer.MakeWithData(hdr.View()),
  3602  				})
  3603  				defer pkt.DecRef()
  3604  				e.InjectInbound(ipv4.ProtocolNumber, pkt)
  3605  			},
  3606  			checkResp: func(t *testing.T, e *channel.Endpoint) {
  3607  				p := e.Read()
  3608  				if p == nil {
  3609  					t.Fatalf("timed out waiting for packet")
  3610  				}
  3611  				defer p.DecRef()
  3612  				if p.NetworkProtocolNumber != header.IPv4ProtocolNumber {
  3613  					t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, header.IPv4ProtocolNumber)
  3614  				}
  3615  				if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr {
  3616  					t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr)
  3617  				}
  3618  				payload := stack.PayloadSince(p.NetworkHeader())
  3619  				defer payload.Release()
  3620  				checker.IPv4(t, payload,
  3621  					checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address),
  3622  					checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address),
  3623  					checker.ICMPv4(
  3624  						checker.ICMPv4Type(header.ICMPv4DstUnreachable),
  3625  						checker.ICMPv4Code(header.ICMPv4PortUnreachable)))
  3626  			},
  3627  		},
  3628  
  3629  		{
  3630  			name: "Ping",
  3631  			rxPkt: func(e *channel.Endpoint) {
  3632  				totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize
  3633  				hdr := prependable.New(totalLen)
  3634  				pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
  3635  				pkt.SetType(header.ICMPv4Echo)
  3636  				pkt.SetCode(0)
  3637  				pkt.SetChecksum(0)
  3638  				pkt.SetChecksum(^checksum.Checksum(pkt, 0))
  3639  				ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
  3640  				ip.Encode(&header.IPv4Fields{
  3641  					TotalLength: uint16(totalLen),
  3642  					Protocol:    uint8(icmp.ProtocolNumber4),
  3643  					TTL:         ipv4.DefaultTTL,
  3644  					SrcAddr:     host2IPv4Addr.AddressWithPrefix.Address,
  3645  					DstAddr:     host1IPv4Addr.AddressWithPrefix.Address,
  3646  				})
  3647  				ip.SetChecksum(^ip.CalculateChecksum())
  3648  				echoPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3649  					Payload: buffer.MakeWithData(hdr.View()),
  3650  				})
  3651  				defer echoPkt.DecRef()
  3652  				e.InjectInbound(header.IPv4ProtocolNumber, echoPkt)
  3653  			},
  3654  			checkResp: func(t *testing.T, e *channel.Endpoint) {
  3655  				p := e.Read()
  3656  				if p == nil {
  3657  					t.Fatalf("timed out waiting for packet")
  3658  				}
  3659  				defer p.DecRef()
  3660  				if p.NetworkProtocolNumber != header.IPv4ProtocolNumber {
  3661  					t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, header.IPv4ProtocolNumber)
  3662  				}
  3663  				if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr {
  3664  					t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr)
  3665  				}
  3666  				payload := stack.PayloadSince(p.NetworkHeader())
  3667  				defer payload.Release()
  3668  				checker.IPv4(t, payload,
  3669  					checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address),
  3670  					checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address),
  3671  					checker.ICMPv4(
  3672  						checker.ICMPv4Type(header.ICMPv4EchoReply),
  3673  						checker.ICMPv4Code(header.ICMPv4UnusedCode)))
  3674  			},
  3675  		},
  3676  	}
  3677  
  3678  	for _, test := range tests {
  3679  		t.Run(test.name, func(t *testing.T) {
  3680  			ctx := newTestContext()
  3681  			defer ctx.cleanup()
  3682  			s := ctx.s
  3683  			clock := ctx.clock
  3684  
  3685  			e := channel.New(1, defaultMTU, host1NICLinkAddr)
  3686  			defer e.Close()
  3687  			e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
  3688  			if err := s.CreateNIC(nicID, e); err != nil {
  3689  				t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  3690  			}
  3691  			if err := s.AddProtocolAddress(nicID, host1IPv4Addr, stack.AddressProperties{}); err != nil {
  3692  				t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, host1IPv4Addr, err)
  3693  			}
  3694  
  3695  			s.SetRouteTable([]tcpip.Route{
  3696  				{
  3697  					Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
  3698  					NIC:         nicID,
  3699  				},
  3700  			})
  3701  
  3702  			// Receive a packet to trigger link resolution before a response is sent.
  3703  			test.rxPkt(e)
  3704  
  3705  			// Wait for a ARP request since link address resolution should be
  3706  			// performed.
  3707  			{
  3708  				clock.RunImmediatelyScheduledJobs()
  3709  				p := e.Read()
  3710  				if p == nil {
  3711  					t.Fatalf("timed out waiting for packet")
  3712  				}
  3713  				if p.NetworkProtocolNumber != arp.ProtocolNumber {
  3714  					t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, arp.ProtocolNumber)
  3715  				}
  3716  				if p.EgressRoute.RemoteLinkAddress != header.EthernetBroadcastAddress {
  3717  					t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, header.EthernetBroadcastAddress)
  3718  				}
  3719  				rep := header.ARP(p.NetworkHeader().Slice())
  3720  				p.DecRef()
  3721  				if got := rep.Op(); got != header.ARPRequest {
  3722  					t.Errorf("got Op() = %d, want = %d", got, header.ARPRequest)
  3723  				}
  3724  				if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != host1NICLinkAddr {
  3725  					t.Errorf("got HardwareAddressSender = %s, want = %s", got, host1NICLinkAddr)
  3726  				}
  3727  				if got := tcpip.AddrFromSlice(rep.ProtocolAddressSender()); got != host1IPv4Addr.AddressWithPrefix.Address {
  3728  					t.Errorf("got ProtocolAddressSender = %s, want = %s", got, host1IPv4Addr.AddressWithPrefix.Address)
  3729  				}
  3730  				if got := tcpip.AddrFromSlice(rep.ProtocolAddressTarget()); got != host2IPv4Addr.AddressWithPrefix.Address {
  3731  					t.Errorf("got ProtocolAddressTarget = %s, want = %s", got, host2IPv4Addr.AddressWithPrefix.Address)
  3732  				}
  3733  			}
  3734  
  3735  			// Send an ARP reply to complete link address resolution.
  3736  			{
  3737  				hdr := make([]byte, header.ARPSize)
  3738  				packet := header.ARP(hdr)
  3739  				packet.SetIPv4OverEthernet()
  3740  				packet.SetOp(header.ARPReply)
  3741  				copy(packet.HardwareAddressSender(), host2NICLinkAddr)
  3742  				copy(packet.ProtocolAddressSender(), host2IPv4Addr.AddressWithPrefix.Address.AsSlice())
  3743  				copy(packet.HardwareAddressTarget(), host1NICLinkAddr)
  3744  				copy(packet.ProtocolAddressTarget(), host1IPv4Addr.AddressWithPrefix.Address.AsSlice())
  3745  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3746  					Payload: buffer.MakeWithData(hdr),
  3747  				})
  3748  				e.InjectInbound(arp.ProtocolNumber, pkt)
  3749  				pkt.DecRef()
  3750  			}
  3751  
  3752  			// Expect the response now that the link address has resolved.
  3753  			clock.RunImmediatelyScheduledJobs()
  3754  			test.checkResp(t, e)
  3755  
  3756  			// Since link resolution was already performed, it shouldn't be performed
  3757  			// again.
  3758  			test.rxPkt(e)
  3759  			test.checkResp(t, e)
  3760  		})
  3761  	}
  3762  }
  3763  
  3764  // TestCloseLocking test that lock ordering is followed when closing an
  3765  // endpoint.
  3766  func TestCloseLocking(t *testing.T) {
  3767  	const (
  3768  		nicID1 = 1
  3769  		nicID2 = 2
  3770  
  3771  		iterations = 1000
  3772  	)
  3773  
  3774  	var (
  3775  		src = testutil.MustParse4("16.0.0.1")
  3776  		dst = testutil.MustParse4("16.0.0.2")
  3777  	)
  3778  
  3779  	ctx := newTestContext()
  3780  	defer ctx.cleanup()
  3781  	s := ctx.s
  3782  
  3783  	// Perform NAT so that the endpoint tries to search for a sibling endpoint
  3784  	// which ends up taking the protocol and endpoint lock (in that order).
  3785  	table := stack.Table{
  3786  		Rules: []stack.Rule{
  3787  			{Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}},
  3788  			{Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}},
  3789  			{Target: &stack.RedirectTarget{Port: 5, NetworkProtocol: header.IPv4ProtocolNumber}},
  3790  			{Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}},
  3791  			{Target: &stack.ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}},
  3792  		},
  3793  		BuiltinChains: [stack.NumHooks]int{
  3794  			stack.Prerouting:  0,
  3795  			stack.Input:       1,
  3796  			stack.Forward:     stack.HookUnset,
  3797  			stack.Output:      2,
  3798  			stack.Postrouting: 3,
  3799  		},
  3800  		Underflows: [stack.NumHooks]int{
  3801  			stack.Prerouting:  0,
  3802  			stack.Input:       1,
  3803  			stack.Forward:     stack.HookUnset,
  3804  			stack.Output:      2,
  3805  			stack.Postrouting: 3,
  3806  		},
  3807  	}
  3808  	s.IPTables().ForceReplaceTable(stack.NATID, table, false /* ipv6 */)
  3809  
  3810  	e := channel.New(0, defaultMTU, "")
  3811  	defer e.Close()
  3812  	if err := s.CreateNIC(nicID1, e); err != nil {
  3813  		t.Fatalf("CreateNIC(%d, _): %s", nicID1, err)
  3814  	}
  3815  
  3816  	protocolAddr := tcpip.ProtocolAddress{
  3817  		Protocol:          ipv4.ProtocolNumber,
  3818  		AddressWithPrefix: src.WithPrefix(),
  3819  	}
  3820  	if err := s.AddProtocolAddress(nicID1, protocolAddr, stack.AddressProperties{}); err != nil {
  3821  		t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID1, protocolAddr, err)
  3822  	}
  3823  
  3824  	s.SetRouteTable([]tcpip.Route{{
  3825  		Destination: header.IPv4EmptySubnet,
  3826  		NIC:         nicID1,
  3827  	}})
  3828  
  3829  	var wq waiter.Queue
  3830  	ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq)
  3831  	if err != nil {
  3832  		t.Fatal(err)
  3833  	}
  3834  	defer ep.Close()
  3835  
  3836  	addr := tcpip.FullAddress{NIC: nicID1, Addr: dst, Port: 53}
  3837  	if err := ep.Connect(addr); err != nil {
  3838  		t.Errorf("ep.Connect(%#v): %s", addr, err)
  3839  	}
  3840  
  3841  	var wg sync.WaitGroup
  3842  	defer wg.Wait()
  3843  
  3844  	// Writing packets should trigger NAT which requires the stack to search the
  3845  	// protocol for network endpoints with the destination address.
  3846  	//
  3847  	// Creating and removing interfaces should modify the protocol and endpoint
  3848  	// which requires taking the locks of each.
  3849  	//
  3850  	// We expect the protocol > endpoint lock ordering to be followed here.
  3851  	wg.Add(2)
  3852  	go func() {
  3853  		defer wg.Done()
  3854  
  3855  		data := []byte{1, 2, 3, 4}
  3856  
  3857  		for i := 0; i < iterations; i++ {
  3858  			var r bytes.Reader
  3859  			r.Reset(data)
  3860  			if n, err := ep.Write(&r, tcpip.WriteOptions{}); err != nil {
  3861  				t.Errorf("ep.Write(_, _): %s", err)
  3862  				return
  3863  			} else if want := int64(len(data)); n != want {
  3864  				t.Errorf("got ep.Write(_, _) = (%d, _), want = (%d, _)", n, want)
  3865  				return
  3866  			}
  3867  		}
  3868  	}()
  3869  	go func() {
  3870  		defer wg.Done()
  3871  
  3872  		for i := 0; i < iterations; i++ {
  3873  			ch := channel.New(0, defaultMTU, "")
  3874  			defer ch.Close()
  3875  			if err := s.CreateNIC(nicID2, ch); err != nil {
  3876  				t.Errorf("CreateNIC(%d, _): %s", nicID2, err)
  3877  				return
  3878  			}
  3879  			if err := s.RemoveNIC(nicID2); err != nil {
  3880  				t.Errorf("RemoveNIC(%d): %s", nicID2, err)
  3881  				return
  3882  			}
  3883  		}
  3884  	}()
  3885  }
  3886  
  3887  func TestIcmpRateLimit(t *testing.T) {
  3888  	var (
  3889  		host1IPv4Addr = tcpip.ProtocolAddress{
  3890  			Protocol: ipv4.ProtocolNumber,
  3891  			AddressWithPrefix: tcpip.AddressWithPrefix{
  3892  				Address:   tcpip.AddrFromSlice(net.ParseIP("192.168.0.1").To4()),
  3893  				PrefixLen: 24,
  3894  			},
  3895  		}
  3896  		host2IPv4Addr = tcpip.ProtocolAddress{
  3897  			Protocol: ipv4.ProtocolNumber,
  3898  			AddressWithPrefix: tcpip.AddressWithPrefix{
  3899  				Address:   tcpip.AddrFromSlice(net.ParseIP("192.168.0.2").To4()),
  3900  				PrefixLen: 24,
  3901  			},
  3902  		}
  3903  	)
  3904  	ctx := newTestContext()
  3905  	defer ctx.cleanup()
  3906  	s := ctx.s
  3907  
  3908  	const icmpBurst = 5
  3909  	s.SetICMPBurst(icmpBurst)
  3910  
  3911  	e := channel.New(1, defaultMTU, tcpip.LinkAddress(""))
  3912  	defer e.Close()
  3913  	if err := s.CreateNIC(nicID, e); err != nil {
  3914  		t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  3915  	}
  3916  	if err := s.AddProtocolAddress(nicID, host1IPv4Addr, stack.AddressProperties{}); err != nil {
  3917  		t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, host1IPv4Addr, err)
  3918  	}
  3919  	s.SetRouteTable([]tcpip.Route{
  3920  		{
  3921  			Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
  3922  			NIC:         nicID,
  3923  		},
  3924  	})
  3925  	tests := []struct {
  3926  		name         string
  3927  		createPacket func() []byte
  3928  		check        func(*testing.T, *channel.Endpoint, int)
  3929  	}{
  3930  		{
  3931  			name: "echo",
  3932  			createPacket: func() []byte {
  3933  				totalLength := header.IPv4MinimumSize + header.ICMPv4MinimumSize
  3934  				hdr := prependable.New(totalLength)
  3935  				icmpH := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
  3936  				icmpH.SetIdent(1)
  3937  				icmpH.SetSequence(1)
  3938  				icmpH.SetType(header.ICMPv4Echo)
  3939  				icmpH.SetCode(header.ICMPv4UnusedCode)
  3940  				icmpH.SetChecksum(0)
  3941  				icmpH.SetChecksum(^checksum.Checksum(icmpH, 0))
  3942  				ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
  3943  				ip.Encode(&header.IPv4Fields{
  3944  					TotalLength: uint16(totalLength),
  3945  					Protocol:    uint8(header.ICMPv4ProtocolNumber),
  3946  					TTL:         1,
  3947  					SrcAddr:     host2IPv4Addr.AddressWithPrefix.Address,
  3948  					DstAddr:     host1IPv4Addr.AddressWithPrefix.Address,
  3949  				})
  3950  				ip.SetChecksum(^ip.CalculateChecksum())
  3951  				return hdr.View()
  3952  			},
  3953  			check: func(t *testing.T, e *channel.Endpoint, round int) {
  3954  				p := e.Read()
  3955  				if p == nil {
  3956  					t.Fatalf("expected echo response, no packet read in endpoint in round %d", round)
  3957  				}
  3958  				defer p.DecRef()
  3959  				if got, want := p.NetworkProtocolNumber, header.IPv4ProtocolNumber; got != want {
  3960  					t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", got, want)
  3961  				}
  3962  				payload := stack.PayloadSince(p.NetworkHeader())
  3963  				defer payload.Release()
  3964  				checker.IPv4(t, payload,
  3965  					checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address),
  3966  					checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address),
  3967  					checker.ICMPv4(
  3968  						checker.ICMPv4Type(header.ICMPv4EchoReply),
  3969  					))
  3970  			},
  3971  		},
  3972  		{
  3973  			name: "dst unreachable",
  3974  			createPacket: func() []byte {
  3975  				totalLength := header.IPv4MinimumSize + header.UDPMinimumSize
  3976  				hdr := prependable.New(totalLength)
  3977  				udpH := header.UDP(hdr.Prepend(header.UDPMinimumSize))
  3978  				udpH.Encode(&header.UDPFields{
  3979  					SrcPort: 100,
  3980  					DstPort: 101,
  3981  					Length:  header.UDPMinimumSize,
  3982  				})
  3983  				ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
  3984  				ip.Encode(&header.IPv4Fields{
  3985  					TotalLength: uint16(totalLength),
  3986  					Protocol:    uint8(header.UDPProtocolNumber),
  3987  					TTL:         1,
  3988  					SrcAddr:     host2IPv4Addr.AddressWithPrefix.Address,
  3989  					DstAddr:     host1IPv4Addr.AddressWithPrefix.Address,
  3990  				})
  3991  				ip.SetChecksum(^ip.CalculateChecksum())
  3992  				return hdr.View()
  3993  			},
  3994  			check: func(t *testing.T, e *channel.Endpoint, round int) {
  3995  				p := e.Read()
  3996  				if round >= icmpBurst {
  3997  					if p != nil {
  3998  						t.Errorf("got packet %x in round %d, expected ICMP rate limit to stop it", p.Data().AsRange().ToSlice(), round)
  3999  						p.DecRef()
  4000  					}
  4001  					return
  4002  				}
  4003  				if p == nil {
  4004  					t.Fatalf("expected unreachable in round %d, no packet read in endpoint", round)
  4005  				}
  4006  				defer p.DecRef()
  4007  				payload := stack.PayloadSince(p.NetworkHeader())
  4008  				defer payload.Release()
  4009  				checker.IPv4(t, payload,
  4010  					checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address),
  4011  					checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address),
  4012  					checker.ICMPv4(
  4013  						checker.ICMPv4Type(header.ICMPv4DstUnreachable),
  4014  					))
  4015  			},
  4016  		},
  4017  	}
  4018  	for _, testCase := range tests {
  4019  		t.Run(testCase.name, func(t *testing.T) {
  4020  			for round := 0; round < icmpBurst+1; round++ {
  4021  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  4022  					Payload: buffer.MakeWithData(testCase.createPacket()),
  4023  				})
  4024  				e.InjectInbound(header.IPv4ProtocolNumber, pkt)
  4025  				pkt.DecRef()
  4026  				testCase.check(t, e, round)
  4027  			}
  4028  		})
  4029  	}
  4030  }