github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/network/ipv6/icmp_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ipv6
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/FlowerWrong/netstack/tcpip"
    24  	"github.com/FlowerWrong/netstack/tcpip/buffer"
    25  	"github.com/FlowerWrong/netstack/tcpip/header"
    26  	"github.com/FlowerWrong/netstack/tcpip/link/channel"
    27  	"github.com/FlowerWrong/netstack/tcpip/link/sniffer"
    28  	"github.com/FlowerWrong/netstack/tcpip/stack"
    29  	"github.com/FlowerWrong/netstack/tcpip/transport/icmp"
    30  	"github.com/FlowerWrong/netstack/waiter"
    31  )
    32  
    33  const (
    34  	linkAddr0 = tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06")
    35  	linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0f")
    36  )
    37  
    38  var (
    39  	lladdr0 = header.LinkLocalAddr(linkAddr0)
    40  	lladdr1 = header.LinkLocalAddr(linkAddr1)
    41  )
    42  
    43  type stubLinkEndpoint struct {
    44  	stack.LinkEndpoint
    45  }
    46  
    47  func (*stubLinkEndpoint) Capabilities() stack.LinkEndpointCapabilities {
    48  	return 0
    49  }
    50  
    51  func (*stubLinkEndpoint) MaxHeaderLength() uint16 {
    52  	return 0
    53  }
    54  
    55  func (*stubLinkEndpoint) LinkAddress() tcpip.LinkAddress {
    56  	return ""
    57  }
    58  
    59  func (*stubLinkEndpoint) WritePacket(*stack.Route, *stack.GSO, buffer.Prependable, buffer.VectorisedView, tcpip.NetworkProtocolNumber) *tcpip.Error {
    60  	return nil
    61  }
    62  
    63  func (*stubLinkEndpoint) Attach(stack.NetworkDispatcher) {}
    64  
    65  type stubDispatcher struct {
    66  	stack.TransportDispatcher
    67  }
    68  
    69  func (*stubDispatcher) DeliverTransportPacket(*stack.Route, tcpip.TransportProtocolNumber, buffer.View, buffer.VectorisedView) {
    70  }
    71  
    72  type stubLinkAddressCache struct {
    73  	stack.LinkAddressCache
    74  }
    75  
    76  func (*stubLinkAddressCache) CheckLocalAddress(tcpip.NICID, tcpip.NetworkProtocolNumber, tcpip.Address) tcpip.NICID {
    77  	return 0
    78  }
    79  
    80  func (*stubLinkAddressCache) AddLinkAddress(tcpip.NICID, tcpip.Address, tcpip.LinkAddress) {
    81  }
    82  
    83  func TestICMPCounts(t *testing.T) {
    84  	s := stack.New(stack.Options{
    85  		NetworkProtocols:   []stack.NetworkProtocol{NewProtocol()},
    86  		TransportProtocols: []stack.TransportProtocol{icmp.NewProtocol6()},
    87  	})
    88  	{
    89  		if err := s.CreateNIC(1, &stubLinkEndpoint{}); err != nil {
    90  			t.Fatalf("CreateNIC(_) = %s", err)
    91  		}
    92  		if err := s.AddAddress(1, ProtocolNumber, lladdr0); err != nil {
    93  			t.Fatalf("AddAddress(_, %d, %s) = %s", ProtocolNumber, lladdr0, err)
    94  		}
    95  	}
    96  	{
    97  		subnet, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
    98  		if err != nil {
    99  			t.Fatal(err)
   100  		}
   101  		s.SetRouteTable(
   102  			[]tcpip.Route{{
   103  				Destination: subnet,
   104  				NIC:         1,
   105  			}},
   106  		)
   107  	}
   108  
   109  	netProto := s.NetworkProtocolInstance(ProtocolNumber)
   110  	if netProto == nil {
   111  		t.Fatalf("cannot find protocol instance for network protocol %d", ProtocolNumber)
   112  	}
   113  	ep, err := netProto.NewEndpoint(0, tcpip.AddressWithPrefix{lladdr1, netProto.DefaultPrefixLen()}, &stubLinkAddressCache{}, &stubDispatcher{}, nil)
   114  	if err != nil {
   115  		t.Fatalf("NewEndpoint(_) = _, %s, want = _, nil", err)
   116  	}
   117  
   118  	r, err := s.FindRoute(1, lladdr0, lladdr1, ProtocolNumber, false /* multicastLoop */)
   119  	if err != nil {
   120  		t.Fatalf("FindRoute(_) = _, %s, want = _, nil", err)
   121  	}
   122  	defer r.Release()
   123  
   124  	types := []struct {
   125  		typ  header.ICMPv6Type
   126  		size int
   127  	}{
   128  		{header.ICMPv6DstUnreachable, header.ICMPv6DstUnreachableMinimumSize},
   129  		{header.ICMPv6PacketTooBig, header.ICMPv6PacketTooBigMinimumSize},
   130  		{header.ICMPv6TimeExceeded, header.ICMPv6MinimumSize},
   131  		{header.ICMPv6ParamProblem, header.ICMPv6MinimumSize},
   132  		{header.ICMPv6EchoRequest, header.ICMPv6EchoMinimumSize},
   133  		{header.ICMPv6EchoReply, header.ICMPv6EchoMinimumSize},
   134  		{header.ICMPv6RouterSolicit, header.ICMPv6MinimumSize},
   135  		{header.ICMPv6RouterAdvert, header.ICMPv6MinimumSize},
   136  		{header.ICMPv6NeighborSolicit, header.ICMPv6NeighborSolicitMinimumSize},
   137  		{header.ICMPv6NeighborAdvert, header.ICMPv6NeighborAdvertSize},
   138  		{header.ICMPv6RedirectMsg, header.ICMPv6MinimumSize},
   139  	}
   140  
   141  	handleIPv6Payload := func(hdr buffer.Prependable) {
   142  		payloadLength := hdr.UsedLength()
   143  		ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   144  		ip.Encode(&header.IPv6Fields{
   145  			PayloadLength: uint16(payloadLength),
   146  			NextHeader:    uint8(header.ICMPv6ProtocolNumber),
   147  			HopLimit:      ndpHopLimit,
   148  			SrcAddr:       r.LocalAddress,
   149  			DstAddr:       r.RemoteAddress,
   150  		})
   151  		ep.HandlePacket(&r, hdr.View().ToVectorisedView())
   152  	}
   153  
   154  	for _, typ := range types {
   155  		hdr := buffer.NewPrependable(header.IPv6MinimumSize + typ.size)
   156  		pkt := header.ICMPv6(hdr.Prepend(typ.size))
   157  		pkt.SetType(typ.typ)
   158  		pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
   159  
   160  		handleIPv6Payload(hdr)
   161  	}
   162  
   163  	// Construct an empty ICMP packet so that
   164  	// Stats().ICMP.ICMPv6ReceivedPacketStats.Invalid is incremented.
   165  	handleIPv6Payload(buffer.NewPrependable(header.IPv6MinimumSize))
   166  
   167  	icmpv6Stats := s.Stats().ICMP.V6PacketsReceived
   168  	visitStats(reflect.ValueOf(&icmpv6Stats).Elem(), func(name string, s *tcpip.StatCounter) {
   169  		if got, want := s.Value(), uint64(1); got != want {
   170  			t.Errorf("got %s = %d, want = %d", name, got, want)
   171  		}
   172  	})
   173  	if t.Failed() {
   174  		t.Logf("stats:\n%+v", s.Stats())
   175  	}
   176  }
   177  
   178  func visitStats(v reflect.Value, f func(string, *tcpip.StatCounter)) {
   179  	t := v.Type()
   180  	for i := 0; i < v.NumField(); i++ {
   181  		v := v.Field(i)
   182  		switch v.Kind() {
   183  		case reflect.Ptr:
   184  			f(t.Field(i).Name, v.Interface().(*tcpip.StatCounter))
   185  		case reflect.Struct:
   186  			visitStats(v, f)
   187  		default:
   188  			panic(fmt.Sprintf("unexpected type %s", v.Type()))
   189  		}
   190  	}
   191  }
   192  
   193  type testContext struct {
   194  	s0 *stack.Stack
   195  	s1 *stack.Stack
   196  
   197  	linkEP0 *channel.Endpoint
   198  	linkEP1 *channel.Endpoint
   199  }
   200  
   201  type endpointWithResolutionCapability struct {
   202  	stack.LinkEndpoint
   203  }
   204  
   205  func (e endpointWithResolutionCapability) Capabilities() stack.LinkEndpointCapabilities {
   206  	return e.LinkEndpoint.Capabilities() | stack.CapabilityResolutionRequired
   207  }
   208  
   209  func newTestContext(t *testing.T) *testContext {
   210  	c := &testContext{
   211  		s0: stack.New(stack.Options{
   212  			NetworkProtocols:   []stack.NetworkProtocol{NewProtocol()},
   213  			TransportProtocols: []stack.TransportProtocol{icmp.NewProtocol6()},
   214  		}),
   215  		s1: stack.New(stack.Options{
   216  			NetworkProtocols:   []stack.NetworkProtocol{NewProtocol()},
   217  			TransportProtocols: []stack.TransportProtocol{icmp.NewProtocol6()},
   218  		}),
   219  	}
   220  
   221  	const defaultMTU = 65536
   222  	c.linkEP0 = channel.New(256, defaultMTU, linkAddr0)
   223  
   224  	wrappedEP0 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP0})
   225  	if testing.Verbose() {
   226  		wrappedEP0 = sniffer.New(wrappedEP0)
   227  	}
   228  	if err := c.s0.CreateNIC(1, wrappedEP0); err != nil {
   229  		t.Fatalf("CreateNIC s0: %v", err)
   230  	}
   231  	if err := c.s0.AddAddress(1, ProtocolNumber, lladdr0); err != nil {
   232  		t.Fatalf("AddAddress lladdr0: %v", err)
   233  	}
   234  
   235  	c.linkEP1 = channel.New(256, defaultMTU, linkAddr1)
   236  	wrappedEP1 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP1})
   237  	if err := c.s1.CreateNIC(1, wrappedEP1); err != nil {
   238  		t.Fatalf("CreateNIC failed: %v", err)
   239  	}
   240  	if err := c.s1.AddAddress(1, ProtocolNumber, lladdr1); err != nil {
   241  		t.Fatalf("AddAddress lladdr1: %v", err)
   242  	}
   243  
   244  	subnet0, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  	c.s0.SetRouteTable(
   249  		[]tcpip.Route{{
   250  			Destination: subnet0,
   251  			NIC:         1,
   252  		}},
   253  	)
   254  	subnet1, err := tcpip.NewSubnet(lladdr0, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr0))))
   255  	if err != nil {
   256  		t.Fatal(err)
   257  	}
   258  	c.s1.SetRouteTable(
   259  		[]tcpip.Route{{
   260  			Destination: subnet1,
   261  			NIC:         1,
   262  		}},
   263  	)
   264  
   265  	return c
   266  }
   267  
   268  func (c *testContext) cleanup() {
   269  	close(c.linkEP0.C)
   270  	close(c.linkEP1.C)
   271  }
   272  
   273  type routeArgs struct {
   274  	src, dst *channel.Endpoint
   275  	typ      header.ICMPv6Type
   276  }
   277  
   278  func routeICMPv6Packet(t *testing.T, args routeArgs, fn func(*testing.T, header.ICMPv6)) {
   279  	t.Helper()
   280  
   281  	pkt := <-args.src.C
   282  
   283  	{
   284  		views := []buffer.View{pkt.Header, pkt.Payload}
   285  		size := len(pkt.Header) + len(pkt.Payload)
   286  		vv := buffer.NewVectorisedView(size, views)
   287  		args.dst.InjectLinkAddr(pkt.Proto, args.dst.LinkAddress(), vv)
   288  	}
   289  
   290  	if pkt.Proto != ProtocolNumber {
   291  		t.Errorf("unexpected protocol number %d", pkt.Proto)
   292  		return
   293  	}
   294  	ipv6 := header.IPv6(pkt.Header)
   295  	transProto := tcpip.TransportProtocolNumber(ipv6.NextHeader())
   296  	if transProto != header.ICMPv6ProtocolNumber {
   297  		t.Errorf("unexpected transport protocol number %d", transProto)
   298  		return
   299  	}
   300  	icmpv6 := header.ICMPv6(ipv6.Payload())
   301  	if got, want := icmpv6.Type(), args.typ; got != want {
   302  		t.Errorf("got ICMPv6 type = %d, want = %d", got, want)
   303  		return
   304  	}
   305  	if fn != nil {
   306  		fn(t, icmpv6)
   307  	}
   308  }
   309  
   310  func TestLinkResolution(t *testing.T) {
   311  	c := newTestContext(t)
   312  	defer c.cleanup()
   313  
   314  	r, err := c.s0.FindRoute(1, lladdr0, lladdr1, ProtocolNumber, false /* multicastLoop */)
   315  	if err != nil {
   316  		t.Fatalf("FindRoute(_) = _, %s, want = _, nil", err)
   317  	}
   318  	defer r.Release()
   319  
   320  	hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6EchoMinimumSize)
   321  	pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6EchoMinimumSize))
   322  	pkt.SetType(header.ICMPv6EchoRequest)
   323  	pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
   324  	payload := tcpip.SlicePayload(hdr.View())
   325  
   326  	// We can't send our payload directly over the route because that
   327  	// doesn't provoke NDP discovery.
   328  	var wq waiter.Queue
   329  	ep, err := c.s0.NewEndpoint(header.ICMPv6ProtocolNumber, ProtocolNumber, &wq)
   330  	if err != nil {
   331  		t.Fatalf("NewEndpoint(_) = _, %s, want = _, nil", err)
   332  	}
   333  
   334  	for {
   335  		_, resCh, err := ep.Write(payload, tcpip.WriteOptions{To: &tcpip.FullAddress{NIC: 1, Addr: lladdr1}})
   336  		if resCh != nil {
   337  			if err != tcpip.ErrNoLinkAddress {
   338  				t.Fatalf("ep.Write(_) = _, <non-nil>, %s, want = _, <non-nil>, tcpip.ErrNoLinkAddress", err)
   339  			}
   340  			for _, args := range []routeArgs{
   341  				{src: c.linkEP0, dst: c.linkEP1, typ: header.ICMPv6NeighborSolicit},
   342  				{src: c.linkEP1, dst: c.linkEP0, typ: header.ICMPv6NeighborAdvert},
   343  			} {
   344  				routeICMPv6Packet(t, args, func(t *testing.T, icmpv6 header.ICMPv6) {
   345  					if got, want := tcpip.Address(icmpv6[8:][:16]), lladdr1; got != want {
   346  						t.Errorf("%d: got target = %s, want = %s", icmpv6.Type(), got, want)
   347  					}
   348  				})
   349  			}
   350  			<-resCh
   351  			continue
   352  		}
   353  		if err != nil {
   354  			t.Fatalf("ep.Write(_) = _, _, %s", err)
   355  		}
   356  		break
   357  	}
   358  
   359  	for _, args := range []routeArgs{
   360  		{src: c.linkEP0, dst: c.linkEP1, typ: header.ICMPv6EchoRequest},
   361  		{src: c.linkEP1, dst: c.linkEP0, typ: header.ICMPv6EchoReply},
   362  	} {
   363  		routeICMPv6Packet(t, args, nil)
   364  	}
   365  }