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