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