github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/network/ipv6/ndp_test.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ipv6 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/FlowerWrong/netstack/tcpip" 22 "github.com/FlowerWrong/netstack/tcpip/buffer" 23 "github.com/FlowerWrong/netstack/tcpip/header" 24 "github.com/FlowerWrong/netstack/tcpip/stack" 25 "github.com/FlowerWrong/netstack/tcpip/transport/icmp" 26 ) 27 28 // setupStackAndEndpoint creates a stack with a single NIC with a link-local 29 // address llladdr and an IPv6 endpoint to a remote with link-local address 30 // rlladdr 31 func setupStackAndEndpoint(t *testing.T, llladdr, rlladdr tcpip.Address) (*stack.Stack, stack.NetworkEndpoint) { 32 t.Helper() 33 34 s := stack.New(stack.Options{ 35 NetworkProtocols: []stack.NetworkProtocol{NewProtocol()}, 36 TransportProtocols: []stack.TransportProtocol{icmp.NewProtocol6()}, 37 }) 38 39 if err := s.CreateNIC(1, &stubLinkEndpoint{}); err != nil { 40 t.Fatalf("CreateNIC(_) = %s", err) 41 } 42 if err := s.AddAddress(1, ProtocolNumber, llladdr); err != nil { 43 t.Fatalf("AddAddress(_, %d, %s) = %s", ProtocolNumber, llladdr, err) 44 } 45 46 { 47 subnet, err := tcpip.NewSubnet(rlladdr, tcpip.AddressMask(strings.Repeat("\xff", len(rlladdr)))) 48 if err != nil { 49 t.Fatal(err) 50 } 51 s.SetRouteTable( 52 []tcpip.Route{{ 53 Destination: subnet, 54 NIC: 1, 55 }}, 56 ) 57 } 58 59 netProto := s.NetworkProtocolInstance(ProtocolNumber) 60 if netProto == nil { 61 t.Fatalf("cannot find protocol instance for network protocol %d", ProtocolNumber) 62 } 63 64 ep, err := netProto.NewEndpoint(0, tcpip.AddressWithPrefix{rlladdr, netProto.DefaultPrefixLen()}, &stubLinkAddressCache{}, &stubDispatcher{}, nil) 65 if err != nil { 66 t.Fatalf("NewEndpoint(_) = _, %s, want = _, nil", err) 67 } 68 69 return s, ep 70 } 71 72 // TestHopLimitValidation is a test that makes sure that NDP packets are only 73 // received if their IP header's hop limit is set to 255. 74 func TestHopLimitValidation(t *testing.T) { 75 setup := func(t *testing.T) (*stack.Stack, stack.NetworkEndpoint, stack.Route) { 76 t.Helper() 77 78 // Create a stack with the assigned link-local address lladdr0 79 // and an endpoint to lladdr1. 80 s, ep := setupStackAndEndpoint(t, lladdr0, lladdr1) 81 82 r, err := s.FindRoute(1, lladdr0, lladdr1, ProtocolNumber, false /* multicastLoop */) 83 if err != nil { 84 t.Fatalf("FindRoute(_) = _, %s, want = _, nil", err) 85 } 86 87 return s, ep, r 88 } 89 90 handleIPv6Payload := func(hdr buffer.Prependable, hopLimit uint8, ep stack.NetworkEndpoint, r *stack.Route) { 91 payloadLength := hdr.UsedLength() 92 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 93 ip.Encode(&header.IPv6Fields{ 94 PayloadLength: uint16(payloadLength), 95 NextHeader: uint8(header.ICMPv6ProtocolNumber), 96 HopLimit: hopLimit, 97 SrcAddr: r.LocalAddress, 98 DstAddr: r.RemoteAddress, 99 }) 100 ep.HandlePacket(r, hdr.View().ToVectorisedView()) 101 } 102 103 types := []struct { 104 name string 105 typ header.ICMPv6Type 106 size int 107 statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter 108 }{ 109 {"RouterSolicit", header.ICMPv6RouterSolicit, header.ICMPv6MinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 110 return stats.RouterSolicit 111 }}, 112 {"RouterAdvert", header.ICMPv6RouterAdvert, header.ICMPv6MinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 113 return stats.RouterAdvert 114 }}, 115 {"NeighborSolicit", header.ICMPv6NeighborSolicit, header.ICMPv6NeighborSolicitMinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 116 return stats.NeighborSolicit 117 }}, 118 {"NeighborAdvert", header.ICMPv6NeighborAdvert, header.ICMPv6NeighborAdvertSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 119 return stats.NeighborAdvert 120 }}, 121 {"RedirectMsg", header.ICMPv6RedirectMsg, header.ICMPv6MinimumSize, func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { 122 return stats.RedirectMsg 123 }}, 124 } 125 126 for _, typ := range types { 127 t.Run(typ.name, func(t *testing.T) { 128 s, ep, r := setup(t) 129 defer r.Release() 130 131 stats := s.Stats().ICMP.V6PacketsReceived 132 invalid := stats.Invalid 133 typStat := typ.statCounter(stats) 134 135 hdr := buffer.NewPrependable(header.IPv6MinimumSize + typ.size) 136 pkt := header.ICMPv6(hdr.Prepend(typ.size)) 137 pkt.SetType(typ.typ) 138 pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{})) 139 140 // Invalid count should initially be 0. 141 if got := invalid.Value(); got != 0 { 142 t.Fatalf("got invalid = %d, want = 0", got) 143 } 144 145 // Should not have received any ICMPv6 packets with 146 // type = typ.typ. 147 if got := typStat.Value(); got != 0 { 148 t.Fatalf("got %s = %d, want = 0", typ.name, got) 149 } 150 151 // Receive the NDP packet with an invalid hop limit 152 // value. 153 handleIPv6Payload(hdr, ndpHopLimit-1, ep, &r) 154 155 // Invalid count should have increased. 156 if got := invalid.Value(); got != 1 { 157 t.Fatalf("got invalid = %d, want = 1", got) 158 } 159 160 // Rx count of NDP packet of type typ.typ should not 161 // have increased. 162 if got := typStat.Value(); got != 0 { 163 t.Fatalf("got %s = %d, want = 0", typ.name, got) 164 } 165 166 // Receive the NDP packet with a valid hop limit value. 167 handleIPv6Payload(hdr, ndpHopLimit, ep, &r) 168 169 // Rx count of NDP packet of type typ.typ should have 170 // increased. 171 if got := typStat.Value(); got != 1 { 172 t.Fatalf("got %s = %d, want = 1", typ.name, got) 173 } 174 175 // Invalid count should not have increased again. 176 if got := invalid.Value(); got != 1 { 177 t.Fatalf("got invalid = %d, want = 1", got) 178 } 179 }) 180 } 181 }