gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/ipv4/ipv4_test.go (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ipv4_test 16 17 import ( 18 "bytes" 19 "encoding/hex" 20 "fmt" 21 "io/ioutil" 22 "math" 23 "net" 24 "testing" 25 "time" 26 27 "github.com/google/go-cmp/cmp" 28 "github.com/google/go-cmp/cmp/cmpopts" 29 "gvisor.dev/gvisor/pkg/buffer" 30 "gvisor.dev/gvisor/pkg/refs" 31 "gvisor.dev/gvisor/pkg/sync" 32 "gvisor.dev/gvisor/pkg/tcpip" 33 "gvisor.dev/gvisor/pkg/tcpip/checker" 34 "gvisor.dev/gvisor/pkg/tcpip/checksum" 35 "gvisor.dev/gvisor/pkg/tcpip/faketime" 36 "gvisor.dev/gvisor/pkg/tcpip/header" 37 "gvisor.dev/gvisor/pkg/tcpip/link/channel" 38 "gvisor.dev/gvisor/pkg/tcpip/link/sniffer" 39 "gvisor.dev/gvisor/pkg/tcpip/network/arp" 40 iptestutil "gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil" 41 "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" 42 "gvisor.dev/gvisor/pkg/tcpip/prependable" 43 "gvisor.dev/gvisor/pkg/tcpip/stack" 44 "gvisor.dev/gvisor/pkg/tcpip/testutil" 45 "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" 46 "gvisor.dev/gvisor/pkg/tcpip/transport/raw" 47 "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" 48 "gvisor.dev/gvisor/pkg/tcpip/transport/udp" 49 "gvisor.dev/gvisor/pkg/waiter" 50 ) 51 52 const ( 53 extraHeaderReserve = 50 54 defaultMTU = 65536 55 ) 56 57 type testContext struct { 58 s *stack.Stack 59 clock *faketime.ManualClock 60 } 61 62 var _ stack.MulticastForwardingEventDispatcher = (*fakeMulticastEventDispatcher)(nil) 63 64 type fakeMulticastEventDispatcher struct{} 65 66 func (m *fakeMulticastEventDispatcher) OnMissingRoute(context stack.MulticastPacketContext) {} 67 68 func (m *fakeMulticastEventDispatcher) OnUnexpectedInputInterface(context stack.MulticastPacketContext, expectedInputInterface tcpip.NICID) { 69 } 70 71 func newTestContext() testContext { 72 clock := faketime.NewManualClock() 73 s := stack.New(stack.Options{ 74 NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol}, 75 TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol}, 76 Clock: clock, 77 RawFactory: raw.EndpointFactory{}, 78 }) 79 return testContext{s: s, clock: clock} 80 } 81 82 func (ctx testContext) cleanup() { 83 ctx.s.Close() 84 ctx.s.Wait() 85 refs.DoRepeatedLeakCheck() 86 } 87 88 func TestExcludeBroadcast(t *testing.T) { 89 ctx := newTestContext() 90 defer ctx.cleanup() 91 s := ctx.s 92 93 ch := channel.New(256, defaultMTU, "") 94 defer ch.Close() 95 ep := stack.LinkEndpoint(ch) 96 if testing.Verbose() { 97 ep = sniffer.New(ep) 98 } 99 if err := s.CreateNIC(1, ep); err != nil { 100 t.Fatalf("CreateNIC failed: %v", err) 101 } 102 103 s.SetRouteTable([]tcpip.Route{{ 104 Destination: header.IPv4EmptySubnet, 105 NIC: 1, 106 }}) 107 108 randomAddr := tcpip.FullAddress{NIC: 1, Addr: tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x01")), Port: 53} 109 110 var wq waiter.Queue 111 t.Run("WithoutPrimaryAddress", func(t *testing.T) { 112 ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 113 if err != nil { 114 t.Fatal(err) 115 } 116 defer ep.Close() 117 118 // Cannot connect using a broadcast address as the source. 119 { 120 err := ep.Connect(randomAddr) 121 if _, ok := err.(*tcpip.ErrHostUnreachable); !ok { 122 t.Errorf("got ep.Connect(...) = %v, want = %v", err, &tcpip.ErrHostUnreachable{}) 123 } 124 } 125 126 // However, we can bind to a broadcast address to listen. 127 if err := ep.Bind(tcpip.FullAddress{Addr: header.IPv4Broadcast, Port: 53, NIC: 1}); err != nil { 128 t.Errorf("Bind failed: %v", err) 129 } 130 }) 131 132 t.Run("WithPrimaryAddress", func(t *testing.T) { 133 ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 134 if err != nil { 135 t.Fatal(err) 136 } 137 defer ep.Close() 138 139 // Add a valid primary endpoint address, now we can connect. 140 protocolAddr := tcpip.ProtocolAddress{ 141 Protocol: ipv4.ProtocolNumber, 142 AddressWithPrefix: tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x02")).WithPrefix(), 143 } 144 if err := s.AddProtocolAddress(1, protocolAddr, stack.AddressProperties{}); err != nil { 145 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", 1, protocolAddr, err) 146 } 147 if err := ep.Connect(randomAddr); err != nil { 148 t.Errorf("Connect failed: %v", err) 149 } 150 }) 151 } 152 153 const ( 154 incomingNICID = 1 155 outgoingNICID = 2 156 ) 157 158 var ( 159 incomingIPv4Addr = tcpip.AddressWithPrefix{ 160 Address: testutil.MustParse4("10.0.0.1"), 161 PrefixLen: 8, 162 } 163 outgoingIPv4Addr = tcpip.AddressWithPrefix{ 164 Address: testutil.MustParse4("11.0.0.1"), 165 PrefixLen: 8, 166 } 167 defaultEndpointConfigs = map[tcpip.NICID]tcpip.AddressWithPrefix{ 168 incomingNICID: incomingIPv4Addr, 169 outgoingNICID: outgoingIPv4Addr, 170 } 171 multicastIPv4Addr = testutil.MustParse4("225.0.0.0") 172 remoteIPv4Addr1 = testutil.MustParse4("10.0.0.2") 173 remoteIPv4Addr2 = testutil.MustParse4("11.0.0.2") 174 ) 175 176 func TestAddMulticastRouteIPv4Errors(t *testing.T) { 177 incomingEpSubnet := incomingIPv4Addr.Subnet() 178 wantErr := &tcpip.ErrBadAddress{} 179 180 tests := []struct { 181 name string 182 srcAddr tcpip.Address 183 }{ 184 { 185 name: "subnet-local broadcast source", 186 srcAddr: incomingEpSubnet.Broadcast().To4(), 187 }, 188 { 189 name: "broadcast source", 190 srcAddr: header.IPv4Broadcast, 191 }, 192 } 193 194 for _, test := range tests { 195 t.Run(test.name, func(t *testing.T) { 196 ctx := newTestContext() 197 defer ctx.cleanup() 198 s := ctx.s 199 200 for nicID, addr := range defaultEndpointConfigs { 201 ep := channel.New(1, ipv4.MaxTotalSize, "") 202 defer ep.Close() 203 204 if err := s.CreateNIC(nicID, ep); err != nil { 205 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 206 } 207 addr := tcpip.ProtocolAddress{ 208 Protocol: header.IPv4ProtocolNumber, 209 AddressWithPrefix: addr, 210 } 211 if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil { 212 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err) 213 } 214 } 215 216 if _, err := s.EnableMulticastForwardingForProtocol(ipv4.ProtocolNumber, &fakeMulticastEventDispatcher{}); err != nil { 217 t.Fatalf("s.EnableMulticastForwardingForProtocol(%d, _): (_, %s)", ipv4.ProtocolNumber, err) 218 } 219 220 outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{{ID: outgoingNICID, MinTTL: 1}} 221 222 addresses := stack.UnicastSourceAndMulticastDestination{ 223 Source: test.srcAddr, 224 Destination: multicastIPv4Addr, 225 } 226 227 route := stack.MulticastRoute{ 228 ExpectedInputInterface: outgoingNICID, 229 OutgoingInterfaces: outgoingInterfaces, 230 } 231 232 err := s.AddMulticastRoute(ipv4.ProtocolNumber, addresses, route) 233 234 if !cmp.Equal(err, wantErr, cmpopts.EquateErrors()) { 235 t.Errorf("got s.AddMulticastRoute(%d, %#v, %#v) = %s, want %s", ipv4.ProtocolNumber, addresses, route, err, wantErr) 236 } 237 }) 238 } 239 } 240 241 type icmpError struct { 242 icmpType header.ICMPv4Type 243 icmpCode header.ICMPv4Code 244 } 245 246 type packetOptions struct { 247 ipFlags uint8 248 payloadLength int 249 options header.IPv4Options 250 } 251 252 func newICMPEchoPacket(t *testing.T, srcAddr, dstAddr tcpip.Address, ttl uint8, options packetOptions) (*stack.PacketBuffer, []byte) { 253 const ( 254 arbitraryICMPHeaderSequence = 123 255 randomIdent = 42 256 ) 257 258 t.Helper() 259 ipHeaderLength := header.IPv4MinimumSize + len(options.options) 260 if ipHeaderLength > header.IPv4MaximumHeaderSize { 261 t.Fatalf("ipHeaderLength = %d, want <= %d ", ipHeaderLength, header.IPv4MaximumHeaderSize) 262 } 263 totalLength := ipHeaderLength + header.ICMPv4MinimumSize + options.payloadLength 264 hdr := prependable.New(totalLength) 265 hdr.Prepend(options.payloadLength) 266 icmpH := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize)) 267 icmpH.SetIdent(randomIdent) 268 icmpH.SetSequence(arbitraryICMPHeaderSequence) 269 icmpH.SetType(header.ICMPv4Echo) 270 icmpH.SetCode(header.ICMPv4UnusedCode) 271 icmpH.SetChecksum(0) 272 icmpH.SetChecksum(^checksum.Checksum(icmpH, 0)) 273 ip := header.IPv4(hdr.Prepend(ipHeaderLength)) 274 ip.Encode(&header.IPv4Fields{ 275 TotalLength: uint16(totalLength), 276 Protocol: uint8(header.ICMPv4ProtocolNumber), 277 TTL: ttl, 278 SrcAddr: srcAddr, 279 DstAddr: dstAddr, 280 Flags: options.ipFlags, 281 }) 282 if len(options.options) != 0 { 283 ip.SetHeaderLength(uint8(ipHeaderLength)) 284 // Copy options manually. We do not use Encode for options so we can 285 // verify malformed options with handcrafted payloads. 286 if want, got := copy(ip.Options(), options.options), len(options.options); want != got { 287 t.Fatalf("got copy(ip.Options(), test.options) = %d, want = %d", got, want) 288 } 289 } 290 ip.SetChecksum(0) 291 ip.SetChecksum(^ip.CalculateChecksum()) 292 293 expectedICMPPayloadLength := func() int { 294 maxICMPPacketLength := header.IPv4MinimumProcessableDatagramSize 295 maxICMPPayloadLength := maxICMPPacketLength - header.ICMPv4MinimumSize - header.IPv4MinimumSize 296 if len(hdr.View()) > maxICMPPayloadLength { 297 return maxICMPPayloadLength 298 } 299 return len(hdr.View()) 300 } 301 302 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 303 Payload: buffer.MakeWithData(hdr.View()), 304 }) 305 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 306 307 return pkt, hdr.View()[:expectedICMPPayloadLength()] 308 } 309 310 func max(a, b int) int { 311 if a > b { 312 return a 313 } 314 return b 315 } 316 317 func checkFragements(t *testing.T, ep *channel.Endpoint, expectedFragments []fragmentInfo, requestPkt *stack.PacketBuffer) { 318 t.Helper() 319 var fragmentedPackets []*stack.PacketBuffer 320 for i := 0; i < len(expectedFragments); i++ { 321 reply := ep.Read() 322 if reply == nil { 323 t.Fatal("Expected ICMP Echo fragment through outgoing NIC") 324 } 325 fragmentedPackets = append(fragmentedPackets, reply) 326 } 327 328 // The forwarded packet's TTL will have been decremented. 329 ipHeader := header.IPv4(requestPkt.NetworkHeader().Slice()) 330 ipHeader.SetTTL(ipHeader.TTL() - 1) 331 332 // Forwarded packets have available header bytes equalling the sum of the 333 // maximum IP header size and the maximum size allocated for link layer 334 // headers. In this case, no size is allocated for link layer headers. 335 expectedAvailableHeaderBytes := header.IPv4MaximumHeaderSize 336 if err := compareFragments(fragmentedPackets, requestPkt, defaultMTU, expectedFragments, header.ICMPv4ProtocolNumber, true /* withIPHeader */, expectedAvailableHeaderBytes); err != nil { 337 t.Error(err) 338 } 339 for _, pkt := range fragmentedPackets { 340 pkt.DecRef() 341 } 342 } 343 344 func TestForwarding(t *testing.T) { 345 const randomTimeOffset = 0x10203040 346 347 unreachableIPv4Addr := testutil.MustParse4("12.0.0.2") 348 linkLocalIPv4Addr := testutil.MustParse4("169.254.0.0") 349 350 tests := []struct { 351 name string 352 TTL uint8 353 srcAddr tcpip.Address 354 dstAddr tcpip.Address 355 options header.IPv4Options 356 forwardedOptions header.IPv4Options 357 icmpError *icmpError 358 expectedPacketUnrouteableErrors uint64 359 expectedInitializingSourceErrors uint64 360 expectedLinkLocalSourceErrors uint64 361 expectedLinkLocalDestErrors uint64 362 expectedMalformedPacketErrors uint64 363 expectedExhaustedTTLErrors uint64 364 expectPacketForwarded bool 365 }{ 366 { 367 name: "TTL of zero", 368 TTL: 0, 369 srcAddr: remoteIPv4Addr1, 370 dstAddr: remoteIPv4Addr2, 371 icmpError: &icmpError{ 372 icmpType: header.ICMPv4TimeExceeded, 373 icmpCode: header.ICMPv4TTLExceeded, 374 }, 375 expectedExhaustedTTLErrors: 1, 376 expectPacketForwarded: false, 377 }, 378 { 379 name: "TTL of one", 380 TTL: 1, 381 srcAddr: remoteIPv4Addr1, 382 dstAddr: remoteIPv4Addr2, 383 expectPacketForwarded: true, 384 }, 385 { 386 name: "TTL of two", 387 TTL: 2, 388 srcAddr: remoteIPv4Addr1, 389 dstAddr: remoteIPv4Addr2, 390 expectPacketForwarded: true, 391 }, 392 { 393 name: "Max TTL", 394 TTL: math.MaxUint8, 395 srcAddr: remoteIPv4Addr1, 396 dstAddr: remoteIPv4Addr2, 397 expectPacketForwarded: true, 398 }, 399 { 400 name: "four EOL options", 401 TTL: 2, 402 srcAddr: remoteIPv4Addr1, 403 dstAddr: remoteIPv4Addr2, 404 options: header.IPv4Options{0, 0, 0, 0}, 405 forwardedOptions: header.IPv4Options{0, 0, 0, 0}, 406 expectPacketForwarded: true, 407 }, 408 { 409 name: "TS type 1 full", 410 TTL: 2, 411 srcAddr: remoteIPv4Addr1, 412 dstAddr: remoteIPv4Addr2, 413 options: header.IPv4Options{ 414 68, 12, 13, 0xF1, 415 192, 168, 1, 12, 416 1, 2, 3, 4, 417 }, 418 icmpError: &icmpError{ 419 icmpType: header.ICMPv4ParamProblem, 420 icmpCode: header.ICMPv4UnusedCode, 421 }, 422 expectedMalformedPacketErrors: 1, 423 }, 424 { 425 name: "TS type 0", 426 TTL: 2, 427 srcAddr: remoteIPv4Addr1, 428 dstAddr: remoteIPv4Addr2, 429 options: header.IPv4Options{ 430 68, 24, 21, 0x00, 431 1, 2, 3, 4, 432 5, 6, 7, 8, 433 9, 10, 11, 12, 434 13, 14, 15, 16, 435 0, 0, 0, 0, 436 }, 437 forwardedOptions: header.IPv4Options{ 438 68, 24, 25, 0x00, 439 1, 2, 3, 4, 440 5, 6, 7, 8, 441 9, 10, 11, 12, 442 13, 14, 15, 16, 443 0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock 444 }, 445 expectPacketForwarded: true, 446 }, 447 { 448 name: "end of options list", 449 TTL: 2, 450 srcAddr: remoteIPv4Addr1, 451 dstAddr: remoteIPv4Addr2, 452 options: header.IPv4Options{ 453 68, 12, 13, 0x11, 454 192, 168, 1, 12, 455 1, 2, 3, 4, 456 0, 10, 3, 99, // EOL followed by junk 457 1, 2, 3, 4, 458 }, 459 forwardedOptions: header.IPv4Options{ 460 68, 12, 13, 0x21, 461 192, 168, 1, 12, 462 1, 2, 3, 4, 463 0, // End of Options hides following bytes. 464 0, 0, 0, // 7 bytes unknown option removed. 465 0, 0, 0, 0, 466 }, 467 expectPacketForwarded: true, 468 }, 469 { 470 name: "Network unreachable", 471 TTL: 2, 472 srcAddr: remoteIPv4Addr1, 473 dstAddr: unreachableIPv4Addr, 474 icmpError: &icmpError{ 475 icmpType: header.ICMPv4DstUnreachable, 476 icmpCode: header.ICMPv4NetUnreachable, 477 }, 478 expectedPacketUnrouteableErrors: 1, 479 expectPacketForwarded: false, 480 }, 481 { 482 name: "Link local destination", 483 TTL: 2, 484 srcAddr: remoteIPv4Addr1, 485 dstAddr: linkLocalIPv4Addr, 486 expectedLinkLocalDestErrors: 1, 487 expectPacketForwarded: false, 488 }, 489 { 490 name: "Link local source", 491 TTL: 2, 492 srcAddr: linkLocalIPv4Addr, 493 dstAddr: remoteIPv4Addr2, 494 expectedLinkLocalSourceErrors: 1, 495 expectPacketForwarded: false, 496 }, 497 { 498 name: "unspecified source", 499 TTL: 2, 500 srcAddr: header.IPv4Any, 501 dstAddr: remoteIPv4Addr2, 502 expectedInitializingSourceErrors: 1, 503 expectPacketForwarded: false, 504 }, 505 { 506 name: "initializing source", 507 TTL: 2, 508 srcAddr: tcpip.AddrFromSlice(net.ParseIP("0.0.0.255").To4()), 509 dstAddr: remoteIPv4Addr2, 510 expectedInitializingSourceErrors: 1, 511 expectPacketForwarded: false, 512 }, 513 } 514 for _, test := range tests { 515 t.Run(test.name, func(t *testing.T) { 516 ctx := newTestContext() 517 defer ctx.cleanup() 518 s := ctx.s 519 clock := ctx.clock 520 521 // Advance the clock by some unimportant amount to make 522 // it give a more recognisable signature than 00,00,00,00. 523 clock.Advance(time.Millisecond * randomTimeOffset) 524 525 endpoints := make(map[tcpip.NICID]*channel.Endpoint) 526 for nicID, addr := range defaultEndpointConfigs { 527 ep := channel.New(1, ipv4.MaxTotalSize, "") 528 defer ep.Close() 529 530 if err := s.CreateNIC(nicID, ep); err != nil { 531 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 532 } 533 addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr} 534 if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil { 535 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err) 536 } 537 endpoints[nicID] = ep 538 } 539 540 s.SetRouteTable([]tcpip.Route{ 541 { 542 Destination: incomingIPv4Addr.Subnet(), 543 NIC: incomingNICID, 544 }, 545 { 546 Destination: outgoingIPv4Addr.Subnet(), 547 NIC: outgoingNICID, 548 }, 549 }) 550 551 if err := s.SetForwardingDefaultAndAllNICs(header.IPv4ProtocolNumber, true); err != nil { 552 t.Fatalf("s.SetForwardingDefaultAndAllNICs(%d, true): %s", header.IPv4ProtocolNumber, err) 553 } 554 555 requestPkt, expectedICMPErrorPayload := newICMPEchoPacket(t, test.srcAddr, test.dstAddr, test.TTL, packetOptions{options: test.options}) 556 defer requestPkt.DecRef() 557 558 incomingEndpoint, ok := endpoints[incomingNICID] 559 if !ok { 560 t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID) 561 } 562 incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt) 563 reply := incomingEndpoint.Read() 564 565 if test.icmpError != nil { 566 if reply == nil { 567 t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.icmpError.icmpType) 568 } 569 570 payload := stack.PayloadSince(reply.NetworkHeader()) 571 defer payload.Release() 572 checker.IPv4(t, payload, 573 checker.SrcAddr(incomingIPv4Addr.Address), 574 checker.DstAddr(test.srcAddr), 575 checker.TTL(ipv4.DefaultTTL), 576 checker.ICMPv4( 577 checker.ICMPv4Checksum(), 578 checker.ICMPv4Type(test.icmpError.icmpType), 579 checker.ICMPv4Code(test.icmpError.icmpCode), 580 checker.ICMPv4Payload(expectedICMPErrorPayload), 581 ), 582 ) 583 reply.DecRef() 584 } else if reply != nil { 585 t.Fatalf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply) 586 } 587 588 outgoingEndpoint, ok := endpoints[outgoingNICID] 589 if !ok { 590 t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID) 591 } 592 593 if test.expectPacketForwarded { 594 reply := outgoingEndpoint.Read() 595 if reply == nil { 596 t.Fatal("Expected ICMP Echo packet through outgoing NIC") 597 } 598 599 payload := stack.PayloadSince(reply.NetworkHeader()) 600 defer payload.Release() 601 checker.IPv4(t, payload, 602 checker.SrcAddr(test.srcAddr), 603 checker.DstAddr(test.dstAddr), 604 checker.TTL(test.TTL-1), 605 checker.IPv4Options(test.forwardedOptions), 606 checker.ICMPv4( 607 checker.ICMPv4Checksum(), 608 checker.ICMPv4Type(header.ICMPv4Echo), 609 checker.ICMPv4Code(header.ICMPv4UnusedCode), 610 checker.ICMPv4Payload(nil), 611 ), 612 ) 613 reply.DecRef() 614 } else { 615 if reply := outgoingEndpoint.Read(); reply != nil { 616 t.Fatalf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply) 617 } 618 } 619 620 if got, want := s.Stats().IP.Forwarding.InitializingSource.Value(), test.expectedInitializingSourceErrors; got != want { 621 t.Errorf("s.Stats().IP.Forwarding.InitializingSource.Value() = %d, want = %d", got, want) 622 } 623 624 if got, want := s.Stats().IP.Forwarding.LinkLocalSource.Value(), test.expectedLinkLocalSourceErrors; got != want { 625 t.Errorf("s.Stats().IP.Forwarding.LinkLocalSource.Value() = %d, want = %d", got, want) 626 } 627 628 if got, want := s.Stats().IP.Forwarding.LinkLocalDestination.Value(), test.expectedLinkLocalDestErrors; got != want { 629 t.Errorf("s.Stats().IP.Forwarding.LinkLocalDestination.Value() = %d, want = %d", got, want) 630 } 631 632 if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.expectedMalformedPacketErrors; got != want { 633 t.Errorf("s.Stats().IP.MalformedPacketsReceived.Value() = %d, want = %d", got, want) 634 } 635 636 if got, want := s.Stats().IP.Forwarding.ExhaustedTTL.Value(), test.expectedExhaustedTTLErrors; got != want { 637 t.Errorf("s.Stats().IP.Forwarding.ExhaustedTTL.Value() = %d, want = %d", got, want) 638 } 639 640 if got, want := s.Stats().IP.Forwarding.Unrouteable.Value(), test.expectedPacketUnrouteableErrors; got != want { 641 t.Errorf("s.Stats().IP.Forwarding.Unrouteable.Value() = %d, want = %d", got, want) 642 } 643 644 expectedTotalErrors := test.expectedLinkLocalSourceErrors + test.expectedLinkLocalDestErrors + test.expectedMalformedPacketErrors + test.expectedExhaustedTTLErrors + test.expectedPacketUnrouteableErrors + test.expectedInitializingSourceErrors 645 if got, want := s.Stats().IP.Forwarding.Errors.Value(), expectedTotalErrors; got != want { 646 t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want) 647 } 648 }) 649 } 650 } 651 652 func TestFragmentForwarding(t *testing.T) { 653 const ( 654 defaultMTU = 1000 655 defaultPayloadLength = defaultMTU + 4 656 packetTTL = 2 657 ) 658 659 tests := []struct { 660 name string 661 ipFlags uint8 662 icmpError *icmpError 663 expectedPacketTooBigErrors uint64 664 expectedFragmentsForwarded []fragmentInfo 665 }{ 666 { 667 name: "Fragmentation needed and DF set", 668 ipFlags: header.IPv4FlagDontFragment, 669 // We've picked this MTU because it is: 670 // 671 // 1) Greater than the minimum MTU that IPv4 hosts are required to process 672 // (576 bytes). As per RFC 1812, Section 4.3.2.3: 673 // 674 // The ICMP datagram SHOULD contain as much of the original datagram as 675 // possible without the length of the ICMP datagram exceeding 576 bytes. 676 // 677 // Therefore, setting an MTU greater than 576 bytes ensures that we can fit a 678 // complete ICMP packet on the incoming endpoint (and make assertions about 679 // it). 680 // 681 // 2) Less than `ipv4.MaxTotalSize`, which lets us build an IPv4 packet whose 682 // size exceeds the MTU. 683 icmpError: &icmpError{ 684 icmpType: header.ICMPv4DstUnreachable, 685 icmpCode: header.ICMPv4FragmentationNeeded, 686 }, 687 expectedFragmentsForwarded: []fragmentInfo{}, 688 expectedPacketTooBigErrors: 1, 689 }, 690 { 691 name: "Fragmentation needed and DF not set", 692 expectedFragmentsForwarded: []fragmentInfo{ 693 // The first fragment has a length of the greatest multiple of 8 which is 694 // less than or equal to to `mtu - header.IPv4MinimumSize`. 695 {offset: 0, payloadSize: uint16(976), more: true}, 696 // The next fragment holds the rest of the packet. 697 {offset: uint16(976), payloadSize: 36, more: false}, 698 }, 699 }, 700 } 701 for _, test := range tests { 702 t.Run(test.name, func(t *testing.T) { 703 ctx := newTestContext() 704 defer ctx.cleanup() 705 s := ctx.s 706 707 endpoints := make(map[tcpip.NICID]*channel.Endpoint) 708 for nicID, addr := range defaultEndpointConfigs { 709 // For the input interface, we expect at most a single packet in 710 // response to our ICMP Echo Request. 711 expectedEmittedPacketCount := 1 712 713 if nicID == outgoingNICID { 714 expectedEmittedPacketCount = max(1, len(test.expectedFragmentsForwarded)) 715 } 716 717 ep := channel.New(expectedEmittedPacketCount, defaultMTU, "") 718 defer ep.Close() 719 720 if err := s.CreateNIC(nicID, ep); err != nil { 721 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 722 } 723 addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr} 724 if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil { 725 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err) 726 } 727 endpoints[nicID] = ep 728 } 729 730 s.SetRouteTable([]tcpip.Route{ 731 { 732 Destination: incomingIPv4Addr.Subnet(), 733 NIC: incomingNICID, 734 }, 735 { 736 Destination: outgoingIPv4Addr.Subnet(), 737 NIC: outgoingNICID, 738 }, 739 }) 740 741 if err := s.SetForwardingDefaultAndAllNICs(header.IPv4ProtocolNumber, true); err != nil { 742 t.Fatalf("s.SetForwardingDefaultAndAllNICs(%d, true): %s", header.IPv4ProtocolNumber, err) 743 } 744 745 requestPkt, expectedICMPErrorPayload := newICMPEchoPacket(t, remoteIPv4Addr1, remoteIPv4Addr2, packetTTL, packetOptions{ipFlags: test.ipFlags, payloadLength: defaultPayloadLength}) 746 defer requestPkt.DecRef() 747 748 incomingEndpoint, ok := endpoints[incomingNICID] 749 if !ok { 750 t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID) 751 } 752 incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt) 753 reply := incomingEndpoint.Read() 754 755 if test.icmpError != nil { 756 if reply == nil { 757 t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.icmpError.icmpType) 758 } 759 760 payload := stack.PayloadSince(reply.NetworkHeader()) 761 defer payload.Release() 762 checker.IPv4(t, payload, 763 checker.SrcAddr(incomingIPv4Addr.Address), 764 checker.DstAddr(remoteIPv4Addr1), 765 checker.TTL(ipv4.DefaultTTL), 766 checker.ICMPv4( 767 checker.ICMPv4Checksum(), 768 checker.ICMPv4Type(test.icmpError.icmpType), 769 checker.ICMPv4Code(test.icmpError.icmpCode), 770 checker.ICMPv4Payload(expectedICMPErrorPayload), 771 ), 772 ) 773 reply.DecRef() 774 } else if reply != nil { 775 t.Fatalf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply) 776 } 777 778 outgoingEndpoint, ok := endpoints[outgoingNICID] 779 if !ok { 780 t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID) 781 } 782 783 if len(test.expectedFragmentsForwarded) > 0 { 784 checkFragements(t, outgoingEndpoint, test.expectedFragmentsForwarded, requestPkt) 785 } else { 786 if reply := outgoingEndpoint.Read(); reply != nil { 787 t.Errorf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply) 788 } 789 } 790 791 if got, want := s.Stats().IP.Forwarding.PacketTooBig.Value(), test.expectedPacketTooBigErrors; got != want { 792 t.Errorf("s.Stats().IP.Forwarding.PacketTooBig.Value() = %d, want = %d", got, want) 793 } 794 795 if got, want := s.Stats().IP.Forwarding.Errors.Value(), test.expectedPacketTooBigErrors; got != want { 796 t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want) 797 } 798 }) 799 } 800 } 801 802 func TestMulticastFragmentForwarding(t *testing.T) { 803 const ( 804 defaultMTU = 1000 805 defaultPayloadLength = defaultMTU + 4 806 packetTTL = 2 807 multicastRouteMinTTL = 2 808 ) 809 810 tests := []struct { 811 name string 812 ipFlags uint8 813 icmpError *icmpError 814 expectedPacketTooBigErrors uint64 815 expectedFragmentsForwarded []fragmentInfo 816 }{ 817 { 818 name: "Fragmentation needed and DF set", 819 ipFlags: header.IPv4FlagDontFragment, 820 // We've picked this MTU because it is: 821 // 822 // 1) Greater than the minimum MTU that IPv4 hosts are required to process 823 // (576 bytes). As per RFC 1812, Section 4.3.2.3: 824 // 825 // The ICMP datagram SHOULD contain as much of the original datagram as 826 // possible without the length of the ICMP datagram exceeding 576 bytes. 827 // 828 // Therefore, setting an MTU greater than 576 bytes ensures that we can fit a 829 // complete ICMP packet on the incoming endpoint (and make assertions about 830 // it). 831 // 832 // 2) Less than `ipv4.MaxTotalSize`, which lets us build an IPv4 packet whose 833 // size exceeds the MTU. 834 icmpError: &icmpError{ 835 icmpType: header.ICMPv4DstUnreachable, 836 icmpCode: header.ICMPv4FragmentationNeeded, 837 }, 838 expectedFragmentsForwarded: []fragmentInfo{}, 839 expectedPacketTooBigErrors: 1, 840 }, 841 { 842 name: "Fragmentation needed and DF not set", 843 expectedFragmentsForwarded: []fragmentInfo{ 844 // The first fragment has a length of the greatest multiple of 8 which is 845 // less than or equal to to `mtu - header.IPv4MinimumSize`. 846 {offset: 0, payloadSize: uint16(976), more: true}, 847 // The next fragment holds the rest of the packet. 848 {offset: uint16(976), payloadSize: 36, more: false}, 849 }, 850 }, 851 } 852 for _, test := range tests { 853 t.Run(test.name, func(t *testing.T) { 854 ctx := newTestContext() 855 defer ctx.cleanup() 856 s := ctx.s 857 858 if _, err := s.EnableMulticastForwardingForProtocol(ipv4.ProtocolNumber, &fakeMulticastEventDispatcher{}); err != nil { 859 t.Fatalf("s.EnableMulticastForwardingForProtocol(%d, _): (_, %s)", ipv4.ProtocolNumber, err) 860 } 861 862 endpoints := make(map[tcpip.NICID]*channel.Endpoint) 863 for nicID, addr := range defaultEndpointConfigs { 864 // For the input interface, we expect at most a single packet in 865 // response to our ICMP Echo Request. 866 expectedEmittedPacketCount := 1 867 868 if nicID == outgoingNICID { 869 expectedEmittedPacketCount = max(1, len(test.expectedFragmentsForwarded)) 870 } 871 872 ep := channel.New(expectedEmittedPacketCount, defaultMTU, "") 873 defer ep.Close() 874 875 if err := s.CreateNIC(nicID, ep); err != nil { 876 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 877 } 878 addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr} 879 if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil { 880 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err) 881 } 882 s.SetNICMulticastForwarding(nicID, ipv4.ProtocolNumber, true /* enabled */) 883 endpoints[nicID] = ep 884 } 885 886 // Add a route that could theoretically be used to send an ICMP error. 887 // Note that such an error should never be sent for multicast. 888 s.SetRouteTable([]tcpip.Route{ 889 { 890 Destination: header.IPv4EmptySubnet, 891 NIC: outgoingNICID, 892 }, 893 }) 894 895 outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{ 896 {ID: outgoingNICID, MinTTL: multicastRouteMinTTL}, 897 } 898 addresses := stack.UnicastSourceAndMulticastDestination{ 899 Source: remoteIPv4Addr1, 900 Destination: multicastIPv4Addr, 901 } 902 903 route := stack.MulticastRoute{ 904 ExpectedInputInterface: incomingNICID, 905 OutgoingInterfaces: outgoingInterfaces, 906 } 907 908 if err := s.AddMulticastRoute(ipv4.ProtocolNumber, addresses, route); err != nil { 909 t.Fatalf("s.AddMulticastRoute(%d, %#v, %#v): %s", ipv4.ProtocolNumber, addresses, route, err) 910 } 911 912 requestPkt, _ := newICMPEchoPacket(t, remoteIPv4Addr1, multicastIPv4Addr, packetTTL, packetOptions{ipFlags: test.ipFlags, payloadLength: defaultPayloadLength}) 913 defer requestPkt.DecRef() 914 915 incomingEndpoint, ok := endpoints[incomingNICID] 916 if !ok { 917 t.Fatalf("got endpoints[%d] = (_, false), want (_, true)", incomingNICID) 918 } 919 incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt) 920 reply := incomingEndpoint.Read() 921 922 if reply != nil { 923 // An ICMP error should never be sent in response to a multicast packet. 924 t.Errorf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply) 925 } 926 927 outgoingEndpoint, ok := endpoints[outgoingNICID] 928 if !ok { 929 t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID) 930 } 931 932 if len(test.expectedFragmentsForwarded) > 0 { 933 checkFragements(t, outgoingEndpoint, test.expectedFragmentsForwarded, requestPkt) 934 } else { 935 if reply := outgoingEndpoint.Read(); reply != nil { 936 t.Errorf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply) 937 } 938 } 939 940 if got, want := s.Stats().IP.Forwarding.PacketTooBig.Value(), test.expectedPacketTooBigErrors; got != want { 941 t.Errorf("s.Stats().IP.Forwarding.PacketTooBig.Value() = %d, want = %d", got, want) 942 } 943 944 if got, want := s.Stats().IP.Forwarding.Errors.Value(), test.expectedPacketTooBigErrors; got != want { 945 t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want) 946 } 947 }) 948 } 949 } 950 951 func TestMulticastForwardingOptions(t *testing.T) { 952 const ( 953 randomTimeOffset = 0x10203040 954 packetTTL = 2 955 multicastRouteMinTTL = 2 956 ) 957 958 tests := []struct { 959 name string 960 options header.IPv4Options 961 forwardedOptions header.IPv4Options 962 expectedMalformedPacketErrors uint64 963 expectPacketForwarded bool 964 }{ 965 { 966 name: "four EOL options", 967 options: header.IPv4Options{0, 0, 0, 0}, 968 forwardedOptions: header.IPv4Options{0, 0, 0, 0}, 969 expectPacketForwarded: true, 970 }, 971 { 972 name: "TS type 1 full", 973 options: header.IPv4Options{ 974 68, 12, 13, 0xF1, 975 192, 168, 1, 12, 976 1, 2, 3, 4, 977 }, 978 expectedMalformedPacketErrors: 1, 979 }, 980 { 981 name: "TS type 0", 982 options: header.IPv4Options{ 983 68, 24, 21, 0x00, 984 1, 2, 3, 4, 985 5, 6, 7, 8, 986 9, 10, 11, 12, 987 13, 14, 15, 16, 988 0, 0, 0, 0, 989 }, 990 forwardedOptions: header.IPv4Options{ 991 68, 24, 25, 0x00, 992 1, 2, 3, 4, 993 5, 6, 7, 8, 994 9, 10, 11, 12, 995 13, 14, 15, 16, 996 0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock 997 }, 998 expectPacketForwarded: true, 999 }, 1000 { 1001 name: "end of options list", 1002 options: header.IPv4Options{ 1003 68, 12, 13, 0x11, 1004 192, 168, 1, 12, 1005 1, 2, 3, 4, 1006 0, 10, 3, 99, // EOL followed by junk 1007 1, 2, 3, 4, 1008 }, 1009 forwardedOptions: header.IPv4Options{ 1010 68, 12, 13, 0x21, 1011 192, 168, 1, 12, 1012 1, 2, 3, 4, 1013 0, // End of Options hides following bytes. 1014 0, 0, 0, // 7 bytes unknown option removed. 1015 0, 0, 0, 0, 1016 }, 1017 expectPacketForwarded: true, 1018 }, 1019 } 1020 for _, test := range tests { 1021 t.Run(test.name, func(t *testing.T) { 1022 ctx := newTestContext() 1023 defer ctx.cleanup() 1024 s := ctx.s 1025 clock := ctx.clock 1026 1027 // Advance the clock by some unimportant amount to make 1028 // it give a more recognisable signature than 00,00,00,00. 1029 clock.Advance(time.Millisecond * randomTimeOffset) 1030 1031 if _, err := s.EnableMulticastForwardingForProtocol(ipv4.ProtocolNumber, &fakeMulticastEventDispatcher{}); err != nil { 1032 t.Fatalf("s.EnableMulticastForwardingForProtocol(%d, _): (_, %s)", ipv4.ProtocolNumber, err) 1033 } 1034 1035 endpoints := make(map[tcpip.NICID]*channel.Endpoint) 1036 for nicID, addr := range defaultEndpointConfigs { 1037 ep := channel.New(1, ipv4.MaxTotalSize, "") 1038 defer ep.Close() 1039 1040 if err := s.CreateNIC(nicID, ep); err != nil { 1041 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 1042 } 1043 addr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: addr} 1044 if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil { 1045 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err) 1046 } 1047 s.SetNICMulticastForwarding(nicID, ipv4.ProtocolNumber, true /* enabled */) 1048 endpoints[nicID] = ep 1049 } 1050 1051 // Add a route that could theoretically be used to send an ICMP error. 1052 // Note that such an error should never be sent for multicast. 1053 s.SetRouteTable([]tcpip.Route{ 1054 { 1055 Destination: header.IPv4EmptySubnet, 1056 NIC: outgoingNICID, 1057 }, 1058 }) 1059 1060 outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{ 1061 {ID: outgoingNICID, MinTTL: multicastRouteMinTTL}, 1062 } 1063 addresses := stack.UnicastSourceAndMulticastDestination{ 1064 Source: remoteIPv4Addr1, 1065 Destination: multicastIPv4Addr, 1066 } 1067 1068 route := stack.MulticastRoute{ 1069 ExpectedInputInterface: incomingNICID, 1070 OutgoingInterfaces: outgoingInterfaces, 1071 } 1072 1073 if err := s.AddMulticastRoute(ipv4.ProtocolNumber, addresses, route); err != nil { 1074 t.Fatalf("s.AddMulticastRoute(%d, %#v, %#v): %s", ipv4.ProtocolNumber, addresses, route, err) 1075 } 1076 1077 requestPkt, _ := newICMPEchoPacket(t, remoteIPv4Addr1, multicastIPv4Addr, packetTTL, packetOptions{options: test.options}) 1078 defer requestPkt.DecRef() 1079 1080 incomingEndpoint, ok := endpoints[incomingNICID] 1081 if !ok { 1082 t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID) 1083 } 1084 incomingEndpoint.InjectInbound(header.IPv4ProtocolNumber, requestPkt) 1085 reply := incomingEndpoint.Read() 1086 1087 if reply != nil { 1088 // An ICMP error should never be sent in response to a multicast packet. 1089 t.Errorf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply) 1090 } 1091 1092 outgoingEndpoint, ok := endpoints[outgoingNICID] 1093 if !ok { 1094 t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID) 1095 } 1096 1097 if test.expectPacketForwarded { 1098 reply := outgoingEndpoint.Read() 1099 if reply == nil { 1100 t.Fatal("Expected ICMP Echo packet through outgoing NIC") 1101 } 1102 1103 payload := stack.PayloadSince(reply.NetworkHeader()) 1104 defer payload.Release() 1105 checker.IPv4(t, payload, 1106 checker.SrcAddr(remoteIPv4Addr1), 1107 checker.DstAddr(multicastIPv4Addr), 1108 checker.TTL(packetTTL-1), 1109 checker.IPv4Options(test.forwardedOptions), 1110 checker.ICMPv4( 1111 checker.ICMPv4Checksum(), 1112 checker.ICMPv4Type(header.ICMPv4Echo), 1113 checker.ICMPv4Code(header.ICMPv4UnusedCode), 1114 checker.ICMPv4Payload(nil), 1115 ), 1116 ) 1117 reply.DecRef() 1118 } else { 1119 if reply := outgoingEndpoint.Read(); reply != nil { 1120 t.Fatalf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply) 1121 } 1122 } 1123 1124 if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.expectedMalformedPacketErrors; got != want { 1125 t.Errorf("s.Stats().IP.MalformedPacketsReceived.Value() = %d, want = %d", got, want) 1126 } 1127 1128 if got, want := s.Stats().IP.Forwarding.Errors.Value(), test.expectedMalformedPacketErrors; got != want { 1129 t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want) 1130 } 1131 }) 1132 } 1133 } 1134 1135 // TestIPv4Sanity sends IP/ICMP packets with various problems to the stack and 1136 // checks the response. 1137 func TestIPv4Sanity(t *testing.T) { 1138 const ( 1139 ttl = 255 1140 nicID = 1 1141 randomSequence = 123 1142 randomIdent = 42 1143 // In some cases Linux sets the error pointer to the start of the option 1144 // (offset 0) instead of the actual wrong value, which is the length byte 1145 // (offset 1). For compatibility we must do the same. Use this constant 1146 // to indicate where this happens. 1147 pointerOffsetForInvalidLength = 0 1148 randomTimeOffset = 0x10203040 1149 ) 1150 var ( 1151 ipv4Addr = tcpip.AddressWithPrefix{ 1152 Address: tcpip.AddrFromSlice(net.ParseIP("192.168.1.58").To4()), 1153 PrefixLen: 24, 1154 } 1155 remoteIPv4Addr = tcpip.AddrFromSlice(net.ParseIP("10.0.0.1").To4()) 1156 ) 1157 1158 tests := []struct { 1159 name string 1160 headerLength uint8 // value of 0 means "use correct size" 1161 badHeaderChecksum bool 1162 maxTotalLength uint16 1163 transportProtocol uint8 1164 TTL uint8 1165 options header.IPv4Options 1166 replyOptions header.IPv4Options // reply should look like this 1167 shouldFail bool 1168 expectErrorICMP bool 1169 ICMPType header.ICMPv4Type 1170 ICMPCode header.ICMPv4Code 1171 paramProblemPointer uint8 1172 }{ 1173 { 1174 name: "valid no options", 1175 maxTotalLength: ipv4.MaxTotalSize, 1176 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1177 TTL: ttl, 1178 }, 1179 { 1180 name: "bad header checksum", 1181 maxTotalLength: ipv4.MaxTotalSize, 1182 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1183 TTL: ttl, 1184 badHeaderChecksum: true, 1185 shouldFail: true, 1186 }, 1187 // The TTL tests check that we are not rejecting an incoming packet 1188 // with a zero or one TTL, which has been a point of confusion in the 1189 // past as RFC 791 says: "If this field contains the value zero, then the 1190 // datagram must be destroyed". However RFC 1122 section 3.2.1.7 clarifies 1191 // for the case of the destination host, stating as follows. 1192 // 1193 // A host MUST NOT send a datagram with a Time-to-Live (TTL) 1194 // value of zero. 1195 // 1196 // A host MUST NOT discard a datagram just because it was 1197 // received with TTL less than 2. 1198 { 1199 name: "zero TTL", 1200 maxTotalLength: ipv4.MaxTotalSize, 1201 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1202 TTL: 0, 1203 }, 1204 { 1205 name: "one TTL", 1206 maxTotalLength: ipv4.MaxTotalSize, 1207 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1208 TTL: 1, 1209 }, 1210 { 1211 name: "End options", 1212 maxTotalLength: ipv4.MaxTotalSize, 1213 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1214 TTL: ttl, 1215 options: header.IPv4Options{0, 0, 0, 0}, 1216 replyOptions: header.IPv4Options{0, 0, 0, 0}, 1217 }, 1218 { 1219 name: "NOP options", 1220 maxTotalLength: ipv4.MaxTotalSize, 1221 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1222 TTL: ttl, 1223 options: header.IPv4Options{1, 1, 1, 1}, 1224 replyOptions: header.IPv4Options{1, 1, 1, 1}, 1225 }, 1226 { 1227 name: "NOP and End options", 1228 maxTotalLength: ipv4.MaxTotalSize, 1229 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1230 TTL: ttl, 1231 options: header.IPv4Options{1, 1, 0, 0}, 1232 replyOptions: header.IPv4Options{1, 1, 0, 0}, 1233 }, 1234 { 1235 name: "bad header length", 1236 headerLength: header.IPv4MinimumSize - 1, 1237 maxTotalLength: ipv4.MaxTotalSize, 1238 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1239 TTL: ttl, 1240 shouldFail: true, 1241 }, 1242 { 1243 name: "bad total length (0)", 1244 maxTotalLength: 0, 1245 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1246 TTL: ttl, 1247 shouldFail: true, 1248 }, 1249 { 1250 name: "bad total length (ip - 1)", 1251 maxTotalLength: uint16(header.IPv4MinimumSize - 1), 1252 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1253 TTL: ttl, 1254 shouldFail: true, 1255 }, 1256 { 1257 name: "bad total length (ip + icmp - 1)", 1258 maxTotalLength: uint16(header.IPv4MinimumSize + header.ICMPv4MinimumSize - 1), 1259 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1260 TTL: ttl, 1261 shouldFail: true, 1262 }, 1263 { 1264 name: "bad protocol", 1265 maxTotalLength: ipv4.MaxTotalSize, 1266 transportProtocol: 99, 1267 TTL: ttl, 1268 shouldFail: true, 1269 expectErrorICMP: true, 1270 ICMPType: header.ICMPv4DstUnreachable, 1271 ICMPCode: header.ICMPv4ProtoUnreachable, 1272 }, 1273 { 1274 name: "timestamp option overflow", 1275 maxTotalLength: ipv4.MaxTotalSize, 1276 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1277 TTL: ttl, 1278 options: header.IPv4Options{ 1279 68, 12, 13, 0x11, 1280 192, 168, 1, 12, 1281 1, 2, 3, 4, 1282 }, 1283 replyOptions: header.IPv4Options{ 1284 68, 12, 13, 0x21, 1285 192, 168, 1, 12, 1286 1, 2, 3, 4, 1287 }, 1288 }, 1289 { 1290 name: "timestamp option overflow full", 1291 maxTotalLength: ipv4.MaxTotalSize, 1292 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1293 TTL: ttl, 1294 options: header.IPv4Options{ 1295 68, 12, 13, 0xF1, 1296 // ^ Counter full (15/0xF) 1297 192, 168, 1, 12, 1298 1, 2, 3, 4, 1299 }, 1300 shouldFail: true, 1301 expectErrorICMP: true, 1302 ICMPType: header.ICMPv4ParamProblem, 1303 ICMPCode: header.ICMPv4UnusedCode, 1304 paramProblemPointer: header.IPv4MinimumSize + 3, 1305 replyOptions: header.IPv4Options{}, 1306 }, 1307 { 1308 name: "unknown option", 1309 maxTotalLength: ipv4.MaxTotalSize, 1310 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1311 TTL: ttl, 1312 options: header.IPv4Options{10, 4, 9, 0}, 1313 // ^^ 1314 // The unknown option should be stripped out of the reply. 1315 replyOptions: header.IPv4Options{}, 1316 }, 1317 { 1318 name: "bad option - no length", 1319 maxTotalLength: ipv4.MaxTotalSize, 1320 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1321 TTL: ttl, 1322 options: header.IPv4Options{ 1323 1, 1, 1, 68, 1324 // ^-start of timestamp.. but no length.. 1325 }, 1326 shouldFail: true, 1327 expectErrorICMP: true, 1328 ICMPType: header.ICMPv4ParamProblem, 1329 ICMPCode: header.ICMPv4UnusedCode, 1330 paramProblemPointer: header.IPv4MinimumSize + 3, 1331 }, 1332 { 1333 name: "bad option - length 0", 1334 maxTotalLength: ipv4.MaxTotalSize, 1335 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1336 TTL: ttl, 1337 options: header.IPv4Options{ 1338 68, 0, 9, 0, 1339 // ^ 1340 1, 2, 3, 4, 1341 }, 1342 shouldFail: true, 1343 expectErrorICMP: true, 1344 ICMPType: header.ICMPv4ParamProblem, 1345 ICMPCode: header.ICMPv4UnusedCode, 1346 paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength, 1347 }, 1348 { 1349 name: "bad option - length 1", 1350 maxTotalLength: ipv4.MaxTotalSize, 1351 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1352 TTL: ttl, 1353 options: header.IPv4Options{ 1354 68, 1, 9, 0, 1355 // ^ 1356 1, 2, 3, 4, 1357 }, 1358 shouldFail: true, 1359 expectErrorICMP: true, 1360 ICMPType: header.ICMPv4ParamProblem, 1361 ICMPCode: header.ICMPv4UnusedCode, 1362 paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength, 1363 }, 1364 { 1365 name: "bad option - length big", 1366 maxTotalLength: ipv4.MaxTotalSize, 1367 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1368 TTL: ttl, 1369 options: header.IPv4Options{ 1370 68, 9, 9, 0, 1371 // ^ 1372 // There are only 8 bytes allocated to options so 9 bytes of timestamp 1373 // space is not possible. (Second byte) 1374 1, 2, 3, 4, 1375 }, 1376 shouldFail: true, 1377 expectErrorICMP: true, 1378 ICMPType: header.ICMPv4ParamProblem, 1379 ICMPCode: header.ICMPv4UnusedCode, 1380 paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength, 1381 }, 1382 { 1383 // This tests for some linux compatible behaviour. 1384 // The ICMP pointer returned is 22 for Linux but the 1385 // error is actually in spot 21. 1386 name: "bad option - length bad", 1387 maxTotalLength: ipv4.MaxTotalSize, 1388 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1389 TTL: ttl, 1390 // Timestamps are in multiples of 4 or 8 but never 7. 1391 // The option space should be padded out. 1392 options: header.IPv4Options{ 1393 68, 7, 5, 0, 1394 // ^ ^ Linux points here which is wrong. 1395 // | Not a multiple of 4 1396 1, 2, 3, 0, 1397 }, 1398 shouldFail: true, 1399 expectErrorICMP: true, 1400 ICMPType: header.ICMPv4ParamProblem, 1401 ICMPCode: header.ICMPv4UnusedCode, 1402 paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptTSPointerOffset, 1403 }, 1404 { 1405 name: "multiple type 0 with room", 1406 maxTotalLength: ipv4.MaxTotalSize, 1407 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1408 TTL: ttl, 1409 options: header.IPv4Options{ 1410 68, 24, 21, 0x00, 1411 1, 2, 3, 4, 1412 5, 6, 7, 8, 1413 9, 10, 11, 12, 1414 13, 14, 15, 16, 1415 0, 0, 0, 0, 1416 }, 1417 replyOptions: header.IPv4Options{ 1418 68, 24, 25, 0x00, 1419 1, 2, 3, 4, 1420 5, 6, 7, 8, 1421 9, 10, 11, 12, 1422 13, 14, 15, 16, 1423 0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock 1424 }, 1425 }, 1426 { 1427 // The timestamp area is full so add to the overflow count. 1428 name: "multiple type 1 timestamps", 1429 maxTotalLength: ipv4.MaxTotalSize, 1430 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1431 TTL: ttl, 1432 options: header.IPv4Options{ 1433 68, 20, 21, 0x11, 1434 // ^ 1435 192, 168, 1, 12, 1436 1, 2, 3, 4, 1437 192, 168, 1, 13, 1438 5, 6, 7, 8, 1439 }, 1440 // Overflow count is the top nibble of the 4th byte. 1441 replyOptions: header.IPv4Options{ 1442 68, 20, 21, 0x21, 1443 // ^ 1444 192, 168, 1, 12, 1445 1, 2, 3, 4, 1446 192, 168, 1, 13, 1447 5, 6, 7, 8, 1448 }, 1449 }, 1450 { 1451 name: "multiple type 1 timestamps with room", 1452 maxTotalLength: ipv4.MaxTotalSize, 1453 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1454 TTL: ttl, 1455 options: header.IPv4Options{ 1456 68, 28, 21, 0x01, 1457 192, 168, 1, 12, 1458 1, 2, 3, 4, 1459 192, 168, 1, 13, 1460 5, 6, 7, 8, 1461 0, 0, 0, 0, 1462 0, 0, 0, 0, 1463 }, 1464 replyOptions: header.IPv4Options{ 1465 68, 28, 29, 0x01, 1466 192, 168, 1, 12, 1467 1, 2, 3, 4, 1468 192, 168, 1, 13, 1469 5, 6, 7, 8, 1470 192, 168, 1, 58, // New IP Address. 1471 0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock 1472 }, 1473 }, 1474 { 1475 // Timestamp pointer uses one based counting so 0 is invalid. 1476 name: "timestamp pointer invalid", 1477 maxTotalLength: ipv4.MaxTotalSize, 1478 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1479 TTL: ttl, 1480 options: header.IPv4Options{ 1481 68, 8, 0, 0x00, 1482 // ^ 0 instead of 5 or more. 1483 0, 0, 0, 0, 1484 }, 1485 shouldFail: true, 1486 expectErrorICMP: true, 1487 ICMPType: header.ICMPv4ParamProblem, 1488 ICMPCode: header.ICMPv4UnusedCode, 1489 paramProblemPointer: header.IPv4MinimumSize + 2, 1490 }, 1491 { 1492 // Timestamp pointer cannot be less than 5. It must point past the header 1493 // which is 4 bytes. (1 based counting) 1494 name: "timestamp pointer too small by 1", 1495 maxTotalLength: ipv4.MaxTotalSize, 1496 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1497 TTL: ttl, 1498 options: header.IPv4Options{ 1499 68, 8, header.IPv4OptionTimestampHdrLength, 0x00, 1500 // ^ header is 4 bytes, so 4 should fail. 1501 0, 0, 0, 0, 1502 }, 1503 shouldFail: true, 1504 expectErrorICMP: true, 1505 ICMPType: header.ICMPv4ParamProblem, 1506 ICMPCode: header.ICMPv4UnusedCode, 1507 paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptTSPointerOffset, 1508 }, 1509 { 1510 name: "valid timestamp pointer", 1511 maxTotalLength: ipv4.MaxTotalSize, 1512 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1513 TTL: ttl, 1514 options: header.IPv4Options{ 1515 68, 8, header.IPv4OptionTimestampHdrLength + 1, 0x00, 1516 // ^ header is 4 bytes, so 5 should succeed. 1517 0, 0, 0, 0, 1518 }, 1519 replyOptions: header.IPv4Options{ 1520 68, 8, 9, 0x00, 1521 0x00, 0xad, 0x1c, 0x40, // time we expect from fakeclock 1522 }, 1523 }, 1524 { 1525 // Needs 8 bytes for a type 1 timestamp but there are only 4 free. 1526 name: "bad timer element alignment", 1527 maxTotalLength: ipv4.MaxTotalSize, 1528 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1529 TTL: ttl, 1530 options: header.IPv4Options{ 1531 68, 20, 17, 0x01, 1532 // ^^ ^^ 20 byte area, next free spot at 17. 1533 192, 168, 1, 12, 1534 1, 2, 3, 4, 1535 0, 0, 0, 0, 1536 0, 0, 0, 0, 1537 }, 1538 shouldFail: true, 1539 expectErrorICMP: true, 1540 ICMPType: header.ICMPv4ParamProblem, 1541 ICMPCode: header.ICMPv4UnusedCode, 1542 paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptTSPointerOffset, 1543 }, 1544 // End of option list with illegal option after it, which should be ignored. 1545 { 1546 name: "end of options list", 1547 maxTotalLength: ipv4.MaxTotalSize, 1548 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1549 TTL: ttl, 1550 options: header.IPv4Options{ 1551 68, 12, 13, 0x11, 1552 192, 168, 1, 12, 1553 1, 2, 3, 4, 1554 0, 10, 3, 99, // EOL followed by junk 1555 }, 1556 replyOptions: header.IPv4Options{ 1557 68, 12, 13, 0x21, 1558 192, 168, 1, 12, 1559 1, 2, 3, 4, 1560 0, // End of Options hides following bytes. 1561 0, 0, 0, // 3 bytes unknown option removed. 1562 }, 1563 }, 1564 { 1565 // Timestamp with a size much too small. 1566 name: "timestamp truncated", 1567 maxTotalLength: ipv4.MaxTotalSize, 1568 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1569 TTL: ttl, 1570 options: header.IPv4Options{ 1571 68, 1, 0, 0, 1572 // ^ Smallest possible is 8. Linux points at the 68. 1573 }, 1574 shouldFail: true, 1575 expectErrorICMP: true, 1576 ICMPType: header.ICMPv4ParamProblem, 1577 ICMPCode: header.ICMPv4UnusedCode, 1578 paramProblemPointer: header.IPv4MinimumSize + pointerOffsetForInvalidLength, 1579 }, 1580 { 1581 name: "single record route with room", 1582 maxTotalLength: ipv4.MaxTotalSize, 1583 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1584 TTL: ttl, 1585 options: header.IPv4Options{ 1586 7, 7, 4, // 3 byte header 1587 0, 0, 0, 0, 1588 0, 1589 }, 1590 replyOptions: header.IPv4Options{ 1591 7, 7, 8, // 3 byte header 1592 192, 168, 1, 58, // New IP Address. 1593 0, // padding to multiple of 4 bytes. 1594 }, 1595 }, 1596 { 1597 name: "multiple record route with room", 1598 maxTotalLength: ipv4.MaxTotalSize, 1599 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1600 TTL: ttl, 1601 options: header.IPv4Options{ 1602 7, 23, 20, // 3 byte header 1603 1, 2, 3, 4, 1604 5, 6, 7, 8, 1605 9, 10, 11, 12, 1606 13, 14, 15, 16, 1607 0, 0, 0, 0, 1608 0, 1609 }, 1610 replyOptions: header.IPv4Options{ 1611 7, 23, 24, 1612 1, 2, 3, 4, 1613 5, 6, 7, 8, 1614 9, 10, 11, 12, 1615 13, 14, 15, 16, 1616 192, 168, 1, 58, // New IP Address. 1617 0, // padding to multiple of 4 bytes. 1618 }, 1619 }, 1620 { 1621 name: "single record route with no room", 1622 maxTotalLength: ipv4.MaxTotalSize, 1623 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1624 TTL: ttl, 1625 options: header.IPv4Options{ 1626 7, 7, 8, // 3 byte header 1627 1, 2, 3, 4, 1628 0, 1629 }, 1630 replyOptions: header.IPv4Options{ 1631 7, 7, 8, // 3 byte header 1632 1, 2, 3, 4, 1633 0, // padding to multiple of 4 bytes. 1634 }, 1635 }, 1636 { 1637 // Unlike timestamp, this should just succeed. 1638 name: "multiple record route with no room", 1639 maxTotalLength: ipv4.MaxTotalSize, 1640 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1641 TTL: ttl, 1642 options: header.IPv4Options{ 1643 7, 23, 24, // 3 byte header 1644 1, 2, 3, 4, 1645 5, 6, 7, 8, 1646 9, 10, 11, 12, 1647 13, 14, 15, 16, 1648 17, 18, 19, 20, 1649 0, 1650 }, 1651 replyOptions: header.IPv4Options{ 1652 7, 23, 24, 1653 1, 2, 3, 4, 1654 5, 6, 7, 8, 1655 9, 10, 11, 12, 1656 13, 14, 15, 16, 1657 17, 18, 19, 20, 1658 0, // padding to multiple of 4 bytes. 1659 }, 1660 }, 1661 { 1662 // Pointer uses one based counting so 0 is invalid. 1663 name: "record route pointer zero", 1664 maxTotalLength: ipv4.MaxTotalSize, 1665 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1666 TTL: ttl, 1667 options: header.IPv4Options{ 1668 7, 8, 0, // 3 byte header 1669 0, 0, 0, 0, 1670 0, 1671 }, 1672 shouldFail: true, 1673 expectErrorICMP: true, 1674 ICMPType: header.ICMPv4ParamProblem, 1675 ICMPCode: header.ICMPv4UnusedCode, 1676 paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptRRPointerOffset, 1677 }, 1678 { 1679 // Pointer must be 4 or more as it must point past the 3 byte header 1680 // using 1 based counting. 3 should fail. 1681 name: "record route pointer too small by 1", 1682 maxTotalLength: ipv4.MaxTotalSize, 1683 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1684 TTL: ttl, 1685 options: header.IPv4Options{ 1686 7, 8, header.IPv4OptionRecordRouteHdrLength, // 3 byte header 1687 0, 0, 0, 0, 1688 0, 1689 }, 1690 shouldFail: true, 1691 expectErrorICMP: true, 1692 ICMPType: header.ICMPv4ParamProblem, 1693 ICMPCode: header.ICMPv4UnusedCode, 1694 paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptRRPointerOffset, 1695 }, 1696 { 1697 // Pointer must be 4 or more as it must point past the 3 byte header 1698 // using 1 based counting. Check 4 passes. (Duplicates "single 1699 // record route with room") 1700 name: "valid record route pointer", 1701 maxTotalLength: ipv4.MaxTotalSize, 1702 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1703 TTL: ttl, 1704 options: header.IPv4Options{ 1705 7, 7, header.IPv4OptionRecordRouteHdrLength + 1, // 3 byte header 1706 0, 0, 0, 0, 1707 0, 1708 }, 1709 replyOptions: header.IPv4Options{ 1710 7, 7, 8, // 3 byte header 1711 192, 168, 1, 58, // New IP Address. 1712 0, // padding to multiple of 4 bytes. 1713 }, 1714 }, 1715 { 1716 // Confirm Linux bug for bug compatibility. 1717 // Linux returns slot 22 but the error is in slot 21. 1718 name: "multiple record route with not enough room", 1719 maxTotalLength: ipv4.MaxTotalSize, 1720 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1721 TTL: ttl, 1722 options: header.IPv4Options{ 1723 7, 8, 8, // 3 byte header 1724 // ^ ^ Linux points here. We must too. 1725 // | Not enough room. 1 byte free, need 4. 1726 1, 2, 3, 4, 1727 0, 1728 }, 1729 shouldFail: true, 1730 expectErrorICMP: true, 1731 ICMPType: header.ICMPv4ParamProblem, 1732 ICMPCode: header.ICMPv4UnusedCode, 1733 paramProblemPointer: header.IPv4MinimumSize + header.IPv4OptRRPointerOffset, 1734 }, 1735 { 1736 name: "duplicate record route", 1737 maxTotalLength: ipv4.MaxTotalSize, 1738 transportProtocol: uint8(header.ICMPv4ProtocolNumber), 1739 TTL: ttl, 1740 options: header.IPv4Options{ 1741 7, 7, 8, // 3 byte header 1742 1, 2, 3, 4, 1743 7, 7, 8, // 3 byte header 1744 1, 2, 3, 4, 1745 0, 0, // pad 1746 }, 1747 shouldFail: true, 1748 expectErrorICMP: true, 1749 ICMPType: header.ICMPv4ParamProblem, 1750 ICMPCode: header.ICMPv4UnusedCode, 1751 paramProblemPointer: header.IPv4MinimumSize + 7, 1752 }, 1753 } 1754 1755 for _, test := range tests { 1756 t.Run(test.name, func(t *testing.T) { 1757 ctx := newTestContext() 1758 defer ctx.cleanup() 1759 s := ctx.s 1760 clock := ctx.clock 1761 1762 // Advance the clock by some unimportant amount to make 1763 // it give a more recognisable signature than 00,00,00,00. 1764 clock.Advance(time.Millisecond * randomTimeOffset) 1765 1766 // We expect at most a single packet in response to our ICMP Echo Request. 1767 e := channel.New(1, ipv4.MaxTotalSize, "") 1768 defer e.Close() 1769 if err := s.CreateNIC(nicID, e); err != nil { 1770 t.Fatalf("CreateNIC(%d, _): %s", nicID, err) 1771 } 1772 ipv4ProtoAddr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: ipv4Addr} 1773 if err := s.AddProtocolAddress(nicID, ipv4ProtoAddr, stack.AddressProperties{}); err != nil { 1774 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, ipv4ProtoAddr, err) 1775 } 1776 1777 // Default routes for IPv4 so ICMP can find a route to the remote 1778 // node when attempting to send the ICMP Echo Reply. 1779 s.SetRouteTable([]tcpip.Route{ 1780 { 1781 Destination: header.IPv4EmptySubnet, 1782 NIC: nicID, 1783 }, 1784 }) 1785 1786 if len(test.options)%4 != 0 { 1787 t.Fatalf("options must be aligned to 32 bits, invalid test options: %x (len=%d)", test.options, len(test.options)) 1788 } 1789 ipHeaderLength := header.IPv4MinimumSize + len(test.options) 1790 if ipHeaderLength > header.IPv4MaximumHeaderSize { 1791 t.Fatalf("IP header length too large: got = %d, want <= %d ", ipHeaderLength, header.IPv4MaximumHeaderSize) 1792 } 1793 totalLen := uint16(ipHeaderLength + header.ICMPv4MinimumSize) 1794 hdr := prependable.New(int(totalLen)) 1795 icmpH := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize)) 1796 1797 // Specify ident/seq to make sure we get the same in the response. 1798 icmpH.SetIdent(randomIdent) 1799 icmpH.SetSequence(randomSequence) 1800 icmpH.SetType(header.ICMPv4Echo) 1801 icmpH.SetCode(header.ICMPv4UnusedCode) 1802 icmpH.SetChecksum(0) 1803 icmpH.SetChecksum(^checksum.Checksum(icmpH, 0)) 1804 ip := header.IPv4(hdr.Prepend(ipHeaderLength)) 1805 if test.maxTotalLength < totalLen { 1806 totalLen = test.maxTotalLength 1807 } 1808 ip.Encode(&header.IPv4Fields{ 1809 TotalLength: totalLen, 1810 Protocol: test.transportProtocol, 1811 TTL: test.TTL, 1812 SrcAddr: remoteIPv4Addr, 1813 DstAddr: ipv4Addr.Address, 1814 }) 1815 if test.headerLength != 0 { 1816 ip.SetHeaderLength(test.headerLength) 1817 } else { 1818 // Set the calculated header length, since we may manually add options. 1819 ip.SetHeaderLength(uint8(ipHeaderLength)) 1820 } 1821 if len(test.options) != 0 { 1822 // Copy options manually. We do not use Encode for options so we can 1823 // verify malformed options with handcrafted payloads. 1824 if want, got := copy(ip.Options(), test.options), len(test.options); want != got { 1825 t.Fatalf("got copy(ip.Options(), test.options) = %d, want = %d", got, want) 1826 } 1827 } 1828 ip.SetChecksum(0) 1829 ipHeaderChecksum := ip.CalculateChecksum() 1830 if test.badHeaderChecksum { 1831 ipHeaderChecksum += 42 1832 } 1833 ip.SetChecksum(^ipHeaderChecksum) 1834 requestPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1835 Payload: buffer.MakeWithData(hdr.View()), 1836 }) 1837 defer requestPkt.DecRef() 1838 e.InjectInbound(header.IPv4ProtocolNumber, requestPkt) 1839 reply := e.Read() 1840 if reply == nil { 1841 if test.shouldFail { 1842 if test.expectErrorICMP { 1843 t.Fatalf("ICMP error response (type %d, code %d) missing", test.ICMPType, test.ICMPCode) 1844 } 1845 return // Expected silent failure. 1846 } 1847 t.Fatal("expected ICMP echo reply missing") 1848 } 1849 defer reply.DecRef() 1850 1851 // We didn't expect a packet. Register our surprise but carry on to 1852 // provide more information about what we got. 1853 if test.shouldFail && !test.expectErrorICMP { 1854 t.Error("unexpected packet response") 1855 } 1856 1857 // Check the route that brought the packet to us. 1858 if reply.EgressRoute.LocalAddress != ipv4Addr.Address { 1859 t.Errorf("got pkt.Route.LocalAddress = %s, want = %s", reply.EgressRoute.LocalAddress, ipv4Addr.Address) 1860 } 1861 if reply.EgressRoute.RemoteAddress != remoteIPv4Addr { 1862 t.Errorf("got pkt.Route.RemoteAddress = %s, want = %s", reply.EgressRoute.RemoteAddress, remoteIPv4Addr) 1863 } 1864 1865 // Make sure it's all in one buffer for checker. 1866 replyIPHeader := stack.PayloadSince(reply.NetworkHeader()) 1867 defer replyIPHeader.Release() 1868 1869 // At this stage we only know it's probably an IP+ICMP header so verify 1870 // that much. 1871 checker.IPv4(t, replyIPHeader, 1872 checker.SrcAddr(ipv4Addr.Address), 1873 checker.DstAddr(remoteIPv4Addr), 1874 checker.ICMPv4( 1875 checker.ICMPv4Checksum(), 1876 ), 1877 ) 1878 1879 // Don't proceed any further if the checker found problems. 1880 if t.Failed() { 1881 t.FailNow() 1882 } 1883 1884 // OK it's ICMP. We can safely look at the type now. 1885 replyICMPHeader := header.ICMPv4(header.IPv4(replyIPHeader.AsSlice()).Payload()) 1886 switch replyICMPHeader.Type() { 1887 case header.ICMPv4ParamProblem: 1888 if !test.shouldFail { 1889 t.Fatalf("got Parameter Problem with pointer %d, wanted Echo Reply", replyICMPHeader.Pointer()) 1890 } 1891 if !test.expectErrorICMP { 1892 t.Fatalf("got Parameter Problem with pointer %d, wanted no response", replyICMPHeader.Pointer()) 1893 } 1894 checker.IPv4(t, replyIPHeader, 1895 checker.IPFullLength(uint16(header.IPv4MinimumSize+header.ICMPv4MinimumSize+requestPkt.Size())), 1896 checker.IPv4HeaderLength(header.IPv4MinimumSize), 1897 checker.ICMPv4( 1898 checker.ICMPv4Type(test.ICMPType), 1899 checker.ICMPv4Code(test.ICMPCode), 1900 checker.ICMPv4Pointer(test.paramProblemPointer), 1901 checker.ICMPv4Payload(hdr.View()), 1902 ), 1903 ) 1904 return 1905 case header.ICMPv4DstUnreachable: 1906 if !test.shouldFail { 1907 t.Fatalf("got ICMP error packet type %d, code %d, wanted Echo Reply", 1908 header.ICMPv4DstUnreachable, replyICMPHeader.Code()) 1909 } 1910 if !test.expectErrorICMP { 1911 t.Fatalf("got ICMP error packet type %d, code %d, wanted no response", 1912 header.ICMPv4DstUnreachable, replyICMPHeader.Code()) 1913 } 1914 checker.IPv4(t, replyIPHeader, 1915 checker.IPFullLength(uint16(header.IPv4MinimumSize+header.ICMPv4MinimumSize+requestPkt.Size())), 1916 checker.IPv4HeaderLength(header.IPv4MinimumSize), 1917 checker.ICMPv4( 1918 checker.ICMPv4Type(test.ICMPType), 1919 checker.ICMPv4Code(test.ICMPCode), 1920 checker.ICMPv4Payload(hdr.View()), 1921 ), 1922 ) 1923 return 1924 case header.ICMPv4EchoReply: 1925 if test.shouldFail { 1926 if !test.expectErrorICMP { 1927 t.Error("got Echo Reply packet, want no response") 1928 } else { 1929 t.Errorf("got Echo Reply, want ICMP error type %d, code %d", test.ICMPType, test.ICMPCode) 1930 } 1931 } 1932 // If the IP options change size then the packet will change size, so 1933 // some IP header fields will need to be adjusted for the checks. 1934 sizeChange := len(test.replyOptions) - len(test.options) 1935 1936 checker.IPv4(t, replyIPHeader, 1937 checker.IPv4HeaderLength(ipHeaderLength+sizeChange), 1938 checker.IPv4Options(test.replyOptions), 1939 checker.IPFullLength(uint16(requestPkt.Size()+sizeChange)), 1940 checker.ICMPv4( 1941 checker.ICMPv4Checksum(), 1942 checker.ICMPv4Code(header.ICMPv4UnusedCode), 1943 checker.ICMPv4Seq(randomSequence), 1944 checker.ICMPv4Ident(randomIdent), 1945 ), 1946 ) 1947 default: 1948 t.Fatalf("unexpected ICMP response, got type %d, want = %d, %d or %d", 1949 replyICMPHeader.Type(), header.ICMPv4EchoReply, header.ICMPv4DstUnreachable, header.ICMPv4ParamProblem) 1950 } 1951 }) 1952 } 1953 } 1954 1955 // compareFragments compares the contents of a set of fragmented packets against 1956 // the contents of a source packet. 1957 // 1958 // If withIPHeader is set to true, we will validate the fragmented packets' IP 1959 // headers against the source packet's IP header. If set to false, we validate 1960 // the fragmented packets' IP headers against each other. 1961 func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketBuffer, mtu uint32, wantFragments []fragmentInfo, proto tcpip.TransportProtocolNumber, withIPHeader bool, expectedAvailableHeaderBytes int) error { 1962 // Make a complete array of the sourcePacket packet. 1963 var source header.IPv4 1964 buf := sourcePacket.ToBuffer() 1965 defer buf.Release() 1966 1967 // If the packet to be fragmented contains an IPv4 header, use that header for 1968 // validating fragment headers. Else, use the header of the first fragment. 1969 if withIPHeader { 1970 source = header.IPv4(buf.Flatten()) 1971 } else { 1972 source = header.IPv4(packets[0].NetworkHeader().Slice()) 1973 source = append(source, buf.Flatten()...) 1974 } 1975 1976 // Make a copy of the IP header, which will be modified in some fields to make 1977 // an expected header. 1978 sourceCopy := header.IPv4(append([]byte{}, source[:source.HeaderLength()]...)) 1979 sourceCopy.SetChecksum(0) 1980 sourceCopy.SetFlagsFragmentOffset(0, 0) 1981 sourceCopy.SetTotalLength(0) 1982 // Build up an array of the bytes sent. 1983 var reassembledPayload buffer.Buffer 1984 defer reassembledPayload.Release() 1985 for i, packet := range packets { 1986 // Confirm that the packet is valid. 1987 allBytes := packet.ToBuffer() 1988 defer allBytes.Release() 1989 fragmentIPHeader := header.IPv4(allBytes.Flatten()) 1990 if !fragmentIPHeader.IsValid(len(fragmentIPHeader)) { 1991 return fmt.Errorf("fragment #%d: IP packet is invalid:\n%s", i, hex.Dump(fragmentIPHeader)) 1992 } 1993 if got := len(fragmentIPHeader); got > int(mtu) { 1994 return fmt.Errorf("fragment #%d: got len(fragmentIPHeader) = %d, want <= %d", i, got, mtu) 1995 } 1996 if got := fragmentIPHeader.TransportProtocol(); got != proto { 1997 return fmt.Errorf("fragment #%d: got fragmentIPHeader.TransportProtocol() = %d, want = %d", i, got, uint8(proto)) 1998 } 1999 if got, want := packet.NetworkProtocolNumber, sourcePacket.NetworkProtocolNumber; got != want { 2000 return fmt.Errorf("fragment #%d: got fragment.NetworkProtocolNumber = %d, want = %d", i, got, want) 2001 } 2002 if got := packet.AvailableHeaderBytes(); got != expectedAvailableHeaderBytes { 2003 return fmt.Errorf("fragment #%d: got packet.AvailableHeaderBytes() = %d, want = %d", i, got, expectedAvailableHeaderBytes) 2004 } 2005 if got, want := fragmentIPHeader.CalculateChecksum(), uint16(0xffff); got != want { 2006 return fmt.Errorf("fragment #%d: got ip.CalculateChecksum() = %#x, want = %#x", i, got, want) 2007 } 2008 if wantFragments[i].more { 2009 sourceCopy.SetFlagsFragmentOffset(sourceCopy.Flags()|header.IPv4FlagMoreFragments, wantFragments[i].offset) 2010 } else { 2011 sourceCopy.SetFlagsFragmentOffset(sourceCopy.Flags()&^header.IPv4FlagMoreFragments, wantFragments[i].offset) 2012 } 2013 reassembledPayload.Append(packet.TransportHeader().View()) 2014 reassembledPayload.Append(packet.Data().AsRange().ToView()) 2015 // Clear out the checksum and length from the ip because we can't compare 2016 // it. 2017 sourceCopy.SetTotalLength(wantFragments[i].payloadSize + header.IPv4MinimumSize) 2018 sourceCopy.SetChecksum(0) 2019 sourceCopy.SetChecksum(^sourceCopy.CalculateChecksum()) 2020 2021 // If we are validating against the original IP header, we should exclude the 2022 // ID field, which will only be set fo fragmented packets. 2023 if withIPHeader { 2024 fragmentIPHeader.SetID(0) 2025 fragmentIPHeader.SetChecksum(0) 2026 fragmentIPHeader.SetChecksum(^fragmentIPHeader.CalculateChecksum()) 2027 } 2028 if diff := cmp.Diff(fragmentIPHeader[:fragmentIPHeader.HeaderLength()], sourceCopy[:sourceCopy.HeaderLength()]); diff != "" { 2029 return fmt.Errorf("fragment #%d: fragmentIPHeader mismatch (-want +got):\n%s", i, diff) 2030 } 2031 } 2032 2033 expected := []byte(source[source.HeaderLength():]) 2034 if diff := cmp.Diff(expected, reassembledPayload.Flatten()); diff != "" { 2035 return fmt.Errorf("reassembledPayload mismatch (-want +got):\n%s", diff) 2036 } 2037 2038 return nil 2039 } 2040 2041 type fragmentInfo struct { 2042 offset uint16 2043 more bool 2044 payloadSize uint16 2045 } 2046 2047 var fragmentationTests = []struct { 2048 description string 2049 mtu uint32 2050 transportHeaderLength int 2051 payloadSize int 2052 wantFragments []fragmentInfo 2053 }{ 2054 { 2055 description: "No fragmentation", 2056 mtu: 1280, 2057 transportHeaderLength: 0, 2058 payloadSize: 1000, 2059 wantFragments: []fragmentInfo{ 2060 {offset: 0, payloadSize: 1000, more: false}, 2061 }, 2062 }, 2063 { 2064 description: "Fragmented", 2065 mtu: 1280, 2066 transportHeaderLength: 0, 2067 payloadSize: 2000, 2068 wantFragments: []fragmentInfo{ 2069 {offset: 0, payloadSize: 1256, more: true}, 2070 {offset: 1256, payloadSize: 744, more: false}, 2071 }, 2072 }, 2073 { 2074 description: "Fragmented with the minimum mtu", 2075 mtu: header.IPv4MinimumMTU, 2076 transportHeaderLength: 0, 2077 payloadSize: 100, 2078 wantFragments: []fragmentInfo{ 2079 {offset: 0, payloadSize: 48, more: true}, 2080 {offset: 48, payloadSize: 48, more: true}, 2081 {offset: 96, payloadSize: 4, more: false}, 2082 }, 2083 }, 2084 { 2085 description: "Fragmented with mtu not a multiple of 8", 2086 mtu: header.IPv4MinimumMTU + 1, 2087 transportHeaderLength: 0, 2088 payloadSize: 100, 2089 wantFragments: []fragmentInfo{ 2090 {offset: 0, payloadSize: 48, more: true}, 2091 {offset: 48, payloadSize: 48, more: true}, 2092 {offset: 96, payloadSize: 4, more: false}, 2093 }, 2094 }, 2095 { 2096 description: "No fragmentation with big header", 2097 mtu: 2000, 2098 transportHeaderLength: 100, 2099 payloadSize: 1000, 2100 wantFragments: []fragmentInfo{ 2101 {offset: 0, payloadSize: 1100, more: false}, 2102 }, 2103 }, 2104 { 2105 description: "Fragmented with big header", 2106 mtu: 1280, 2107 transportHeaderLength: 100, 2108 payloadSize: 1200, 2109 wantFragments: []fragmentInfo{ 2110 {offset: 0, payloadSize: 1256, more: true}, 2111 {offset: 1256, payloadSize: 44, more: false}, 2112 }, 2113 }, 2114 { 2115 description: "Fragmented with MTU smaller than header", 2116 mtu: 300, 2117 transportHeaderLength: 1000, 2118 payloadSize: 500, 2119 wantFragments: []fragmentInfo{ 2120 {offset: 0, payloadSize: 280, more: true}, 2121 {offset: 280, payloadSize: 280, more: true}, 2122 {offset: 560, payloadSize: 280, more: true}, 2123 {offset: 840, payloadSize: 280, more: true}, 2124 {offset: 1120, payloadSize: 280, more: true}, 2125 {offset: 1400, payloadSize: 100, more: false}, 2126 }, 2127 }, 2128 } 2129 2130 func TestFragmentationWritePacket(t *testing.T) { 2131 const ttl = 42 2132 2133 for _, ft := range fragmentationTests { 2134 t.Run(ft.description, func(t *testing.T) { 2135 ctx := newTestContext() 2136 defer ctx.cleanup() 2137 2138 ep := iptestutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32) 2139 defer ep.Close() 2140 r := buildRoute(t, ctx, ep) 2141 defer r.Release() 2142 pkt := iptestutil.MakeRandPkt(ft.transportHeaderLength, extraHeaderReserve+header.IPv4MinimumSize, []int{ft.payloadSize}, header.IPv4ProtocolNumber) 2143 defer pkt.DecRef() 2144 source := pkt.Clone() 2145 defer source.DecRef() 2146 err := r.WritePacket(stack.NetworkHeaderParams{ 2147 Protocol: tcp.ProtocolNumber, 2148 TTL: ttl, 2149 TOS: stack.DefaultTOS, 2150 }, pkt) 2151 if err != nil { 2152 t.Fatalf("r.WritePacket(...): %s", err) 2153 } 2154 if got := len(ep.WrittenPackets); got != len(ft.wantFragments) { 2155 t.Errorf("got len(ep.WrittenPackets) = %d, want = %d", got, len(ft.wantFragments)) 2156 } 2157 if got := int(r.Stats().IP.PacketsSent.Value()); got != len(ft.wantFragments) { 2158 t.Errorf("got c.Route.Stats().IP.PacketsSent.Value() = %d, want = %d", got, len(ft.wantFragments)) 2159 } 2160 if got := r.Stats().IP.OutgoingPacketErrors.Value(); got != 0 { 2161 t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = 0", got) 2162 } 2163 if err := compareFragments(ep.WrittenPackets, source, ft.mtu, ft.wantFragments, tcp.ProtocolNumber, false /* withIPHeader */, extraHeaderReserve); err != nil { 2164 t.Error(err) 2165 } 2166 }) 2167 } 2168 } 2169 2170 // TestFragmentationErrors checks that errors are returned from WritePacket 2171 // correctly. 2172 func TestFragmentationErrors(t *testing.T) { 2173 const ttl = 42 2174 2175 tests := []struct { 2176 description string 2177 mtu uint32 2178 transportHeaderLength int 2179 payloadSize int 2180 allowPackets int 2181 outgoingErrors int 2182 mockError tcpip.Error 2183 wantError tcpip.Error 2184 }{ 2185 { 2186 description: "No frag", 2187 mtu: 2000, 2188 payloadSize: 1000, 2189 transportHeaderLength: 0, 2190 allowPackets: 0, 2191 outgoingErrors: 1, 2192 mockError: &tcpip.ErrAborted{}, 2193 wantError: &tcpip.ErrAborted{}, 2194 }, 2195 { 2196 description: "Error on first frag", 2197 mtu: 500, 2198 payloadSize: 1000, 2199 transportHeaderLength: 0, 2200 allowPackets: 0, 2201 outgoingErrors: 3, 2202 mockError: &tcpip.ErrAborted{}, 2203 wantError: &tcpip.ErrAborted{}, 2204 }, 2205 { 2206 description: "Error on second frag", 2207 mtu: 500, 2208 payloadSize: 1000, 2209 transportHeaderLength: 0, 2210 allowPackets: 1, 2211 outgoingErrors: 2, 2212 mockError: &tcpip.ErrAborted{}, 2213 wantError: &tcpip.ErrAborted{}, 2214 }, 2215 { 2216 description: "Error on first frag MTU smaller than header", 2217 mtu: 500, 2218 transportHeaderLength: 1000, 2219 payloadSize: 500, 2220 allowPackets: 0, 2221 outgoingErrors: 4, 2222 mockError: &tcpip.ErrAborted{}, 2223 wantError: &tcpip.ErrAborted{}, 2224 }, 2225 { 2226 description: "Error when MTU is smaller than IPv4 minimum MTU", 2227 mtu: header.IPv4MinimumMTU - 1, 2228 transportHeaderLength: 0, 2229 payloadSize: 500, 2230 allowPackets: 0, 2231 outgoingErrors: 1, 2232 mockError: nil, 2233 wantError: &tcpip.ErrInvalidEndpointState{}, 2234 }, 2235 } 2236 2237 for _, ft := range tests { 2238 t.Run(ft.description, func(t *testing.T) { 2239 ctx := newTestContext() 2240 defer ctx.cleanup() 2241 2242 ep := iptestutil.NewMockLinkEndpoint(ft.mtu, ft.mockError, ft.allowPackets) 2243 defer ep.Close() 2244 r := buildRoute(t, ctx, ep) 2245 defer r.Release() 2246 pkt := iptestutil.MakeRandPkt(ft.transportHeaderLength, extraHeaderReserve+header.IPv4MinimumSize, []int{ft.payloadSize}, header.IPv4ProtocolNumber) 2247 defer pkt.DecRef() 2248 err := r.WritePacket(stack.NetworkHeaderParams{ 2249 Protocol: tcp.ProtocolNumber, 2250 TTL: ttl, 2251 TOS: stack.DefaultTOS, 2252 }, pkt) 2253 if diff := cmp.Diff(ft.wantError, err); diff != "" { 2254 t.Fatalf("unexpected error from r.WritePacket(_, _, _), (-want, +got):\n%s", diff) 2255 } 2256 if got := int(r.Stats().IP.PacketsSent.Value()); got != ft.allowPackets { 2257 t.Errorf("got r.Stats().IP.PacketsSent.Value() = %d, want = %d", got, ft.allowPackets) 2258 } 2259 if got := int(r.Stats().IP.OutgoingPacketErrors.Value()); got != ft.outgoingErrors { 2260 t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = %d", got, ft.outgoingErrors) 2261 } 2262 }) 2263 } 2264 } 2265 2266 func TestInvalidFragments(t *testing.T) { 2267 const ( 2268 nicID = 1 2269 linkAddr = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e") 2270 tos = 0 2271 ident = 1 2272 ttl = 48 2273 protocol = 6 2274 ) 2275 2276 var ( 2277 addr1 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x01")) 2278 addr2 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x02")) 2279 ) 2280 2281 payloadGen := func(payloadLen int) []byte { 2282 payload := make([]byte, payloadLen) 2283 for i := 0; i < len(payload); i++ { 2284 payload[i] = 0x30 2285 } 2286 return payload 2287 } 2288 2289 type fragmentData struct { 2290 ipv4fields header.IPv4Fields 2291 // 0 means insert the correct IHL. Non 0 means override the correct IHL. 2292 overrideIHL int // For 0 use 1 as it is an int and will be divided by 4. 2293 payload []byte 2294 autoChecksum bool // If true, the Checksum field will be overwritten. 2295 } 2296 2297 tests := []struct { 2298 name string 2299 fragments []fragmentData 2300 wantMalformedIPPackets uint64 2301 wantMalformedFragments uint64 2302 }{ 2303 { 2304 name: "IHL and TotalLength zero, FragmentOffset non-zero", 2305 fragments: []fragmentData{ 2306 { 2307 ipv4fields: header.IPv4Fields{ 2308 TOS: tos, 2309 TotalLength: 0, 2310 ID: ident, 2311 Flags: header.IPv4FlagDontFragment | header.IPv4FlagMoreFragments, 2312 FragmentOffset: 59776, 2313 TTL: ttl, 2314 Protocol: protocol, 2315 SrcAddr: addr1, 2316 DstAddr: addr2, 2317 }, 2318 overrideIHL: 1, // See note above. 2319 payload: payloadGen(12), 2320 autoChecksum: true, 2321 }, 2322 }, 2323 wantMalformedIPPackets: 1, 2324 wantMalformedFragments: 0, 2325 }, 2326 { 2327 name: "IHL and TotalLength zero, FragmentOffset zero", 2328 fragments: []fragmentData{ 2329 { 2330 ipv4fields: header.IPv4Fields{ 2331 TOS: tos, 2332 TotalLength: 0, 2333 ID: ident, 2334 Flags: header.IPv4FlagMoreFragments, 2335 FragmentOffset: 0, 2336 TTL: ttl, 2337 Protocol: protocol, 2338 SrcAddr: addr1, 2339 DstAddr: addr2, 2340 }, 2341 overrideIHL: 1, // See note above. 2342 payload: payloadGen(12), 2343 autoChecksum: true, 2344 }, 2345 }, 2346 wantMalformedIPPackets: 1, 2347 wantMalformedFragments: 0, 2348 }, 2349 { 2350 // Payload 17 octets and Fragment offset 65520 2351 // Leading to the fragment end to be past 65536. 2352 name: "fragment ends past 65536", 2353 fragments: []fragmentData{ 2354 { 2355 ipv4fields: header.IPv4Fields{ 2356 TOS: tos, 2357 TotalLength: header.IPv4MinimumSize + 17, 2358 ID: ident, 2359 Flags: 0, 2360 FragmentOffset: 65520, 2361 TTL: ttl, 2362 Protocol: protocol, 2363 SrcAddr: addr1, 2364 DstAddr: addr2, 2365 }, 2366 payload: payloadGen(17), 2367 autoChecksum: true, 2368 }, 2369 }, 2370 wantMalformedIPPackets: 1, 2371 wantMalformedFragments: 1, 2372 }, 2373 { 2374 // Payload 16 octets and fragment offset 65520 2375 // Leading to the fragment end to be exactly 65536. 2376 name: "fragment ends exactly at 65536", 2377 fragments: []fragmentData{ 2378 { 2379 ipv4fields: header.IPv4Fields{ 2380 TOS: tos, 2381 TotalLength: header.IPv4MinimumSize + 16, 2382 ID: ident, 2383 Flags: 0, 2384 FragmentOffset: 65520, 2385 TTL: ttl, 2386 Protocol: protocol, 2387 SrcAddr: addr1, 2388 DstAddr: addr2, 2389 }, 2390 payload: payloadGen(16), 2391 autoChecksum: true, 2392 }, 2393 }, 2394 wantMalformedIPPackets: 0, 2395 wantMalformedFragments: 0, 2396 }, 2397 { 2398 name: "IHL less than IPv4 minimum size", 2399 fragments: []fragmentData{ 2400 { 2401 ipv4fields: header.IPv4Fields{ 2402 TOS: tos, 2403 TotalLength: header.IPv4MinimumSize + 28, 2404 ID: ident, 2405 Flags: 0, 2406 FragmentOffset: 1944, 2407 TTL: ttl, 2408 Protocol: protocol, 2409 SrcAddr: addr1, 2410 DstAddr: addr2, 2411 }, 2412 payload: payloadGen(28), 2413 overrideIHL: header.IPv4MinimumSize - 12, 2414 autoChecksum: true, 2415 }, 2416 { 2417 ipv4fields: header.IPv4Fields{ 2418 TOS: tos, 2419 TotalLength: header.IPv4MinimumSize - 12, 2420 ID: ident, 2421 Flags: header.IPv4FlagMoreFragments, 2422 FragmentOffset: 0, 2423 TTL: ttl, 2424 Protocol: protocol, 2425 SrcAddr: addr1, 2426 DstAddr: addr2, 2427 }, 2428 payload: payloadGen(28), 2429 overrideIHL: header.IPv4MinimumSize - 12, 2430 autoChecksum: true, 2431 }, 2432 }, 2433 wantMalformedIPPackets: 2, 2434 wantMalformedFragments: 0, 2435 }, 2436 { 2437 name: "fragment with short TotalLength and extra payload", 2438 fragments: []fragmentData{ 2439 { 2440 ipv4fields: header.IPv4Fields{ 2441 TOS: tos, 2442 TotalLength: header.IPv4MinimumSize + 28, 2443 ID: ident, 2444 Flags: 0, 2445 FragmentOffset: 28816, 2446 TTL: ttl, 2447 Protocol: protocol, 2448 SrcAddr: addr1, 2449 DstAddr: addr2, 2450 }, 2451 payload: payloadGen(28), 2452 overrideIHL: header.IPv4MinimumSize + 4, 2453 autoChecksum: true, 2454 }, 2455 { 2456 ipv4fields: header.IPv4Fields{ 2457 TOS: tos, 2458 TotalLength: header.IPv4MinimumSize + 4, 2459 ID: ident, 2460 Flags: header.IPv4FlagMoreFragments, 2461 FragmentOffset: 0, 2462 TTL: ttl, 2463 Protocol: protocol, 2464 SrcAddr: addr1, 2465 DstAddr: addr2, 2466 }, 2467 payload: payloadGen(28), 2468 overrideIHL: header.IPv4MinimumSize + 4, 2469 autoChecksum: true, 2470 }, 2471 }, 2472 wantMalformedIPPackets: 1, 2473 wantMalformedFragments: 1, 2474 }, 2475 { 2476 name: "multiple fragments with More Fragments flag set to false", 2477 fragments: []fragmentData{ 2478 { 2479 ipv4fields: header.IPv4Fields{ 2480 TOS: tos, 2481 TotalLength: header.IPv4MinimumSize + 8, 2482 ID: ident, 2483 Flags: 0, 2484 FragmentOffset: 128, 2485 TTL: ttl, 2486 Protocol: protocol, 2487 SrcAddr: addr1, 2488 DstAddr: addr2, 2489 }, 2490 payload: payloadGen(8), 2491 autoChecksum: true, 2492 }, 2493 { 2494 ipv4fields: header.IPv4Fields{ 2495 TOS: tos, 2496 TotalLength: header.IPv4MinimumSize + 8, 2497 ID: ident, 2498 Flags: 0, 2499 FragmentOffset: 8, 2500 TTL: ttl, 2501 Protocol: protocol, 2502 SrcAddr: addr1, 2503 DstAddr: addr2, 2504 }, 2505 payload: payloadGen(8), 2506 autoChecksum: true, 2507 }, 2508 { 2509 ipv4fields: header.IPv4Fields{ 2510 TOS: tos, 2511 TotalLength: header.IPv4MinimumSize + 8, 2512 ID: ident, 2513 Flags: header.IPv4FlagMoreFragments, 2514 FragmentOffset: 0, 2515 TTL: ttl, 2516 Protocol: protocol, 2517 SrcAddr: addr1, 2518 DstAddr: addr2, 2519 }, 2520 payload: payloadGen(8), 2521 autoChecksum: true, 2522 }, 2523 }, 2524 wantMalformedIPPackets: 1, 2525 wantMalformedFragments: 1, 2526 }, 2527 } 2528 2529 for _, test := range tests { 2530 t.Run(test.name, func(t *testing.T) { 2531 ctx := newTestContext() 2532 defer ctx.cleanup() 2533 s := ctx.s 2534 2535 e := channel.New(0, 1500, linkAddr) 2536 defer e.Close() 2537 if err := s.CreateNIC(nicID, e); err != nil { 2538 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 2539 } 2540 protocolAddr := tcpip.ProtocolAddress{ 2541 Protocol: ipv4.ProtocolNumber, 2542 AddressWithPrefix: addr2.WithPrefix(), 2543 } 2544 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 2545 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 2546 } 2547 2548 for _, f := range test.fragments { 2549 pktSize := header.IPv4MinimumSize + len(f.payload) 2550 hdr := prependable.New(pktSize) 2551 2552 ip := header.IPv4(hdr.Prepend(pktSize)) 2553 ip.Encode(&f.ipv4fields) 2554 if want, got := len(f.payload), copy(ip[header.IPv4MinimumSize:], f.payload); want != got { 2555 t.Fatalf("copied %d bytes, expected %d bytes.", got, want) 2556 } 2557 // Encode sets this up correctly. If we want a different value for 2558 // testing then we need to overwrite the good value. 2559 if f.overrideIHL != 0 { 2560 ip.SetHeaderLength(uint8(f.overrideIHL)) 2561 // If we are asked to add options (type not specified) then pad 2562 // with 0 (EOL). RFC 791 page 23 says "The padding is zero". 2563 for i := header.IPv4MinimumSize; i < f.overrideIHL; i++ { 2564 ip[i] = byte(header.IPv4OptionListEndType) 2565 } 2566 } 2567 2568 if f.autoChecksum { 2569 ip.SetChecksum(0) 2570 ip.SetChecksum(^ip.CalculateChecksum()) 2571 } 2572 2573 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 2574 Payload: buffer.MakeWithData(hdr.View()), 2575 }) 2576 e.InjectInbound(header.IPv4ProtocolNumber, pkt) 2577 pkt.DecRef() 2578 } 2579 2580 if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.wantMalformedIPPackets; got != want { 2581 t.Errorf("incorrect Stats.IP.MalformedPacketsReceived, got: %d, want: %d", got, want) 2582 } 2583 if got, want := s.Stats().IP.MalformedFragmentsReceived.Value(), test.wantMalformedFragments; got != want { 2584 t.Errorf("incorrect Stats.IP.MalformedFragmentsReceived, got: %d, want: %d", got, want) 2585 } 2586 }) 2587 } 2588 } 2589 2590 func TestFragmentReassemblyTimeout(t *testing.T) { 2591 const ( 2592 nicID = 1 2593 linkAddr = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e") 2594 tos = 0 2595 ident = 1 2596 ttl = 48 2597 protocol = 99 2598 data = "TEST_FRAGMENT_REASSEMBLY_TIMEOUT" 2599 ) 2600 2601 var ( 2602 addr1 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x01")) 2603 addr2 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x02")) 2604 ) 2605 2606 type fragmentData struct { 2607 ipv4fields header.IPv4Fields 2608 payload []byte 2609 } 2610 2611 tests := []struct { 2612 name string 2613 fragments []fragmentData 2614 expectICMP bool 2615 }{ 2616 { 2617 name: "first fragment only", 2618 fragments: []fragmentData{ 2619 { 2620 ipv4fields: header.IPv4Fields{ 2621 TOS: tos, 2622 TotalLength: header.IPv4MinimumSize + 16, 2623 ID: ident, 2624 Flags: header.IPv4FlagMoreFragments, 2625 FragmentOffset: 0, 2626 TTL: ttl, 2627 Protocol: protocol, 2628 SrcAddr: addr1, 2629 DstAddr: addr2, 2630 }, 2631 payload: []byte(data)[:16], 2632 }, 2633 }, 2634 expectICMP: true, 2635 }, 2636 { 2637 name: "two first fragments", 2638 fragments: []fragmentData{ 2639 { 2640 ipv4fields: header.IPv4Fields{ 2641 TOS: tos, 2642 TotalLength: header.IPv4MinimumSize + 16, 2643 ID: ident, 2644 Flags: header.IPv4FlagMoreFragments, 2645 FragmentOffset: 0, 2646 TTL: ttl, 2647 Protocol: protocol, 2648 SrcAddr: addr1, 2649 DstAddr: addr2, 2650 }, 2651 payload: []byte(data)[:16], 2652 }, 2653 { 2654 ipv4fields: header.IPv4Fields{ 2655 TOS: tos, 2656 TotalLength: header.IPv4MinimumSize + 16, 2657 ID: ident, 2658 Flags: header.IPv4FlagMoreFragments, 2659 FragmentOffset: 0, 2660 TTL: ttl, 2661 Protocol: protocol, 2662 SrcAddr: addr1, 2663 DstAddr: addr2, 2664 }, 2665 payload: []byte(data)[:16], 2666 }, 2667 }, 2668 expectICMP: true, 2669 }, 2670 { 2671 name: "second fragment only", 2672 fragments: []fragmentData{ 2673 { 2674 ipv4fields: header.IPv4Fields{ 2675 TOS: tos, 2676 TotalLength: uint16(header.IPv4MinimumSize + len(data) - 16), 2677 ID: ident, 2678 Flags: 0, 2679 FragmentOffset: 8, 2680 TTL: ttl, 2681 Protocol: protocol, 2682 SrcAddr: addr1, 2683 DstAddr: addr2, 2684 }, 2685 payload: []byte(data)[16:], 2686 }, 2687 }, 2688 expectICMP: false, 2689 }, 2690 { 2691 name: "two fragments with a gap", 2692 fragments: []fragmentData{ 2693 { 2694 ipv4fields: header.IPv4Fields{ 2695 TOS: tos, 2696 TotalLength: header.IPv4MinimumSize + 8, 2697 ID: ident, 2698 Flags: header.IPv4FlagMoreFragments, 2699 FragmentOffset: 0, 2700 TTL: ttl, 2701 Protocol: protocol, 2702 SrcAddr: addr1, 2703 DstAddr: addr2, 2704 }, 2705 payload: []byte(data)[:8], 2706 }, 2707 { 2708 ipv4fields: header.IPv4Fields{ 2709 TOS: tos, 2710 TotalLength: uint16(header.IPv4MinimumSize + len(data) - 16), 2711 ID: ident, 2712 Flags: 0, 2713 FragmentOffset: 16, 2714 TTL: ttl, 2715 Protocol: protocol, 2716 SrcAddr: addr1, 2717 DstAddr: addr2, 2718 }, 2719 payload: []byte(data)[16:], 2720 }, 2721 }, 2722 expectICMP: true, 2723 }, 2724 { 2725 name: "two fragments with a gap in reverse order", 2726 fragments: []fragmentData{ 2727 { 2728 ipv4fields: header.IPv4Fields{ 2729 TOS: tos, 2730 TotalLength: uint16(header.IPv4MinimumSize + len(data) - 16), 2731 ID: ident, 2732 Flags: 0, 2733 FragmentOffset: 16, 2734 TTL: ttl, 2735 Protocol: protocol, 2736 SrcAddr: addr1, 2737 DstAddr: addr2, 2738 }, 2739 payload: []byte(data)[16:], 2740 }, 2741 { 2742 ipv4fields: header.IPv4Fields{ 2743 TOS: tos, 2744 TotalLength: header.IPv4MinimumSize + 8, 2745 ID: ident, 2746 Flags: header.IPv4FlagMoreFragments, 2747 FragmentOffset: 0, 2748 TTL: ttl, 2749 Protocol: protocol, 2750 SrcAddr: addr1, 2751 DstAddr: addr2, 2752 }, 2753 payload: []byte(data)[:8], 2754 }, 2755 }, 2756 expectICMP: true, 2757 }, 2758 } 2759 2760 for _, test := range tests { 2761 t.Run(test.name, func(t *testing.T) { 2762 ctx := newTestContext() 2763 defer ctx.cleanup() 2764 s := ctx.s 2765 clock := ctx.clock 2766 2767 e := channel.New(1, 1500, linkAddr) 2768 defer e.Close() 2769 if err := s.CreateNIC(nicID, e); err != nil { 2770 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 2771 } 2772 protocolAddr := tcpip.ProtocolAddress{ 2773 Protocol: ipv4.ProtocolNumber, 2774 AddressWithPrefix: addr2.WithPrefix(), 2775 } 2776 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 2777 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 2778 } 2779 s.SetRouteTable([]tcpip.Route{{ 2780 Destination: header.IPv4EmptySubnet, 2781 NIC: nicID, 2782 }}) 2783 2784 var firstFragmentSent buffer.Buffer 2785 for _, f := range test.fragments { 2786 pktSize := header.IPv4MinimumSize 2787 hdr := prependable.New(pktSize) 2788 2789 ip := header.IPv4(hdr.Prepend(pktSize)) 2790 ip.Encode(&f.ipv4fields) 2791 2792 ip.SetChecksum(0) 2793 ip.SetChecksum(^ip.CalculateChecksum()) 2794 2795 buf := buffer.MakeWithData(hdr.View()) 2796 buf.Append(buffer.NewViewWithData(f.payload)) 2797 2798 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 2799 Payload: buf, 2800 }) 2801 2802 if firstFragmentSent.Size() == 0 && ip.FragmentOffset() == 0 { 2803 firstFragmentSent = buffer.MakeWithView(stack.PayloadSince(pkt.NetworkHeader())) 2804 defer firstFragmentSent.Release() 2805 } 2806 2807 e.InjectInbound(header.IPv4ProtocolNumber, pkt) 2808 pkt.DecRef() 2809 } 2810 2811 clock.Advance(ipv4.ReassembleTimeout) 2812 2813 reply := e.Read() 2814 if !test.expectICMP { 2815 if reply != nil { 2816 t.Fatalf("unexpected ICMP error message received: %#v", reply) 2817 } 2818 return 2819 } 2820 if reply == nil { 2821 t.Fatal("expected ICMP error message missing") 2822 } 2823 if firstFragmentSent.Size() == 0 { 2824 t.Fatalf("unexpected ICMP error message received: %#v", reply) 2825 } 2826 2827 payload := stack.PayloadSince(reply.NetworkHeader()) 2828 defer payload.Release() 2829 checker.IPv4(t, payload, 2830 checker.SrcAddr(addr2), 2831 checker.DstAddr(addr1), 2832 checker.IPFullLength(uint16(header.IPv4MinimumSize+header.ICMPv4MinimumSize+firstFragmentSent.Size())), 2833 checker.IPv4HeaderLength(header.IPv4MinimumSize), 2834 checker.ICMPv4( 2835 checker.ICMPv4Type(header.ICMPv4TimeExceeded), 2836 checker.ICMPv4Code(header.ICMPv4ReassemblyTimeout), 2837 checker.ICMPv4Checksum(), 2838 checker.ICMPv4Payload(firstFragmentSent.Flatten()), 2839 ), 2840 ) 2841 reply.DecRef() 2842 }) 2843 } 2844 } 2845 2846 // TestReceiveFragments feeds fragments in through the incoming packet path to 2847 // test reassembly 2848 func TestReceiveFragments(t *testing.T) { 2849 const ( 2850 nicID = 1 2851 ) 2852 2853 var ( 2854 addr1 = tcpip.AddrFromSlice([]byte("\x0c\xa8\x00\x01")) // 192.168.0.1 2855 addr2 = tcpip.AddrFromSlice([]byte("\x0c\xa8\x00\x02")) // 192.168.0.2 2856 addr3 = tcpip.AddrFromSlice([]byte("\x0c\xa8\x00\x03")) // 192.168.0.3 2857 ) 2858 2859 // Build and return a UDP header containing payload. 2860 udpGen := func(payloadLen int, multiplier uint8, src, dst tcpip.Address) []byte { 2861 payload := make([]byte, payloadLen) 2862 for i := 0; i < len(payload); i++ { 2863 payload[i] = uint8(i) * multiplier 2864 } 2865 2866 udpLength := header.UDPMinimumSize + len(payload) 2867 2868 hdr := prependable.New(udpLength) 2869 u := header.UDP(hdr.Prepend(udpLength)) 2870 u.Encode(&header.UDPFields{ 2871 SrcPort: 5555, 2872 DstPort: 80, 2873 Length: uint16(udpLength), 2874 }) 2875 copy(u.Payload(), payload) 2876 sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(udpLength)) 2877 sum = checksum.Checksum(payload, sum) 2878 u.SetChecksum(^u.CalculateChecksum(sum)) 2879 return hdr.View() 2880 } 2881 2882 // UDP header plus a payload of 0..256 2883 ipv4Payload1Addr1ToAddr2 := udpGen(256, 1, addr1, addr2) 2884 udpPayload1Addr1ToAddr2 := ipv4Payload1Addr1ToAddr2[header.UDPMinimumSize:] 2885 ipv4Payload1Addr3ToAddr2 := udpGen(256, 1, addr3, addr2) 2886 udpPayload1Addr3ToAddr2 := ipv4Payload1Addr3ToAddr2[header.UDPMinimumSize:] 2887 // UDP header plus a payload of 0..256 in increments of 2. 2888 ipv4Payload2Addr1ToAddr2 := udpGen(128, 2, addr1, addr2) 2889 udpPayload2Addr1ToAddr2 := ipv4Payload2Addr1ToAddr2[header.UDPMinimumSize:] 2890 // UDP header plus a payload of 0..256 in increments of 3. 2891 // Used to test cases where the fragment blocks are not a multiple of 2892 // the fragment block size of 8 (RFC 791 section 3.1 page 14). 2893 ipv4Payload3Addr1ToAddr2 := udpGen(127, 3, addr1, addr2) 2894 udpPayload3Addr1ToAddr2 := ipv4Payload3Addr1ToAddr2[header.UDPMinimumSize:] 2895 // Used to test the max reassembled IPv4 payload length. 2896 ipv4Payload4Addr1ToAddr2 := udpGen(header.UDPMaximumSize-header.UDPMinimumSize, 4, addr1, addr2) 2897 udpPayload4Addr1ToAddr2 := ipv4Payload4Addr1ToAddr2[header.UDPMinimumSize:] 2898 2899 type fragmentData struct { 2900 srcAddr tcpip.Address 2901 dstAddr tcpip.Address 2902 id uint16 2903 flags uint8 2904 fragmentOffset uint16 2905 payload []byte 2906 } 2907 2908 tests := []struct { 2909 name string 2910 fragments []fragmentData 2911 expectedPayloads [][]byte 2912 }{ 2913 { 2914 name: "No fragmentation", 2915 fragments: []fragmentData{ 2916 { 2917 srcAddr: addr1, 2918 dstAddr: addr2, 2919 id: 1, 2920 flags: 0, 2921 fragmentOffset: 0, 2922 payload: ipv4Payload1Addr1ToAddr2, 2923 }, 2924 }, 2925 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 2926 }, 2927 { 2928 name: "No fragmentation with size not a multiple of fragment block size", 2929 fragments: []fragmentData{ 2930 { 2931 srcAddr: addr1, 2932 dstAddr: addr2, 2933 id: 1, 2934 flags: 0, 2935 fragmentOffset: 0, 2936 payload: ipv4Payload3Addr1ToAddr2, 2937 }, 2938 }, 2939 expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2}, 2940 }, 2941 { 2942 name: "More fragments without payload", 2943 fragments: []fragmentData{ 2944 { 2945 srcAddr: addr1, 2946 dstAddr: addr2, 2947 id: 1, 2948 flags: header.IPv4FlagMoreFragments, 2949 fragmentOffset: 0, 2950 payload: ipv4Payload1Addr1ToAddr2, 2951 }, 2952 }, 2953 expectedPayloads: nil, 2954 }, 2955 { 2956 name: "Non-zero fragment offset without payload", 2957 fragments: []fragmentData{ 2958 { 2959 srcAddr: addr1, 2960 dstAddr: addr2, 2961 id: 1, 2962 flags: 0, 2963 fragmentOffset: 8, 2964 payload: ipv4Payload1Addr1ToAddr2, 2965 }, 2966 }, 2967 expectedPayloads: nil, 2968 }, 2969 { 2970 name: "Two fragments", 2971 fragments: []fragmentData{ 2972 { 2973 srcAddr: addr1, 2974 dstAddr: addr2, 2975 id: 1, 2976 flags: header.IPv4FlagMoreFragments, 2977 fragmentOffset: 0, 2978 payload: ipv4Payload1Addr1ToAddr2[:64], 2979 }, 2980 { 2981 srcAddr: addr1, 2982 dstAddr: addr2, 2983 id: 1, 2984 flags: 0, 2985 fragmentOffset: 64, 2986 payload: ipv4Payload1Addr1ToAddr2[64:], 2987 }, 2988 }, 2989 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 2990 }, 2991 { 2992 name: "Two fragments out of order", 2993 fragments: []fragmentData{ 2994 { 2995 srcAddr: addr1, 2996 dstAddr: addr2, 2997 id: 1, 2998 flags: 0, 2999 fragmentOffset: 64, 3000 payload: ipv4Payload1Addr1ToAddr2[64:], 3001 }, 3002 { 3003 srcAddr: addr1, 3004 dstAddr: addr2, 3005 id: 1, 3006 flags: header.IPv4FlagMoreFragments, 3007 fragmentOffset: 0, 3008 payload: ipv4Payload1Addr1ToAddr2[:64], 3009 }, 3010 }, 3011 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, 3012 }, 3013 { 3014 name: "Two fragments with last fragment size not a multiple of fragment block size", 3015 fragments: []fragmentData{ 3016 { 3017 srcAddr: addr1, 3018 dstAddr: addr2, 3019 id: 1, 3020 flags: header.IPv4FlagMoreFragments, 3021 fragmentOffset: 0, 3022 payload: ipv4Payload3Addr1ToAddr2[:64], 3023 }, 3024 { 3025 srcAddr: addr1, 3026 dstAddr: addr2, 3027 id: 1, 3028 flags: 0, 3029 fragmentOffset: 64, 3030 payload: ipv4Payload3Addr1ToAddr2[64:], 3031 }, 3032 }, 3033 expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2}, 3034 }, 3035 { 3036 name: "Two fragments with first fragment size not a multiple of fragment block size", 3037 fragments: []fragmentData{ 3038 { 3039 srcAddr: addr1, 3040 dstAddr: addr2, 3041 id: 1, 3042 flags: header.IPv4FlagMoreFragments, 3043 fragmentOffset: 0, 3044 payload: ipv4Payload3Addr1ToAddr2[:63], 3045 }, 3046 { 3047 srcAddr: addr1, 3048 dstAddr: addr2, 3049 id: 1, 3050 flags: 0, 3051 fragmentOffset: 63, 3052 payload: ipv4Payload3Addr1ToAddr2[63:], 3053 }, 3054 }, 3055 expectedPayloads: nil, 3056 }, 3057 { 3058 name: "Second fragment has MoreFlags set", 3059 fragments: []fragmentData{ 3060 { 3061 srcAddr: addr1, 3062 dstAddr: addr2, 3063 id: 1, 3064 flags: header.IPv4FlagMoreFragments, 3065 fragmentOffset: 0, 3066 payload: ipv4Payload1Addr1ToAddr2[:64], 3067 }, 3068 { 3069 srcAddr: addr1, 3070 dstAddr: addr2, 3071 id: 1, 3072 flags: header.IPv4FlagMoreFragments, 3073 fragmentOffset: 64, 3074 payload: ipv4Payload1Addr1ToAddr2[64:], 3075 }, 3076 }, 3077 expectedPayloads: nil, 3078 }, 3079 { 3080 name: "Two fragments with different IDs", 3081 fragments: []fragmentData{ 3082 { 3083 srcAddr: addr1, 3084 dstAddr: addr2, 3085 id: 1, 3086 flags: header.IPv4FlagMoreFragments, 3087 fragmentOffset: 0, 3088 payload: ipv4Payload1Addr1ToAddr2[:64], 3089 }, 3090 { 3091 srcAddr: addr1, 3092 dstAddr: addr2, 3093 id: 2, 3094 flags: 0, 3095 fragmentOffset: 64, 3096 payload: ipv4Payload1Addr1ToAddr2[64:], 3097 }, 3098 }, 3099 expectedPayloads: nil, 3100 }, 3101 { 3102 name: "Two interleaved fragmented packets", 3103 fragments: []fragmentData{ 3104 { 3105 srcAddr: addr1, 3106 dstAddr: addr2, 3107 id: 1, 3108 flags: header.IPv4FlagMoreFragments, 3109 fragmentOffset: 0, 3110 payload: ipv4Payload1Addr1ToAddr2[:64], 3111 }, 3112 { 3113 srcAddr: addr1, 3114 dstAddr: addr2, 3115 id: 2, 3116 flags: header.IPv4FlagMoreFragments, 3117 fragmentOffset: 0, 3118 payload: ipv4Payload2Addr1ToAddr2[:64], 3119 }, 3120 { 3121 srcAddr: addr1, 3122 dstAddr: addr2, 3123 id: 1, 3124 flags: 0, 3125 fragmentOffset: 64, 3126 payload: ipv4Payload1Addr1ToAddr2[64:], 3127 }, 3128 { 3129 srcAddr: addr1, 3130 dstAddr: addr2, 3131 id: 2, 3132 flags: 0, 3133 fragmentOffset: 64, 3134 payload: ipv4Payload2Addr1ToAddr2[64:], 3135 }, 3136 }, 3137 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload2Addr1ToAddr2}, 3138 }, 3139 { 3140 name: "Two interleaved fragmented packets from different sources but with same ID", 3141 fragments: []fragmentData{ 3142 { 3143 srcAddr: addr1, 3144 dstAddr: addr2, 3145 id: 1, 3146 flags: header.IPv4FlagMoreFragments, 3147 fragmentOffset: 0, 3148 payload: ipv4Payload1Addr1ToAddr2[:64], 3149 }, 3150 { 3151 srcAddr: addr3, 3152 dstAddr: addr2, 3153 id: 1, 3154 flags: header.IPv4FlagMoreFragments, 3155 fragmentOffset: 0, 3156 payload: ipv4Payload1Addr3ToAddr2[:32], 3157 }, 3158 { 3159 srcAddr: addr1, 3160 dstAddr: addr2, 3161 id: 1, 3162 flags: 0, 3163 fragmentOffset: 64, 3164 payload: ipv4Payload1Addr1ToAddr2[64:], 3165 }, 3166 { 3167 srcAddr: addr3, 3168 dstAddr: addr2, 3169 id: 1, 3170 flags: 0, 3171 fragmentOffset: 32, 3172 payload: ipv4Payload1Addr3ToAddr2[32:], 3173 }, 3174 }, 3175 expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload1Addr3ToAddr2}, 3176 }, 3177 { 3178 name: "Fragment without followup", 3179 fragments: []fragmentData{ 3180 { 3181 srcAddr: addr1, 3182 dstAddr: addr2, 3183 id: 1, 3184 flags: header.IPv4FlagMoreFragments, 3185 fragmentOffset: 0, 3186 payload: ipv4Payload1Addr1ToAddr2[:64], 3187 }, 3188 }, 3189 expectedPayloads: nil, 3190 }, 3191 { 3192 name: "Two fragments reassembled into a maximum UDP packet", 3193 fragments: []fragmentData{ 3194 { 3195 srcAddr: addr1, 3196 dstAddr: addr2, 3197 id: 1, 3198 flags: header.IPv4FlagMoreFragments, 3199 fragmentOffset: 0, 3200 payload: ipv4Payload4Addr1ToAddr2[:65512], 3201 }, 3202 { 3203 srcAddr: addr1, 3204 dstAddr: addr2, 3205 id: 1, 3206 flags: 0, 3207 fragmentOffset: 65512, 3208 payload: ipv4Payload4Addr1ToAddr2[65512:], 3209 }, 3210 }, 3211 expectedPayloads: [][]byte{udpPayload4Addr1ToAddr2}, 3212 }, 3213 { 3214 name: "Two fragments with MF flag reassembled into a maximum UDP packet", 3215 fragments: []fragmentData{ 3216 { 3217 srcAddr: addr1, 3218 dstAddr: addr2, 3219 id: 1, 3220 flags: header.IPv4FlagMoreFragments, 3221 fragmentOffset: 0, 3222 payload: ipv4Payload4Addr1ToAddr2[:65512], 3223 }, 3224 { 3225 srcAddr: addr1, 3226 dstAddr: addr2, 3227 id: 1, 3228 flags: header.IPv4FlagMoreFragments, 3229 fragmentOffset: 65512, 3230 payload: ipv4Payload4Addr1ToAddr2[65512:], 3231 }, 3232 }, 3233 expectedPayloads: nil, 3234 }, 3235 } 3236 3237 for _, test := range tests { 3238 t.Run(test.name, func(t *testing.T) { 3239 ctx := newTestContext() 3240 defer ctx.cleanup() 3241 s := ctx.s 3242 3243 e := channel.New(0, 1280, "\xf0\x00") 3244 defer e.Close() 3245 if err := s.CreateNIC(nicID, e); err != nil { 3246 t.Fatalf("CreateNIC(%d, _) = %s", nicID, err) 3247 } 3248 protocolAddr := tcpip.ProtocolAddress{ 3249 Protocol: header.IPv4ProtocolNumber, 3250 AddressWithPrefix: addr2.WithPrefix(), 3251 } 3252 if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil { 3253 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) 3254 } 3255 3256 wq := waiter.Queue{} 3257 we, ch := waiter.NewChannelEntry(waiter.ReadableEvents) 3258 wq.EventRegister(&we) 3259 defer wq.EventUnregister(&we) 3260 defer close(ch) 3261 ep, err := s.NewEndpoint(udp.ProtocolNumber, header.IPv4ProtocolNumber, &wq) 3262 if err != nil { 3263 t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, header.IPv4ProtocolNumber, err) 3264 } 3265 defer ep.Close() 3266 3267 bindAddr := tcpip.FullAddress{Addr: addr2, Port: 80} 3268 if err := ep.Bind(bindAddr); err != nil { 3269 t.Fatalf("Bind(%+v): %s", bindAddr, err) 3270 } 3271 3272 // Bring up a raw endpoint so we can examine network headers. 3273 epRaw, err := s.NewRawEndpoint(udp.ProtocolNumber, header.IPv4ProtocolNumber, &wq, true /* associated */) 3274 if err != nil { 3275 t.Fatalf("NewRawEndpoint(%d, %d, _, true): %s", udp.ProtocolNumber, header.IPv4ProtocolNumber, err) 3276 } 3277 defer epRaw.Close() 3278 3279 // Prepare and send the fragments. 3280 for _, frag := range test.fragments { 3281 hdr := prependable.New(header.IPv4MinimumSize) 3282 3283 // Serialize IPv4 fixed header. 3284 ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) 3285 ip.Encode(&header.IPv4Fields{ 3286 TotalLength: header.IPv4MinimumSize + uint16(len(frag.payload)), 3287 ID: frag.id, 3288 Flags: frag.flags, 3289 FragmentOffset: frag.fragmentOffset, 3290 TTL: 64, 3291 Protocol: uint8(header.UDPProtocolNumber), 3292 SrcAddr: frag.srcAddr, 3293 DstAddr: frag.dstAddr, 3294 }) 3295 ip.SetChecksum(^ip.CalculateChecksum()) 3296 3297 buf := buffer.MakeWithData(hdr.View()) 3298 buf.Append(buffer.NewViewWithData(frag.payload)) 3299 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 3300 Payload: buf, 3301 }) 3302 e.InjectInbound(header.IPv4ProtocolNumber, pkt) 3303 pkt.DecRef() 3304 } 3305 3306 if got, want := s.Stats().UDP.PacketsReceived.Value(), uint64(len(test.expectedPayloads)); got != want { 3307 t.Errorf("got UDP Rx Packets = %d, want = %d", got, want) 3308 } 3309 3310 for i, expectedPayload := range test.expectedPayloads { 3311 // Check UDP payload delivered by UDP endpoint. 3312 var buf bytes.Buffer 3313 result, err := ep.Read(&buf, tcpip.ReadOptions{}) 3314 if err != nil { 3315 t.Fatalf("(i=%d) ep.Read: %s", i, err) 3316 } 3317 if diff := cmp.Diff(tcpip.ReadResult{ 3318 Count: len(expectedPayload), 3319 Total: len(expectedPayload), 3320 }, result, checker.IgnoreCmpPath("ControlMessages")); diff != "" { 3321 t.Errorf("(i=%d) ep.Read: unexpected result (-want +got):\n%s", i, diff) 3322 } 3323 if diff := cmp.Diff(expectedPayload, buf.Bytes()); diff != "" { 3324 t.Errorf("(i=%d) ep.Read: UDP payload mismatch (-want +got):\n%s", i, diff) 3325 } 3326 3327 // Check IPv4 header in packet delivered by raw endpoint. 3328 buf.Reset() 3329 _, err = epRaw.Read(&buf, tcpip.ReadOptions{}) 3330 if err != nil { 3331 t.Fatalf("(i=%d) epRaw.Read: %s", i, err) 3332 } 3333 // Reassambly does not take care of checksum. Here we write our own 3334 // check routine instead of using checker.IPv4. 3335 ip := header.IPv4(buf.Bytes()) 3336 for _, check := range []checker.NetworkChecker{ 3337 checker.FragmentFlags(0), 3338 checker.FragmentOffset(0), 3339 checker.IPFullLength(uint16(header.IPv4MinimumSize + header.UDPMinimumSize + len(expectedPayload))), 3340 } { 3341 check(t, []header.Network{ip}) 3342 } 3343 } 3344 3345 res, err := ep.Read(ioutil.Discard, tcpip.ReadOptions{}) 3346 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 3347 t.Fatalf("(last) got Read = (%#v, %v), want = (_, %s)", res, err, &tcpip.ErrWouldBlock{}) 3348 } 3349 }) 3350 } 3351 } 3352 3353 func TestWriteStats(t *testing.T) { 3354 const nPackets = 3 3355 3356 tests := []struct { 3357 name string 3358 setup func(*testing.T, *stack.Stack) 3359 allowPackets int 3360 expectSent int 3361 expectOutputDropped int 3362 expectPostroutingDropped int 3363 expectWritten int 3364 }{ 3365 { 3366 name: "Accept all", 3367 // No setup needed, tables accept everything by default. 3368 setup: func(*testing.T, *stack.Stack) {}, 3369 allowPackets: math.MaxInt32, 3370 expectSent: nPackets, 3371 expectOutputDropped: 0, 3372 expectPostroutingDropped: 0, 3373 expectWritten: nPackets, 3374 }, { 3375 name: "Accept all with error", 3376 // No setup needed, tables accept everything by default. 3377 setup: func(*testing.T, *stack.Stack) {}, 3378 allowPackets: nPackets - 1, 3379 expectSent: nPackets - 1, 3380 expectOutputDropped: 0, 3381 expectPostroutingDropped: 0, 3382 expectWritten: nPackets - 1, 3383 }, { 3384 name: "Drop all with Output chain", 3385 setup: func(t *testing.T, stk *stack.Stack) { 3386 // Install Output DROP rule. 3387 ipt := stk.IPTables() 3388 filter := ipt.GetTable(stack.FilterID, false /* ipv6 */) 3389 ruleIdx := filter.BuiltinChains[stack.Output] 3390 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 3391 ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) 3392 }, 3393 allowPackets: math.MaxInt32, 3394 expectSent: 0, 3395 expectOutputDropped: nPackets, 3396 expectPostroutingDropped: 0, 3397 expectWritten: nPackets, 3398 }, { 3399 name: "Drop all with Postrouting chain", 3400 setup: func(t *testing.T, stk *stack.Stack) { 3401 ipt := stk.IPTables() 3402 filter := ipt.GetTable(stack.NATID, false /* ipv6 */) 3403 ruleIdx := filter.BuiltinChains[stack.Postrouting] 3404 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 3405 ipt.ForceReplaceTable(stack.NATID, filter, false /* ipv6 */) 3406 }, 3407 allowPackets: math.MaxInt32, 3408 expectSent: 0, 3409 expectOutputDropped: 0, 3410 expectPostroutingDropped: nPackets, 3411 expectWritten: nPackets, 3412 }, { 3413 name: "Drop some with Output chain", 3414 setup: func(t *testing.T, stk *stack.Stack) { 3415 // Install Output DROP rule that matches only 1 3416 // of the 3 packets. 3417 ipt := stk.IPTables() 3418 filter := ipt.GetTable(stack.FilterID, false /* ipv6 */) 3419 // We'll match and DROP the last packet. 3420 ruleIdx := filter.BuiltinChains[stack.Output] 3421 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 3422 filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} 3423 // Make sure the next rule is ACCEPT. 3424 filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} 3425 ipt.ForceReplaceTable(stack.FilterID, filter, false /* ipv6 */) 3426 }, 3427 allowPackets: math.MaxInt32, 3428 expectSent: nPackets - 1, 3429 expectOutputDropped: 1, 3430 expectPostroutingDropped: 0, 3431 expectWritten: nPackets, 3432 }, { 3433 name: "Drop some with Postrouting chain", 3434 setup: func(t *testing.T, stk *stack.Stack) { 3435 // Install Postrouting DROP rule that matches only 1 3436 // of the 3 packets. 3437 ipt := stk.IPTables() 3438 filter := ipt.GetTable(stack.NATID, false /* ipv6 */) 3439 // We'll match and DROP the last packet. 3440 ruleIdx := filter.BuiltinChains[stack.Postrouting] 3441 filter.Rules[ruleIdx].Target = &stack.DropTarget{} 3442 filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}} 3443 // Make sure the next rule is ACCEPT. 3444 filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{} 3445 ipt.ForceReplaceTable(stack.NATID, filter, false /* ipv6 */) 3446 }, 3447 allowPackets: math.MaxInt32, 3448 expectSent: nPackets - 1, 3449 expectOutputDropped: 0, 3450 expectPostroutingDropped: 1, 3451 expectWritten: nPackets, 3452 }, 3453 } 3454 3455 for _, test := range tests { 3456 t.Run(test.name, func(t *testing.T) { 3457 ctx := newTestContext() 3458 defer ctx.cleanup() 3459 3460 ep := iptestutil.NewMockLinkEndpoint(header.IPv4MinimumMTU, &tcpip.ErrInvalidEndpointState{}, test.allowPackets) 3461 defer ep.Close() 3462 rt := buildRoute(t, ctx, ep) 3463 defer rt.Release() 3464 3465 test.setup(t, rt.Stack()) 3466 nWritten := 0 3467 for i := 0; i < nPackets; i++ { 3468 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 3469 ReserveHeaderBytes: header.UDPMinimumSize + int(rt.MaxHeaderLength()), 3470 Payload: buffer.Buffer{}, 3471 }) 3472 defer pkt.DecRef() 3473 pkt.TransportHeader().Push(header.UDPMinimumSize) 3474 if err := rt.WritePacket(stack.NetworkHeaderParams{}, pkt); err != nil { 3475 break 3476 } 3477 nWritten++ 3478 } 3479 3480 if got := int(rt.Stats().IP.PacketsSent.Value()); got != test.expectSent { 3481 t.Errorf("got rt.Stats().IP.PacketsSent.Value() = %d, want = %d", got, test.expectSent) 3482 } 3483 if got := int(rt.Stats().IP.IPTablesOutputDropped.Value()); got != test.expectOutputDropped { 3484 t.Errorf("got rt.Stats().IP.IPTablesOutputDropped.Value() = %d, want = %d", got, test.expectOutputDropped) 3485 } 3486 if got := int(rt.Stats().IP.IPTablesPostroutingDropped.Value()); got != test.expectPostroutingDropped { 3487 t.Errorf("got rt.Stats().IP.IPTablesPostroutingDropped.Value() = %d, want = %d", got, test.expectPostroutingDropped) 3488 } 3489 if nWritten != test.expectWritten { 3490 t.Errorf("got nWritten = %d, want = %d", nWritten, test.expectWritten) 3491 } 3492 }) 3493 } 3494 } 3495 3496 func buildRoute(t *testing.T, c testContext, ep stack.LinkEndpoint) *stack.Route { 3497 s := c.s 3498 if err := s.CreateNIC(1, ep); err != nil { 3499 t.Fatalf("CreateNIC(1, _) failed: %s", err) 3500 } 3501 var ( 3502 src = tcpip.AddrFromSlice([]byte("\x10\x00\x00\x01")) 3503 dst = tcpip.AddrFromSlice([]byte("\x10\x00\x00\x02")) 3504 ) 3505 protocolAddr := tcpip.ProtocolAddress{ 3506 Protocol: ipv4.ProtocolNumber, 3507 AddressWithPrefix: src.WithPrefix(), 3508 } 3509 if err := s.AddProtocolAddress(1, protocolAddr, stack.AddressProperties{}); err != nil { 3510 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", 1, protocolAddr, err) 3511 } 3512 { 3513 mask := tcpip.MaskFromBytes(header.IPv4Broadcast.AsSlice()) 3514 subnet, err := tcpip.NewSubnet(dst, mask) 3515 if err != nil { 3516 t.Fatalf("NewSubnet(%s, %s) failed: %v", dst, mask, err) 3517 } 3518 s.SetRouteTable([]tcpip.Route{{ 3519 Destination: subnet, 3520 NIC: 1, 3521 }}) 3522 } 3523 rt, err := s.FindRoute(1, src, dst, ipv4.ProtocolNumber, false /* multicastLoop */) 3524 if err != nil { 3525 t.Fatalf("FindRoute(1, %s, %s, %d, false) = %s", src, dst, ipv4.ProtocolNumber, err) 3526 } 3527 return rt 3528 } 3529 3530 // limitedMatcher is an iptables matcher that matches after a certain number of 3531 // packets are checked against it. 3532 type limitedMatcher struct { 3533 limit int 3534 } 3535 3536 // Name implements Matcher.Name. 3537 func (*limitedMatcher) Name() string { 3538 return "limitedMatcher" 3539 } 3540 3541 // Match implements Matcher.Match. 3542 func (lm *limitedMatcher) Match(stack.Hook, *stack.PacketBuffer, string, string) (bool, bool) { 3543 if lm.limit == 0 { 3544 return true, false 3545 } 3546 lm.limit-- 3547 return false, false 3548 } 3549 3550 func TestPacketQueuing(t *testing.T) { 3551 const nicID = 1 3552 3553 var ( 3554 host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06") 3555 host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09") 3556 3557 host1IPv4Addr = tcpip.ProtocolAddress{ 3558 Protocol: ipv4.ProtocolNumber, 3559 AddressWithPrefix: tcpip.AddressWithPrefix{ 3560 Address: tcpip.AddrFromSlice(net.ParseIP("192.168.0.1").To4()), 3561 PrefixLen: 24, 3562 }, 3563 } 3564 host2IPv4Addr = tcpip.ProtocolAddress{ 3565 Protocol: ipv4.ProtocolNumber, 3566 AddressWithPrefix: tcpip.AddressWithPrefix{ 3567 Address: tcpip.AddrFromSlice(net.ParseIP("192.168.0.2").To4()), 3568 PrefixLen: 8, 3569 }, 3570 } 3571 ) 3572 3573 tests := []struct { 3574 name string 3575 rxPkt func(*channel.Endpoint) 3576 checkResp func(*testing.T, *channel.Endpoint) 3577 }{ 3578 { 3579 name: "ICMP Error", 3580 rxPkt: func(e *channel.Endpoint) { 3581 hdr := prependable.New(header.IPv4MinimumSize + header.UDPMinimumSize) 3582 u := header.UDP(hdr.Prepend(header.UDPMinimumSize)) 3583 u.Encode(&header.UDPFields{ 3584 SrcPort: 5555, 3585 DstPort: 80, 3586 Length: header.UDPMinimumSize, 3587 }) 3588 sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv4Addr.AddressWithPrefix.Address, host1IPv4Addr.AddressWithPrefix.Address, header.UDPMinimumSize) 3589 sum = checksum.Checksum(nil, sum) 3590 u.SetChecksum(^u.CalculateChecksum(sum)) 3591 ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) 3592 ip.Encode(&header.IPv4Fields{ 3593 TotalLength: header.IPv4MinimumSize + header.UDPMinimumSize, 3594 TTL: ipv4.DefaultTTL, 3595 Protocol: uint8(udp.ProtocolNumber), 3596 SrcAddr: host2IPv4Addr.AddressWithPrefix.Address, 3597 DstAddr: host1IPv4Addr.AddressWithPrefix.Address, 3598 }) 3599 ip.SetChecksum(^ip.CalculateChecksum()) 3600 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 3601 Payload: buffer.MakeWithData(hdr.View()), 3602 }) 3603 defer pkt.DecRef() 3604 e.InjectInbound(ipv4.ProtocolNumber, pkt) 3605 }, 3606 checkResp: func(t *testing.T, e *channel.Endpoint) { 3607 p := e.Read() 3608 if p == nil { 3609 t.Fatalf("timed out waiting for packet") 3610 } 3611 defer p.DecRef() 3612 if p.NetworkProtocolNumber != header.IPv4ProtocolNumber { 3613 t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, header.IPv4ProtocolNumber) 3614 } 3615 if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { 3616 t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) 3617 } 3618 payload := stack.PayloadSince(p.NetworkHeader()) 3619 defer payload.Release() 3620 checker.IPv4(t, payload, 3621 checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), 3622 checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), 3623 checker.ICMPv4( 3624 checker.ICMPv4Type(header.ICMPv4DstUnreachable), 3625 checker.ICMPv4Code(header.ICMPv4PortUnreachable))) 3626 }, 3627 }, 3628 3629 { 3630 name: "Ping", 3631 rxPkt: func(e *channel.Endpoint) { 3632 totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize 3633 hdr := prependable.New(totalLen) 3634 pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize)) 3635 pkt.SetType(header.ICMPv4Echo) 3636 pkt.SetCode(0) 3637 pkt.SetChecksum(0) 3638 pkt.SetChecksum(^checksum.Checksum(pkt, 0)) 3639 ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) 3640 ip.Encode(&header.IPv4Fields{ 3641 TotalLength: uint16(totalLen), 3642 Protocol: uint8(icmp.ProtocolNumber4), 3643 TTL: ipv4.DefaultTTL, 3644 SrcAddr: host2IPv4Addr.AddressWithPrefix.Address, 3645 DstAddr: host1IPv4Addr.AddressWithPrefix.Address, 3646 }) 3647 ip.SetChecksum(^ip.CalculateChecksum()) 3648 echoPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 3649 Payload: buffer.MakeWithData(hdr.View()), 3650 }) 3651 defer echoPkt.DecRef() 3652 e.InjectInbound(header.IPv4ProtocolNumber, echoPkt) 3653 }, 3654 checkResp: func(t *testing.T, e *channel.Endpoint) { 3655 p := e.Read() 3656 if p == nil { 3657 t.Fatalf("timed out waiting for packet") 3658 } 3659 defer p.DecRef() 3660 if p.NetworkProtocolNumber != header.IPv4ProtocolNumber { 3661 t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, header.IPv4ProtocolNumber) 3662 } 3663 if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { 3664 t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) 3665 } 3666 payload := stack.PayloadSince(p.NetworkHeader()) 3667 defer payload.Release() 3668 checker.IPv4(t, payload, 3669 checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), 3670 checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), 3671 checker.ICMPv4( 3672 checker.ICMPv4Type(header.ICMPv4EchoReply), 3673 checker.ICMPv4Code(header.ICMPv4UnusedCode))) 3674 }, 3675 }, 3676 } 3677 3678 for _, test := range tests { 3679 t.Run(test.name, func(t *testing.T) { 3680 ctx := newTestContext() 3681 defer ctx.cleanup() 3682 s := ctx.s 3683 clock := ctx.clock 3684 3685 e := channel.New(1, defaultMTU, host1NICLinkAddr) 3686 defer e.Close() 3687 e.LinkEPCapabilities |= stack.CapabilityResolutionRequired 3688 if err := s.CreateNIC(nicID, e); err != nil { 3689 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 3690 } 3691 if err := s.AddProtocolAddress(nicID, host1IPv4Addr, stack.AddressProperties{}); err != nil { 3692 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, host1IPv4Addr, err) 3693 } 3694 3695 s.SetRouteTable([]tcpip.Route{ 3696 { 3697 Destination: host1IPv4Addr.AddressWithPrefix.Subnet(), 3698 NIC: nicID, 3699 }, 3700 }) 3701 3702 // Receive a packet to trigger link resolution before a response is sent. 3703 test.rxPkt(e) 3704 3705 // Wait for a ARP request since link address resolution should be 3706 // performed. 3707 { 3708 clock.RunImmediatelyScheduledJobs() 3709 p := e.Read() 3710 if p == nil { 3711 t.Fatalf("timed out waiting for packet") 3712 } 3713 if p.NetworkProtocolNumber != arp.ProtocolNumber { 3714 t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", p.NetworkProtocolNumber, arp.ProtocolNumber) 3715 } 3716 if p.EgressRoute.RemoteLinkAddress != header.EthernetBroadcastAddress { 3717 t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, header.EthernetBroadcastAddress) 3718 } 3719 rep := header.ARP(p.NetworkHeader().Slice()) 3720 p.DecRef() 3721 if got := rep.Op(); got != header.ARPRequest { 3722 t.Errorf("got Op() = %d, want = %d", got, header.ARPRequest) 3723 } 3724 if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != host1NICLinkAddr { 3725 t.Errorf("got HardwareAddressSender = %s, want = %s", got, host1NICLinkAddr) 3726 } 3727 if got := tcpip.AddrFromSlice(rep.ProtocolAddressSender()); got != host1IPv4Addr.AddressWithPrefix.Address { 3728 t.Errorf("got ProtocolAddressSender = %s, want = %s", got, host1IPv4Addr.AddressWithPrefix.Address) 3729 } 3730 if got := tcpip.AddrFromSlice(rep.ProtocolAddressTarget()); got != host2IPv4Addr.AddressWithPrefix.Address { 3731 t.Errorf("got ProtocolAddressTarget = %s, want = %s", got, host2IPv4Addr.AddressWithPrefix.Address) 3732 } 3733 } 3734 3735 // Send an ARP reply to complete link address resolution. 3736 { 3737 hdr := make([]byte, header.ARPSize) 3738 packet := header.ARP(hdr) 3739 packet.SetIPv4OverEthernet() 3740 packet.SetOp(header.ARPReply) 3741 copy(packet.HardwareAddressSender(), host2NICLinkAddr) 3742 copy(packet.ProtocolAddressSender(), host2IPv4Addr.AddressWithPrefix.Address.AsSlice()) 3743 copy(packet.HardwareAddressTarget(), host1NICLinkAddr) 3744 copy(packet.ProtocolAddressTarget(), host1IPv4Addr.AddressWithPrefix.Address.AsSlice()) 3745 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 3746 Payload: buffer.MakeWithData(hdr), 3747 }) 3748 e.InjectInbound(arp.ProtocolNumber, pkt) 3749 pkt.DecRef() 3750 } 3751 3752 // Expect the response now that the link address has resolved. 3753 clock.RunImmediatelyScheduledJobs() 3754 test.checkResp(t, e) 3755 3756 // Since link resolution was already performed, it shouldn't be performed 3757 // again. 3758 test.rxPkt(e) 3759 test.checkResp(t, e) 3760 }) 3761 } 3762 } 3763 3764 // TestCloseLocking test that lock ordering is followed when closing an 3765 // endpoint. 3766 func TestCloseLocking(t *testing.T) { 3767 const ( 3768 nicID1 = 1 3769 nicID2 = 2 3770 3771 iterations = 1000 3772 ) 3773 3774 var ( 3775 src = testutil.MustParse4("16.0.0.1") 3776 dst = testutil.MustParse4("16.0.0.2") 3777 ) 3778 3779 ctx := newTestContext() 3780 defer ctx.cleanup() 3781 s := ctx.s 3782 3783 // Perform NAT so that the endpoint tries to search for a sibling endpoint 3784 // which ends up taking the protocol and endpoint lock (in that order). 3785 table := stack.Table{ 3786 Rules: []stack.Rule{ 3787 {Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, 3788 {Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, 3789 {Target: &stack.RedirectTarget{Port: 5, NetworkProtocol: header.IPv4ProtocolNumber}}, 3790 {Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, 3791 {Target: &stack.ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber}}, 3792 }, 3793 BuiltinChains: [stack.NumHooks]int{ 3794 stack.Prerouting: 0, 3795 stack.Input: 1, 3796 stack.Forward: stack.HookUnset, 3797 stack.Output: 2, 3798 stack.Postrouting: 3, 3799 }, 3800 Underflows: [stack.NumHooks]int{ 3801 stack.Prerouting: 0, 3802 stack.Input: 1, 3803 stack.Forward: stack.HookUnset, 3804 stack.Output: 2, 3805 stack.Postrouting: 3, 3806 }, 3807 } 3808 s.IPTables().ForceReplaceTable(stack.NATID, table, false /* ipv6 */) 3809 3810 e := channel.New(0, defaultMTU, "") 3811 defer e.Close() 3812 if err := s.CreateNIC(nicID1, e); err != nil { 3813 t.Fatalf("CreateNIC(%d, _): %s", nicID1, err) 3814 } 3815 3816 protocolAddr := tcpip.ProtocolAddress{ 3817 Protocol: ipv4.ProtocolNumber, 3818 AddressWithPrefix: src.WithPrefix(), 3819 } 3820 if err := s.AddProtocolAddress(nicID1, protocolAddr, stack.AddressProperties{}); err != nil { 3821 t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID1, protocolAddr, err) 3822 } 3823 3824 s.SetRouteTable([]tcpip.Route{{ 3825 Destination: header.IPv4EmptySubnet, 3826 NIC: nicID1, 3827 }}) 3828 3829 var wq waiter.Queue 3830 ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 3831 if err != nil { 3832 t.Fatal(err) 3833 } 3834 defer ep.Close() 3835 3836 addr := tcpip.FullAddress{NIC: nicID1, Addr: dst, Port: 53} 3837 if err := ep.Connect(addr); err != nil { 3838 t.Errorf("ep.Connect(%#v): %s", addr, err) 3839 } 3840 3841 var wg sync.WaitGroup 3842 defer wg.Wait() 3843 3844 // Writing packets should trigger NAT which requires the stack to search the 3845 // protocol for network endpoints with the destination address. 3846 // 3847 // Creating and removing interfaces should modify the protocol and endpoint 3848 // which requires taking the locks of each. 3849 // 3850 // We expect the protocol > endpoint lock ordering to be followed here. 3851 wg.Add(2) 3852 go func() { 3853 defer wg.Done() 3854 3855 data := []byte{1, 2, 3, 4} 3856 3857 for i := 0; i < iterations; i++ { 3858 var r bytes.Reader 3859 r.Reset(data) 3860 if n, err := ep.Write(&r, tcpip.WriteOptions{}); err != nil { 3861 t.Errorf("ep.Write(_, _): %s", err) 3862 return 3863 } else if want := int64(len(data)); n != want { 3864 t.Errorf("got ep.Write(_, _) = (%d, _), want = (%d, _)", n, want) 3865 return 3866 } 3867 } 3868 }() 3869 go func() { 3870 defer wg.Done() 3871 3872 for i := 0; i < iterations; i++ { 3873 ch := channel.New(0, defaultMTU, "") 3874 defer ch.Close() 3875 if err := s.CreateNIC(nicID2, ch); err != nil { 3876 t.Errorf("CreateNIC(%d, _): %s", nicID2, err) 3877 return 3878 } 3879 if err := s.RemoveNIC(nicID2); err != nil { 3880 t.Errorf("RemoveNIC(%d): %s", nicID2, err) 3881 return 3882 } 3883 } 3884 }() 3885 } 3886 3887 func TestIcmpRateLimit(t *testing.T) { 3888 var ( 3889 host1IPv4Addr = tcpip.ProtocolAddress{ 3890 Protocol: ipv4.ProtocolNumber, 3891 AddressWithPrefix: tcpip.AddressWithPrefix{ 3892 Address: tcpip.AddrFromSlice(net.ParseIP("192.168.0.1").To4()), 3893 PrefixLen: 24, 3894 }, 3895 } 3896 host2IPv4Addr = tcpip.ProtocolAddress{ 3897 Protocol: ipv4.ProtocolNumber, 3898 AddressWithPrefix: tcpip.AddressWithPrefix{ 3899 Address: tcpip.AddrFromSlice(net.ParseIP("192.168.0.2").To4()), 3900 PrefixLen: 24, 3901 }, 3902 } 3903 ) 3904 ctx := newTestContext() 3905 defer ctx.cleanup() 3906 s := ctx.s 3907 3908 const icmpBurst = 5 3909 s.SetICMPBurst(icmpBurst) 3910 3911 e := channel.New(1, defaultMTU, tcpip.LinkAddress("")) 3912 defer e.Close() 3913 if err := s.CreateNIC(nicID, e); err != nil { 3914 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 3915 } 3916 if err := s.AddProtocolAddress(nicID, host1IPv4Addr, stack.AddressProperties{}); err != nil { 3917 t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, host1IPv4Addr, err) 3918 } 3919 s.SetRouteTable([]tcpip.Route{ 3920 { 3921 Destination: host1IPv4Addr.AddressWithPrefix.Subnet(), 3922 NIC: nicID, 3923 }, 3924 }) 3925 tests := []struct { 3926 name string 3927 createPacket func() []byte 3928 check func(*testing.T, *channel.Endpoint, int) 3929 }{ 3930 { 3931 name: "echo", 3932 createPacket: func() []byte { 3933 totalLength := header.IPv4MinimumSize + header.ICMPv4MinimumSize 3934 hdr := prependable.New(totalLength) 3935 icmpH := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize)) 3936 icmpH.SetIdent(1) 3937 icmpH.SetSequence(1) 3938 icmpH.SetType(header.ICMPv4Echo) 3939 icmpH.SetCode(header.ICMPv4UnusedCode) 3940 icmpH.SetChecksum(0) 3941 icmpH.SetChecksum(^checksum.Checksum(icmpH, 0)) 3942 ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) 3943 ip.Encode(&header.IPv4Fields{ 3944 TotalLength: uint16(totalLength), 3945 Protocol: uint8(header.ICMPv4ProtocolNumber), 3946 TTL: 1, 3947 SrcAddr: host2IPv4Addr.AddressWithPrefix.Address, 3948 DstAddr: host1IPv4Addr.AddressWithPrefix.Address, 3949 }) 3950 ip.SetChecksum(^ip.CalculateChecksum()) 3951 return hdr.View() 3952 }, 3953 check: func(t *testing.T, e *channel.Endpoint, round int) { 3954 p := e.Read() 3955 if p == nil { 3956 t.Fatalf("expected echo response, no packet read in endpoint in round %d", round) 3957 } 3958 defer p.DecRef() 3959 if got, want := p.NetworkProtocolNumber, header.IPv4ProtocolNumber; got != want { 3960 t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", got, want) 3961 } 3962 payload := stack.PayloadSince(p.NetworkHeader()) 3963 defer payload.Release() 3964 checker.IPv4(t, payload, 3965 checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), 3966 checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), 3967 checker.ICMPv4( 3968 checker.ICMPv4Type(header.ICMPv4EchoReply), 3969 )) 3970 }, 3971 }, 3972 { 3973 name: "dst unreachable", 3974 createPacket: func() []byte { 3975 totalLength := header.IPv4MinimumSize + header.UDPMinimumSize 3976 hdr := prependable.New(totalLength) 3977 udpH := header.UDP(hdr.Prepend(header.UDPMinimumSize)) 3978 udpH.Encode(&header.UDPFields{ 3979 SrcPort: 100, 3980 DstPort: 101, 3981 Length: header.UDPMinimumSize, 3982 }) 3983 ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) 3984 ip.Encode(&header.IPv4Fields{ 3985 TotalLength: uint16(totalLength), 3986 Protocol: uint8(header.UDPProtocolNumber), 3987 TTL: 1, 3988 SrcAddr: host2IPv4Addr.AddressWithPrefix.Address, 3989 DstAddr: host1IPv4Addr.AddressWithPrefix.Address, 3990 }) 3991 ip.SetChecksum(^ip.CalculateChecksum()) 3992 return hdr.View() 3993 }, 3994 check: func(t *testing.T, e *channel.Endpoint, round int) { 3995 p := e.Read() 3996 if round >= icmpBurst { 3997 if p != nil { 3998 t.Errorf("got packet %x in round %d, expected ICMP rate limit to stop it", p.Data().AsRange().ToSlice(), round) 3999 p.DecRef() 4000 } 4001 return 4002 } 4003 if p == nil { 4004 t.Fatalf("expected unreachable in round %d, no packet read in endpoint", round) 4005 } 4006 defer p.DecRef() 4007 payload := stack.PayloadSince(p.NetworkHeader()) 4008 defer payload.Release() 4009 checker.IPv4(t, payload, 4010 checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), 4011 checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), 4012 checker.ICMPv4( 4013 checker.ICMPv4Type(header.ICMPv4DstUnreachable), 4014 )) 4015 }, 4016 }, 4017 } 4018 for _, testCase := range tests { 4019 t.Run(testCase.name, func(t *testing.T) { 4020 for round := 0; round < icmpBurst+1; round++ { 4021 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 4022 Payload: buffer.MakeWithData(testCase.createPacket()), 4023 }) 4024 e.InjectInbound(header.IPv4ProtocolNumber, pkt) 4025 pkt.DecRef() 4026 testCase.check(t, e, round) 4027 } 4028 }) 4029 } 4030 }