github.com/vpnishe/netstack@v1.10.6/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/vpnishe/netstack/tcpip" 21 "github.com/vpnishe/netstack/tcpip/buffer" 22 "github.com/vpnishe/netstack/tcpip/header" 23 "github.com/vpnishe/netstack/tcpip/link/loopback" 24 "github.com/vpnishe/netstack/tcpip/network/ipv4" 25 "github.com/vpnishe/netstack/tcpip/network/ipv6" 26 "github.com/vpnishe/netstack/tcpip/stack" 27 "github.com/vpnishe/netstack/tcpip/transport/tcp" 28 "github.com/vpnishe/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, pkt tcpip.PacketBuffer) { 100 t.checkValues(protocol, pkt.Data, 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, pkt tcpip.PacketBuffer) { 108 t.checkValues(trans, pkt.Data, 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, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) *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(pkt.Header.View()) 160 prot = tcpip.TransportProtocolNumber(h.Protocol()) 161 srcAddr = h.SourceAddress() 162 dstAddr = h.DestinationAddress() 163 164 } else { 165 h := header.IPv6(pkt.Header.View()) 166 prot = tcpip.TransportProtocolNumber(h.NextHeader()) 167 srcAddr = h.SourceAddress() 168 dstAddr = h.DestinationAddress() 169 } 170 t.checkValues(prot, pkt.Data, srcAddr, dstAddr) 171 return nil 172 } 173 174 // WritePackets implements stack.LinkEndpoint.WritePackets. 175 func (t *testObject) WritePackets(_ *stack.Route, _ *stack.GSO, hdr []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) { 176 panic("not implemented") 177 } 178 179 func (t *testObject) WriteRawPacket(_ buffer.VectorisedView) *tcpip.Error { 180 return tcpip.ErrNotSupported 181 } 182 183 func buildIPv4Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) { 184 s := stack.New(stack.Options{ 185 NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol()}, 186 TransportProtocols: []stack.TransportProtocol{udp.NewProtocol(), tcp.NewProtocol()}, 187 }) 188 s.CreateNIC(1, loopback.New()) 189 s.AddAddress(1, ipv4.ProtocolNumber, local) 190 s.SetRouteTable([]tcpip.Route{{ 191 Destination: header.IPv4EmptySubnet, 192 Gateway: ipv4Gateway, 193 NIC: 1, 194 }}) 195 196 return s.FindRoute(1, local, remote, ipv4.ProtocolNumber, false /* multicastLoop */) 197 } 198 199 func buildIPv6Route(local, remote tcpip.Address) (stack.Route, *tcpip.Error) { 200 s := stack.New(stack.Options{ 201 NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()}, 202 TransportProtocols: []stack.TransportProtocol{udp.NewProtocol(), tcp.NewProtocol()}, 203 }) 204 s.CreateNIC(1, loopback.New()) 205 s.AddAddress(1, ipv6.ProtocolNumber, local) 206 s.SetRouteTable([]tcpip.Route{{ 207 Destination: header.IPv6EmptySubnet, 208 Gateway: ipv6Gateway, 209 NIC: 1, 210 }}) 211 212 return s.FindRoute(1, local, remote, ipv6.ProtocolNumber, false /* multicastLoop */) 213 } 214 215 func TestIPv4Send(t *testing.T) { 216 o := testObject{t: t, v4: true} 217 proto := ipv4.NewProtocol() 218 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, nil, &o) 219 if err != nil { 220 t.Fatalf("NewEndpoint failed: %v", err) 221 } 222 223 // Allocate and initialize the payload view. 224 payload := buffer.NewView(100) 225 for i := 0; i < len(payload); i++ { 226 payload[i] = uint8(i) 227 } 228 229 // Allocate the header buffer. 230 hdr := buffer.NewPrependable(int(ep.MaxHeaderLength())) 231 232 // Issue the write. 233 o.protocol = 123 234 o.srcAddr = localIpv4Addr 235 o.dstAddr = remoteIpv4Addr 236 o.contents = payload 237 238 r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr) 239 if err != nil { 240 t.Fatalf("could not find route: %v", err) 241 } 242 if err := ep.WritePacket(&r, nil /* gso */, stack.NetworkHeaderParams{Protocol: 123, TTL: 123, TOS: stack.DefaultTOS}, stack.PacketOut, tcpip.PacketBuffer{ 243 Header: hdr, 244 Data: payload.ToVectorisedView(), 245 }); err != nil { 246 t.Fatalf("WritePacket failed: %v", err) 247 } 248 } 249 250 func TestIPv4Receive(t *testing.T) { 251 o := testObject{t: t, v4: true} 252 proto := ipv4.NewProtocol() 253 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil) 254 if err != nil { 255 t.Fatalf("NewEndpoint failed: %v", err) 256 } 257 258 totalLen := header.IPv4MinimumSize + 30 259 view := buffer.NewView(totalLen) 260 ip := header.IPv4(view) 261 ip.Encode(&header.IPv4Fields{ 262 IHL: header.IPv4MinimumSize, 263 TotalLength: uint16(totalLen), 264 TTL: 20, 265 Protocol: 10, 266 SrcAddr: remoteIpv4Addr, 267 DstAddr: localIpv4Addr, 268 }) 269 270 // Make payload be non-zero. 271 for i := header.IPv4MinimumSize; i < totalLen; i++ { 272 view[i] = uint8(i) 273 } 274 275 // Give packet to ipv4 endpoint, dispatcher will validate that it's ok. 276 o.protocol = 10 277 o.srcAddr = remoteIpv4Addr 278 o.dstAddr = localIpv4Addr 279 o.contents = view[header.IPv4MinimumSize:totalLen] 280 281 r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr) 282 if err != nil { 283 t.Fatalf("could not find route: %v", err) 284 } 285 ep.HandlePacket(&r, tcpip.PacketBuffer{ 286 Data: view.ToVectorisedView(), 287 }) 288 if o.dataCalls != 1 { 289 t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls) 290 } 291 } 292 293 func TestIPv4ReceiveControl(t *testing.T) { 294 const mtu = 0xbeef - header.IPv4MinimumSize 295 cases := []struct { 296 name string 297 expectedCount int 298 fragmentOffset uint16 299 code uint8 300 expectedTyp stack.ControlType 301 expectedExtra uint32 302 trunc int 303 }{ 304 {"FragmentationNeeded", 1, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 0}, 305 {"Truncated (10 bytes missing)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 10}, 306 {"Truncated (missing IPv4 header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.IPv4MinimumSize + 8}, 307 {"Truncated (missing 'extra info')", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 4 + header.IPv4MinimumSize + 8}, 308 {"Truncated (missing ICMP header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.ICMPv4MinimumSize + header.IPv4MinimumSize + 8}, 309 {"Port unreachable", 1, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 310 {"Non-zero fragment offset", 0, 100, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 311 {"Zero-length packet", 0, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv4MinimumSize + header.ICMPv4MinimumSize + 8}, 312 } 313 r, err := buildIPv4Route(localIpv4Addr, "\x0a\x00\x00\xbb") 314 if err != nil { 315 t.Fatal(err) 316 } 317 for _, c := range cases { 318 t.Run(c.name, func(t *testing.T) { 319 o := testObject{t: t} 320 proto := ipv4.NewProtocol() 321 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil) 322 if err != nil { 323 t.Fatalf("NewEndpoint failed: %v", err) 324 } 325 defer ep.Close() 326 327 const dataOffset = header.IPv4MinimumSize*2 + header.ICMPv4MinimumSize 328 view := buffer.NewView(dataOffset + 8) 329 330 // Create the outer IPv4 header. 331 ip := header.IPv4(view) 332 ip.Encode(&header.IPv4Fields{ 333 IHL: header.IPv4MinimumSize, 334 TotalLength: uint16(len(view) - c.trunc), 335 TTL: 20, 336 Protocol: uint8(header.ICMPv4ProtocolNumber), 337 SrcAddr: "\x0a\x00\x00\xbb", 338 DstAddr: localIpv4Addr, 339 }) 340 341 // Create the ICMP header. 342 icmp := header.ICMPv4(view[header.IPv4MinimumSize:]) 343 icmp.SetType(header.ICMPv4DstUnreachable) 344 icmp.SetCode(c.code) 345 icmp.SetIdent(0xdead) 346 icmp.SetSequence(0xbeef) 347 348 // Create the inner IPv4 header. 349 ip = header.IPv4(view[header.IPv4MinimumSize+header.ICMPv4MinimumSize:]) 350 ip.Encode(&header.IPv4Fields{ 351 IHL: header.IPv4MinimumSize, 352 TotalLength: 100, 353 TTL: 20, 354 Protocol: 10, 355 FragmentOffset: c.fragmentOffset, 356 SrcAddr: localIpv4Addr, 357 DstAddr: remoteIpv4Addr, 358 }) 359 360 // Make payload be non-zero. 361 for i := dataOffset; i < len(view); i++ { 362 view[i] = uint8(i) 363 } 364 365 // Give packet to IPv4 endpoint, dispatcher will validate that 366 // it's ok. 367 o.protocol = 10 368 o.srcAddr = remoteIpv4Addr 369 o.dstAddr = localIpv4Addr 370 o.contents = view[dataOffset:] 371 o.typ = c.expectedTyp 372 o.extra = c.expectedExtra 373 374 vv := view[:len(view)-c.trunc].ToVectorisedView() 375 ep.HandlePacket(&r, tcpip.PacketBuffer{ 376 Data: vv, 377 }) 378 if want := c.expectedCount; o.controlCalls != want { 379 t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, o.controlCalls, want) 380 } 381 }) 382 } 383 } 384 385 func TestIPv4FragmentationReceive(t *testing.T) { 386 o := testObject{t: t, v4: true} 387 proto := ipv4.NewProtocol() 388 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv4Addr, localIpv4PrefixLen}, nil, &o, nil) 389 if err != nil { 390 t.Fatalf("NewEndpoint failed: %v", err) 391 } 392 393 totalLen := header.IPv4MinimumSize + 24 394 395 frag1 := buffer.NewView(totalLen) 396 ip1 := header.IPv4(frag1) 397 ip1.Encode(&header.IPv4Fields{ 398 IHL: header.IPv4MinimumSize, 399 TotalLength: uint16(totalLen), 400 TTL: 20, 401 Protocol: 10, 402 FragmentOffset: 0, 403 Flags: header.IPv4FlagMoreFragments, 404 SrcAddr: remoteIpv4Addr, 405 DstAddr: localIpv4Addr, 406 }) 407 // Make payload be non-zero. 408 for i := header.IPv4MinimumSize; i < totalLen; i++ { 409 frag1[i] = uint8(i) 410 } 411 412 frag2 := buffer.NewView(totalLen) 413 ip2 := header.IPv4(frag2) 414 ip2.Encode(&header.IPv4Fields{ 415 IHL: header.IPv4MinimumSize, 416 TotalLength: uint16(totalLen), 417 TTL: 20, 418 Protocol: 10, 419 FragmentOffset: 24, 420 SrcAddr: remoteIpv4Addr, 421 DstAddr: localIpv4Addr, 422 }) 423 // Make payload be non-zero. 424 for i := header.IPv4MinimumSize; i < totalLen; i++ { 425 frag2[i] = uint8(i) 426 } 427 428 // Give packet to ipv4 endpoint, dispatcher will validate that it's ok. 429 o.protocol = 10 430 o.srcAddr = remoteIpv4Addr 431 o.dstAddr = localIpv4Addr 432 o.contents = append(frag1[header.IPv4MinimumSize:totalLen], frag2[header.IPv4MinimumSize:totalLen]...) 433 434 r, err := buildIPv4Route(localIpv4Addr, remoteIpv4Addr) 435 if err != nil { 436 t.Fatalf("could not find route: %v", err) 437 } 438 439 // Send first segment. 440 ep.HandlePacket(&r, tcpip.PacketBuffer{ 441 Data: frag1.ToVectorisedView(), 442 }) 443 if o.dataCalls != 0 { 444 t.Fatalf("Bad number of data calls: got %x, want 0", o.dataCalls) 445 } 446 447 // Send second segment. 448 ep.HandlePacket(&r, tcpip.PacketBuffer{ 449 Data: frag2.ToVectorisedView(), 450 }) 451 if o.dataCalls != 1 { 452 t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls) 453 } 454 } 455 456 func TestIPv6Send(t *testing.T) { 457 o := testObject{t: t} 458 proto := ipv6.NewProtocol() 459 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, nil, &o) 460 if err != nil { 461 t.Fatalf("NewEndpoint failed: %v", err) 462 } 463 464 // Allocate and initialize the payload view. 465 payload := buffer.NewView(100) 466 for i := 0; i < len(payload); i++ { 467 payload[i] = uint8(i) 468 } 469 470 // Allocate the header buffer. 471 hdr := buffer.NewPrependable(int(ep.MaxHeaderLength())) 472 473 // Issue the write. 474 o.protocol = 123 475 o.srcAddr = localIpv6Addr 476 o.dstAddr = remoteIpv6Addr 477 o.contents = payload 478 479 r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr) 480 if err != nil { 481 t.Fatalf("could not find route: %v", err) 482 } 483 if err := ep.WritePacket(&r, nil /* gso */, stack.NetworkHeaderParams{Protocol: 123, TTL: 123, TOS: stack.DefaultTOS}, stack.PacketOut, tcpip.PacketBuffer{ 484 Header: hdr, 485 Data: payload.ToVectorisedView(), 486 }); err != nil { 487 t.Fatalf("WritePacket failed: %v", err) 488 } 489 } 490 491 func TestIPv6Receive(t *testing.T) { 492 o := testObject{t: t} 493 proto := ipv6.NewProtocol() 494 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, &o, nil) 495 if err != nil { 496 t.Fatalf("NewEndpoint failed: %v", err) 497 } 498 499 totalLen := header.IPv6MinimumSize + 30 500 view := buffer.NewView(totalLen) 501 ip := header.IPv6(view) 502 ip.Encode(&header.IPv6Fields{ 503 PayloadLength: uint16(totalLen - header.IPv6MinimumSize), 504 NextHeader: 10, 505 HopLimit: 20, 506 SrcAddr: remoteIpv6Addr, 507 DstAddr: localIpv6Addr, 508 }) 509 510 // Make payload be non-zero. 511 for i := header.IPv6MinimumSize; i < totalLen; i++ { 512 view[i] = uint8(i) 513 } 514 515 // Give packet to ipv6 endpoint, dispatcher will validate that it's ok. 516 o.protocol = 10 517 o.srcAddr = remoteIpv6Addr 518 o.dstAddr = localIpv6Addr 519 o.contents = view[header.IPv6MinimumSize:totalLen] 520 521 r, err := buildIPv6Route(localIpv6Addr, remoteIpv6Addr) 522 if err != nil { 523 t.Fatalf("could not find route: %v", err) 524 } 525 526 ep.HandlePacket(&r, tcpip.PacketBuffer{ 527 Data: view.ToVectorisedView(), 528 }) 529 if o.dataCalls != 1 { 530 t.Fatalf("Bad number of data calls: got %x, want 1", o.dataCalls) 531 } 532 } 533 534 func TestIPv6ReceiveControl(t *testing.T) { 535 newUint16 := func(v uint16) *uint16 { return &v } 536 537 const mtu = 0xffff 538 const outerSrcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa" 539 cases := []struct { 540 name string 541 expectedCount int 542 fragmentOffset *uint16 543 typ header.ICMPv6Type 544 code uint8 545 expectedTyp stack.ControlType 546 expectedExtra uint32 547 trunc int 548 }{ 549 {"PacketTooBig", 1, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 0}, 550 {"Truncated (10 bytes missing)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 10}, 551 {"Truncated (missing IPv6 header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.IPv6MinimumSize + 8}, 552 {"Truncated PacketTooBig (missing 'extra info')", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 4 + header.IPv6MinimumSize + 8}, 553 {"Truncated (missing ICMP header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.ICMPv6PacketTooBigMinimumSize + header.IPv6MinimumSize + 8}, 554 {"Port unreachable", 1, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 555 {"Truncated DstUnreachable (missing 'extra info')", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 4 + header.IPv6MinimumSize + 8}, 556 {"Fragmented, zero offset", 1, newUint16(0), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 557 {"Non-zero fragment offset", 0, newUint16(100), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0}, 558 {"Zero-length packet", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv6MinimumSize + header.ICMPv6DstUnreachableMinimumSize + 8}, 559 } 560 r, err := buildIPv6Route( 561 localIpv6Addr, 562 "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa", 563 ) 564 if err != nil { 565 t.Fatal(err) 566 } 567 for _, c := range cases { 568 t.Run(c.name, func(t *testing.T) { 569 o := testObject{t: t} 570 proto := ipv6.NewProtocol() 571 ep, err := proto.NewEndpoint(1, tcpip.AddressWithPrefix{localIpv6Addr, localIpv6PrefixLen}, nil, &o, nil) 572 if err != nil { 573 t.Fatalf("NewEndpoint failed: %v", err) 574 } 575 576 defer ep.Close() 577 578 dataOffset := header.IPv6MinimumSize*2 + header.ICMPv6MinimumSize 579 if c.fragmentOffset != nil { 580 dataOffset += header.IPv6FragmentHeaderSize 581 } 582 view := buffer.NewView(dataOffset + 8) 583 584 // Create the outer IPv6 header. 585 ip := header.IPv6(view) 586 ip.Encode(&header.IPv6Fields{ 587 PayloadLength: uint16(len(view) - header.IPv6MinimumSize - c.trunc), 588 NextHeader: uint8(header.ICMPv6ProtocolNumber), 589 HopLimit: 20, 590 SrcAddr: outerSrcAddr, 591 DstAddr: localIpv6Addr, 592 }) 593 594 // Create the ICMP header. 595 icmp := header.ICMPv6(view[header.IPv6MinimumSize:]) 596 icmp.SetType(c.typ) 597 icmp.SetCode(c.code) 598 icmp.SetIdent(0xdead) 599 icmp.SetSequence(0xbeef) 600 601 // Create the inner IPv6 header. 602 ip = header.IPv6(view[header.IPv6MinimumSize+header.ICMPv6PayloadOffset:]) 603 ip.Encode(&header.IPv6Fields{ 604 PayloadLength: 100, 605 NextHeader: 10, 606 HopLimit: 20, 607 SrcAddr: localIpv6Addr, 608 DstAddr: remoteIpv6Addr, 609 }) 610 611 // Build the fragmentation header if needed. 612 if c.fragmentOffset != nil { 613 ip.SetNextHeader(header.IPv6FragmentHeader) 614 frag := header.IPv6Fragment(view[2*header.IPv6MinimumSize+header.ICMPv6MinimumSize:]) 615 frag.Encode(&header.IPv6FragmentFields{ 616 NextHeader: 10, 617 FragmentOffset: *c.fragmentOffset, 618 M: true, 619 Identification: 0x12345678, 620 }) 621 } 622 623 // Make payload be non-zero. 624 for i := dataOffset; i < len(view); i++ { 625 view[i] = uint8(i) 626 } 627 628 // Give packet to IPv6 endpoint, dispatcher will validate that 629 // it's ok. 630 o.protocol = 10 631 o.srcAddr = remoteIpv6Addr 632 o.dstAddr = localIpv6Addr 633 o.contents = view[dataOffset:] 634 o.typ = c.expectedTyp 635 o.extra = c.expectedExtra 636 637 // Set ICMPv6 checksum. 638 icmp.SetChecksum(header.ICMPv6Checksum(icmp, outerSrcAddr, localIpv6Addr, buffer.VectorisedView{})) 639 640 ep.HandlePacket(&r, tcpip.PacketBuffer{ 641 Data: view[:len(view)-c.trunc].ToVectorisedView(), 642 }) 643 if want := c.expectedCount; o.controlCalls != want { 644 t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, o.controlCalls, want) 645 } 646 }) 647 } 648 }