github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/transport/icmp/icmp_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 icmp_test 16 17 import ( 18 "testing" 19 20 "github.com/SagerNet/gvisor/pkg/tcpip" 21 "github.com/SagerNet/gvisor/pkg/tcpip/buffer" 22 "github.com/SagerNet/gvisor/pkg/tcpip/checker" 23 "github.com/SagerNet/gvisor/pkg/tcpip/header" 24 "github.com/SagerNet/gvisor/pkg/tcpip/link/channel" 25 "github.com/SagerNet/gvisor/pkg/tcpip/link/sniffer" 26 "github.com/SagerNet/gvisor/pkg/tcpip/network/ipv4" 27 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 28 "github.com/SagerNet/gvisor/pkg/tcpip/testutil" 29 "github.com/SagerNet/gvisor/pkg/tcpip/transport/icmp" 30 "github.com/SagerNet/gvisor/pkg/waiter" 31 ) 32 33 // TODO(https://github.com/SagerNet/issues/5623): Finish unit testing the icmp package. 34 // See the issue for remaining areas of work. 35 36 var ( 37 localV4Addr1 = testutil.MustParse4("10.0.0.1") 38 localV4Addr2 = testutil.MustParse4("10.0.0.2") 39 remoteV4Addr = testutil.MustParse4("10.0.0.3") 40 ) 41 42 func addNICWithDefaultRoute(t *testing.T, s *stack.Stack, id tcpip.NICID, name string, addrV4 tcpip.Address) *channel.Endpoint { 43 t.Helper() 44 45 ep := channel.New(1 /* size */, header.IPv4MinimumMTU, "" /* linkAddr */) 46 t.Cleanup(ep.Close) 47 48 wep := stack.LinkEndpoint(ep) 49 if testing.Verbose() { 50 wep = sniffer.New(ep) 51 } 52 53 opts := stack.NICOptions{Name: name} 54 if err := s.CreateNICWithOptions(id, wep, opts); err != nil { 55 t.Fatalf("s.CreateNIC(%d, _) = %s", id, err) 56 } 57 58 if err := s.AddAddress(id, ipv4.ProtocolNumber, addrV4); err != nil { 59 t.Fatalf("s.AddAddress(%d, %d, %s) = %s", id, ipv4.ProtocolNumber, addrV4, err) 60 } 61 62 s.AddRoute(tcpip.Route{ 63 Destination: header.IPv4EmptySubnet, 64 NIC: id, 65 }) 66 67 return ep 68 } 69 70 func writePayload(buf []byte) { 71 for i := range buf { 72 buf[i] = byte(i) 73 } 74 } 75 76 func newICMPv4EchoRequest(payloadSize uint32) buffer.View { 77 buf := buffer.NewView(header.ICMPv4MinimumSize + int(payloadSize)) 78 writePayload(buf[header.ICMPv4MinimumSize:]) 79 80 icmp := header.ICMPv4(buf) 81 icmp.SetType(header.ICMPv4Echo) 82 // No need to set the checksum; it is reset by the socket before the packet 83 // is sent. 84 85 return buf 86 } 87 88 // TestWriteUnboundWithBindToDevice exercises writing to an unbound ICMP socket 89 // when SO_BINDTODEVICE is set to the non-default NIC for that subnet. 90 // 91 // Only IPv4 is tested. The logic to determine which NIC to use is agnostic to 92 // the version of IP. 93 func TestWriteUnboundWithBindToDevice(t *testing.T) { 94 s := stack.New(stack.Options{ 95 NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol}, 96 TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4}, 97 HandleLocal: true, 98 }) 99 100 // Add two NICs, both with default routes on the same subnet. The first NIC 101 // added will be the default NIC for that subnet. 102 defaultEP := addNICWithDefaultRoute(t, s, 1, "default", localV4Addr1) 103 alternateEP := addNICWithDefaultRoute(t, s, 2, "alternate", localV4Addr2) 104 105 socket, err := s.NewEndpoint(icmp.ProtocolNumber4, ipv4.ProtocolNumber, &waiter.Queue{}) 106 if err != nil { 107 t.Fatalf("s.NewEndpoint(%d, %d, _) = %s", icmp.ProtocolNumber4, ipv4.ProtocolNumber, err) 108 } 109 defer socket.Close() 110 111 echoPayloadSize := defaultEP.MTU() - header.IPv4MinimumSize - header.ICMPv4MinimumSize 112 113 // Send a packet without SO_BINDTODEVICE. This verifies that the first NIC 114 // to be added is the default NIC to send packets when not explicitly bound. 115 { 116 buf := newICMPv4EchoRequest(echoPayloadSize) 117 r := buf.Reader() 118 n, err := socket.Write(&r, tcpip.WriteOptions{ 119 To: &tcpip.FullAddress{Addr: remoteV4Addr}, 120 }) 121 if err != nil { 122 t.Fatalf("socket.Write(_, {To:%s}) = %s", remoteV4Addr, err) 123 } 124 if n != int64(len(buf)) { 125 t.Fatalf("got n = %d, want n = %d", n, len(buf)) 126 } 127 128 // Verify the packet was sent out the default NIC. 129 p, ok := defaultEP.Read() 130 if !ok { 131 t.Fatalf("got defaultEP.Read(_) = _, false; want = _, true (packet wasn't written out)") 132 } 133 134 vv := buffer.NewVectorisedView(p.Pkt.Size(), p.Pkt.Views()) 135 b := vv.ToView() 136 137 checker.IPv4(t, b, []checker.NetworkChecker{ 138 checker.SrcAddr(localV4Addr1), 139 checker.DstAddr(remoteV4Addr), 140 checker.ICMPv4( 141 checker.ICMPv4Type(header.ICMPv4Echo), 142 checker.ICMPv4Payload(buf[header.ICMPv4MinimumSize:]), 143 ), 144 }...) 145 146 // Verify the packet was not sent out the alternate NIC. 147 if p, ok := alternateEP.Read(); ok { 148 t.Fatalf("got alternateEP.Read(_) = %+v, true; want = _, false", p) 149 } 150 } 151 152 // Send a packet with SO_BINDTODEVICE. This exercises reliance on 153 // SO_BINDTODEVICE to route the packet to the alternate NIC. 154 { 155 // Use SO_BINDTODEVICE to send over the alternate NIC by default. 156 socket.SocketOptions().SetBindToDevice(2) 157 158 buf := newICMPv4EchoRequest(echoPayloadSize) 159 r := buf.Reader() 160 n, err := socket.Write(&r, tcpip.WriteOptions{ 161 To: &tcpip.FullAddress{Addr: remoteV4Addr}, 162 }) 163 if err != nil { 164 t.Fatalf("socket.Write(_, {To:%s}) = %s", tcpip.Address(remoteV4Addr), err) 165 } 166 if n != int64(len(buf)) { 167 t.Fatalf("got n = %d, want n = %d", n, len(buf)) 168 } 169 170 // Verify the packet was not sent out the default NIC. 171 if p, ok := defaultEP.Read(); ok { 172 t.Fatalf("got defaultEP.Read(_) = %+v, true; want = _, false", p) 173 } 174 175 // Verify the packet was sent out the alternate NIC. 176 p, ok := alternateEP.Read() 177 if !ok { 178 t.Fatalf("got alternateEP.Read(_) = _, false; want = _, true (packet wasn't written out)") 179 } 180 181 vv := buffer.NewVectorisedView(p.Pkt.Size(), p.Pkt.Views()) 182 b := vv.ToView() 183 184 checker.IPv4(t, b, []checker.NetworkChecker{ 185 checker.SrcAddr(localV4Addr2), 186 checker.DstAddr(remoteV4Addr), 187 checker.ICMPv4( 188 checker.ICMPv4Type(header.ICMPv4Echo), 189 checker.ICMPv4Payload(buf[header.ICMPv4MinimumSize:]), 190 ), 191 }...) 192 } 193 194 // Send a packet with SO_BINDTODEVICE cleared. This verifies that clearing 195 // the device binding will fallback to using the default NIC to send 196 // packets. 197 { 198 socket.SocketOptions().SetBindToDevice(0) 199 200 buf := newICMPv4EchoRequest(echoPayloadSize) 201 r := buf.Reader() 202 n, err := socket.Write(&r, tcpip.WriteOptions{ 203 To: &tcpip.FullAddress{Addr: remoteV4Addr}, 204 }) 205 if err != nil { 206 t.Fatalf("socket.Write(_, {To:%s}) = %s", tcpip.Address(remoteV4Addr), err) 207 } 208 if n != int64(len(buf)) { 209 t.Fatalf("got n = %d, want n = %d", n, len(buf)) 210 } 211 212 // Verify the packet was sent out the default NIC. 213 p, ok := defaultEP.Read() 214 if !ok { 215 t.Fatalf("got defaultEP.Read(_) = _, false; want = _, true (packet wasn't written out)") 216 } 217 218 vv := buffer.NewVectorisedView(p.Pkt.Size(), p.Pkt.Views()) 219 b := vv.ToView() 220 221 checker.IPv4(t, b, []checker.NetworkChecker{ 222 checker.SrcAddr(localV4Addr1), 223 checker.DstAddr(remoteV4Addr), 224 checker.ICMPv4( 225 checker.ICMPv4Type(header.ICMPv4Echo), 226 checker.ICMPv4Payload(buf[header.ICMPv4MinimumSize:]), 227 ), 228 }...) 229 230 // Verify the packet was not sent out the alternate NIC. 231 if p, ok := alternateEP.Read(); ok { 232 t.Fatalf("got alternateEP.Read(_) = %+v, true; want = _, false", p) 233 } 234 } 235 }