github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/network/ipv6/ipv6_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 "bytes" 19 "encoding/hex" 20 "fmt" 21 "io/ioutil" 22 "math" 23 "net" 24 "reflect" 25 "testing" 26 27 "github.com/google/go-cmp/cmp" 28 "github.com/SagerNet/gvisor/pkg/tcpip" 29 "github.com/SagerNet/gvisor/pkg/tcpip/buffer" 30 "github.com/SagerNet/gvisor/pkg/tcpip/checker" 31 "github.com/SagerNet/gvisor/pkg/tcpip/faketime" 32 "github.com/SagerNet/gvisor/pkg/tcpip/header" 33 "github.com/SagerNet/gvisor/pkg/tcpip/link/channel" 34 iptestutil "github.com/SagerNet/gvisor/pkg/tcpip/network/internal/testutil" 35 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 36 "github.com/SagerNet/gvisor/pkg/tcpip/testutil" 37 "github.com/SagerNet/gvisor/pkg/tcpip/transport/icmp" 38 "github.com/SagerNet/gvisor/pkg/tcpip/transport/tcp" 39 "github.com/SagerNet/gvisor/pkg/tcpip/transport/udp" 40 "github.com/SagerNet/gvisor/pkg/waiter" 41 ) 42 43 const ( 44 addr1 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" 45 addr2 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" 46 // The least significant 3 bytes are the same as addr2 so both addr2 and 47 // addr3 will have the same solicited-node address. 48 addr3 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x02" 49 addr4 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x03" 50 51 // Tests use the extension header identifier values as uint8 instead of 52 // header.IPv6ExtensionHeaderIdentifier. 53 hopByHopExtHdrID = uint8(header.IPv6HopByHopOptionsExtHdrIdentifier) 54 routingExtHdrID = uint8(header.IPv6RoutingExtHdrIdentifier) 55 fragmentExtHdrID = uint8(header.IPv6FragmentExtHdrIdentifier) 56 destinationExtHdrID = uint8(header.IPv6DestinationOptionsExtHdrIdentifier) 57 noNextHdrID = uint8(header.IPv6NoNextHeaderIdentifier) 58 unknownHdrID = uint8(header.IPv6UnknownExtHdrIdentifier) 59 60 extraHeaderReserve = 50 61 ) 62 63 // testReceiveICMP tests receiving an ICMP packet from src to dst. want is the 64 // expected Neighbor Advertisement received count after receiving the packet. 65 func testReceiveICMP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) { 66 t.Helper() 67 68 // Receive ICMP packet. 69 hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.ICMPv6NeighborAdvertMinimumSize) 70 pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertMinimumSize)) 71 pkt.SetType(header.ICMPv6NeighborAdvert) 72 pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 73 Header: pkt, 74 Src: src, 75 Dst: dst, 76 })) 77 payloadLength := hdr.UsedLength() 78 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 79 ip.Encode(&header.IPv6Fields{ 80 PayloadLength: uint16(payloadLength), 81 TransportProtocol: header.ICMPv6ProtocolNumber, 82 HopLimit: 255, 83 SrcAddr: src, 84 DstAddr: dst, 85 }) 86 87 e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ 88 Data: hdr.View().ToVectorisedView(), 89 })) 90 91 stats := s.Stats().ICMP.V6.PacketsReceived 92 93 if got := stats.NeighborAdvert.Value(); got != want { 94 t.Fatalf("got NeighborAdvert = %d, want = %d", got, want) 95 } 96 } 97 98 // testReceiveUDP tests receiving a UDP packet from src to dst. want is the 99 // expected UDP received count after receiving the packet. 100 func testReceiveUDP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) { 101 t.Helper() 102 103 wq := waiter.Queue{} 104 we, ch := waiter.NewChannelEntry(nil) 105 wq.EventRegister(&we, waiter.ReadableEvents) 106 defer wq.EventUnregister(&we) 107 defer close(ch) 108 109 ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq) 110 if err != nil { 111 t.Fatalf("NewEndpoint failed: %v", err) 112 } 113 defer ep.Close() 114 115 if err := ep.Bind(tcpip.FullAddress{Addr: dst, Port: 80}); err != nil { 116 t.Fatalf("ep.Bind(...) failed: %v", err) 117 } 118 119 // Receive UDP Packet. 120 hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.UDPMinimumSize) 121 u := header.UDP(hdr.Prepend(header.UDPMinimumSize)) 122 u.Encode(&header.UDPFields{ 123 SrcPort: 5555, 124 DstPort: 80, 125 Length: header.UDPMinimumSize, 126 }) 127 128 // UDP pseudo-header checksum. 129 sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, header.UDPMinimumSize) 130 131 // UDP checksum 132 sum = header.Checksum(nil, sum) 133 u.SetChecksum(^u.CalculateChecksum(sum)) 134 135 payloadLength := hdr.UsedLength() 136 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 137 ip.Encode(&header.IPv6Fields{ 138 PayloadLength: uint16(payloadLength), 139 TransportProtocol: udp.ProtocolNumber, 140 HopLimit: 255, 141 SrcAddr: src, 142 DstAddr: dst, 143 }) 144 145 e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ 146 Data: hdr.View().ToVectorisedView(), 147 })) 148 149 stat := s.Stats().UDP.PacketsReceived 150 151 if got := stat.Value(); got != want { 152 t.Fatalf("got UDPPacketsReceived = %d, want = %d", got, want) 153 } 154 } 155 156 func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketBuffer, mtu uint32, wantFragments []fragmentInfo, proto tcpip.TransportProtocolNumber) error { 157 // sourcePacket does not have its IP Header populated. Let's copy the one 158 // from the first fragment. 159 source := header.IPv6(packets[0].NetworkHeader().View()) 160 sourceIPHeadersLen := len(source) 161 vv := buffer.NewVectorisedView(sourcePacket.Size(), sourcePacket.Views()) 162 source = append(source, vv.ToView()...) 163 164 var reassembledPayload buffer.VectorisedView 165 for i, fragment := range packets { 166 // Confirm that the packet is valid. 167 allBytes := buffer.NewVectorisedView(fragment.Size(), fragment.Views()) 168 fragmentIPHeaders := header.IPv6(allBytes.ToView()) 169 if !fragmentIPHeaders.IsValid(len(fragmentIPHeaders)) { 170 return fmt.Errorf("fragment #%d: IP packet is invalid:\n%s", i, hex.Dump(fragmentIPHeaders)) 171 } 172 173 fragmentIPHeadersLength := fragment.NetworkHeader().View().Size() 174 if fragmentIPHeadersLength != sourceIPHeadersLen { 175 return fmt.Errorf("fragment #%d: got fragmentIPHeadersLength = %d, want = %d", i, fragmentIPHeadersLength, sourceIPHeadersLen) 176 } 177 178 if got := len(fragmentIPHeaders); got > int(mtu) { 179 return fmt.Errorf("fragment #%d: got len(fragmentIPHeaders) = %d, want <= %d", i, got, mtu) 180 } 181 182 sourceIPHeader := source[:header.IPv6MinimumSize] 183 fragmentIPHeader := fragmentIPHeaders[:header.IPv6MinimumSize] 184 185 if got := fragmentIPHeaders.PayloadLength(); got != wantFragments[i].payloadSize { 186 return fmt.Errorf("fragment #%d: got fragmentIPHeaders.PayloadLength() = %d, want = %d", i, got, wantFragments[i].payloadSize) 187 } 188 189 // We expect the IPv6 Header to be similar across each fragment, besides the 190 // payload length. 191 sourceIPHeader.SetPayloadLength(0) 192 fragmentIPHeader.SetPayloadLength(0) 193 if diff := cmp.Diff(fragmentIPHeader, sourceIPHeader); diff != "" { 194 return fmt.Errorf("fragment #%d: fragmentIPHeader mismatch (-want +got):\n%s", i, diff) 195 } 196 197 if got := fragment.AvailableHeaderBytes(); got != extraHeaderReserve { 198 return fmt.Errorf("fragment #%d: got packet.AvailableHeaderBytes() = %d, want = %d", i, got, extraHeaderReserve) 199 } 200 if fragment.NetworkProtocolNumber != sourcePacket.NetworkProtocolNumber { 201 return fmt.Errorf("fragment #%d: got fragment.NetworkProtocolNumber = %d, want = %d", i, fragment.NetworkProtocolNumber, sourcePacket.NetworkProtocolNumber) 202 } 203 204 if len(packets) > 1 { 205 // If the source packet was big enough that it needed fragmentation, let's 206 // inspect the fragment header. Because no other extension headers are 207 // supported, it will always be the last extension header. 208 fragmentHeader := header.IPv6Fragment(fragmentIPHeaders[fragmentIPHeadersLength-header.IPv6FragmentHeaderSize : fragmentIPHeadersLength]) 209 210 if got := fragmentHeader.More(); got != wantFragments[i].more { 211 return fmt.Errorf("fragment #%d: got fragmentHeader.More() = %t, want = %t", i, got, wantFragments[i].more) 212 } 213 if got := fragmentHeader.FragmentOffset(); got != wantFragments[i].offset { 214 return fmt.Errorf("fragment #%d: got fragmentHeader.FragmentOffset() = %d, want = %d", i, got, wantFragments[i].offset) 215 } 216 if got := fragmentHeader.NextHeader(); got != uint8(proto) { 217 return fmt.Errorf("fragment #%d: got fragmentHeader.NextHeader() = %d, want = %d", i, got, uint8(proto)) 218 } 219 } 220 221 // Store the reassembled payload as we parse each fragment. The payload 222 // includes the Transport header and everything after. 223 reassembledPayload.AppendView(fragment.TransportHeader().View()) 224 reassembledPayload.AppendView(fragment.Data().AsRange().ToOwnedView()) 225 } 226 227 if diff := cmp.Diff(buffer.View(source[sourceIPHeadersLen:]), reassembledPayload.ToView()); diff != "" { 228 return fmt.Errorf("reassembledPayload mismatch (-want +got):\n%s", diff) 229 } 230 231 return nil 232 } 233 234 // TestReceiveOnAllNodesMulticastAddr tests that IPv6 endpoints receive ICMP and 235 // UDP packets destined to the IPv6 link-local all-nodes multicast address. 236 func TestReceiveOnAllNodesMulticastAddr(t *testing.T) { 237 tests := []struct { 238 name string 239 protocolFactory stack.TransportProtocolFactory 240 rxf func(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) 241 }{ 242 {"ICMP", icmp.NewProtocol6, testReceiveICMP}, 243 {"UDP", udp.NewProtocol, testReceiveUDP}, 244 } 245 246 for _, test := range tests { 247 t.Run(test.name, func(t *testing.T) { 248 s := stack.New(stack.Options{ 249 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 250 TransportProtocols: []stack.TransportProtocolFactory{test.protocolFactory}, 251 }) 252 e := channel.New(10, header.IPv6MinimumMTU, linkAddr1) 253 if err := s.CreateNIC(1, e); err != nil { 254 t.Fatalf("CreateNIC(_) = %s", err) 255 } 256 257 // Should receive a packet destined to the all-nodes 258 // multicast address. 259 test.rxf(t, s, e, addr1, header.IPv6AllNodesMulticastAddress, 1) 260 }) 261 } 262 } 263 264 // TestReceiveOnSolicitedNodeAddr tests that IPv6 endpoints receive ICMP and UDP 265 // packets destined to the IPv6 solicited-node address of an assigned IPv6 266 // address. 267 func TestReceiveOnSolicitedNodeAddr(t *testing.T) { 268 tests := []struct { 269 name string 270 protocolFactory stack.TransportProtocolFactory 271 rxf func(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) 272 }{ 273 {"ICMP", icmp.NewProtocol6, testReceiveICMP}, 274 {"UDP", udp.NewProtocol, testReceiveUDP}, 275 } 276 277 snmc := header.SolicitedNodeAddr(addr2) 278 279 for _, test := range tests { 280 t.Run(test.name, func(t *testing.T) { 281 s := stack.New(stack.Options{ 282 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 283 TransportProtocols: []stack.TransportProtocolFactory{test.protocolFactory}, 284 }) 285 e := channel.New(1, header.IPv6MinimumMTU, linkAddr1) 286 if err := s.CreateNIC(nicID, e); err != nil { 287 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 288 } 289 290 s.SetRouteTable([]tcpip.Route{ 291 { 292 Destination: header.IPv6EmptySubnet, 293 NIC: nicID, 294 }, 295 }) 296 297 // Should not receive a packet destined to the solicited node address of 298 // addr2/addr3 yet as we haven't added those addresses. 299 test.rxf(t, s, e, addr1, snmc, 0) 300 301 if err := s.AddAddress(nicID, ProtocolNumber, addr2); err != nil { 302 t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, addr2, err) 303 } 304 305 // Should receive a packet destined to the solicited node address of 306 // addr2/addr3 now that we have added added addr2. 307 test.rxf(t, s, e, addr1, snmc, 1) 308 309 if err := s.AddAddress(nicID, ProtocolNumber, addr3); err != nil { 310 t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, addr3, err) 311 } 312 313 // Should still receive a packet destined to the solicited node address of 314 // addr2/addr3 now that we have added addr3. 315 test.rxf(t, s, e, addr1, snmc, 2) 316 317 if err := s.RemoveAddress(nicID, addr2); err != nil { 318 t.Fatalf("RemoveAddress(%d, %s) = %s", nicID, addr2, err) 319 } 320 321 // Should still receive a packet destined to the solicited node address of 322 // addr2/addr3 now that we have removed addr2. 323 test.rxf(t, s, e, addr1, snmc, 3) 324 325 // Make sure addr3's endpoint does not get removed from the NIC by 326 // incrementing its reference count with a route. 327 r, err := s.FindRoute(nicID, addr3, addr4, ProtocolNumber, false) 328 if err != nil { 329 t.Fatalf("FindRoute(%d, %s, %s, %d, false): %s", nicID, addr3, addr4, ProtocolNumber, err) 330 } 331 defer r.Release() 332 333 if err := s.RemoveAddress(nicID, addr3); err != nil { 334 t.Fatalf("RemoveAddress(%d, %s) = %s", nicID, addr3, err) 335 } 336 337 // Should not receive a packet destined to the solicited node address of 338 // addr2/addr3 yet as both of them got removed, even though a route using 339 // addr3 exists. 340 test.rxf(t, s, e, addr1, snmc, 3) 341 }) 342 } 343 } 344 345 // TestAddIpv6Address tests adding IPv6 addresses. 346 func TestAddIpv6Address(t *testing.T) { 347 const nicID = 1 348 349 tests := []struct { 350 name string 351 addr tcpip.Address 352 }{ 353 // This test is in response to b/140943433. 354 { 355 "Nil", 356 tcpip.Address([]byte(nil)), 357 }, 358 { 359 "ValidUnicast", 360 addr1, 361 }, 362 { 363 "ValidLinkLocalUnicast", 364 lladdr0, 365 }, 366 } 367 368 for _, test := range tests { 369 t.Run(test.name, func(t *testing.T) { 370 s := stack.New(stack.Options{ 371 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 372 }) 373 if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil { 374 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 375 } 376 377 if err := s.AddAddress(nicID, ProtocolNumber, test.addr); err != nil { 378 t.Fatalf("AddAddress(%d, %d, nil) = %s", nicID, ProtocolNumber, err) 379 } 380 381 if addr, err := s.GetMainNICAddress(nicID, ProtocolNumber); err != nil { 382 t.Fatalf("stack.GetMainNICAddress(%d, %d): %s", nicID, ProtocolNumber, err) 383 } else if addr.Address != test.addr { 384 t.Fatalf("got stack.GetMainNICAddress(%d, %d) = %s, want = %s", nicID, ProtocolNumber, addr.Address, test.addr) 385 } 386 }) 387 } 388 } 389 390 func TestReceiveIPv6ExtHdrs(t *testing.T) { 391 tests := []struct { 392 name string 393 extHdr func(nextHdr uint8) ([]byte, uint8) 394 shouldAccept bool 395 countersToBeIncremented func(*tcpip.Stats) []*tcpip.StatCounter 396 // Should we expect an ICMP response and if so, with what contents? 397 expectICMP bool 398 ICMPType header.ICMPv6Type 399 ICMPCode header.ICMPv6Code 400 pointer uint32 401 multicast bool 402 }{ 403 { 404 name: "None", 405 extHdr: func(nextHdr uint8) ([]byte, uint8) { return nil, nextHdr }, 406 shouldAccept: true, 407 expectICMP: false, 408 }, 409 { 410 name: "hopbyhop with router alert option", 411 extHdr: func(nextHdr uint8) ([]byte, uint8) { 412 return []byte{ 413 nextHdr, 0, 414 415 // Router Alert option. 416 5, 2, 0, 0, 0, 0, 417 }, hopByHopExtHdrID 418 }, 419 shouldAccept: true, 420 countersToBeIncremented: func(stats *tcpip.Stats) []*tcpip.StatCounter { 421 return []*tcpip.StatCounter{stats.IP.OptionRouterAlertReceived} 422 }, 423 }, 424 { 425 name: "hopbyhop with two router alert options", 426 extHdr: func(nextHdr uint8) ([]byte, uint8) { 427 return []byte{ 428 nextHdr, 1, 429 430 // Router Alert option. 431 5, 2, 0, 0, 0, 0, 432 433 // Router Alert option. 434 5, 2, 0, 0, 0, 0, 0, 0, 435 }, hopByHopExtHdrID 436 }, 437 shouldAccept: false, 438 countersToBeIncremented: func(stats *tcpip.Stats) []*tcpip.StatCounter { 439 return []*tcpip.StatCounter{ 440 stats.IP.OptionRouterAlertReceived, 441 stats.IP.MalformedPacketsReceived, 442 } 443 }, 444 }, 445 { 446 name: "hopbyhop with unknown option skippable action", 447 extHdr: func(nextHdr uint8) ([]byte, uint8) { 448 return []byte{ 449 nextHdr, 1, 450 451 // Skippable unknown. 452 63, 4, 1, 2, 3, 4, 453 454 // Skippable unknown. 455 62, 6, 1, 2, 3, 4, 5, 6, 456 }, hopByHopExtHdrID 457 }, 458 shouldAccept: true, 459 }, 460 { 461 name: "hopbyhop with unknown option discard action", 462 extHdr: func(nextHdr uint8) ([]byte, uint8) { 463 return []byte{ 464 nextHdr, 1, 465 466 // Skippable unknown. 467 63, 4, 1, 2, 3, 4, 468 469 // Discard unknown. 470 127, 6, 1, 2, 3, 4, 5, 6, 471 }, hopByHopExtHdrID 472 }, 473 shouldAccept: false, 474 expectICMP: false, 475 }, 476 { 477 name: "hopbyhop with unknown option discard and send icmp action (unicast)", 478 extHdr: func(nextHdr uint8) ([]byte, uint8) { 479 return []byte{ 480 nextHdr, 1, 481 482 // Skippable unknown. 483 63, 4, 1, 2, 3, 4, 484 485 // Discard & send ICMP if option is unknown. 486 191, 6, 1, 2, 3, 4, 5, 6, 487 //^ Unknown option. 488 }, hopByHopExtHdrID 489 }, 490 shouldAccept: false, 491 expectICMP: true, 492 ICMPType: header.ICMPv6ParamProblem, 493 ICMPCode: header.ICMPv6UnknownOption, 494 pointer: header.IPv6FixedHeaderSize + 8, 495 }, 496 { 497 name: "hopbyhop with unknown option discard and send icmp action (multicast)", 498 extHdr: func(nextHdr uint8) ([]byte, uint8) { 499 return []byte{ 500 nextHdr, 1, 501 502 // Skippable unknown. 503 63, 4, 1, 2, 3, 4, 504 505 // Discard & send ICMP if option is unknown. 506 191, 6, 1, 2, 3, 4, 5, 6, 507 //^ Unknown option. 508 }, hopByHopExtHdrID 509 }, 510 multicast: true, 511 shouldAccept: false, 512 expectICMP: true, 513 ICMPType: header.ICMPv6ParamProblem, 514 ICMPCode: header.ICMPv6UnknownOption, 515 pointer: header.IPv6FixedHeaderSize + 8, 516 }, 517 { 518 name: "hopbyhop with unknown option discard and send icmp action unless multicast dest (unicast)", 519 extHdr: func(nextHdr uint8) ([]byte, uint8) { 520 return []byte{ 521 nextHdr, 1, 522 523 // Skippable unknown. 524 63, 4, 1, 2, 3, 4, 525 526 // Discard & send ICMP unless packet is for multicast destination if 527 // option is unknown. 528 255, 6, 1, 2, 3, 4, 5, 6, 529 //^ Unknown option. 530 }, hopByHopExtHdrID 531 }, 532 expectICMP: true, 533 ICMPType: header.ICMPv6ParamProblem, 534 ICMPCode: header.ICMPv6UnknownOption, 535 pointer: header.IPv6FixedHeaderSize + 8, 536 }, 537 { 538 name: "hopbyhop with unknown option discard and send icmp action unless multicast dest (multicast)", 539 extHdr: func(nextHdr uint8) ([]byte, uint8) { 540 return []byte{ 541 nextHdr, 1, 542 543 // Skippable unknown. 544 63, 4, 1, 2, 3, 4, 545 546 // Discard & send ICMP unless packet is for multicast destination if 547 // option is unknown. 548 255, 6, 1, 2, 3, 4, 5, 6, 549 //^ Unknown option. 550 }, hopByHopExtHdrID 551 }, 552 multicast: true, 553 shouldAccept: false, 554 expectICMP: false, 555 }, 556 { 557 name: "routing with zero segments left", 558 extHdr: func(nextHdr uint8) ([]byte, uint8) { 559 return []byte{ 560 nextHdr, 0, 561 1, 0, 2, 3, 4, 5, 562 }, routingExtHdrID 563 }, 564 shouldAccept: true, 565 }, 566 { 567 name: "routing with non-zero segments left", 568 extHdr: func(nextHdr uint8) ([]byte, uint8) { 569 return []byte{ 570 nextHdr, 0, 571 1, 1, 2, 3, 4, 5, 572 }, routingExtHdrID 573 }, 574 shouldAccept: false, 575 expectICMP: true, 576 ICMPType: header.ICMPv6ParamProblem, 577 ICMPCode: header.ICMPv6ErroneousHeader, 578 pointer: header.IPv6FixedHeaderSize + 2, 579 }, 580 { 581 name: "atomic fragment with zero ID", 582 extHdr: func(nextHdr uint8) ([]byte, uint8) { 583 return []byte{ 584 nextHdr, 0, 585 0, 0, 0, 0, 0, 0, 586 }, fragmentExtHdrID 587 }, 588 shouldAccept: true, 589 }, 590 { 591 name: "atomic fragment with non-zero ID", 592 extHdr: func(nextHdr uint8) ([]byte, uint8) { 593 return []byte{ 594 nextHdr, 0, 595 0, 0, 1, 2, 3, 4, 596 }, fragmentExtHdrID 597 }, 598 shouldAccept: true, 599 expectICMP: false, 600 }, 601 { 602 name: "fragment", 603 extHdr: func(nextHdr uint8) ([]byte, uint8) { 604 return []byte{ 605 nextHdr, 0, 606 1, 0, 1, 2, 3, 4, 607 }, fragmentExtHdrID 608 }, 609 shouldAccept: false, 610 expectICMP: false, 611 }, 612 { 613 name: "No next header", 614 extHdr: func(nextHdr uint8) ([]byte, uint8) { 615 return nil, noNextHdrID 616 }, 617 shouldAccept: false, 618 expectICMP: false, 619 }, 620 { 621 name: "unknown next header (first)", 622 extHdr: func(nextHdr uint8) ([]byte, uint8) { 623 return []byte{ 624 nextHdr, 0, 63, 4, 1, 2, 3, 4, 625 }, unknownHdrID 626 }, 627 shouldAccept: false, 628 expectICMP: true, 629 ICMPType: header.ICMPv6ParamProblem, 630 ICMPCode: header.ICMPv6UnknownHeader, 631 pointer: header.IPv6NextHeaderOffset, 632 }, 633 { 634 name: "unknown next header (not first)", 635 extHdr: func(nextHdr uint8) ([]byte, uint8) { 636 return []byte{ 637 unknownHdrID, 0, 638 63, 4, 1, 2, 3, 4, 639 }, hopByHopExtHdrID 640 }, 641 shouldAccept: false, 642 expectICMP: true, 643 ICMPType: header.ICMPv6ParamProblem, 644 ICMPCode: header.ICMPv6UnknownHeader, 645 pointer: header.IPv6FixedHeaderSize, 646 }, 647 { 648 name: "destination with unknown option skippable action", 649 extHdr: func(nextHdr uint8) ([]byte, uint8) { 650 return []byte{ 651 nextHdr, 1, 652 653 // Skippable unknown. 654 63, 4, 1, 2, 3, 4, 655 656 // Skippable unknown. 657 62, 6, 1, 2, 3, 4, 5, 6, 658 }, destinationExtHdrID 659 }, 660 shouldAccept: true, 661 expectICMP: false, 662 }, 663 { 664 name: "destination with unknown option discard action", 665 extHdr: func(nextHdr uint8) ([]byte, uint8) { 666 return []byte{ 667 nextHdr, 1, 668 669 // Skippable unknown. 670 63, 4, 1, 2, 3, 4, 671 672 // Discard unknown. 673 127, 6, 1, 2, 3, 4, 5, 6, 674 }, destinationExtHdrID 675 }, 676 shouldAccept: false, 677 expectICMP: false, 678 }, 679 { 680 name: "destination with unknown option discard and send icmp action (unicast)", 681 extHdr: func(nextHdr uint8) ([]byte, uint8) { 682 return []byte{ 683 nextHdr, 1, 684 685 // Skippable unknown. 686 63, 4, 1, 2, 3, 4, 687 688 // Discard & send ICMP if option is unknown. 689 191, 6, 1, 2, 3, 4, 5, 6, 690 //^ 191 is an unknown option. 691 }, destinationExtHdrID 692 }, 693 shouldAccept: false, 694 expectICMP: true, 695 ICMPType: header.ICMPv6ParamProblem, 696 ICMPCode: header.ICMPv6UnknownOption, 697 pointer: header.IPv6FixedHeaderSize + 8, 698 }, 699 { 700 name: "destination with unknown option discard and send icmp action (muilticast)", 701 extHdr: func(nextHdr uint8) ([]byte, uint8) { 702 return []byte{ 703 nextHdr, 1, 704 705 // Skippable unknown. 706 63, 4, 1, 2, 3, 4, 707 708 // Discard & send ICMP if option is unknown. 709 191, 6, 1, 2, 3, 4, 5, 6, 710 //^ 191 is an unknown option. 711 }, destinationExtHdrID 712 }, 713 multicast: true, 714 shouldAccept: false, 715 expectICMP: true, 716 ICMPType: header.ICMPv6ParamProblem, 717 ICMPCode: header.ICMPv6UnknownOption, 718 pointer: header.IPv6FixedHeaderSize + 8, 719 }, 720 { 721 name: "destination with unknown option discard and send icmp action unless multicast dest (unicast)", 722 extHdr: func(nextHdr uint8) ([]byte, uint8) { 723 return []byte{ 724 nextHdr, 1, 725 726 // Skippable unknown. 727 63, 4, 1, 2, 3, 4, 728 729 // Discard & send ICMP unless packet is for multicast destination if 730 // option is unknown. 731 255, 6, 1, 2, 3, 4, 5, 6, 732 //^ 255 is unknown. 733 }, destinationExtHdrID 734 }, 735 shouldAccept: false, 736 expectICMP: true, 737 ICMPType: header.ICMPv6ParamProblem, 738 ICMPCode: header.ICMPv6UnknownOption, 739 pointer: header.IPv6FixedHeaderSize + 8, 740 }, 741 { 742 name: "destination with unknown option discard and send icmp action unless multicast dest (multicast)", 743 extHdr: func(nextHdr uint8) ([]byte, uint8) { 744 return []byte{ 745 nextHdr, 1, 746 747 // Skippable unknown. 748 63, 4, 1, 2, 3, 4, 749 750 // Discard & send ICMP unless packet is for multicast destination if 751 // option is unknown. 752 255, 6, 1, 2, 3, 4, 5, 6, 753 //^ 255 is unknown. 754 }, destinationExtHdrID 755 }, 756 shouldAccept: false, 757 expectICMP: false, 758 multicast: true, 759 }, 760 { 761 name: "atomic fragment - routing", 762 extHdr: func(nextHdr uint8) ([]byte, uint8) { 763 return []byte{ 764 // Fragment extension header. 765 routingExtHdrID, 0, 0, 0, 1, 2, 3, 4, 766 767 // Routing extension header. 768 nextHdr, 0, 1, 0, 2, 3, 4, 5, 769 }, fragmentExtHdrID 770 }, 771 shouldAccept: true, 772 }, 773 { 774 name: "hop by hop (with skippable unknown) - routing", 775 extHdr: func(nextHdr uint8) ([]byte, uint8) { 776 return []byte{ 777 // Hop By Hop extension header with skippable unknown option. 778 routingExtHdrID, 0, 62, 4, 1, 2, 3, 4, 779 780 // Routing extension header. 781 nextHdr, 0, 1, 0, 2, 3, 4, 5, 782 }, hopByHopExtHdrID 783 }, 784 shouldAccept: true, 785 }, 786 { 787 name: "routing - hop by hop (with skippable unknown)", 788 extHdr: func(nextHdr uint8) ([]byte, uint8) { 789 return []byte{ 790 // Routing extension header. 791 hopByHopExtHdrID, 0, 1, 0, 2, 3, 4, 5, 792 // ^^^ The HopByHop extension header may not appear after the first 793 // extension header. 794 795 // Hop By Hop extension header with skippable unknown option. 796 nextHdr, 0, 62, 4, 1, 2, 3, 4, 797 }, routingExtHdrID 798 }, 799 shouldAccept: false, 800 expectICMP: true, 801 ICMPType: header.ICMPv6ParamProblem, 802 ICMPCode: header.ICMPv6UnknownHeader, 803 pointer: header.IPv6FixedHeaderSize, 804 }, 805 { 806 name: "routing - hop by hop (with send icmp unknown)", 807 extHdr: func(nextHdr uint8) ([]byte, uint8) { 808 return []byte{ 809 // Routing extension header. 810 hopByHopExtHdrID, 0, 1, 0, 2, 3, 4, 5, 811 // ^^^ The HopByHop extension header may not appear after the first 812 // extension header. 813 814 nextHdr, 1, 815 816 // Skippable unknown. 817 63, 4, 1, 2, 3, 4, 818 819 // Skippable unknown. 820 191, 6, 1, 2, 3, 4, 5, 6, 821 }, routingExtHdrID 822 }, 823 shouldAccept: false, 824 expectICMP: true, 825 ICMPType: header.ICMPv6ParamProblem, 826 ICMPCode: header.ICMPv6UnknownHeader, 827 pointer: header.IPv6FixedHeaderSize, 828 }, 829 { 830 name: "hopbyhop (with skippable unknown) - routing - atomic fragment - destination (with skippable unknown)", 831 extHdr: func(nextHdr uint8) ([]byte, uint8) { 832 return []byte{ 833 // Hop By Hop extension header with skippable unknown option. 834 routingExtHdrID, 0, 62, 4, 1, 2, 3, 4, 835 836 // Routing extension header. 837 fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5, 838 839 // Fragment extension header. 840 destinationExtHdrID, 0, 0, 0, 1, 2, 3, 4, 841 842 // Destination extension header with skippable unknown option. 843 nextHdr, 0, 63, 4, 1, 2, 3, 4, 844 }, hopByHopExtHdrID 845 }, 846 shouldAccept: true, 847 }, 848 { 849 name: "hopbyhop (with discard unknown) - routing - atomic fragment - destination (with skippable unknown)", 850 extHdr: func(nextHdr uint8) ([]byte, uint8) { 851 return []byte{ 852 // Hop By Hop extension header with discard action for unknown option. 853 routingExtHdrID, 0, 65, 4, 1, 2, 3, 4, 854 855 // Routing extension header. 856 fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5, 857 858 // Fragment extension header. 859 destinationExtHdrID, 0, 0, 0, 1, 2, 3, 4, 860 861 // Destination extension header with skippable unknown option. 862 nextHdr, 0, 63, 4, 1, 2, 3, 4, 863 }, hopByHopExtHdrID 864 }, 865 shouldAccept: false, 866 expectICMP: false, 867 }, 868 { 869 name: "hopbyhop (with skippable unknown) - routing - atomic fragment - destination (with discard unknown)", 870 extHdr: func(nextHdr uint8) ([]byte, uint8) { 871 return []byte{ 872 // Hop By Hop extension header with skippable unknown option. 873 routingExtHdrID, 0, 62, 4, 1, 2, 3, 4, 874 875 // Routing extension header. 876 fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5, 877 878 // Fragment extension header. 879 destinationExtHdrID, 0, 0, 0, 1, 2, 3, 4, 880 881 // Destination extension header with discard action for unknown 882 // option. 883 nextHdr, 0, 65, 4, 1, 2, 3, 4, 884 }, hopByHopExtHdrID 885 }, 886 shouldAccept: false, 887 expectICMP: false, 888 }, 889 } 890 891 for _, test := range tests { 892 t.Run(test.name, func(t *testing.T) { 893 s := stack.New(stack.Options{ 894 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 895 TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol}, 896 }) 897 e := channel.New(1, header.IPv6MinimumMTU, linkAddr1) 898 if err := s.CreateNIC(nicID, e); err != nil { 899 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 900 } 901 if err := s.AddAddress(nicID, ProtocolNumber, addr2); err != nil { 902 t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, addr2, err) 903 } 904 905 // Add a default route so that a return packet knows where to go. 906 s.SetRouteTable([]tcpip.Route{ 907 { 908 Destination: header.IPv6EmptySubnet, 909 NIC: nicID, 910 }, 911 }) 912 913 wq := waiter.Queue{} 914 we, ch := waiter.NewChannelEntry(nil) 915 wq.EventRegister(&we, waiter.WritableEvents) 916 defer wq.EventUnregister(&we) 917 defer close(ch) 918 ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq) 919 if err != nil { 920 t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, ProtocolNumber, err) 921 } 922 defer ep.Close() 923 924 bindAddr := tcpip.FullAddress{Addr: addr2, Port: 80} 925 if err := ep.Bind(bindAddr); err != nil { 926 t.Fatalf("Bind(%+v): %s", bindAddr, err) 927 } 928 929 udpPayload := []byte{1, 2, 3, 4, 5, 6, 7, 8} 930 udpLength := header.UDPMinimumSize + len(udpPayload) 931 extHdrBytes, ipv6NextHdr := test.extHdr(uint8(header.UDPProtocolNumber)) 932 extHdrLen := len(extHdrBytes) 933 hdr := buffer.NewPrependable(header.IPv6MinimumSize + extHdrLen + udpLength) 934 935 // Serialize UDP message. 936 u := header.UDP(hdr.Prepend(udpLength)) 937 u.Encode(&header.UDPFields{ 938 SrcPort: 5555, 939 DstPort: 80, 940 Length: uint16(udpLength), 941 }) 942 copy(u.Payload(), udpPayload) 943 944 dstAddr := tcpip.Address(addr2) 945 if test.multicast { 946 dstAddr = header.IPv6AllNodesMulticastAddress 947 } 948 949 sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, addr1, dstAddr, uint16(udpLength)) 950 sum = header.Checksum(udpPayload, sum) 951 u.SetChecksum(^u.CalculateChecksum(sum)) 952 953 // Copy extension header bytes between the UDP message and the IPv6 954 // fixed header. 955 copy(hdr.Prepend(extHdrLen), extHdrBytes) 956 957 // Serialize IPv6 fixed header. 958 payloadLength := hdr.UsedLength() 959 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 960 ip.Encode(&header.IPv6Fields{ 961 PayloadLength: uint16(payloadLength), 962 // We're lying about transport protocol here to be able to generate 963 // raw extension headers from the test definitions. 964 TransportProtocol: tcpip.TransportProtocolNumber(ipv6NextHdr), 965 HopLimit: 255, 966 SrcAddr: addr1, 967 DstAddr: dstAddr, 968 }) 969 970 stats := s.Stats() 971 var counters []*tcpip.StatCounter 972 // Make sure that the counters we expect to be incremented are initially 973 // set to zero. 974 if fn := test.countersToBeIncremented; fn != nil { 975 counters = fn(&stats) 976 } 977 for i := range counters { 978 if got := counters[i].Value(); got != 0 { 979 t.Errorf("before writing packet: got test.countersToBeIncremented(&stats)[%d].Value() = %d, want = 0", i, got) 980 } 981 } 982 983 e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ 984 Data: hdr.View().ToVectorisedView(), 985 })) 986 987 for i := range counters { 988 if got := counters[i].Value(); got != 1 { 989 t.Errorf("after writing packet: got test.countersToBeIncremented(&stats)[%d].Value() = %d, want = 1", i, got) 990 } 991 } 992 993 udpReceiveStat := stats.UDP.PacketsReceived 994 if !test.shouldAccept { 995 if got := udpReceiveStat.Value(); got != 0 { 996 t.Errorf("got UDP Rx Packets = %d, want = 0", got) 997 } 998 999 if !test.expectICMP { 1000 if p, ok := e.Read(); ok { 1001 t.Fatalf("unexpected packet received: %#v", p) 1002 } 1003 return 1004 } 1005 1006 // ICMP required. 1007 p, ok := e.Read() 1008 if !ok { 1009 t.Fatalf("expected packet wasn't written out") 1010 } 1011 1012 // Pack the output packet into a single buffer.View as the checkers 1013 // assume that. 1014 vv := buffer.NewVectorisedView(p.Pkt.Size(), p.Pkt.Views()) 1015 pkt := vv.ToView() 1016 if got, want := len(pkt), header.IPv6FixedHeaderSize+header.ICMPv6MinimumSize+hdr.UsedLength(); got != want { 1017 t.Fatalf("got an ICMP packet of size = %d, want = %d", got, want) 1018 } 1019 1020 ipHdr := header.IPv6(pkt) 1021 checker.IPv6(t, ipHdr, checker.ICMPv6( 1022 checker.ICMPv6Type(test.ICMPType), 1023 checker.ICMPv6Code(test.ICMPCode))) 1024 1025 // We know we are looking at no extension headers in the error ICMP 1026 // packets. 1027 icmpPkt := header.ICMPv6(ipHdr.Payload()) 1028 // We know we sent small packets that won't be truncated when reflected 1029 // back to us. 1030 originalPacket := icmpPkt.Payload() 1031 if got, want := icmpPkt.TypeSpecific(), test.pointer; got != want { 1032 t.Errorf("unexpected ICMPv6 pointer, got = %d, want = %d\n", got, want) 1033 } 1034 if diff := cmp.Diff(hdr.View(), buffer.View(originalPacket)); diff != "" { 1035 t.Errorf("ICMPv6 payload mismatch (-want +got):\n%s", diff) 1036 } 1037 return 1038 } 1039 1040 // Expect a UDP packet. 1041 if got := udpReceiveStat.Value(); got != 1 { 1042 t.Errorf("got UDP Rx Packets = %d, want = 1", got) 1043 } 1044 var buf bytes.Buffer 1045 result, err := ep.Read(&buf, tcpip.ReadOptions{}) 1046 if err != nil { 1047 t.Fatalf("Read: %s", err) 1048 } 1049 if diff := cmp.Diff(tcpip.ReadResult{ 1050 Count: len(udpPayload), 1051 Total: len(udpPayload), 1052 }, result, checker.IgnoreCmpPath("ControlMessages")); diff != "" { 1053 t.Errorf("Read: unexpected result (-want +got):\n%s", diff) 1054 } 1055 if diff := cmp.Diff(udpPayload, buf.Bytes()); diff != "" { 1056 t.Errorf("got UDP payload mismatch (-want +got):\n%s", diff) 1057 } 1058 1059 // Should not have any more UDP packets. 1060 res, err := ep.Read(ioutil.Discard, tcpip.ReadOptions{}) 1061 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 1062 t.Fatalf("got Read = (%v, %v), want = (_, %s)", res, err, &tcpip.ErrWouldBlock{}) 1063 } 1064 }) 1065 } 1066 } 1067 1068 // fragmentData holds the IPv6 payload for a fragmented IPv6 packet. 1069 type fragmentData struct { 1070 srcAddr tcpip.Address 1071 dstAddr tcpip.Address 1072 nextHdr uint8 1073 data buffer.VectorisedView 1074 } 1075 1076 func TestReceiveIPv6Fragments(t *testing.T) { 1077 const ( 1078 udpPayload1Length = 256 1079 udpPayload2Length = 128 1080 // Used to test cases where the fragment blocks are not a multiple of 1081 // the fragment block size of 8 (RFC 8200 section 4.5). 1082 udpPayload3Length = 127 1083 udpPayload4Length = header.IPv6MaximumPayloadSize - header.UDPMinimumSize 1084 udpMaximumSizeMinus15 = header.UDPMaximumSize - 15 1085 fragmentExtHdrLen = 8 1086 // Note, not all routing extension headers will be 8 bytes but this test 1087 // uses 8 byte routing extension headers for most sub tests. 1088 routingExtHdrLen = 8 1089 ) 1090 1091 udpGen := func(payload []byte, multiplier uint8, src, dst tcpip.Address) buffer.View { 1092 payloadLen := len(payload) 1093 for i := 0; i < payloadLen; i++ { 1094 payload[i] = uint8(i) * multiplier 1095 } 1096 1097 udpLength := header.UDPMinimumSize + payloadLen 1098 1099 hdr := buffer.NewPrependable(udpLength) 1100 u := header.UDP(hdr.Prepend(udpLength)) 1101 u.Encode(&header.UDPFields{ 1102 SrcPort: 5555, 1103 DstPort: 80, 1104 Length: uint16(udpLength), 1105 }) 1106 copy(u.Payload(), payload) 1107 sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(udpLength)) 1108 sum = header.Checksum(payload, sum) 1109 u.SetChecksum(^u.CalculateChecksum(sum)) 1110 return hdr.View() 1111 } 1112 1113 var udpPayload1Addr1ToAddr2Buf [udpPayload1Length]byte 1114 udpPayload1Addr1ToAddr2 := udpPayload1Addr1ToAddr2Buf[:] 1115 ipv6Payload1Addr1ToAddr2 := udpGen(udpPayload1Addr1ToAddr2, 1, addr1, addr2) 1116 1117 var udpPayload1Addr3ToAddr2Buf [udpPayload1Length]byte 1118 udpPayload1Addr3ToAddr2 := udpPayload1Addr3ToAddr2Buf[:] 1119 ipv6Payload1Addr3ToAddr2 := udpGen(udpPayload1Addr3ToAddr2, 4, addr3, addr2) 1120 1121 var udpPayload2Addr1ToAddr2Buf [udpPayload2Length]byte 1122 udpPayload2Addr1ToAddr2 := udpPayload2Addr1ToAddr2Buf[:] 1123 ipv6Payload2Addr1ToAddr2 := udpGen(udpPayload2Addr1ToAddr2, 2, addr1, addr2) 1124 1125 var udpPayload3Addr1ToAddr2Buf [udpPayload3Length]byte 1126 udpPayload3Addr1ToAddr2 := udpPayload3Addr1ToAddr2Buf[:] 1127 ipv6Payload3Addr1ToAddr2 := udpGen(udpPayload3Addr1ToAddr2, 3, addr1, addr2) 1128 1129 var udpPayload4Addr1ToAddr2Buf [udpPayload4Length]byte 1130 udpPayload4Addr1ToAddr2 := udpPayload4Addr1ToAddr2Buf[:] 1131 ipv6Payload4Addr1ToAddr2 := udpGen(udpPayload4Addr1ToAddr2, 4, addr1, addr2) 1132 1133 tests := []struct { 1134 name string 1135 expectedPayload []byte 1136 fragments []fragmentData 1137 expectedPayloads [][]byte 1138 }{ 1139 { 1140 name: "No fragmentation", 1141 fragments: []fragmentData{ 1142 { 1143 srcAddr: addr1, 1144 dstAddr: addr2, 1145 nextHdr: uint8(header.UDPProtocolNumber), 1146 data: ipv6Payload1Addr1ToAddr2.ToVectorisedView(), 1147 }, 1148 }, 1149 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 1150 }, 1151 { 1152 name: "Atomic fragment", 1153 fragments: []fragmentData{ 1154 { 1155 srcAddr: addr1, 1156 dstAddr: addr2, 1157 nextHdr: fragmentExtHdrID, 1158 data: buffer.NewVectorisedView( 1159 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2), 1160 []buffer.View{ 1161 // Fragment extension header. 1162 []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0}, 1163 1164 ipv6Payload1Addr1ToAddr2, 1165 }, 1166 ), 1167 }, 1168 }, 1169 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 1170 }, 1171 { 1172 name: "Atomic fragment with size not a multiple of fragment block size", 1173 fragments: []fragmentData{ 1174 { 1175 srcAddr: addr1, 1176 dstAddr: addr2, 1177 nextHdr: fragmentExtHdrID, 1178 data: buffer.NewVectorisedView( 1179 fragmentExtHdrLen+len(ipv6Payload3Addr1ToAddr2), 1180 []buffer.View{ 1181 // Fragment extension header. 1182 []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0}, 1183 1184 ipv6Payload3Addr1ToAddr2, 1185 }, 1186 ), 1187 }, 1188 }, 1189 expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2}, 1190 }, 1191 { 1192 name: "Two fragments", 1193 fragments: []fragmentData{ 1194 { 1195 srcAddr: addr1, 1196 dstAddr: addr2, 1197 nextHdr: fragmentExtHdrID, 1198 data: buffer.NewVectorisedView( 1199 fragmentExtHdrLen+64, 1200 []buffer.View{ 1201 // Fragment extension header. 1202 // 1203 // Fragment offset = 0, More = true, ID = 1 1204 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1205 1206 ipv6Payload1Addr1ToAddr2[:64], 1207 }, 1208 ), 1209 }, 1210 { 1211 srcAddr: addr1, 1212 dstAddr: addr2, 1213 nextHdr: fragmentExtHdrID, 1214 data: buffer.NewVectorisedView( 1215 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1216 []buffer.View{ 1217 // Fragment extension header. 1218 // 1219 // Fragment offset = 8, More = false, ID = 1 1220 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1221 1222 ipv6Payload1Addr1ToAddr2[64:], 1223 }, 1224 ), 1225 }, 1226 }, 1227 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 1228 }, 1229 { 1230 name: "Two fragments out of order", 1231 fragments: []fragmentData{ 1232 { 1233 srcAddr: addr1, 1234 dstAddr: addr2, 1235 nextHdr: fragmentExtHdrID, 1236 data: buffer.NewVectorisedView( 1237 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1238 []buffer.View{ 1239 // Fragment extension header. 1240 // 1241 // Fragment offset = 8, More = false, ID = 1 1242 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1243 1244 ipv6Payload1Addr1ToAddr2[64:], 1245 }, 1246 ), 1247 }, 1248 { 1249 srcAddr: addr1, 1250 dstAddr: addr2, 1251 nextHdr: fragmentExtHdrID, 1252 data: buffer.NewVectorisedView( 1253 fragmentExtHdrLen+64, 1254 []buffer.View{ 1255 // Fragment extension header. 1256 // 1257 // Fragment offset = 0, More = true, ID = 1 1258 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1259 1260 ipv6Payload1Addr1ToAddr2[:64], 1261 }, 1262 ), 1263 }, 1264 }, 1265 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 1266 }, 1267 { 1268 name: "Two fragments with different Next Header values", 1269 fragments: []fragmentData{ 1270 { 1271 srcAddr: addr1, 1272 dstAddr: addr2, 1273 nextHdr: fragmentExtHdrID, 1274 data: buffer.NewVectorisedView( 1275 fragmentExtHdrLen+64, 1276 []buffer.View{ 1277 // Fragment extension header. 1278 // 1279 // Fragment offset = 0, More = true, ID = 1 1280 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1281 1282 ipv6Payload1Addr1ToAddr2[:64], 1283 }, 1284 ), 1285 }, 1286 { 1287 srcAddr: addr1, 1288 dstAddr: addr2, 1289 nextHdr: fragmentExtHdrID, 1290 data: buffer.NewVectorisedView( 1291 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1292 []buffer.View{ 1293 // Fragment extension header. 1294 // 1295 // Fragment offset = 8, More = false, ID = 1 1296 // NextHeader value is different than the one in the first fragment, so 1297 // this NextHeader should be ignored. 1298 []byte{uint8(header.IPv6NoNextHeaderIdentifier), 0, 0, 64, 0, 0, 0, 1}, 1299 1300 ipv6Payload1Addr1ToAddr2[64:], 1301 }, 1302 ), 1303 }, 1304 }, 1305 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 1306 }, 1307 { 1308 name: "Two fragments with last fragment size not a multiple of fragment block size", 1309 fragments: []fragmentData{ 1310 { 1311 srcAddr: addr1, 1312 dstAddr: addr2, 1313 nextHdr: fragmentExtHdrID, 1314 data: buffer.NewVectorisedView( 1315 fragmentExtHdrLen+64, 1316 []buffer.View{ 1317 // Fragment extension header. 1318 // 1319 // Fragment offset = 0, More = true, ID = 1 1320 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1321 1322 ipv6Payload3Addr1ToAddr2[:64], 1323 }, 1324 ), 1325 }, 1326 { 1327 srcAddr: addr1, 1328 dstAddr: addr2, 1329 nextHdr: fragmentExtHdrID, 1330 data: buffer.NewVectorisedView( 1331 fragmentExtHdrLen+len(ipv6Payload3Addr1ToAddr2)-64, 1332 []buffer.View{ 1333 // Fragment extension header. 1334 // 1335 // Fragment offset = 8, More = false, ID = 1 1336 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1337 1338 ipv6Payload3Addr1ToAddr2[64:], 1339 }, 1340 ), 1341 }, 1342 }, 1343 expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2}, 1344 }, 1345 { 1346 name: "Two fragments with first fragment size not a multiple of fragment block size", 1347 fragments: []fragmentData{ 1348 { 1349 srcAddr: addr1, 1350 dstAddr: addr2, 1351 nextHdr: fragmentExtHdrID, 1352 data: buffer.NewVectorisedView( 1353 fragmentExtHdrLen+63, 1354 []buffer.View{ 1355 // Fragment extension header. 1356 // 1357 // Fragment offset = 0, More = true, ID = 1 1358 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1359 1360 ipv6Payload3Addr1ToAddr2[:63], 1361 }, 1362 ), 1363 }, 1364 { 1365 srcAddr: addr1, 1366 dstAddr: addr2, 1367 nextHdr: fragmentExtHdrID, 1368 data: buffer.NewVectorisedView( 1369 fragmentExtHdrLen+len(ipv6Payload3Addr1ToAddr2)-63, 1370 []buffer.View{ 1371 // Fragment extension header. 1372 // 1373 // Fragment offset = 8, More = false, ID = 1 1374 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1375 1376 ipv6Payload3Addr1ToAddr2[63:], 1377 }, 1378 ), 1379 }, 1380 }, 1381 expectedPayloads: nil, 1382 }, 1383 { 1384 name: "Two fragments with different IDs", 1385 fragments: []fragmentData{ 1386 { 1387 srcAddr: addr1, 1388 dstAddr: addr2, 1389 nextHdr: fragmentExtHdrID, 1390 data: buffer.NewVectorisedView( 1391 fragmentExtHdrLen+64, 1392 []buffer.View{ 1393 // Fragment extension header. 1394 // 1395 // Fragment offset = 0, More = true, ID = 1 1396 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1397 1398 ipv6Payload1Addr1ToAddr2[:64], 1399 }, 1400 ), 1401 }, 1402 { 1403 srcAddr: addr1, 1404 dstAddr: addr2, 1405 nextHdr: fragmentExtHdrID, 1406 data: buffer.NewVectorisedView( 1407 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1408 []buffer.View{ 1409 // Fragment extension header. 1410 // 1411 // Fragment offset = 8, More = false, ID = 2 1412 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 2}, 1413 1414 ipv6Payload1Addr1ToAddr2[64:], 1415 }, 1416 ), 1417 }, 1418 }, 1419 expectedPayloads: nil, 1420 }, 1421 { 1422 name: "Two fragments reassembled into a maximum UDP packet", 1423 fragments: []fragmentData{ 1424 { 1425 srcAddr: addr1, 1426 dstAddr: addr2, 1427 nextHdr: fragmentExtHdrID, 1428 data: buffer.NewVectorisedView( 1429 fragmentExtHdrLen+udpMaximumSizeMinus15, 1430 []buffer.View{ 1431 // Fragment extension header. 1432 // 1433 // Fragment offset = 0, More = true, ID = 1 1434 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1435 1436 ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15], 1437 }, 1438 ), 1439 }, 1440 { 1441 srcAddr: addr1, 1442 dstAddr: addr2, 1443 nextHdr: fragmentExtHdrID, 1444 data: buffer.NewVectorisedView( 1445 fragmentExtHdrLen+len(ipv6Payload4Addr1ToAddr2)-udpMaximumSizeMinus15, 1446 []buffer.View{ 1447 // Fragment extension header. 1448 // 1449 // Fragment offset = udpMaximumSizeMinus15/8, More = false, ID = 1 1450 []byte{uint8(header.UDPProtocolNumber), 0, 1451 udpMaximumSizeMinus15 >> 8, 1452 udpMaximumSizeMinus15 & 0xff, 1453 0, 0, 0, 1}, 1454 1455 ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:], 1456 }, 1457 ), 1458 }, 1459 }, 1460 expectedPayloads: [][]byte{udpPayload4Addr1ToAddr2}, 1461 }, 1462 { 1463 name: "Two fragments with MF flag reassembled into a maximum UDP packet", 1464 fragments: []fragmentData{ 1465 { 1466 srcAddr: addr1, 1467 dstAddr: addr2, 1468 nextHdr: fragmentExtHdrID, 1469 data: buffer.NewVectorisedView( 1470 fragmentExtHdrLen+udpMaximumSizeMinus15, 1471 []buffer.View{ 1472 // Fragment extension header. 1473 // 1474 // Fragment offset = 0, More = true, ID = 1 1475 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1476 1477 ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15], 1478 }, 1479 ), 1480 }, 1481 { 1482 srcAddr: addr1, 1483 dstAddr: addr2, 1484 nextHdr: fragmentExtHdrID, 1485 data: buffer.NewVectorisedView( 1486 fragmentExtHdrLen+len(ipv6Payload4Addr1ToAddr2)-udpMaximumSizeMinus15, 1487 []buffer.View{ 1488 // Fragment extension header. 1489 // 1490 // Fragment offset = udpMaximumSizeMinus15/8, More = true, ID = 1 1491 []byte{uint8(header.UDPProtocolNumber), 0, 1492 udpMaximumSizeMinus15 >> 8, 1493 (udpMaximumSizeMinus15 & 0xff) + 1, 1494 0, 0, 0, 1}, 1495 1496 ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:], 1497 }, 1498 ), 1499 }, 1500 }, 1501 expectedPayloads: nil, 1502 }, 1503 { 1504 name: "Two fragments with per-fragment routing header with zero segments left", 1505 fragments: []fragmentData{ 1506 { 1507 srcAddr: addr1, 1508 dstAddr: addr2, 1509 nextHdr: routingExtHdrID, 1510 data: buffer.NewVectorisedView( 1511 routingExtHdrLen+fragmentExtHdrLen+64, 1512 []buffer.View{ 1513 // Routing extension header. 1514 // 1515 // Segments left = 0. 1516 []byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5}, 1517 1518 // Fragment extension header. 1519 // 1520 // Fragment offset = 0, More = true, ID = 1 1521 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1522 1523 ipv6Payload1Addr1ToAddr2[:64], 1524 }, 1525 ), 1526 }, 1527 { 1528 srcAddr: addr1, 1529 dstAddr: addr2, 1530 nextHdr: routingExtHdrID, 1531 data: buffer.NewVectorisedView( 1532 routingExtHdrLen+fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1533 []buffer.View{ 1534 // Routing extension header. 1535 // 1536 // Segments left = 0. 1537 []byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5}, 1538 1539 // Fragment extension header. 1540 // 1541 // Fragment offset = 8, More = false, ID = 1 1542 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1543 1544 ipv6Payload1Addr1ToAddr2[64:], 1545 }, 1546 ), 1547 }, 1548 }, 1549 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 1550 }, 1551 { 1552 name: "Two fragments with per-fragment routing header with non-zero segments left", 1553 fragments: []fragmentData{ 1554 { 1555 srcAddr: addr1, 1556 dstAddr: addr2, 1557 nextHdr: routingExtHdrID, 1558 data: buffer.NewVectorisedView( 1559 routingExtHdrLen+fragmentExtHdrLen+64, 1560 []buffer.View{ 1561 // Routing extension header. 1562 // 1563 // Segments left = 1. 1564 []byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5}, 1565 1566 // Fragment extension header. 1567 // 1568 // Fragment offset = 0, More = true, ID = 1 1569 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1570 1571 ipv6Payload1Addr1ToAddr2[:64], 1572 }, 1573 ), 1574 }, 1575 { 1576 srcAddr: addr1, 1577 dstAddr: addr2, 1578 nextHdr: routingExtHdrID, 1579 data: buffer.NewVectorisedView( 1580 routingExtHdrLen+fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1581 []buffer.View{ 1582 // Routing extension header. 1583 // 1584 // Segments left = 1. 1585 []byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5}, 1586 1587 // Fragment extension header. 1588 // 1589 // Fragment offset = 9, More = false, ID = 1 1590 []byte{uint8(header.UDPProtocolNumber), 0, 0, 72, 0, 0, 0, 1}, 1591 1592 ipv6Payload1Addr1ToAddr2[64:], 1593 }, 1594 ), 1595 }, 1596 }, 1597 expectedPayloads: nil, 1598 }, 1599 { 1600 name: "Two fragments with routing header with zero segments left", 1601 fragments: []fragmentData{ 1602 { 1603 srcAddr: addr1, 1604 dstAddr: addr2, 1605 nextHdr: fragmentExtHdrID, 1606 data: buffer.NewVectorisedView( 1607 routingExtHdrLen+fragmentExtHdrLen+64, 1608 []buffer.View{ 1609 // Fragment extension header. 1610 // 1611 // Fragment offset = 0, More = true, ID = 1 1612 []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, 1613 1614 // Routing extension header. 1615 // 1616 // Segments left = 0. 1617 []byte{uint8(header.UDPProtocolNumber), 0, 1, 0, 2, 3, 4, 5}, 1618 1619 ipv6Payload1Addr1ToAddr2[:64], 1620 }, 1621 ), 1622 }, 1623 { 1624 srcAddr: addr1, 1625 dstAddr: addr2, 1626 nextHdr: fragmentExtHdrID, 1627 data: buffer.NewVectorisedView( 1628 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1629 []buffer.View{ 1630 // Fragment extension header. 1631 // 1632 // Fragment offset = 9, More = false, ID = 1 1633 []byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1}, 1634 1635 ipv6Payload1Addr1ToAddr2[64:], 1636 }, 1637 ), 1638 }, 1639 }, 1640 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 1641 }, 1642 { 1643 name: "Two fragments with routing header with non-zero segments left", 1644 fragments: []fragmentData{ 1645 { 1646 srcAddr: addr1, 1647 dstAddr: addr2, 1648 nextHdr: fragmentExtHdrID, 1649 data: buffer.NewVectorisedView( 1650 routingExtHdrLen+fragmentExtHdrLen+64, 1651 []buffer.View{ 1652 // Fragment extension header. 1653 // 1654 // Fragment offset = 0, More = true, ID = 1 1655 []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, 1656 1657 // Routing extension header. 1658 // 1659 // Segments left = 1. 1660 []byte{uint8(header.UDPProtocolNumber), 0, 1, 1, 2, 3, 4, 5}, 1661 1662 ipv6Payload1Addr1ToAddr2[:64], 1663 }, 1664 ), 1665 }, 1666 { 1667 srcAddr: addr1, 1668 dstAddr: addr2, 1669 nextHdr: fragmentExtHdrID, 1670 data: buffer.NewVectorisedView( 1671 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1672 []buffer.View{ 1673 // Fragment extension header. 1674 // 1675 // Fragment offset = 9, More = false, ID = 1 1676 []byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1}, 1677 1678 ipv6Payload1Addr1ToAddr2[64:], 1679 }, 1680 ), 1681 }, 1682 }, 1683 expectedPayloads: nil, 1684 }, 1685 { 1686 name: "Two fragments with routing header with zero segments left across fragments", 1687 fragments: []fragmentData{ 1688 { 1689 srcAddr: addr1, 1690 dstAddr: addr2, 1691 nextHdr: fragmentExtHdrID, 1692 data: buffer.NewVectorisedView( 1693 // The length of this payload is fragmentExtHdrLen+8 because the 1694 // first 8 bytes of the 16 byte routing extension header is in 1695 // this fragment. 1696 fragmentExtHdrLen+8, 1697 []buffer.View{ 1698 // Fragment extension header. 1699 // 1700 // Fragment offset = 0, More = true, ID = 1 1701 []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, 1702 1703 // Routing extension header (part 1) 1704 // 1705 // Segments left = 0. 1706 []byte{uint8(header.UDPProtocolNumber), 1, 1, 0, 2, 3, 4, 5}, 1707 }, 1708 ), 1709 }, 1710 { 1711 srcAddr: addr1, 1712 dstAddr: addr2, 1713 nextHdr: fragmentExtHdrID, 1714 data: buffer.NewVectorisedView( 1715 // The length of this payload is 1716 // fragmentExtHdrLen+8+len(ipv6Payload1Addr1ToAddr2) because the last 8 bytes of 1717 // the 16 byte routing extension header is in this fagment. 1718 fragmentExtHdrLen+8+len(ipv6Payload1Addr1ToAddr2), 1719 []buffer.View{ 1720 // Fragment extension header. 1721 // 1722 // Fragment offset = 1, More = false, ID = 1 1723 []byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1}, 1724 1725 // Routing extension header (part 2) 1726 []byte{6, 7, 8, 9, 10, 11, 12, 13}, 1727 1728 ipv6Payload1Addr1ToAddr2, 1729 }, 1730 ), 1731 }, 1732 }, 1733 expectedPayloads: nil, 1734 }, 1735 { 1736 name: "Two fragments with routing header with non-zero segments left across fragments", 1737 fragments: []fragmentData{ 1738 { 1739 srcAddr: addr1, 1740 dstAddr: addr2, 1741 nextHdr: fragmentExtHdrID, 1742 data: buffer.NewVectorisedView( 1743 // The length of this payload is fragmentExtHdrLen+8 because the 1744 // first 8 bytes of the 16 byte routing extension header is in 1745 // this fragment. 1746 fragmentExtHdrLen+8, 1747 []buffer.View{ 1748 // Fragment extension header. 1749 // 1750 // Fragment offset = 0, More = true, ID = 1 1751 []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, 1752 1753 // Routing extension header (part 1) 1754 // 1755 // Segments left = 1. 1756 []byte{uint8(header.UDPProtocolNumber), 1, 1, 1, 2, 3, 4, 5}, 1757 }, 1758 ), 1759 }, 1760 { 1761 srcAddr: addr1, 1762 dstAddr: addr2, 1763 nextHdr: fragmentExtHdrID, 1764 data: buffer.NewVectorisedView( 1765 // The length of this payload is 1766 // fragmentExtHdrLen+8+len(ipv6Payload1Addr1ToAddr2) because the last 8 bytes of 1767 // the 16 byte routing extension header is in this fagment. 1768 fragmentExtHdrLen+8+len(ipv6Payload1Addr1ToAddr2), 1769 []buffer.View{ 1770 // Fragment extension header. 1771 // 1772 // Fragment offset = 1, More = false, ID = 1 1773 []byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1}, 1774 1775 // Routing extension header (part 2) 1776 []byte{6, 7, 8, 9, 10, 11, 12, 13}, 1777 1778 ipv6Payload1Addr1ToAddr2, 1779 }, 1780 ), 1781 }, 1782 }, 1783 expectedPayloads: nil, 1784 }, 1785 // As per RFC 6946, IPv6 atomic fragments MUST NOT interfere with "normal" 1786 // fragmented traffic. 1787 { 1788 name: "Two fragments with atomic", 1789 fragments: []fragmentData{ 1790 { 1791 srcAddr: addr1, 1792 dstAddr: addr2, 1793 nextHdr: fragmentExtHdrID, 1794 data: buffer.NewVectorisedView( 1795 fragmentExtHdrLen+64, 1796 []buffer.View{ 1797 // Fragment extension header. 1798 // 1799 // Fragment offset = 0, More = true, ID = 1 1800 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1801 1802 ipv6Payload1Addr1ToAddr2[:64], 1803 }, 1804 ), 1805 }, 1806 // This fragment has the same ID as the other fragments but is an atomic 1807 // fragment. It should not interfere with the other fragments. 1808 { 1809 srcAddr: addr1, 1810 dstAddr: addr2, 1811 nextHdr: fragmentExtHdrID, 1812 data: buffer.NewVectorisedView( 1813 fragmentExtHdrLen+len(ipv6Payload2Addr1ToAddr2), 1814 []buffer.View{ 1815 // Fragment extension header. 1816 // 1817 // Fragment offset = 0, More = false, ID = 1 1818 []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 1}, 1819 1820 ipv6Payload2Addr1ToAddr2, 1821 }, 1822 ), 1823 }, 1824 { 1825 srcAddr: addr1, 1826 dstAddr: addr2, 1827 nextHdr: fragmentExtHdrID, 1828 data: buffer.NewVectorisedView( 1829 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1830 []buffer.View{ 1831 // Fragment extension header. 1832 // 1833 // Fragment offset = 8, More = false, ID = 1 1834 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1835 1836 ipv6Payload1Addr1ToAddr2[64:], 1837 }, 1838 ), 1839 }, 1840 }, 1841 expectedPayloads: [][]byte{udpPayload2Addr1ToAddr2, udpPayload1Addr1ToAddr2}, 1842 }, 1843 { 1844 name: "Two interleaved fragmented packets", 1845 fragments: []fragmentData{ 1846 { 1847 srcAddr: addr1, 1848 dstAddr: addr2, 1849 nextHdr: fragmentExtHdrID, 1850 data: buffer.NewVectorisedView( 1851 fragmentExtHdrLen+64, 1852 []buffer.View{ 1853 // Fragment extension header. 1854 // 1855 // Fragment offset = 0, More = true, ID = 1 1856 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1857 1858 ipv6Payload1Addr1ToAddr2[:64], 1859 }, 1860 ), 1861 }, 1862 { 1863 srcAddr: addr1, 1864 dstAddr: addr2, 1865 nextHdr: fragmentExtHdrID, 1866 data: buffer.NewVectorisedView( 1867 fragmentExtHdrLen+32, 1868 []buffer.View{ 1869 // Fragment extension header. 1870 // 1871 // Fragment offset = 0, More = true, ID = 2 1872 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 2}, 1873 1874 ipv6Payload2Addr1ToAddr2[:32], 1875 }, 1876 ), 1877 }, 1878 { 1879 srcAddr: addr1, 1880 dstAddr: addr2, 1881 nextHdr: fragmentExtHdrID, 1882 data: buffer.NewVectorisedView( 1883 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1884 []buffer.View{ 1885 // Fragment extension header. 1886 // 1887 // Fragment offset = 8, More = false, ID = 1 1888 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1889 1890 ipv6Payload1Addr1ToAddr2[64:], 1891 }, 1892 ), 1893 }, 1894 { 1895 srcAddr: addr1, 1896 dstAddr: addr2, 1897 nextHdr: fragmentExtHdrID, 1898 data: buffer.NewVectorisedView( 1899 fragmentExtHdrLen+len(ipv6Payload2Addr1ToAddr2)-32, 1900 []buffer.View{ 1901 // Fragment extension header. 1902 // 1903 // Fragment offset = 4, More = false, ID = 2 1904 []byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 2}, 1905 1906 ipv6Payload2Addr1ToAddr2[32:], 1907 }, 1908 ), 1909 }, 1910 }, 1911 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload2Addr1ToAddr2}, 1912 }, 1913 { 1914 name: "Two interleaved fragmented packets from different sources but with same ID", 1915 fragments: []fragmentData{ 1916 { 1917 srcAddr: addr1, 1918 dstAddr: addr2, 1919 nextHdr: fragmentExtHdrID, 1920 data: buffer.NewVectorisedView( 1921 fragmentExtHdrLen+64, 1922 []buffer.View{ 1923 // Fragment extension header. 1924 // 1925 // Fragment offset = 0, More = true, ID = 1 1926 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1927 1928 ipv6Payload1Addr1ToAddr2[:64], 1929 }, 1930 ), 1931 }, 1932 { 1933 srcAddr: addr3, 1934 dstAddr: addr2, 1935 nextHdr: fragmentExtHdrID, 1936 data: buffer.NewVectorisedView( 1937 fragmentExtHdrLen+32, 1938 []buffer.View{ 1939 // Fragment extension header. 1940 // 1941 // Fragment offset = 0, More = true, ID = 1 1942 []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, 1943 1944 ipv6Payload1Addr3ToAddr2[:32], 1945 }, 1946 ), 1947 }, 1948 { 1949 srcAddr: addr1, 1950 dstAddr: addr2, 1951 nextHdr: fragmentExtHdrID, 1952 data: buffer.NewVectorisedView( 1953 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-64, 1954 []buffer.View{ 1955 // Fragment extension header. 1956 // 1957 // Fragment offset = 8, More = false, ID = 1 1958 []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, 1959 1960 ipv6Payload1Addr1ToAddr2[64:], 1961 }, 1962 ), 1963 }, 1964 { 1965 srcAddr: addr3, 1966 dstAddr: addr2, 1967 nextHdr: fragmentExtHdrID, 1968 data: buffer.NewVectorisedView( 1969 fragmentExtHdrLen+len(ipv6Payload1Addr1ToAddr2)-32, 1970 []buffer.View{ 1971 // Fragment extension header. 1972 // 1973 // Fragment offset = 4, More = false, ID = 1 1974 []byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 1}, 1975 1976 ipv6Payload1Addr3ToAddr2[32:], 1977 }, 1978 ), 1979 }, 1980 }, 1981 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload1Addr3ToAddr2}, 1982 }, 1983 } 1984 1985 for _, test := range tests { 1986 t.Run(test.name, func(t *testing.T) { 1987 s := stack.New(stack.Options{ 1988 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 1989 TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol}, 1990 }) 1991 e := channel.New(0, header.IPv6MinimumMTU, linkAddr1) 1992 if err := s.CreateNIC(nicID, e); err != nil { 1993 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 1994 } 1995 if err := s.AddAddress(nicID, ProtocolNumber, addr2); err != nil { 1996 t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, addr2, err) 1997 } 1998 1999 wq := waiter.Queue{} 2000 we, ch := waiter.NewChannelEntry(nil) 2001 wq.EventRegister(&we, waiter.ReadableEvents) 2002 defer wq.EventUnregister(&we) 2003 defer close(ch) 2004 ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq) 2005 if err != nil { 2006 t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, ProtocolNumber, err) 2007 } 2008 defer ep.Close() 2009 2010 bindAddr := tcpip.FullAddress{Addr: addr2, Port: 80} 2011 if err := ep.Bind(bindAddr); err != nil { 2012 t.Fatalf("Bind(%+v): %s", bindAddr, err) 2013 } 2014 2015 for _, f := range test.fragments { 2016 hdr := buffer.NewPrependable(header.IPv6MinimumSize) 2017 2018 // Serialize IPv6 fixed header. 2019 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) 2020 ip.Encode(&header.IPv6Fields{ 2021 PayloadLength: uint16(f.data.Size()), 2022 // We're lying about transport protocol here so that we can generate 2023 // raw extension headers for the tests. 2024 TransportProtocol: tcpip.TransportProtocolNumber(f.nextHdr), 2025 HopLimit: 255, 2026 SrcAddr: f.srcAddr, 2027 DstAddr: f.dstAddr, 2028 }) 2029 2030 vv := hdr.View().ToVectorisedView() 2031 vv.Append(f.data) 2032 2033 e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ 2034 Data: vv, 2035 })) 2036 } 2037 2038 if got, want := s.Stats().UDP.PacketsReceived.Value(), uint64(len(test.expectedPayloads)); got != want { 2039 t.Errorf("got UDP Rx Packets = %d, want = %d", got, want) 2040 } 2041 2042 for i, p := range test.expectedPayloads { 2043 var buf bytes.Buffer 2044 _, err := ep.Read(&buf, tcpip.ReadOptions{}) 2045 if err != nil { 2046 t.Fatalf("(i=%d) Read: %s", i, err) 2047 } 2048 if diff := cmp.Diff(p, buf.Bytes()); diff != "" { 2049 t.Errorf("(i=%d) got UDP payload mismatch (-want +got):\n%s", i, diff) 2050 } 2051 } 2052 2053 res, err := ep.Read(ioutil.Discard, tcpip.ReadOptions{}) 2054 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 2055 t.Fatalf("(last) got Read = (%v, %v), want = (_, %s)", res, err, &tcpip.ErrWouldBlock{}) 2056 } 2057 }) 2058 } 2059 } 2060 2061 func TestInvalidIPv6Fragments(t *testing.T) { 2062 const ( 2063 addr1 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" 2064 addr2 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" 2065 linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e") 2066 nicID = 1 2067 hoplimit = 255 2068 ident = 1 2069 data = "TEST_INVALID_IPV6_FRAGMENTS" 2070 ) 2071 2072 type fragmentData struct { 2073 ipv6Fields header.IPv6Fields 2074 ipv6FragmentFields header.IPv6SerializableFragmentExtHdr 2075 payload []byte 2076 } 2077 2078 tests := []struct { 2079 name string 2080 fragments []fragmentData 2081 wantMalformedIPPackets uint64 2082 wantMalformedFragments uint64 2083 expectICMP bool 2084 expectICMPType header.ICMPv6Type 2085 expectICMPCode header.ICMPv6Code 2086 expectICMPTypeSpecific uint32 2087 }{ 2088 { 2089 name: "fragment size is not a multiple of 8 and the M flag is true", 2090 fragments: []fragmentData{ 2091 { 2092 ipv6Fields: header.IPv6Fields{ 2093 PayloadLength: header.IPv6FragmentHeaderSize + 9, 2094 TransportProtocol: header.UDPProtocolNumber, 2095 HopLimit: hoplimit, 2096 SrcAddr: addr1, 2097 DstAddr: addr2, 2098 }, 2099 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2100 FragmentOffset: 0 >> 3, 2101 M: true, 2102 Identification: ident, 2103 }, 2104 payload: []byte(data)[:9], 2105 }, 2106 }, 2107 wantMalformedIPPackets: 1, 2108 wantMalformedFragments: 1, 2109 expectICMP: true, 2110 expectICMPType: header.ICMPv6ParamProblem, 2111 expectICMPCode: header.ICMPv6ErroneousHeader, 2112 expectICMPTypeSpecific: header.IPv6PayloadLenOffset, 2113 }, 2114 { 2115 name: "fragments reassembled into a payload exceeding the max IPv6 payload size", 2116 fragments: []fragmentData{ 2117 { 2118 ipv6Fields: header.IPv6Fields{ 2119 PayloadLength: header.IPv6FragmentHeaderSize + 16, 2120 TransportProtocol: header.UDPProtocolNumber, 2121 HopLimit: hoplimit, 2122 SrcAddr: addr1, 2123 DstAddr: addr2, 2124 }, 2125 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2126 FragmentOffset: ((header.IPv6MaximumPayloadSize + 1) - 16) >> 3, 2127 M: false, 2128 Identification: ident, 2129 }, 2130 payload: []byte(data)[:16], 2131 }, 2132 }, 2133 wantMalformedIPPackets: 1, 2134 wantMalformedFragments: 1, 2135 expectICMP: true, 2136 expectICMPType: header.ICMPv6ParamProblem, 2137 expectICMPCode: header.ICMPv6ErroneousHeader, 2138 expectICMPTypeSpecific: header.IPv6MinimumSize + 2, /* offset for 'Fragment Offset' in the fragment header */ 2139 }, 2140 } 2141 2142 for _, test := range tests { 2143 t.Run(test.name, func(t *testing.T) { 2144 s := stack.New(stack.Options{ 2145 NetworkProtocols: []stack.NetworkProtocolFactory{ 2146 NewProtocol, 2147 }, 2148 }) 2149 e := channel.New(1, 1500, linkAddr1) 2150 if err := s.CreateNIC(nicID, e); err != nil { 2151 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 2152 } 2153 if err := s.AddAddress(nicID, ProtocolNumber, addr2); err != nil { 2154 t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, addr2, err) 2155 } 2156 s.SetRouteTable([]tcpip.Route{{ 2157 Destination: header.IPv6EmptySubnet, 2158 NIC: nicID, 2159 }}) 2160 2161 var expectICMPPayload buffer.View 2162 for _, f := range test.fragments { 2163 hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize) 2164 2165 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize)) 2166 encodeArgs := f.ipv6Fields 2167 encodeArgs.ExtensionHeaders = append(encodeArgs.ExtensionHeaders, &f.ipv6FragmentFields) 2168 ip.Encode(&encodeArgs) 2169 2170 vv := hdr.View().ToVectorisedView() 2171 vv.AppendView(f.payload) 2172 2173 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 2174 Data: vv, 2175 }) 2176 2177 if test.expectICMP { 2178 expectICMPPayload = stack.PayloadSince(pkt.NetworkHeader()) 2179 } 2180 2181 e.InjectInbound(ProtocolNumber, pkt) 2182 } 2183 2184 if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.wantMalformedIPPackets; got != want { 2185 t.Errorf("got Stats.IP.MalformedPacketsReceived = %d, want = %d", got, want) 2186 } 2187 if got, want := s.Stats().IP.MalformedFragmentsReceived.Value(), test.wantMalformedFragments; got != want { 2188 t.Errorf("got Stats.IP.MalformedFragmentsReceived = %d, want = %d", got, want) 2189 } 2190 2191 reply, ok := e.Read() 2192 if !test.expectICMP { 2193 if ok { 2194 t.Fatalf("unexpected ICMP error message received: %#v", reply) 2195 } 2196 return 2197 } 2198 if !ok { 2199 t.Fatal("expected ICMP error message missing") 2200 } 2201 2202 checker.IPv6(t, stack.PayloadSince(reply.Pkt.NetworkHeader()), 2203 checker.SrcAddr(addr2), 2204 checker.DstAddr(addr1), 2205 checker.IPFullLength(uint16(header.IPv6MinimumSize+header.ICMPv6MinimumSize+expectICMPPayload.Size())), 2206 checker.ICMPv6( 2207 checker.ICMPv6Type(test.expectICMPType), 2208 checker.ICMPv6Code(test.expectICMPCode), 2209 checker.ICMPv6TypeSpecific(test.expectICMPTypeSpecific), 2210 checker.ICMPv6Payload(expectICMPPayload), 2211 ), 2212 ) 2213 }) 2214 } 2215 } 2216 2217 func TestFragmentReassemblyTimeout(t *testing.T) { 2218 const ( 2219 addr1 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" 2220 addr2 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" 2221 linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e") 2222 nicID = 1 2223 hoplimit = 255 2224 ident = 1 2225 data = "TEST_FRAGMENT_REASSEMBLY_TIMEOUT" 2226 ) 2227 2228 type fragmentData struct { 2229 ipv6Fields header.IPv6Fields 2230 ipv6FragmentFields header.IPv6SerializableFragmentExtHdr 2231 payload []byte 2232 } 2233 2234 tests := []struct { 2235 name string 2236 fragments []fragmentData 2237 expectICMP bool 2238 }{ 2239 { 2240 name: "first fragment only", 2241 fragments: []fragmentData{ 2242 { 2243 ipv6Fields: header.IPv6Fields{ 2244 PayloadLength: header.IPv6FragmentHeaderSize + 16, 2245 TransportProtocol: header.UDPProtocolNumber, 2246 HopLimit: hoplimit, 2247 SrcAddr: addr1, 2248 DstAddr: addr2, 2249 }, 2250 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2251 FragmentOffset: 0, 2252 M: true, 2253 Identification: ident, 2254 }, 2255 payload: []byte(data)[:16], 2256 }, 2257 }, 2258 expectICMP: true, 2259 }, 2260 { 2261 name: "two first fragments", 2262 fragments: []fragmentData{ 2263 { 2264 ipv6Fields: header.IPv6Fields{ 2265 PayloadLength: header.IPv6FragmentHeaderSize + 16, 2266 TransportProtocol: header.UDPProtocolNumber, 2267 HopLimit: hoplimit, 2268 SrcAddr: addr1, 2269 DstAddr: addr2, 2270 }, 2271 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2272 FragmentOffset: 0, 2273 M: true, 2274 Identification: ident, 2275 }, 2276 payload: []byte(data)[:16], 2277 }, 2278 { 2279 ipv6Fields: header.IPv6Fields{ 2280 PayloadLength: header.IPv6FragmentHeaderSize + 16, 2281 TransportProtocol: header.UDPProtocolNumber, 2282 HopLimit: hoplimit, 2283 SrcAddr: addr1, 2284 DstAddr: addr2, 2285 }, 2286 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2287 FragmentOffset: 0, 2288 M: true, 2289 Identification: ident, 2290 }, 2291 payload: []byte(data)[:16], 2292 }, 2293 }, 2294 expectICMP: true, 2295 }, 2296 { 2297 name: "second fragment only", 2298 fragments: []fragmentData{ 2299 { 2300 ipv6Fields: header.IPv6Fields{ 2301 PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16), 2302 TransportProtocol: header.UDPProtocolNumber, 2303 HopLimit: hoplimit, 2304 SrcAddr: addr1, 2305 DstAddr: addr2, 2306 }, 2307 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2308 FragmentOffset: 8, 2309 M: false, 2310 Identification: ident, 2311 }, 2312 payload: []byte(data)[16:], 2313 }, 2314 }, 2315 expectICMP: false, 2316 }, 2317 { 2318 name: "two fragments with a gap", 2319 fragments: []fragmentData{ 2320 { 2321 ipv6Fields: header.IPv6Fields{ 2322 PayloadLength: header.IPv6FragmentHeaderSize + 16, 2323 TransportProtocol: header.UDPProtocolNumber, 2324 HopLimit: hoplimit, 2325 SrcAddr: addr1, 2326 DstAddr: addr2, 2327 }, 2328 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2329 FragmentOffset: 0, 2330 M: true, 2331 Identification: ident, 2332 }, 2333 payload: []byte(data)[:16], 2334 }, 2335 { 2336 ipv6Fields: header.IPv6Fields{ 2337 PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16), 2338 TransportProtocol: header.UDPProtocolNumber, 2339 HopLimit: hoplimit, 2340 SrcAddr: addr1, 2341 DstAddr: addr2, 2342 }, 2343 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2344 FragmentOffset: 8, 2345 M: false, 2346 Identification: ident, 2347 }, 2348 payload: []byte(data)[16:], 2349 }, 2350 }, 2351 expectICMP: true, 2352 }, 2353 { 2354 name: "two fragments with a gap in reverse order", 2355 fragments: []fragmentData{ 2356 { 2357 ipv6Fields: header.IPv6Fields{ 2358 PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16), 2359 TransportProtocol: header.UDPProtocolNumber, 2360 HopLimit: hoplimit, 2361 SrcAddr: addr1, 2362 DstAddr: addr2, 2363 }, 2364 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2365 FragmentOffset: 8, 2366 M: false, 2367 Identification: ident, 2368 }, 2369 payload: []byte(data)[16:], 2370 }, 2371 { 2372 ipv6Fields: header.IPv6Fields{ 2373 PayloadLength: header.IPv6FragmentHeaderSize + 16, 2374 TransportProtocol: header.UDPProtocolNumber, 2375 HopLimit: hoplimit, 2376 SrcAddr: addr1, 2377 DstAddr: addr2, 2378 }, 2379 ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{ 2380 FragmentOffset: 0, 2381 M: true, 2382 Identification: ident, 2383 }, 2384 payload: []byte(data)[:16], 2385 }, 2386 }, 2387 expectICMP: true, 2388 }, 2389 } 2390 2391 for _, test := range tests { 2392 t.Run(test.name, func(t *testing.T) { 2393 clock := faketime.NewManualClock() 2394 s := stack.New(stack.Options{ 2395 NetworkProtocols: []stack.NetworkProtocolFactory{ 2396 NewProtocol, 2397 }, 2398 Clock: clock, 2399 }) 2400 2401 e := channel.New(1, 1500, linkAddr1) 2402 if err := s.CreateNIC(nicID, e); err != nil { 2403 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 2404 } 2405 if err := s.AddAddress(nicID, ProtocolNumber, addr2); err != nil { 2406 t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, header.IPv6ProtocolNumber, addr2, err) 2407 } 2408 s.SetRouteTable([]tcpip.Route{{ 2409 Destination: header.IPv6EmptySubnet, 2410 NIC: nicID, 2411 }}) 2412 2413 var firstFragmentSent buffer.View 2414 for _, f := range test.fragments { 2415 hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize) 2416 2417 ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize)) 2418 encodeArgs := f.ipv6Fields 2419 encodeArgs.ExtensionHeaders = append(encodeArgs.ExtensionHeaders, &f.ipv6FragmentFields) 2420 ip.Encode(&encodeArgs) 2421 2422 fragHDR := header.IPv6Fragment(hdr.View()[header.IPv6MinimumSize:]) 2423 2424 vv := hdr.View().ToVectorisedView() 2425 vv.AppendView(f.payload) 2426 2427 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 2428 Data: vv, 2429 }) 2430 2431 if firstFragmentSent == nil && fragHDR.FragmentOffset() == 0 { 2432 firstFragmentSent = stack.PayloadSince(pkt.NetworkHeader()) 2433 } 2434 2435 e.InjectInbound(ProtocolNumber, pkt) 2436 } 2437 2438 clock.Advance(ReassembleTimeout) 2439 2440 reply, ok := e.Read() 2441 if !test.expectICMP { 2442 if ok { 2443 t.Fatalf("unexpected ICMP error message received: %#v", reply) 2444 } 2445 return 2446 } 2447 if !ok { 2448 t.Fatal("expected ICMP error message missing") 2449 } 2450 if firstFragmentSent == nil { 2451 t.Fatalf("unexpected ICMP error message received: %#v", reply) 2452 } 2453 2454 checker.IPv6(t, stack.PayloadSince(reply.Pkt.NetworkHeader()), 2455 checker.SrcAddr(addr2), 2456 checker.DstAddr(addr1), 2457 checker.IPFullLength(uint16(header.IPv6MinimumSize+header.ICMPv6MinimumSize+firstFragmentSent.Size())), 2458 checker.ICMPv6( 2459 checker.ICMPv6Type(header.ICMPv6TimeExceeded), 2460 checker.ICMPv6Code(header.ICMPv6ReassemblyTimeout), 2461 checker.ICMPv6Payload(firstFragmentSent), 2462 ), 2463 ) 2464 }) 2465 } 2466 } 2467 2468 func TestWriteStats(t *testing.T) { 2469 const nPackets = 3 2470 tests := []struct { 2471 name string 2472 setup func(*testing.T, *stack.Stack) 2473 allowPackets int 2474 expectSent int 2475 expectOutputDropped int 2476 expectPostroutingDropped int 2477 expectWritten int 2478 }{ 2479 { 2480 name: "Accept all", 2481 // No setup needed, tables accept everything by default. 2482 setup: func(*testing.T, *stack.Stack) {}, 2483 allowPackets: math.MaxInt32, 2484 expectSent: nPackets, 2485 expectOutputDropped: 0, 2486 expectPostroutingDropped: 0, 2487 expectWritten: nPackets, 2488 }, { 2489 name: "Accept all with error", 2490 // No setup needed, tables accept everything by default. 2491 setup: func(*testing.T, *stack.Stack) {}, 2492 allowPackets: nPackets - 1, 2493 expectSent: nPackets - 1, 2494 expectOutputDropped: 0, 2495 expectPostroutingDropped: 0, 2496 expectWritten: nPackets - 1, 2497 }, { 2498 name: "Drop all with Output chain", 2499 setup: func(t *testing.T, stk *stack.Stack) { 2500 // Install Output DROP rule. 2501 ipt := stk.IPTables() 2502 filter := ipt.GetTable(stack.FilterID, true /* ipv6 */) 2503 ruleIdx := filter.BuiltinChains[stack.Output] 2504 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 2505 if err := ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */); err != nil { 2506 t.Fatalf("failed to replace table: %v", err) 2507 } 2508 }, 2509 allowPackets: math.MaxInt32, 2510 expectSent: 0, 2511 expectOutputDropped: nPackets, 2512 expectPostroutingDropped: 0, 2513 expectWritten: nPackets, 2514 }, { 2515 name: "Drop all with Postrouting chain", 2516 setup: func(t *testing.T, stk *stack.Stack) { 2517 // Install Output DROP rule. 2518 ipt := stk.IPTables() 2519 filter := ipt.GetTable(stack.NATID, true /* ipv6 */) 2520 ruleIdx := filter.BuiltinChains[stack.Postrouting] 2521 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 2522 if err := ipt.ReplaceTable(stack.NATID, filter, true /* ipv6 */); err != nil { 2523 t.Fatalf("failed to replace table: %v", err) 2524 } 2525 }, 2526 allowPackets: math.MaxInt32, 2527 expectSent: 0, 2528 expectOutputDropped: 0, 2529 expectPostroutingDropped: nPackets, 2530 expectWritten: nPackets, 2531 }, { 2532 name: "Drop some with Output chain", 2533 setup: func(t *testing.T, stk *stack.Stack) { 2534 // Install Output DROP rule that matches only 1 2535 // of the 3 packets. 2536 ipt := stk.IPTables() 2537 filter := ipt.GetTable(stack.FilterID, true /* ipv6 */) 2538 // We'll match and DROP the last packet. 2539 ruleIdx := filter.BuiltinChains[stack.Output] 2540 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 2541 filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} 2542 // Make sure the next rule is ACCEPT. 2543 filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} 2544 if err := ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */); err != nil { 2545 t.Fatalf("failed to replace table: %v", err) 2546 } 2547 }, 2548 allowPackets: math.MaxInt32, 2549 expectSent: nPackets - 1, 2550 expectOutputDropped: 1, 2551 expectPostroutingDropped: 0, 2552 expectWritten: nPackets, 2553 }, { 2554 name: "Drop some with Postrouting chain", 2555 setup: func(t *testing.T, stk *stack.Stack) { 2556 // Install Postrouting DROP rule that matches only 1 2557 // of the 3 packets. 2558 ipt := stk.IPTables() 2559 filter := ipt.GetTable(stack.NATID, true /* ipv6 */) 2560 // We'll match and DROP the last packet. 2561 ruleIdx := filter.BuiltinChains[stack.Postrouting] 2562 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 2563 filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} 2564 // Make sure the next rule is ACCEPT. 2565 filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} 2566 if err := ipt.ReplaceTable(stack.NATID, filter, true /* ipv6 */); err != nil { 2567 t.Fatalf("failed to replace table: %v", err) 2568 } 2569 }, 2570 allowPackets: math.MaxInt32, 2571 expectSent: nPackets - 1, 2572 expectOutputDropped: 0, 2573 expectPostroutingDropped: 1, 2574 expectWritten: nPackets, 2575 }, 2576 } 2577 2578 writers := []struct { 2579 name string 2580 writePackets func(*stack.Route, stack.PacketBufferList) (int, tcpip.Error) 2581 }{ 2582 { 2583 name: "WritePacket", 2584 writePackets: func(rt *stack.Route, pkts stack.PacketBufferList) (int, tcpip.Error) { 2585 nWritten := 0 2586 for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() { 2587 if err := rt.WritePacket(stack.NetworkHeaderParams{}, pkt); err != nil { 2588 return nWritten, err 2589 } 2590 nWritten++ 2591 } 2592 return nWritten, nil 2593 }, 2594 }, { 2595 name: "WritePackets", 2596 writePackets: func(rt *stack.Route, pkts stack.PacketBufferList) (int, tcpip.Error) { 2597 return rt.WritePackets(pkts, stack.NetworkHeaderParams{}) 2598 }, 2599 }, 2600 } 2601 2602 for _, writer := range writers { 2603 t.Run(writer.name, func(t *testing.T) { 2604 for _, test := range tests { 2605 t.Run(test.name, func(t *testing.T) { 2606 ep := iptestutil.NewMockLinkEndpoint(header.IPv6MinimumMTU, &tcpip.ErrInvalidEndpointState{}, test.allowPackets) 2607 rt := buildRoute(t, ep) 2608 var pkts stack.PacketBufferList 2609 for i := 0; i < nPackets; i++ { 2610 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 2611 ReserveHeaderBytes: header.UDPMinimumSize + int(rt.MaxHeaderLength()), 2612 Data: buffer.NewView(0).ToVectorisedView(), 2613 }) 2614 pkt.TransportHeader().Push(header.UDPMinimumSize) 2615 pkts.PushBack(pkt) 2616 } 2617 2618 test.setup(t, rt.Stack()) 2619 2620 nWritten, _ := writer.writePackets(rt, pkts) 2621 2622 if got := int(rt.Stats().IP.PacketsSent.Value()); got != test.expectSent { 2623 t.Errorf("got rt.Stats().IP.PacketsSent.Value() = %d, want = %d", got, test.expectSent) 2624 } 2625 if got := int(rt.Stats().IP.IPTablesOutputDropped.Value()); got != test.expectOutputDropped { 2626 t.Errorf("got rt.Stats().IP.IPTablesOutputDropped.Value() = %d, want = %d", got, test.expectOutputDropped) 2627 } 2628 if got := int(rt.Stats().IP.IPTablesPostroutingDropped.Value()); got != test.expectPostroutingDropped { 2629 t.Errorf("got r.Stats().IP.IPTablesPostroutingDropped.Value() = %d, want = %d", got, test.expectPostroutingDropped) 2630 } 2631 if nWritten != test.expectWritten { 2632 t.Errorf("got nWritten = %d, want = %d", nWritten, test.expectWritten) 2633 } 2634 }) 2635 } 2636 }) 2637 } 2638 } 2639 2640 func buildRoute(t *testing.T, ep stack.LinkEndpoint) *stack.Route { 2641 s := stack.New(stack.Options{ 2642 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 2643 }) 2644 if err := s.CreateNIC(1, ep); err != nil { 2645 t.Fatalf("CreateNIC(1, _) failed: %s", err) 2646 } 2647 const ( 2648 src = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" 2649 dst = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" 2650 ) 2651 if err := s.AddAddress(1, ProtocolNumber, src); err != nil { 2652 t.Fatalf("AddAddress(1, %d, %s) failed: %s", ProtocolNumber, src, err) 2653 } 2654 { 2655 mask := tcpip.AddressMask("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") 2656 subnet, err := tcpip.NewSubnet(dst, mask) 2657 if err != nil { 2658 t.Fatalf("NewSubnet(%s, %s) failed: %v", dst, mask, err) 2659 } 2660 s.SetRouteTable([]tcpip.Route{{ 2661 Destination: subnet, 2662 NIC: 1, 2663 }}) 2664 } 2665 rt, err := s.FindRoute(1, src, dst, ProtocolNumber, false /* multicastLoop */) 2666 if err != nil { 2667 t.Fatalf("FindRoute(1, %s, %s, %d, false) = %s, want = nil", src, dst, ProtocolNumber, err) 2668 } 2669 return rt 2670 } 2671 2672 // limitedMatcher is an iptables matcher that matches after a certain number of 2673 // packets are checked against it. 2674 type limitedMatcher struct { 2675 limit int 2676 } 2677 2678 // Name implements Matcher.Name. 2679 func (*limitedMatcher) Name() string { 2680 return "limitedMatcher" 2681 } 2682 2683 // Match implements Matcher.Match. 2684 func (lm *limitedMatcher) Match(stack.Hook, *stack.PacketBuffer, string, string) (bool, bool) { 2685 if lm.limit == 0 { 2686 return true, false 2687 } 2688 lm.limit-- 2689 return false, false 2690 } 2691 2692 func knownNICIDs(proto *protocol) []tcpip.NICID { 2693 var nicIDs []tcpip.NICID 2694 2695 for k := range proto.mu.eps { 2696 nicIDs = append(nicIDs, k) 2697 } 2698 2699 return nicIDs 2700 } 2701 2702 func TestClearEndpointFromProtocolOnClose(t *testing.T) { 2703 s := stack.New(stack.Options{ 2704 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 2705 }) 2706 proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol) 2707 var nic testInterface 2708 ep := proto.NewEndpoint(&nic, nil).(*endpoint) 2709 var nicIDs []tcpip.NICID 2710 2711 proto.mu.Lock() 2712 foundEP, hasEndpointBeforeClose := proto.mu.eps[nic.ID()] 2713 nicIDs = knownNICIDs(proto) 2714 proto.mu.Unlock() 2715 if !hasEndpointBeforeClose { 2716 t.Fatalf("expected to find the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs) 2717 } 2718 if foundEP != ep { 2719 t.Fatalf("found an incorrect endpoint mapped to nic id %d", nic.ID()) 2720 } 2721 2722 ep.Close() 2723 2724 proto.mu.Lock() 2725 _, hasEndpointAfterClose := proto.mu.eps[nic.ID()] 2726 nicIDs = knownNICIDs(proto) 2727 proto.mu.Unlock() 2728 if hasEndpointAfterClose { 2729 t.Fatalf("unexpectedly found an endpoint mapped to the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs) 2730 } 2731 } 2732 2733 type fragmentInfo struct { 2734 offset uint16 2735 more bool 2736 payloadSize uint16 2737 } 2738 2739 var fragmentationTests = []struct { 2740 description string 2741 mtu uint32 2742 transHdrLen int 2743 payloadSize int 2744 wantFragments []fragmentInfo 2745 }{ 2746 { 2747 description: "No fragmentation", 2748 mtu: header.IPv6MinimumMTU, 2749 transHdrLen: 0, 2750 payloadSize: 1000, 2751 wantFragments: []fragmentInfo{ 2752 {offset: 0, payloadSize: 1000, more: false}, 2753 }, 2754 }, 2755 { 2756 description: "Fragmented", 2757 mtu: header.IPv6MinimumMTU, 2758 transHdrLen: 0, 2759 payloadSize: 2000, 2760 wantFragments: []fragmentInfo{ 2761 {offset: 0, payloadSize: 1240, more: true}, 2762 {offset: 154, payloadSize: 776, more: false}, 2763 }, 2764 }, 2765 { 2766 description: "Fragmented with mtu not a multiple of 8", 2767 mtu: header.IPv6MinimumMTU + 1, 2768 transHdrLen: 0, 2769 payloadSize: 2000, 2770 wantFragments: []fragmentInfo{ 2771 {offset: 0, payloadSize: 1240, more: true}, 2772 {offset: 154, payloadSize: 776, more: false}, 2773 }, 2774 }, 2775 { 2776 description: "No fragmentation with big header", 2777 mtu: 2000, 2778 transHdrLen: 100, 2779 payloadSize: 1000, 2780 wantFragments: []fragmentInfo{ 2781 {offset: 0, payloadSize: 1100, more: false}, 2782 }, 2783 }, 2784 { 2785 description: "Fragmented with big header", 2786 mtu: header.IPv6MinimumMTU, 2787 transHdrLen: 100, 2788 payloadSize: 1200, 2789 wantFragments: []fragmentInfo{ 2790 {offset: 0, payloadSize: 1240, more: true}, 2791 {offset: 154, payloadSize: 76, more: false}, 2792 }, 2793 }, 2794 } 2795 2796 func TestFragmentationWritePacket(t *testing.T) { 2797 const ttl = 42 2798 2799 for _, ft := range fragmentationTests { 2800 t.Run(ft.description, func(t *testing.T) { 2801 pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber) 2802 source := pkt.Clone() 2803 ep := iptestutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32) 2804 r := buildRoute(t, ep) 2805 err := r.WritePacket(stack.NetworkHeaderParams{ 2806 Protocol: tcp.ProtocolNumber, 2807 TTL: ttl, 2808 TOS: stack.DefaultTOS, 2809 }, pkt) 2810 if err != nil { 2811 t.Fatalf("WritePacket(_, _, _): = %s", err) 2812 } 2813 if got := len(ep.WrittenPackets); got != len(ft.wantFragments) { 2814 t.Errorf("got len(ep.WrittenPackets) = %d, want = %d", got, len(ft.wantFragments)) 2815 } 2816 if got := int(r.Stats().IP.PacketsSent.Value()); got != len(ft.wantFragments) { 2817 t.Errorf("got c.Route.Stats().IP.PacketsSent.Value() = %d, want = %d", got, len(ft.wantFragments)) 2818 } 2819 if got := r.Stats().IP.OutgoingPacketErrors.Value(); got != 0 { 2820 t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = 0", got) 2821 } 2822 if err := compareFragments(ep.WrittenPackets, source, ft.mtu, ft.wantFragments, tcp.ProtocolNumber); err != nil { 2823 t.Error(err) 2824 } 2825 }) 2826 } 2827 } 2828 2829 func TestFragmentationWritePackets(t *testing.T) { 2830 const ttl = 42 2831 tests := []struct { 2832 description string 2833 insertBefore int 2834 insertAfter int 2835 }{ 2836 { 2837 description: "Single packet", 2838 insertBefore: 0, 2839 insertAfter: 0, 2840 }, 2841 { 2842 description: "With packet before", 2843 insertBefore: 1, 2844 insertAfter: 0, 2845 }, 2846 { 2847 description: "With packet after", 2848 insertBefore: 0, 2849 insertAfter: 1, 2850 }, 2851 { 2852 description: "With packet before and after", 2853 insertBefore: 1, 2854 insertAfter: 1, 2855 }, 2856 } 2857 tinyPacket := iptestutil.MakeRandPkt(header.TCPMinimumSize, extraHeaderReserve+header.IPv6MinimumSize, []int{1}, header.IPv6ProtocolNumber) 2858 2859 for _, test := range tests { 2860 t.Run(test.description, func(t *testing.T) { 2861 for _, ft := range fragmentationTests { 2862 t.Run(ft.description, func(t *testing.T) { 2863 var pkts stack.PacketBufferList 2864 for i := 0; i < test.insertBefore; i++ { 2865 pkts.PushBack(tinyPacket.Clone()) 2866 } 2867 pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber) 2868 source := pkt 2869 pkts.PushBack(pkt.Clone()) 2870 for i := 0; i < test.insertAfter; i++ { 2871 pkts.PushBack(tinyPacket.Clone()) 2872 } 2873 2874 ep := iptestutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32) 2875 r := buildRoute(t, ep) 2876 2877 wantTotalPackets := len(ft.wantFragments) + test.insertBefore + test.insertAfter 2878 n, err := r.WritePackets(pkts, stack.NetworkHeaderParams{ 2879 Protocol: tcp.ProtocolNumber, 2880 TTL: ttl, 2881 TOS: stack.DefaultTOS, 2882 }) 2883 if n != wantTotalPackets || err != nil { 2884 t.Errorf("got WritePackets(_, _, _) = (%d, %s), want = (%d, nil)", n, err, wantTotalPackets) 2885 } 2886 if got := len(ep.WrittenPackets); got != wantTotalPackets { 2887 t.Errorf("got len(ep.WrittenPackets) = %d, want = %d", got, wantTotalPackets) 2888 } 2889 if got := int(r.Stats().IP.PacketsSent.Value()); got != wantTotalPackets { 2890 t.Errorf("got c.Route.Stats().IP.PacketsSent.Value() = %d, want = %d", got, wantTotalPackets) 2891 } 2892 if got := r.Stats().IP.OutgoingPacketErrors.Value(); got != 0 { 2893 t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = 0", got) 2894 } 2895 2896 if wantTotalPackets == 0 { 2897 return 2898 } 2899 2900 fragments := ep.WrittenPackets[test.insertBefore : len(ft.wantFragments)+test.insertBefore] 2901 if err := compareFragments(fragments, source, ft.mtu, ft.wantFragments, tcp.ProtocolNumber); err != nil { 2902 t.Error(err) 2903 } 2904 }) 2905 } 2906 }) 2907 } 2908 } 2909 2910 // TestFragmentationErrors checks that errors are returned from WritePacket 2911 // correctly. 2912 func TestFragmentationErrors(t *testing.T) { 2913 const ttl = 42 2914 2915 tests := []struct { 2916 description string 2917 mtu uint32 2918 transHdrLen int 2919 payloadSize int 2920 allowPackets int 2921 outgoingErrors int 2922 mockError tcpip.Error 2923 wantError tcpip.Error 2924 }{ 2925 { 2926 description: "No frag", 2927 mtu: 2000, 2928 payloadSize: 1000, 2929 transHdrLen: 0, 2930 allowPackets: 0, 2931 outgoingErrors: 1, 2932 mockError: &tcpip.ErrAborted{}, 2933 wantError: &tcpip.ErrAborted{}, 2934 }, 2935 { 2936 description: "Error on first frag", 2937 mtu: 1300, 2938 payloadSize: 3000, 2939 transHdrLen: 0, 2940 allowPackets: 0, 2941 outgoingErrors: 3, 2942 mockError: &tcpip.ErrAborted{}, 2943 wantError: &tcpip.ErrAborted{}, 2944 }, 2945 { 2946 description: "Error on second frag", 2947 mtu: 1500, 2948 payloadSize: 4000, 2949 transHdrLen: 0, 2950 allowPackets: 1, 2951 outgoingErrors: 2, 2952 mockError: &tcpip.ErrAborted{}, 2953 wantError: &tcpip.ErrAborted{}, 2954 }, 2955 { 2956 description: "Error when MTU is smaller than transport header", 2957 mtu: header.IPv6MinimumMTU, 2958 transHdrLen: 1500, 2959 payloadSize: 500, 2960 allowPackets: 0, 2961 outgoingErrors: 1, 2962 mockError: nil, 2963 wantError: &tcpip.ErrMessageTooLong{}, 2964 }, 2965 { 2966 description: "Error when MTU is smaller than IPv6 minimum MTU", 2967 mtu: header.IPv6MinimumMTU - 1, 2968 transHdrLen: 0, 2969 payloadSize: 500, 2970 allowPackets: 0, 2971 outgoingErrors: 1, 2972 mockError: nil, 2973 wantError: &tcpip.ErrInvalidEndpointState{}, 2974 }, 2975 } 2976 2977 for _, ft := range tests { 2978 t.Run(ft.description, func(t *testing.T) { 2979 pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber) 2980 ep := iptestutil.NewMockLinkEndpoint(ft.mtu, ft.mockError, ft.allowPackets) 2981 r := buildRoute(t, ep) 2982 err := r.WritePacket(stack.NetworkHeaderParams{ 2983 Protocol: tcp.ProtocolNumber, 2984 TTL: ttl, 2985 TOS: stack.DefaultTOS, 2986 }, pkt) 2987 if diff := cmp.Diff(ft.wantError, err); diff != "" { 2988 t.Errorf("unexpected error from WritePacket(_, _, _), (-want, +got):\n%s", diff) 2989 } 2990 if got := int(r.Stats().IP.PacketsSent.Value()); got != ft.allowPackets { 2991 t.Errorf("got r.Stats().IP.PacketsSent.Value() = %d, want = %d", got, ft.allowPackets) 2992 } 2993 if got := int(r.Stats().IP.OutgoingPacketErrors.Value()); got != ft.outgoingErrors { 2994 t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = %d", got, ft.outgoingErrors) 2995 } 2996 }) 2997 } 2998 } 2999 3000 func TestForwarding(t *testing.T) { 3001 const ( 3002 incomingNICID = 1 3003 outgoingNICID = 2 3004 randomSequence = 123 3005 randomIdent = 42 3006 ) 3007 3008 incomingIPv6Addr := tcpip.AddressWithPrefix{ 3009 Address: tcpip.Address(net.ParseIP("10::1").To16()), 3010 PrefixLen: 64, 3011 } 3012 outgoingIPv6Addr := tcpip.AddressWithPrefix{ 3013 Address: tcpip.Address(net.ParseIP("11::1").To16()), 3014 PrefixLen: 64, 3015 } 3016 multicastIPv6Addr := tcpip.AddressWithPrefix{ 3017 Address: tcpip.Address(net.ParseIP("ff00::").To16()), 3018 PrefixLen: 64, 3019 } 3020 3021 remoteIPv6Addr1 := tcpip.Address(net.ParseIP("10::2").To16()) 3022 remoteIPv6Addr2 := tcpip.Address(net.ParseIP("11::2").To16()) 3023 unreachableIPv6Addr := tcpip.Address(net.ParseIP("12::2").To16()) 3024 linkLocalIPv6Addr := tcpip.Address(net.ParseIP("fe80::").To16()) 3025 3026 tests := []struct { 3027 name string 3028 extHdr func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) 3029 TTL uint8 3030 expectErrorICMP bool 3031 expectPacketForwarded bool 3032 payloadLength int 3033 countUnrouteablePackets uint64 3034 sourceAddr tcpip.Address 3035 destAddr tcpip.Address 3036 icmpType header.ICMPv6Type 3037 icmpCode header.ICMPv6Code 3038 expectPacketUnrouteableError bool 3039 expectLinkLocalSourceError bool 3040 expectLinkLocalDestError bool 3041 expectExtensionHeaderError bool 3042 }{ 3043 { 3044 name: "TTL of zero", 3045 TTL: 0, 3046 expectErrorICMP: true, 3047 sourceAddr: remoteIPv6Addr1, 3048 destAddr: remoteIPv6Addr2, 3049 icmpType: header.ICMPv6TimeExceeded, 3050 icmpCode: header.ICMPv6HopLimitExceeded, 3051 }, 3052 { 3053 name: "TTL of one", 3054 TTL: 1, 3055 expectErrorICMP: true, 3056 sourceAddr: remoteIPv6Addr1, 3057 destAddr: remoteIPv6Addr2, 3058 icmpType: header.ICMPv6TimeExceeded, 3059 icmpCode: header.ICMPv6HopLimitExceeded, 3060 }, 3061 { 3062 name: "TTL of two", 3063 TTL: 2, 3064 expectPacketForwarded: true, 3065 sourceAddr: remoteIPv6Addr1, 3066 destAddr: remoteIPv6Addr2, 3067 }, 3068 { 3069 name: "TTL of three", 3070 TTL: 3, 3071 expectPacketForwarded: true, 3072 sourceAddr: remoteIPv6Addr1, 3073 destAddr: remoteIPv6Addr2, 3074 }, 3075 { 3076 name: "Max TTL", 3077 TTL: math.MaxUint8, 3078 expectPacketForwarded: true, 3079 sourceAddr: remoteIPv6Addr1, 3080 destAddr: remoteIPv6Addr2, 3081 }, 3082 { 3083 name: "Network unreachable", 3084 TTL: 2, 3085 expectErrorICMP: true, 3086 sourceAddr: remoteIPv6Addr1, 3087 destAddr: unreachableIPv6Addr, 3088 icmpType: header.ICMPv6DstUnreachable, 3089 icmpCode: header.ICMPv6NetworkUnreachable, 3090 expectPacketUnrouteableError: true, 3091 }, 3092 { 3093 name: "Multicast destination", 3094 TTL: 2, 3095 countUnrouteablePackets: 1, 3096 sourceAddr: remoteIPv6Addr1, 3097 destAddr: multicastIPv6Addr.Address, 3098 expectPacketForwarded: true, 3099 }, 3100 { 3101 name: "Link local destination", 3102 TTL: 2, 3103 sourceAddr: remoteIPv6Addr1, 3104 destAddr: linkLocalIPv6Addr, 3105 expectLinkLocalDestError: true, 3106 }, 3107 { 3108 name: "Link local source", 3109 TTL: 2, 3110 sourceAddr: linkLocalIPv6Addr, 3111 destAddr: remoteIPv6Addr2, 3112 expectLinkLocalSourceError: true, 3113 }, 3114 { 3115 name: "Hopbyhop with unknown option skippable action", 3116 TTL: 2, 3117 sourceAddr: remoteIPv6Addr1, 3118 destAddr: remoteIPv6Addr2, 3119 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3120 return []byte{ 3121 nextHdr, 1, 3122 3123 // Skippable unknown. 3124 63, 4, 1, 2, 3, 4, 3125 3126 // Skippable unknown. 3127 62, 6, 1, 2, 3, 4, 5, 6, 3128 }, hopByHopExtHdrID, checker.IPv6ExtHdr(checker.IPv6HopByHopExtensionHeader(checker.IPv6UnknownOption(), checker.IPv6UnknownOption())) 3129 }, 3130 expectPacketForwarded: true, 3131 }, 3132 { 3133 name: "Hopbyhop with unknown option discard action", 3134 TTL: 2, 3135 sourceAddr: remoteIPv6Addr1, 3136 destAddr: remoteIPv6Addr2, 3137 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3138 return []byte{ 3139 nextHdr, 1, 3140 3141 // Skippable unknown. 3142 63, 4, 1, 2, 3, 4, 3143 3144 // Discard unknown. 3145 127, 6, 1, 2, 3, 4, 5, 6, 3146 }, hopByHopExtHdrID, nil 3147 }, 3148 expectExtensionHeaderError: true, 3149 }, 3150 { 3151 name: "Hopbyhop with unknown option discard and send icmp action (unicast)", 3152 TTL: 2, 3153 sourceAddr: remoteIPv6Addr1, 3154 destAddr: remoteIPv6Addr2, 3155 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3156 return []byte{ 3157 nextHdr, 1, 3158 3159 // Skippable unknown. 3160 63, 4, 1, 2, 3, 4, 3161 3162 // Discard & send ICMP if option is unknown. 3163 191, 6, 1, 2, 3, 4, 5, 6, 3164 }, hopByHopExtHdrID, nil 3165 }, 3166 expectErrorICMP: true, 3167 icmpType: header.ICMPv6ParamProblem, 3168 icmpCode: header.ICMPv6UnknownOption, 3169 expectExtensionHeaderError: true, 3170 }, 3171 { 3172 name: "Hopbyhop with unknown option discard and send icmp action (multicast)", 3173 TTL: 2, 3174 sourceAddr: remoteIPv6Addr1, 3175 destAddr: multicastIPv6Addr.Address, 3176 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3177 return []byte{ 3178 nextHdr, 1, 3179 3180 // Skippable unknown. 3181 63, 4, 1, 2, 3, 4, 3182 3183 // Discard & send ICMP if option is unknown. 3184 191, 6, 1, 2, 3, 4, 5, 6, 3185 }, hopByHopExtHdrID, nil 3186 }, 3187 expectErrorICMP: true, 3188 icmpType: header.ICMPv6ParamProblem, 3189 icmpCode: header.ICMPv6UnknownOption, 3190 expectExtensionHeaderError: true, 3191 }, 3192 { 3193 name: "Hopbyhop with unknown option discard and send icmp action unless multicast dest (unicast)", 3194 TTL: 2, 3195 sourceAddr: remoteIPv6Addr1, 3196 destAddr: remoteIPv6Addr2, 3197 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3198 return []byte{ 3199 nextHdr, 1, 3200 3201 // Skippable unknown. 3202 63, 4, 1, 2, 3, 4, 3203 3204 // Discard & send ICMP unless packet is for multicast destination if 3205 // option is unknown. 3206 255, 6, 1, 2, 3, 4, 5, 6, 3207 }, hopByHopExtHdrID, nil 3208 }, 3209 expectErrorICMP: true, 3210 icmpType: header.ICMPv6ParamProblem, 3211 icmpCode: header.ICMPv6UnknownOption, 3212 expectExtensionHeaderError: true, 3213 }, 3214 { 3215 name: "Hopbyhop with unknown option discard and send icmp action unless multicast dest (multicast)", 3216 TTL: 2, 3217 sourceAddr: remoteIPv6Addr1, 3218 destAddr: multicastIPv6Addr.Address, 3219 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3220 return []byte{ 3221 nextHdr, 1, 3222 3223 // Skippable unknown. 3224 63, 4, 1, 2, 3, 4, 3225 3226 // Discard & send ICMP unless packet is for multicast destination if 3227 // option is unknown. 3228 255, 6, 1, 2, 3, 4, 5, 6, 3229 }, hopByHopExtHdrID, nil 3230 }, 3231 expectExtensionHeaderError: true, 3232 }, 3233 { 3234 name: "Hopbyhop with router alert option", 3235 TTL: 2, 3236 sourceAddr: remoteIPv6Addr1, 3237 destAddr: remoteIPv6Addr2, 3238 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3239 return []byte{ 3240 nextHdr, 0, 3241 3242 // Router Alert option. 3243 5, 2, 0, 0, 0, 0, 3244 }, hopByHopExtHdrID, checker.IPv6ExtHdr(checker.IPv6HopByHopExtensionHeader(checker.IPv6RouterAlert(header.IPv6RouterAlertMLD))) 3245 }, 3246 expectPacketForwarded: true, 3247 }, 3248 { 3249 name: "Hopbyhop with two router alert options", 3250 TTL: 2, 3251 sourceAddr: remoteIPv6Addr1, 3252 destAddr: remoteIPv6Addr2, 3253 extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) { 3254 return []byte{ 3255 nextHdr, 1, 3256 3257 // Router Alert option. 3258 5, 2, 0, 0, 0, 0, 3259 3260 // Router Alert option. 3261 5, 2, 0, 0, 0, 0, 3262 }, hopByHopExtHdrID, nil 3263 }, 3264 expectExtensionHeaderError: true, 3265 }, 3266 { 3267 name: "Can't fragment", 3268 TTL: 2, 3269 payloadLength: header.IPv6MinimumMTU + 1, 3270 expectErrorICMP: true, 3271 sourceAddr: remoteIPv6Addr1, 3272 destAddr: remoteIPv6Addr2, 3273 icmpType: header.ICMPv6PacketTooBig, 3274 icmpCode: header.ICMPv6UnusedCode, 3275 }, 3276 { 3277 name: "Can't fragment multicast", 3278 TTL: 2, 3279 payloadLength: header.IPv6MinimumMTU + 1, 3280 sourceAddr: remoteIPv6Addr1, 3281 destAddr: multicastIPv6Addr.Address, 3282 expectErrorICMP: true, 3283 icmpType: header.ICMPv6PacketTooBig, 3284 icmpCode: header.ICMPv6UnusedCode, 3285 }, 3286 } 3287 3288 for _, test := range tests { 3289 t.Run(test.name, func(t *testing.T) { 3290 s := stack.New(stack.Options{ 3291 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 3292 TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6}, 3293 }) 3294 // We expect at most a single packet in response to our ICMP Echo Request. 3295 incomingEndpoint := channel.New(1, header.IPv6MinimumMTU, "") 3296 if err := s.CreateNIC(incomingNICID, incomingEndpoint); err != nil { 3297 t.Fatalf("CreateNIC(%d, _): %s", incomingNICID, err) 3298 } 3299 incomingIPv6ProtoAddr := tcpip.ProtocolAddress{Protocol: ProtocolNumber, AddressWithPrefix: incomingIPv6Addr} 3300 if err := s.AddProtocolAddress(incomingNICID, incomingIPv6ProtoAddr); err != nil { 3301 t.Fatalf("AddProtocolAddress(%d, %#v): %s", incomingNICID, incomingIPv6ProtoAddr, err) 3302 } 3303 3304 outgoingEndpoint := channel.New(1, header.IPv6MinimumMTU, "") 3305 if err := s.CreateNIC(outgoingNICID, outgoingEndpoint); err != nil { 3306 t.Fatalf("CreateNIC(%d, _): %s", outgoingNICID, err) 3307 } 3308 outgoingIPv6ProtoAddr := tcpip.ProtocolAddress{Protocol: ProtocolNumber, AddressWithPrefix: outgoingIPv6Addr} 3309 if err := s.AddProtocolAddress(outgoingNICID, outgoingIPv6ProtoAddr); err != nil { 3310 t.Fatalf("AddProtocolAddress(%d, %#v): %s", outgoingNICID, outgoingIPv6ProtoAddr, err) 3311 } 3312 3313 s.SetRouteTable([]tcpip.Route{ 3314 { 3315 Destination: incomingIPv6Addr.Subnet(), 3316 NIC: incomingNICID, 3317 }, 3318 { 3319 Destination: outgoingIPv6Addr.Subnet(), 3320 NIC: outgoingNICID, 3321 }, 3322 { 3323 Destination: multicastIPv6Addr.Subnet(), 3324 NIC: outgoingNICID, 3325 }, 3326 }) 3327 3328 if err := s.SetForwardingDefaultAndAllNICs(ProtocolNumber, true); err != nil { 3329 t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ProtocolNumber, err) 3330 } 3331 3332 transportProtocol := header.ICMPv6ProtocolNumber 3333 var extHdrBytes []byte 3334 extHdrChecker := checker.IPv6ExtHdr() 3335 if test.extHdr != nil { 3336 nextHdrID := hopByHopExtHdrID 3337 extHdrBytes, nextHdrID, extHdrChecker = test.extHdr(uint8(header.ICMPv6ProtocolNumber)) 3338 transportProtocol = tcpip.TransportProtocolNumber(nextHdrID) 3339 } 3340 extHdrLen := len(extHdrBytes) 3341 3342 ipHeaderLength := header.IPv6MinimumSize 3343 icmpHeaderLength := header.ICMPv6MinimumSize 3344 totalLength := ipHeaderLength + icmpHeaderLength + test.payloadLength + extHdrLen 3345 hdr := buffer.NewPrependable(totalLength) 3346 hdr.Prepend(test.payloadLength) 3347 icmpH := header.ICMPv6(hdr.Prepend(icmpHeaderLength)) 3348 3349 icmpH.SetIdent(randomIdent) 3350 icmpH.SetSequence(randomSequence) 3351 icmpH.SetType(header.ICMPv6EchoRequest) 3352 icmpH.SetCode(header.ICMPv6UnusedCode) 3353 icmpH.SetChecksum(0) 3354 icmpH.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 3355 Header: icmpH, 3356 Src: test.sourceAddr, 3357 Dst: test.destAddr, 3358 })) 3359 copy(hdr.Prepend(extHdrLen), extHdrBytes) 3360 ip := header.IPv6(hdr.Prepend(ipHeaderLength)) 3361 ip.Encode(&header.IPv6Fields{ 3362 PayloadLength: uint16(header.ICMPv6MinimumSize + test.payloadLength), 3363 TransportProtocol: transportProtocol, 3364 HopLimit: test.TTL, 3365 SrcAddr: test.sourceAddr, 3366 DstAddr: test.destAddr, 3367 }) 3368 requestPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 3369 Data: hdr.View().ToVectorisedView(), 3370 }) 3371 incomingEndpoint.InjectInbound(ProtocolNumber, requestPkt) 3372 3373 reply, ok := incomingEndpoint.Read() 3374 3375 if test.expectErrorICMP { 3376 if !ok { 3377 t.Fatalf("expected ICMP packet type %d through incoming NIC", test.icmpType) 3378 } 3379 3380 // As per RFC 4443, page 9: 3381 // 3382 // The returned ICMP packet will contain as much of invoking packet 3383 // as possible without the ICMPv6 packet exceeding the minimum IPv6 3384 // MTU. 3385 expectedICMPPayloadLength := func() int { 3386 maxICMPPayloadLength := header.IPv6MinimumMTU - ipHeaderLength - icmpHeaderLength 3387 if len(hdr.View()) > maxICMPPayloadLength { 3388 return maxICMPPayloadLength 3389 } 3390 return len(hdr.View()) 3391 } 3392 3393 checker.IPv6(t, stack.PayloadSince(reply.Pkt.NetworkHeader()), 3394 checker.SrcAddr(incomingIPv6Addr.Address), 3395 checker.DstAddr(test.sourceAddr), 3396 checker.TTL(DefaultTTL), 3397 checker.ICMPv6( 3398 checker.ICMPv6Type(test.icmpType), 3399 checker.ICMPv6Code(test.icmpCode), 3400 checker.ICMPv6Payload(hdr.View()[:expectedICMPPayloadLength()]), 3401 ), 3402 ) 3403 3404 if n := outgoingEndpoint.Drain(); n != 0 { 3405 t.Fatalf("got e2.Drain() = %d, want = 0", n) 3406 } 3407 } else if ok { 3408 t.Fatalf("expected no ICMP packet through incoming NIC, instead found: %#v", reply) 3409 } 3410 3411 reply, ok = outgoingEndpoint.Read() 3412 if test.expectPacketForwarded { 3413 if !ok { 3414 t.Fatal("expected ICMP Echo Request packet through outgoing NIC") 3415 } 3416 3417 checker.IPv6WithExtHdr(t, stack.PayloadSince(reply.Pkt.NetworkHeader()), 3418 checker.SrcAddr(test.sourceAddr), 3419 checker.DstAddr(test.destAddr), 3420 checker.TTL(test.TTL-1), 3421 extHdrChecker, 3422 checker.ICMPv6( 3423 checker.ICMPv6Type(header.ICMPv6EchoRequest), 3424 checker.ICMPv6Code(header.ICMPv6UnusedCode), 3425 checker.ICMPv6Payload(nil), 3426 ), 3427 ) 3428 3429 if n := incomingEndpoint.Drain(); n != 0 { 3430 t.Fatalf("got e1.Drain() = %d, want = 0", n) 3431 } 3432 } else if ok { 3433 t.Fatalf("expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply) 3434 } 3435 3436 boolToInt := func(val bool) uint64 { 3437 if val { 3438 return 1 3439 } 3440 return 0 3441 } 3442 3443 if got, want := s.Stats().IP.Forwarding.LinkLocalSource.Value(), boolToInt(test.expectLinkLocalSourceError); got != want { 3444 t.Errorf("got s.Stats().IP.Forwarding.LinkLocalSource.Value() = %d, want = %d", got, want) 3445 } 3446 3447 if got, want := s.Stats().IP.Forwarding.LinkLocalDestination.Value(), boolToInt(test.expectLinkLocalDestError); got != want { 3448 t.Errorf("got s.Stats().IP.Forwarding.LinkLocalDestination.Value() = %d, want = %d", got, want) 3449 } 3450 3451 if got, want := s.Stats().IP.Forwarding.ExhaustedTTL.Value(), boolToInt(test.TTL <= 1); got != want { 3452 t.Errorf("got rt.Stats().IP.Forwarding.ExhaustedTTL.Value() = %d, want = %d", got, want) 3453 } 3454 3455 if got, want := s.Stats().IP.Forwarding.Unrouteable.Value(), boolToInt(test.expectPacketUnrouteableError); got != want { 3456 t.Errorf("got s.Stats().IP.Forwarding.Unrouteable.Value() = %d, want = %d", got, want) 3457 } 3458 3459 if got, want := s.Stats().IP.Forwarding.Errors.Value(), boolToInt(!test.expectPacketForwarded); got != want { 3460 t.Errorf("got s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want) 3461 } 3462 3463 if got, want := s.Stats().IP.Forwarding.ExtensionHeaderProblem.Value(), boolToInt(test.expectExtensionHeaderError); got != want { 3464 t.Errorf("got s.Stats().IP.Forwarding.ExtensionHeaderProblem.Value() = %d, want = %d", got, want) 3465 } 3466 3467 if got, want := s.Stats().IP.Forwarding.PacketTooBig.Value(), boolToInt(test.icmpType == header.ICMPv6PacketTooBig); got != want { 3468 t.Errorf("got s.Stats().IP.Forwarding.PacketTooBig.Value() = %d, want = %d", got, want) 3469 } 3470 }) 3471 } 3472 } 3473 3474 func TestMultiCounterStatsInitialization(t *testing.T) { 3475 s := stack.New(stack.Options{ 3476 NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol}, 3477 }) 3478 proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol) 3479 var nic testInterface 3480 ep := proto.NewEndpoint(&nic, nil).(*endpoint) 3481 // At this point, the Stack's stats and the NetworkEndpoint's stats are 3482 // supposed to be bound. 3483 refStack := s.Stats() 3484 refEP := ep.stats.localStats 3485 if err := testutil.ValidateMultiCounterStats(reflect.ValueOf(&ep.stats.ip).Elem(), []reflect.Value{reflect.ValueOf(&refStack.IP).Elem(), reflect.ValueOf(&refEP.IP).Elem()}); err != nil { 3486 t.Error(err) 3487 } 3488 if err := testutil.ValidateMultiCounterStats(reflect.ValueOf(&ep.stats.icmp).Elem(), []reflect.Value{reflect.ValueOf(&refStack.ICMP.V6).Elem(), reflect.ValueOf(&refEP.ICMP).Elem()}); err != nil { 3489 t.Error(err) 3490 } 3491 }