github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/network/ip_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 ip_test 16 17 import ( 18 "testing" 19 20 "github.com/FlowerWrong/netstack/tcpip" 21 "github.com/FlowerWrong/netstack/tcpip/buffer" 22 "github.com/FlowerWrong/netstack/tcpip/header" 23 "github.com/FlowerWrong/netstack/tcpip/link/loopback" 24 "github.com/FlowerWrong/netstack/tcpip/network/ipv4" 25 "github.com/FlowerWrong/netstack/tcpip/network/ipv6" 26 "github.com/FlowerWrong/netstack/tcpip/stack" 27 "github.com/FlowerWrong/netstack/tcpip/transport/tcp" 28 "github.com/FlowerWrong/netstack/tcpip/transport/udp" 29 ) 30 31 const ( 32 localIpv4Addr = "\x0a\x00\x00\x01" 33 localIpv4PrefixLen = 24 34 remoteIpv4Addr = "\x0a\x00\x00\x02" 35 ipv4SubnetAddr = "\x0a\x00\x00\x00" 36 ipv4SubnetMask = "\xff\xff\xff\x00" 37 ipv4Gateway = "\x0a\x00\x00\x03" 38 localIpv6Addr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" 39 localIpv6PrefixLen = 120 40 remoteIpv6Addr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" 41 ipv6SubnetAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 42 ipv6SubnetMask = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00" 43 ipv6Gateway = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03" 44 ) 45 46 // testObject implements two interfaces: LinkEndpoint and TransportDispatcher. 47 // The former is used to pretend that it's a link endpoint so that we can 48 // inspect packets written by the network endpoints. The latter is used to 49 // pretend that it's the network stack so that it can inspect incoming packets 50 // that have been handled by the network endpoints. 51 // 52 // Packets are checked by comparing their fields/values against the expected 53 // values stored in the test object itself. 54 type testObject struct { 55 t *testing.T 56 protocol tcpip.TransportProtocolNumber 57 contents []byte 58 srcAddr tcpip.Address 59 dstAddr tcpip.Address 60 v4 bool 61 typ stack.ControlType 62 extra uint32 63 64 dataCalls int 65 controlCalls int 66 } 67 68 // checkValues verifies that the transport protocol, data contents, src & dst 69 // addresses of a packet match what's expected. If any field doesn't match, the 70 // test fails. 71 func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, vv buffer.VectorisedView, srcAddr, dstAddr tcpip.Address) { 72 v := vv.ToView() 73 if protocol != t.protocol { 74 t.t.Errorf("protocol = %v, want %v", protocol, t.protocol) 75 } 76 77 if srcAddr != t.srcAddr { 78 t.t.Errorf("srcAddr = %v, want %v", srcAddr, t.srcAddr) 79 } 80 81 if dstAddr != t.dstAddr { 82 t.t.Errorf("dstAddr = %v, want %v", dstAddr, t.dstAddr) 83 } 84 85 if len(v) != len(t.contents) { 86 t.t.Fatalf("len(payload) = %v, want %v", len(v), len(t.contents)) 87 } 88 89 for i := range t.contents { 90 if t.contents[i] != v[i] { 91 t.t.Fatalf("payload[%v] = %v, want %v", i, v[i], t.contents[i]) 92 } 93 } 94 } 95 96 // DeliverTransportPacket is called by network endpoints after parsing incoming 97 // packets. This is used by the test object to verify that the results of the 98 // parsing are expected. 99 func (t *testObject) DeliverTransportPacket(r *stack.Route, protocol tcpip.TransportProtocolNumber, netHeader buffer.View, vv buffer.VectorisedView) { 100 t.checkValues(protocol, vv, r.RemoteAddress, r.LocalAddress) 101 t.dataCalls++ 102 } 103 104 // DeliverTransportControlPacket is called by network endpoints after parsing 105 // incoming control (ICMP) packets. This is used by the test object to verify 106 // that the results of the parsing are expected. 107 func (t *testObject) DeliverTransportControlPacket(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, typ stack.ControlType, extra uint32, vv buffer.VectorisedView) { 108 t.checkValues(trans, vv, remote, local) 109 if typ != t.typ { 110 t.t.Errorf("typ = %v, want %v", typ, t.typ) 111 } 112 if extra != t.extra { 113 t.t.Errorf("extra = %v, want %v", extra, t.extra) 114 } 115 t.controlCalls++ 116 } 117 118 // Attach is only implemented to satisfy the LinkEndpoint interface. 119 func (*testObject) Attach(stack.NetworkDispatcher) {} 120 121 // IsAttached implements stack.LinkEndpoint.IsAttached. 122 func (*testObject) IsAttached() bool { 123 return true 124 } 125 126 // MTU implements stack.LinkEndpoint.MTU. It just returns a constant that 127 // matches the linux loopback MTU. 128 func (*testObject) MTU() uint32 { 129 return 65536 130 } 131 132 // Capabilities implements stack.LinkEndpoint.Capabilities. 133 func (*testObject) Capabilities() stack.LinkEndpointCapabilities { 134 return 0 135 } 136 137 // MaxHeaderLength is only implemented to satisfy the LinkEndpoint interface. 138 func (*testObject) MaxHeaderLength() uint16 { 139 return 0 140 } 141 142 // LinkAddress returns the link address of this endpoint. 143 func (*testObject) LinkAddress() tcpip.LinkAddress { 144 return "" 145 } 146 147 // Wait implements stack.LinkEndpoint.Wait. 148 func (*testObject) Wait() {} 149 150 // WritePacket is called by network endpoints after producing a packet and 151 // writing it to the link endpoint. This is used by the test object to verify 152 // that the produced packet is as expected. 153 func (t *testObject) WritePacket(_ *stack.Route, _ *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error { 154 var prot tcpip.TransportProtocolNumber 155 var srcAddr tcpip.Address 156 var dstAddr tcpip.Address 157 158 if t.v4 { 159 h := header.IPv4(hdr.View()) 160 prot = tcpip.TransportProtocolNumber(h.Protocol()) 161 srcAddr = h.SourceAddress() 162 dstAddr = h.DestinationAddress() 163 164 } else { 165 h := header.IPv6(hdr.View()) 166 prot = tcpip.TransportProtocolNumber(h.NextHeader()) 167 srcAddr = h.SourceAddress() 168 dstAddr = h.DestinationAddress() 169 } 170 t.checkValues(prot, payload, srcAddr, dstAddr) 171 return nil 172 } 173 174 func buildIPv4Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) { 175 s := stack.New(stack.Options{ 176 NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol()}, 177 TransportProtocols: []stack.TransportProtocol{udp.NewProtocol(), tcp.NewProtocol()}, 178 }) 179 s.CreateNIC(1, loopback.New()) 180 s.AddAddress(1, ipv4.ProtocolNumber, local) 181 s.SetRouteTable([]tcpip.Route{{ 182 Destination: header.IPv4EmptySubnet, 183 Gateway: ipv4Gateway, 184 NIC: 1, 185 }}) 186 187 return s.FindRoute(1, local, remote, ipv4.ProtocolNumber, false /* multicastLoop */) 188 } 189 190 func buildIPv6Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) { 191 s := stack.New(stack.Options{ 192 NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()}, 193 TransportProtocols: []stack.TransportProtocol{udp.NewProtocol(), tcp.NewProtocol()}, 194 }) 195 s.CreateNIC(1, loopback.New()) 196 s.AddAddress(1, ipv6.ProtocolNumber, local) 197 s.SetRouteTable([]tcpip.Route{{ 198 Destination: header.IPv6EmptySubnet, 199 Gateway: ipv6Gateway, 200 NIC: 1, 201 }}) 202 203 return s.FindRoute(1, local, remote, ipv6.ProtocolNumber, false /* multicastLoop */) 204 } 205 206 func TestIPv4Send(t *testing.T) { 207 o := testObject{t: t, v4: true} 208 proto := ipv4.NewProtocol() 209 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, nil, &o) 210 if err != nil { 211 t.Fatalf("NewEndpoint failed: %v", err) 212 } 213 214 // Allocate and initialize the payload view. 215 payload := buffer.NewView(100) 216 for i := 0; i < len(payload); i++ { 217 payload[i] = uint8(i) 218 } 219 220 // Allocate the header buffer. 221 hdr := buffer.NewPrependable(int(ep.MaxHeaderLength())) 222 223 // Issue the write. 224 o.protocol = 123 225 o.srcAddr = localIpv4Addr 226 o.dstAddr = remoteIpv4Addr 227 o.contents = payload 228 229 r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr) 230 if err != nil { 231 t.Fatalf("could not find route: %v", err) 232 } 233 if err := ep.WritePacket(&r, nil /* gso */, hdr, payload.ToVectorisedView(), 123, 123, stack.PacketOut); err != nil { 234 t.Fatalf("WritePacket failed: %v", err) 235 } 236 } 237 238 func TestIPv4Receive(t *testing.T) { 239 o := testObject{t: t, v4: true} 240 proto := ipv4.NewProtocol() 241 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil) 242 if err != nil { 243 t.Fatalf("NewEndpoint failed: %v", err) 244 } 245 246 totalLen := header.IPv4MinimumSize + 30 247 view := buffer.NewView(totalLen) 248 ip := header.IPv4(view) 249 ip.Encode(&header.IPv4Fields{ 250 IHL: header.IPv4MinimumSize, 251 TotalLength: uint16(totalLen), 252 TTL: 20, 253 Protocol: 10, 254 SrcAddr: remoteIpv4Addr, 255 DstAddr: localIpv4Addr, 256 }) 257 258 // Make payload be non-zero. 259 for i := header.IPv4MinimumSize; i < totalLen; i++ { 260 view[i] = uint8(i) 261 } 262 263 // Give packet to ipv4 endpoint, dispatcher will validate that it's ok. 264 o.protocol = 10 265 o.srcAddr = remoteIpv4Addr 266 o.dstAddr = localIpv4Addr 267 o.contents = view[header.IPv4MinimumSize:totalLen] 268 269 r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr) 270 if err != nil { 271 t.Fatalf("could not find route: %v", err) 272 } 273 ep.HandlePacket(&r, view.ToVectorisedView()) 274 if o.dataCalls != 1 { 275 t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls) 276 } 277 } 278 279 func TestIPv4ReceiveControl(t *testing.T) { 280 const mtu = 0xbeef - header.IPv4MinimumSize 281 cases := []struct { 282 name string 283 expectedCount int 284 fragmentOffset uint16 285 code uint8 286 expectedTyp stack.ControlType 287 expectedExtra uint32 288 trunc int 289 }{ 290 {"FragmentationNeeded", 1, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 0}, 291 {"Truncated (10 bytes missing)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 10}, 292 {"Truncated (missing IPv4 header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.IPv4MinimumSize + 8}, 293 {"Truncated (missing 'extra info')", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 4 + header.IPv4MinimumSize + 8}, 294 {"Truncated (missing ICMP header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.ICMPv4MinimumSize + header.IPv4MinimumSize + 8}, 295 {"Port unreachable", 1, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 296 {"Non-zero fragment offset", 0, 100, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 297 {"Zero-length packet", 0, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv4MinimumSize + header.ICMPv4MinimumSize + 8}, 298 } 299 r, err := buildIPv4Route(localIpv4Addr, "\x0a\x00\x00\xbb") 300 if err != nil { 301 t.Fatal(err) 302 } 303 for _, c := range cases { 304 t.Run(c.name, func(t *testing.T) { 305 o := testObject{t: t} 306 proto := ipv4.NewProtocol() 307 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil) 308 if err != nil { 309 t.Fatalf("NewEndpoint failed: %v", err) 310 } 311 defer ep.Close() 312 313 const dataOffset = header.IPv4MinimumSize*2 + header.ICMPv4MinimumSize 314 view := buffer.NewView(dataOffset + 8) 315 316 // Create the outer IPv4 header. 317 ip := header.IPv4(view) 318 ip.Encode(&header.IPv4Fields{ 319 IHL: header.IPv4MinimumSize, 320 TotalLength: uint16(len(view) - c.trunc), 321 TTL: 20, 322 Protocol: uint8(header.ICMPv4ProtocolNumber), 323 SrcAddr: "\x0a\x00\x00\xbb", 324 DstAddr: localIpv4Addr, 325 }) 326 327 // Create the ICMP header. 328 icmp := header.ICMPv4(view[header.IPv4MinimumSize:]) 329 icmp.SetType(header.ICMPv4DstUnreachable) 330 icmp.SetCode(c.code) 331 icmp.SetIdent(0xdead) 332 icmp.SetSequence(0xbeef) 333 334 // Create the inner IPv4 header. 335 ip = header.IPv4(view[header.IPv4MinimumSize+header.ICMPv4MinimumSize:]) 336 ip.Encode(&header.IPv4Fields{ 337 IHL: header.IPv4MinimumSize, 338 TotalLength: 100, 339 TTL: 20, 340 Protocol: 10, 341 FragmentOffset: c.fragmentOffset, 342 SrcAddr: localIpv4Addr, 343 DstAddr: remoteIpv4Addr, 344 }) 345 346 // Make payload be non-zero. 347 for i := dataOffset; i < len(view); i++ { 348 view[i] = uint8(i) 349 } 350 351 // Give packet to IPv4 endpoint, dispatcher will validate that 352 // it's ok. 353 o.protocol = 10 354 o.srcAddr = remoteIpv4Addr 355 o.dstAddr = localIpv4Addr 356 o.contents = view[dataOffset:] 357 o.typ = c.expectedTyp 358 o.extra = c.expectedExtra 359 360 vv := view[:len(view)-c.trunc].ToVectorisedView() 361 ep.HandlePacket(&r, vv) 362 if want := c.expectedCount; o.controlCalls != want { 363 t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, o.controlCalls, want) 364 } 365 }) 366 } 367 } 368 369 func TestIPv4FragmentationReceive(t *testing.T) { 370 o := testObject{t: t, v4: true} 371 proto := ipv4.NewProtocol() 372 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil) 373 if err != nil { 374 t.Fatalf("NewEndpoint failed: %v", err) 375 } 376 377 totalLen := header.IPv4MinimumSize + 24 378 379 frag1 := buffer.NewView(totalLen) 380 ip1 := header.IPv4(frag1) 381 ip1.Encode(&header.IPv4Fields{ 382 IHL: header.IPv4MinimumSize, 383 TotalLength: uint16(totalLen), 384 TTL: 20, 385 Protocol: 10, 386 FragmentOffset: 0, 387 Flags: header.IPv4FlagMoreFragments, 388 SrcAddr: remoteIpv4Addr, 389 DstAddr: localIpv4Addr, 390 }) 391 // Make payload be non-zero. 392 for i := header.IPv4MinimumSize; i < totalLen; i++ { 393 frag1[i] = uint8(i) 394 } 395 396 frag2 := buffer.NewView(totalLen) 397 ip2 := header.IPv4(frag2) 398 ip2.Encode(&header.IPv4Fields{ 399 IHL: header.IPv4MinimumSize, 400 TotalLength: uint16(totalLen), 401 TTL: 20, 402 Protocol: 10, 403 FragmentOffset: 24, 404 SrcAddr: remoteIpv4Addr, 405 DstAddr: localIpv4Addr, 406 }) 407 // Make payload be non-zero. 408 for i := header.IPv4MinimumSize; i < totalLen; i++ { 409 frag2[i] = uint8(i) 410 } 411 412 // Give packet to ipv4 endpoint, dispatcher will validate that it's ok. 413 o.protocol = 10 414 o.srcAddr = remoteIpv4Addr 415 o.dstAddr = localIpv4Addr 416 o.contents = append(frag1[header.IPv4MinimumSize:totalLen], frag2[header.IPv4MinimumSize:totalLen]...) 417 418 r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr) 419 if err != nil { 420 t.Fatalf("could not find route: %v", err) 421 } 422 423 // Send first segment. 424 ep.HandlePacket(&r, frag1.ToVectorisedView()) 425 if o.dataCalls != 0 { 426 t.Fatalf("Bad number of data calls: got %x, want 0", o.dataCalls) 427 } 428 429 // Send second segment. 430 ep.HandlePacket(&r, frag2.ToVectorisedView()) 431 if o.dataCalls != 1 { 432 t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls) 433 } 434 } 435 436 func TestIPv6Send(t *testing.T) { 437 o := testObject{t: t} 438 proto := ipv6.NewProtocol() 439 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, nil, &o) 440 if err != nil { 441 t.Fatalf("NewEndpoint failed: %v", err) 442 } 443 444 // Allocate and initialize the payload view. 445 payload := buffer.NewView(100) 446 for i := 0; i < len(payload); i++ { 447 payload[i] = uint8(i) 448 } 449 450 // Allocate the header buffer. 451 hdr := buffer.NewPrependable(int(ep.MaxHeaderLength())) 452 453 // Issue the write. 454 o.protocol = 123 455 o.srcAddr = localIpv6Addr 456 o.dstAddr = remoteIpv6Addr 457 o.contents = payload 458 459 r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr) 460 if err != nil { 461 t.Fatalf("could not find route: %v", err) 462 } 463 if err := ep.WritePacket(&r, nil /* gso */, hdr, payload.ToVectorisedView(), 123, 123, stack.PacketOut); err != nil { 464 t.Fatalf("WritePacket failed: %v", err) 465 } 466 } 467 468 func TestIPv6Receive(t *testing.T) { 469 o := testObject{t: t} 470 proto := ipv6.NewProtocol() 471 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, &o, nil) 472 if err != nil { 473 t.Fatalf("NewEndpoint failed: %v", err) 474 } 475 476 totalLen := header.IPv6MinimumSize + 30 477 view := buffer.NewView(totalLen) 478 ip := header.IPv6(view) 479 ip.Encode(&header.IPv6Fields{ 480 PayloadLength: uint16(totalLen - header.IPv6MinimumSize), 481 NextHeader: 10, 482 HopLimit: 20, 483 SrcAddr: remoteIpv6Addr, 484 DstAddr: localIpv6Addr, 485 }) 486 487 // Make payload be non-zero. 488 for i := header.IPv6MinimumSize; i < totalLen; i++ { 489 view[i] = uint8(i) 490 } 491 492 // Give packet to ipv6 endpoint, dispatcher will validate that it's ok. 493 o.protocol = 10 494 o.srcAddr = remoteIpv6Addr 495 o.dstAddr = localIpv6Addr 496 o.contents = view[header.IPv6MinimumSize:totalLen] 497 498 r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr) 499 if err != nil { 500 t.Fatalf("could not find route: %v", err) 501 } 502 503 ep.HandlePacket(&r, view.ToVectorisedView()) 504 if o.dataCalls != 1 { 505 t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls) 506 } 507 } 508 509 func TestIPv6ReceiveControl(t *testing.T) { 510 newUint16 := func(v uint16) *uint16 { return &v } 511 512 const mtu = 0xffff 513 cases := []struct { 514 name string 515 expectedCount int 516 fragmentOffset *uint16 517 typ header.ICMPv6Type 518 code uint8 519 expectedTyp stack.ControlType 520 expectedExtra uint32 521 trunc int 522 }{ 523 {"PacketTooBig", 1, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 0}, 524 {"Truncated (10 bytes missing)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 10}, 525 {"Truncated (missing IPv6 header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.IPv6MinimumSize + 8}, 526 {"Truncated PacketTooBig (missing 'extra info')", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 4 + header.IPv6MinimumSize + 8}, 527 {"Truncated (missing ICMP header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.ICMPv6PacketTooBigMinimumSize + header.IPv6MinimumSize + 8}, 528 {"Port unreachable", 1, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 529 {"Truncated DstUnreachable (missing 'extra info')", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 4 + header.IPv6MinimumSize + 8}, 530 {"Fragmented, zero offset", 1, newUint16(0), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 531 {"Non-zero fragment offset", 0, newUint16(100), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 532 {"Zero-length packet", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv6MinimumSize + header.ICMPv6DstUnreachableMinimumSize + 8}, 533 } 534 r, err := buildIPv6Route( 535 localIpv6Addr, 536 "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa", 537 ) 538 if err != nil { 539 t.Fatal(err) 540 } 541 for _, c := range cases { 542 t.Run(c.name, func(t *testing.T) { 543 o := testObject{t: t} 544 proto := ipv6.NewProtocol() 545 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, &o, nil) 546 if err != nil { 547 t.Fatalf("NewEndpoint failed: %v", err) 548 } 549 550 defer ep.Close() 551 552 dataOffset := header.IPv6MinimumSize*2 + header.ICMPv6MinimumSize 553 if c.fragmentOffset != nil { 554 dataOffset += header.IPv6FragmentHeaderSize 555 } 556 view := buffer.NewView(dataOffset + 8) 557 558 // Create the outer IPv6 header. 559 ip := header.IPv6(view) 560 ip.Encode(&header.IPv6Fields{ 561 PayloadLength: uint16(len(view) - header.IPv6MinimumSize - c.trunc), 562 NextHeader: uint8(header.ICMPv6ProtocolNumber), 563 HopLimit: 20, 564 SrcAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa", 565 DstAddr: localIpv6Addr, 566 }) 567 568 // Create the ICMP header. 569 icmp := header.ICMPv6(view[header.IPv6MinimumSize:]) 570 icmp.SetType(c.typ) 571 icmp.SetCode(c.code) 572 icmp.SetIdent(0xdead) 573 icmp.SetSequence(0xbeef) 574 575 // Create the inner IPv6 header. 576 ip = header.IPv6(view[header.IPv6MinimumSize+header.ICMPv6PayloadOffset:]) 577 ip.Encode(&header.IPv6Fields{ 578 PayloadLength: 100, 579 NextHeader: 10, 580 HopLimit: 20, 581 SrcAddr: localIpv6Addr, 582 DstAddr: remoteIpv6Addr, 583 }) 584 585 // Build the fragmentation header if needed. 586 if c.fragmentOffset != nil { 587 ip.SetNextHeader(header.IPv6FragmentHeader) 588 frag := header.IPv6Fragment(view[2*header.IPv6MinimumSize+header.ICMPv6MinimumSize:]) 589 frag.Encode(&header.IPv6FragmentFields{ 590 NextHeader: 10, 591 FragmentOffset: *c.fragmentOffset, 592 M: true, 593 Identification: 0x12345678, 594 }) 595 } 596 597 // Make payload be non-zero. 598 for i := dataOffset; i < len(view); i++ { 599 view[i] = uint8(i) 600 } 601 602 // Give packet to IPv6 endpoint, dispatcher will validate that 603 // it's ok. 604 o.protocol = 10 605 o.srcAddr = remoteIpv6Addr 606 o.dstAddr = localIpv6Addr 607 o.contents = view[dataOffset:] 608 o.typ = c.expectedTyp 609 o.extra = c.expectedExtra 610 611 vv := view[:len(view)-c.trunc].ToVectorisedView() 612 ep.HandlePacket(&r, vv) 613 if want := c.expectedCount; o.controlCalls != want { 614 t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, o.controlCalls, want) 615 } 616 }) 617 } 618 }