inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/tcpip/network/ipv4/icmp.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 16 17 import ( 18 "fmt" 19 20 "inet.af/netstack/tcpip" 21 "inet.af/netstack/tcpip/buffer" 22 "inet.af/netstack/tcpip/header" 23 "inet.af/netstack/tcpip/stack" 24 ) 25 26 // icmpv4DestinationUnreachableSockError is a general ICMPv4 Destination 27 // Unreachable error. 28 // 29 // +stateify savable 30 type icmpv4DestinationUnreachableSockError struct{} 31 32 // Origin implements tcpip.SockErrorCause. 33 func (*icmpv4DestinationUnreachableSockError) Origin() tcpip.SockErrOrigin { 34 return tcpip.SockExtErrorOriginICMP 35 } 36 37 // Type implements tcpip.SockErrorCause. 38 func (*icmpv4DestinationUnreachableSockError) Type() uint8 { 39 return uint8(header.ICMPv4DstUnreachable) 40 } 41 42 // Info implements tcpip.SockErrorCause. 43 func (*icmpv4DestinationUnreachableSockError) Info() uint32 { 44 return 0 45 } 46 47 var _ stack.TransportError = (*icmpv4DestinationHostUnreachableSockError)(nil) 48 49 // icmpv4DestinationHostUnreachableSockError is an ICMPv4 Destination Host 50 // Unreachable error. 51 // 52 // It indicates that a packet was not able to reach the destination host. 53 // 54 // +stateify savable 55 type icmpv4DestinationHostUnreachableSockError struct { 56 icmpv4DestinationUnreachableSockError 57 } 58 59 // Code implements tcpip.SockErrorCause. 60 func (*icmpv4DestinationHostUnreachableSockError) Code() uint8 { 61 return uint8(header.ICMPv4HostUnreachable) 62 } 63 64 // Kind implements stack.TransportError. 65 func (*icmpv4DestinationHostUnreachableSockError) Kind() stack.TransportErrorKind { 66 return stack.DestinationHostUnreachableTransportError 67 } 68 69 var _ stack.TransportError = (*icmpv4DestinationPortUnreachableSockError)(nil) 70 71 // icmpv4DestinationPortUnreachableSockError is an ICMPv4 Destination Port 72 // Unreachable error. 73 // 74 // It indicates that a packet reached the destination host, but the transport 75 // protocol was not active on the destination port. 76 // 77 // +stateify savable 78 type icmpv4DestinationPortUnreachableSockError struct { 79 icmpv4DestinationUnreachableSockError 80 } 81 82 // Code implements tcpip.SockErrorCause. 83 func (*icmpv4DestinationPortUnreachableSockError) Code() uint8 { 84 return uint8(header.ICMPv4PortUnreachable) 85 } 86 87 // Kind implements stack.TransportError. 88 func (*icmpv4DestinationPortUnreachableSockError) Kind() stack.TransportErrorKind { 89 return stack.DestinationPortUnreachableTransportError 90 } 91 92 var _ stack.TransportError = (*icmpv4FragmentationNeededSockError)(nil) 93 94 // icmpv4FragmentationNeededSockError is an ICMPv4 Destination Unreachable error 95 // due to fragmentation being required but the packet was set to not be 96 // fragmented. 97 // 98 // It indicates that a link exists on the path to the destination with an MTU 99 // that is too small to carry the packet. 100 // 101 // +stateify savable 102 type icmpv4FragmentationNeededSockError struct { 103 icmpv4DestinationUnreachableSockError 104 105 mtu uint32 106 } 107 108 // Code implements tcpip.SockErrorCause. 109 func (*icmpv4FragmentationNeededSockError) Code() uint8 { 110 return uint8(header.ICMPv4FragmentationNeeded) 111 } 112 113 // Info implements tcpip.SockErrorCause. 114 func (e *icmpv4FragmentationNeededSockError) Info() uint32 { 115 return e.mtu 116 } 117 118 // Kind implements stack.TransportError. 119 func (*icmpv4FragmentationNeededSockError) Kind() stack.TransportErrorKind { 120 return stack.PacketTooBigTransportError 121 } 122 123 func (e *endpoint) checkLocalAddress(addr tcpip.Address) bool { 124 if e.nic.Spoofing() { 125 return true 126 } 127 128 if addressEndpoint := e.AcquireAssignedAddress(addr, false, stack.NeverPrimaryEndpoint); addressEndpoint != nil { 129 addressEndpoint.DecRef() 130 return true 131 } 132 return false 133 } 134 135 // handleControl handles the case when an ICMP error packet contains the headers 136 // of the original packet that caused the ICMP one to be sent. This information 137 // is used to find out which transport endpoint must be notified about the ICMP 138 // packet. We only expect the payload, not the enclosing ICMP packet. 139 func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.PacketBuffer) { 140 h, ok := pkt.Data().PullUp(header.IPv4MinimumSize) 141 if !ok { 142 return 143 } 144 hdr := header.IPv4(h) 145 146 // We don't use IsValid() here because ICMP only requires that the IP 147 // header plus 8 bytes of the transport header be included. So it's 148 // likely that it is truncated, which would cause IsValid to return 149 // false. 150 // 151 // Drop packet if it doesn't have the basic IPv4 header or if the 152 // original source address doesn't match an address we own. 153 srcAddr := hdr.SourceAddress() 154 if !e.checkLocalAddress(srcAddr) { 155 return 156 } 157 158 hlen := int(hdr.HeaderLength()) 159 if pkt.Data().Size() < hlen || hdr.FragmentOffset() != 0 { 160 // We won't be able to handle this if it doesn't contain the 161 // full IPv4 header, or if it's a fragment not at offset 0 162 // (because it won't have the transport header). 163 return 164 } 165 166 // Keep needed information before trimming header. 167 p := hdr.TransportProtocol() 168 dstAddr := hdr.DestinationAddress() 169 // Skip the ip header, then deliver the error. 170 if _, ok := pkt.Data().Consume(hlen); !ok { 171 panic(fmt.Sprintf("could not consume the IP header of %d bytes", hlen)) 172 } 173 e.dispatcher.DeliverTransportError(srcAddr, dstAddr, ProtocolNumber, p, errInfo, pkt) 174 } 175 176 func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { 177 received := e.stats.icmp.packetsReceived 178 h := header.ICMPv4(pkt.TransportHeader().View()) 179 if len(h) < header.ICMPv4MinimumSize { 180 received.invalid.Increment() 181 return 182 } 183 184 // Only do in-stack processing if the checksum is correct. 185 if header.Checksum(h, pkt.Data().AsRange().Checksum()) != 0xffff { 186 received.invalid.Increment() 187 // It's possible that a raw socket expects to receive this regardless 188 // of checksum errors. If it's an echo request we know it's safe because 189 // we are the only handler, however other types do not cope well with 190 // packets with checksum errors. 191 switch h.Type() { 192 case header.ICMPv4Echo: 193 e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt) 194 } 195 return 196 } 197 198 iph := header.IPv4(pkt.NetworkHeader().View()) 199 var newOptions header.IPv4Options 200 if opts := iph.Options(); len(opts) != 0 { 201 // RFC 1122 section 3.2.2.6 (page 43) (and similar for other round trip 202 // type ICMP packets): 203 // If a Record Route and/or Time Stamp option is received in an 204 // ICMP Echo Request, this option (these options) SHOULD be 205 // updated to include the current host and included in the IP 206 // header of the Echo Reply message, without "truncation". 207 // Thus, the recorded route will be for the entire round trip. 208 // 209 // So we need to let the option processor know how it should handle them. 210 var op optionsUsage 211 if h.Type() == header.ICMPv4Echo { 212 op = &optionUsageEcho{} 213 } else { 214 op = &optionUsageReceive{} 215 } 216 var optProblem *header.IPv4OptParameterProblem 217 newOptions, _, optProblem = e.processIPOptions(pkt, opts, op) 218 if optProblem != nil { 219 if optProblem.NeedICMP { 220 _ = e.protocol.returnError(&icmpReasonParamProblem{ 221 pointer: optProblem.Pointer, 222 }, pkt) 223 e.stats.ip.MalformedPacketsReceived.Increment() 224 } 225 return 226 } 227 copied := copy(opts, newOptions) 228 if copied != len(newOptions) { 229 panic(fmt.Sprintf("copied %d bytes of new options, expected %d bytes", copied, len(newOptions))) 230 } 231 for i := copied; i < len(opts); i++ { 232 // Pad with 0 (EOL). RFC 791 page 23 says "The padding is zero". 233 opts[i] = byte(header.IPv4OptionListEndType) 234 } 235 } 236 237 // TODO(b/112892170): Meaningfully handle all ICMP types. 238 switch h.Type() { 239 case header.ICMPv4Echo: 240 received.echoRequest.Increment() 241 242 // DeliverTransportPacket may modify pkt so don't use it beyond 243 // this point. Make a deep copy of the data before pkt gets sent as we will 244 // be modifying fields. Both the ICMP header (with its type modified to 245 // EchoReply) and payload are reused in the reply packet. 246 // 247 // TODO(gvisor.dev/issue/4399): The copy may not be needed if there are no 248 // waiting endpoints. Consider moving responsibility for doing the copy to 249 // DeliverTransportPacket so that is is only done when needed. 250 replyData := stack.PayloadSince(pkt.TransportHeader()) 251 ipHdr := header.IPv4(pkt.NetworkHeader().View()) 252 localAddressBroadcast := pkt.NetworkPacketInfo.LocalAddressBroadcast 253 254 // It's possible that a raw socket expects to receive this. 255 e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt) 256 pkt = nil 257 258 // Take the base of the incoming request IP header but replace the options. 259 replyHeaderLength := uint8(header.IPv4MinimumSize + len(newOptions)) 260 replyIPHdr := header.IPv4(append(iph[:header.IPv4MinimumSize:header.IPv4MinimumSize], newOptions...)) 261 replyIPHdr.SetHeaderLength(replyHeaderLength) 262 263 // As per RFC 1122 section 3.2.1.3, when a host sends any datagram, the IP 264 // source address MUST be one of its own IP addresses (but not a broadcast 265 // or multicast address). 266 localAddr := ipHdr.DestinationAddress() 267 if localAddressBroadcast || header.IsV4MulticastAddress(localAddr) { 268 localAddr = "" 269 } 270 271 r, err := e.protocol.stack.FindRoute(e.nic.ID(), localAddr, ipHdr.SourceAddress(), ProtocolNumber, false /* multicastLoop */) 272 if err != nil { 273 // If we cannot find a route to the destination, silently drop the packet. 274 return 275 } 276 defer r.Release() 277 278 sent := e.stats.icmp.packetsSent 279 if !e.protocol.allowICMPReply(header.ICMPv4EchoReply, header.ICMPv4UnusedCode) { 280 sent.rateLimited.Increment() 281 return 282 } 283 284 // TODO(gvisor.dev/issue/3810:) When adding protocol numbers into the 285 // header information, we may have to change this code to handle the 286 // ICMP header no longer being in the data buffer. 287 288 // Because IP and ICMP are so closely intertwined, we need to handcraft our 289 // IP header to be able to follow RFC 792. The wording on page 13 is as 290 // follows: 291 // IP Fields: 292 // Addresses 293 // The address of the source in an echo message will be the 294 // destination of the echo reply message. To form an echo reply 295 // message, the source and destination addresses are simply reversed, 296 // the type code changed to 0, and the checksum recomputed. 297 // 298 // This was interpreted by early implementors to mean that all options must 299 // be copied from the echo request IP header to the echo reply IP header 300 // and this behaviour is still relied upon by some applications. 301 // 302 // Create a copy of the IP header we received, options and all, and change 303 // The fields we need to alter. 304 // 305 // We need to produce the entire packet in the data segment in order to 306 // use WriteHeaderIncludedPacket(). WriteHeaderIncludedPacket sets the 307 // total length and the header checksum so we don't need to set those here. 308 replyIPHdr.SetSourceAddress(r.LocalAddress()) 309 replyIPHdr.SetDestinationAddress(r.RemoteAddress()) 310 replyIPHdr.SetTTL(r.DefaultTTL()) 311 312 replyICMPHdr := header.ICMPv4(replyData) 313 replyICMPHdr.SetType(header.ICMPv4EchoReply) 314 replyICMPHdr.SetChecksum(0) 315 replyICMPHdr.SetChecksum(^header.Checksum(replyData, 0)) 316 317 replyVV := buffer.View(replyIPHdr).ToVectorisedView() 318 replyVV.AppendView(replyData) 319 replyPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 320 ReserveHeaderBytes: int(r.MaxHeaderLength()), 321 Data: replyVV, 322 }) 323 defer replyPkt.DecRef() 324 replyPkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber 325 326 if err := r.WriteHeaderIncludedPacket(replyPkt); err != nil { 327 sent.dropped.Increment() 328 return 329 } 330 sent.echoReply.Increment() 331 332 case header.ICMPv4EchoReply: 333 received.echoReply.Increment() 334 335 // ICMP sockets expect the ICMP header to be present, so we don't consume 336 // the ICMP header. 337 e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt) 338 339 case header.ICMPv4DstUnreachable: 340 received.dstUnreachable.Increment() 341 342 mtu := h.MTU() 343 code := h.Code() 344 switch code { 345 case header.ICMPv4HostUnreachable: 346 e.handleControl(&icmpv4DestinationHostUnreachableSockError{}, pkt) 347 case header.ICMPv4PortUnreachable: 348 e.handleControl(&icmpv4DestinationPortUnreachableSockError{}, pkt) 349 case header.ICMPv4FragmentationNeeded: 350 networkMTU, err := calculateNetworkMTU(uint32(mtu), header.IPv4MinimumSize) 351 if err != nil { 352 networkMTU = 0 353 } 354 e.handleControl(&icmpv4FragmentationNeededSockError{mtu: networkMTU}, pkt) 355 } 356 case header.ICMPv4SrcQuench: 357 received.srcQuench.Increment() 358 359 case header.ICMPv4Redirect: 360 received.redirect.Increment() 361 362 case header.ICMPv4TimeExceeded: 363 received.timeExceeded.Increment() 364 365 case header.ICMPv4ParamProblem: 366 received.paramProblem.Increment() 367 368 case header.ICMPv4Timestamp: 369 received.timestamp.Increment() 370 371 case header.ICMPv4TimestampReply: 372 received.timestampReply.Increment() 373 374 case header.ICMPv4InfoRequest: 375 received.infoRequest.Increment() 376 377 case header.ICMPv4InfoReply: 378 received.infoReply.Increment() 379 380 default: 381 received.invalid.Increment() 382 } 383 } 384 385 // ======= ICMP Error packet generation ========= 386 387 // icmpReason is a marker interface for IPv4 specific ICMP errors. 388 type icmpReason interface { 389 isICMPReason() 390 // isForwarding indicates whether or not the error arose while attempting to 391 // forward a packet. 392 isForwarding() bool 393 } 394 395 // icmpReasonPortUnreachable is an error where the transport protocol has no 396 // listener and no alternative means to inform the sender. 397 type icmpReasonPortUnreachable struct{} 398 399 func (*icmpReasonPortUnreachable) isICMPReason() {} 400 func (*icmpReasonPortUnreachable) isForwarding() bool { 401 return false 402 } 403 404 // icmpReasonProtoUnreachable is an error where the transport protocol is 405 // not supported. 406 type icmpReasonProtoUnreachable struct{} 407 408 func (*icmpReasonProtoUnreachable) isICMPReason() {} 409 func (*icmpReasonProtoUnreachable) isForwarding() bool { 410 return false 411 } 412 413 // icmpReasonTTLExceeded is an error where a packet's time to live exceeded in 414 // transit to its final destination, as per RFC 792 page 6, Time Exceeded 415 // Message. 416 type icmpReasonTTLExceeded struct{} 417 418 func (*icmpReasonTTLExceeded) isICMPReason() {} 419 func (*icmpReasonTTLExceeded) isForwarding() bool { 420 // If we hit a TTL Exceeded error, then we know we are operating as a router. 421 // As per RFC 792 page 6, Time Exceeded Message, 422 // 423 // If the gateway processing a datagram finds the time to live field 424 // is zero it must discard the datagram. The gateway may also notify 425 // the source host via the time exceeded message. 426 return true 427 } 428 429 // icmpReasonReassemblyTimeout is an error where insufficient fragments are 430 // received to complete reassembly of a packet within a configured time after 431 // the reception of the first-arriving fragment of that packet. 432 type icmpReasonReassemblyTimeout struct{} 433 434 func (*icmpReasonReassemblyTimeout) isICMPReason() {} 435 func (*icmpReasonReassemblyTimeout) isForwarding() bool { 436 return false 437 } 438 439 // icmpReasonParamProblem is an error to use to request a Parameter Problem 440 // message to be sent. 441 type icmpReasonParamProblem struct { 442 pointer byte 443 forwarding bool 444 } 445 446 func (*icmpReasonParamProblem) isICMPReason() {} 447 func (r *icmpReasonParamProblem) isForwarding() bool { 448 return r.forwarding 449 } 450 451 // icmpReasonNetworkUnreachable is an error in which the network specified in 452 // the internet destination field of the datagram is unreachable. 453 type icmpReasonNetworkUnreachable struct{} 454 455 func (*icmpReasonNetworkUnreachable) isICMPReason() {} 456 func (*icmpReasonNetworkUnreachable) isForwarding() bool { 457 // If we hit a Net Unreachable error, then we know we are operating as 458 // a router. As per RFC 792 page 5, Destination Unreachable Message, 459 // 460 // If, according to the information in the gateway's routing tables, 461 // the network specified in the internet destination field of a 462 // datagram is unreachable, e.g., the distance to the network is 463 // infinity, the gateway may send a destination unreachable message to 464 // the internet source host of the datagram. 465 return true 466 } 467 468 // icmpReasonFragmentationNeeded is an error where a packet requires 469 // fragmentation while also having the Don't Fragment flag set, as per RFC 792 470 // page 3, Destination Unreachable Message. 471 type icmpReasonFragmentationNeeded struct{} 472 473 func (*icmpReasonFragmentationNeeded) isICMPReason() {} 474 func (*icmpReasonFragmentationNeeded) isForwarding() bool { 475 // If we hit a Don't Fragment error, then we know we are operating as a router. 476 // As per RFC 792 page 4, Destination Unreachable Message, 477 // 478 // Another case is when a datagram must be fragmented to be forwarded by a 479 // gateway yet the Don't Fragment flag is on. In this case the gateway must 480 // discard the datagram and may return a destination unreachable message. 481 return true 482 } 483 484 // icmpReasonHostUnreachable is an error in which the host specified in the 485 // internet destination field of the datagram is unreachable. 486 type icmpReasonHostUnreachable struct{} 487 488 func (*icmpReasonHostUnreachable) isICMPReason() {} 489 func (*icmpReasonHostUnreachable) isForwarding() bool { 490 // If we hit a Host Unreachable error, then we know we are operating as a 491 // router. As per RFC 792 page 5, Destination Unreachable Message, 492 // 493 // In addition, in some networks, the gateway may be able to determine 494 // if the internet destination host is unreachable. Gateways in these 495 // networks may send destination unreachable messages to the source host 496 // when the destination host is unreachable. 497 return true 498 } 499 500 // returnError takes an error descriptor and generates the appropriate ICMP 501 // error packet for IPv4 and sends it back to the remote device that sent 502 // the problematic packet. It incorporates as much of that packet as 503 // possible as well as any error metadata as is available. returnError 504 // expects pkt to hold a valid IPv4 packet as per the wire format. 505 func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip.Error { 506 origIPHdr := header.IPv4(pkt.NetworkHeader().View()) 507 origIPHdrSrc := origIPHdr.SourceAddress() 508 origIPHdrDst := origIPHdr.DestinationAddress() 509 510 // We check we are responding only when we are allowed to. 511 // See RFC 1812 section 4.3.2.7 (shown below). 512 // 513 // ========= 514 // 4.3.2.7 When Not to Send ICMP Errors 515 // 516 // An ICMP error message MUST NOT be sent as the result of receiving: 517 // 518 // o An ICMP error message, or 519 // 520 // o A packet which fails the IP header validation tests described in 521 // Section [5.2.2] (except where that section specifically permits 522 // the sending of an ICMP error message), or 523 // 524 // o A packet destined to an IP broadcast or IP multicast address, or 525 // 526 // o A packet sent as a Link Layer broadcast or multicast, or 527 // 528 // o Any fragment of a datagram other then the first fragment (i.e., a 529 // packet for which the fragment offset in the IP header is nonzero). 530 // 531 // TODO(gvisor.dev/issues/4058): Make sure we don't send ICMP errors in 532 // response to a non-initial fragment, but it currently can not happen. 533 if pkt.NetworkPacketInfo.LocalAddressBroadcast || header.IsV4MulticastAddress(origIPHdrDst) || origIPHdrSrc == header.IPv4Any { 534 return nil 535 } 536 537 // If we are operating as a router/gateway, don't use the packet's destination 538 // address as the response's source address as we should not not own the 539 // destination address of a packet we are forwarding. 540 localAddr := origIPHdrDst 541 if reason.isForwarding() { 542 localAddr = "" 543 } 544 545 // Even if we were able to receive a packet from some remote, we may not have 546 // a route to it - the remote may be blocked via routing rules. We must always 547 // consult our routing table and find a route to the remote before sending any 548 // packet. 549 route, err := p.stack.FindRoute(pkt.NICID, localAddr, origIPHdrSrc, ProtocolNumber, false /* multicastLoop */) 550 if err != nil { 551 return err 552 } 553 defer route.Release() 554 555 p.mu.Lock() 556 // We retrieve an endpoint using the newly constructed route's NICID rather 557 // than the packet's NICID. The packet's NICID corresponds to the NIC on 558 // which it arrived, which isn't necessarily the same as the NIC on which it 559 // will be transmitted. On the other hand, the route's NIC *is* guaranteed 560 // to be the NIC on which the packet will be transmitted. 561 netEP, ok := p.mu.eps[route.NICID()] 562 p.mu.Unlock() 563 if !ok { 564 return &tcpip.ErrNotConnected{} 565 } 566 567 transportHeader := pkt.TransportHeader().View() 568 569 // Don't respond to icmp error packets. 570 if origIPHdr.Protocol() == uint8(header.ICMPv4ProtocolNumber) { 571 // We need to decide to explicitly name the packets we can respond to or 572 // the ones we can not respond to. The decision is somewhat arbitrary and 573 // if problems arise this could be reversed. It was judged less of a breach 574 // of protocol to not respond to unknown non-error packets than to respond 575 // to unknown error packets so we take the first approach. 576 if len(transportHeader) < header.ICMPv4MinimumSize { 577 // The packet is malformed. 578 return nil 579 } 580 switch header.ICMPv4(transportHeader).Type() { 581 case 582 header.ICMPv4EchoReply, 583 header.ICMPv4Echo, 584 header.ICMPv4Timestamp, 585 header.ICMPv4TimestampReply, 586 header.ICMPv4InfoRequest, 587 header.ICMPv4InfoReply: 588 default: 589 // Assume any type we don't know about may be an error type. 590 return nil 591 } 592 } 593 594 sent := netEP.stats.icmp.packetsSent 595 icmpType, icmpCode, counter, pointer := func() (header.ICMPv4Type, header.ICMPv4Code, tcpip.MultiCounterStat, byte) { 596 switch reason := reason.(type) { 597 case *icmpReasonPortUnreachable: 598 return header.ICMPv4DstUnreachable, header.ICMPv4PortUnreachable, sent.dstUnreachable, 0 599 case *icmpReasonProtoUnreachable: 600 return header.ICMPv4DstUnreachable, header.ICMPv4ProtoUnreachable, sent.dstUnreachable, 0 601 case *icmpReasonNetworkUnreachable: 602 return header.ICMPv4DstUnreachable, header.ICMPv4NetUnreachable, sent.dstUnreachable, 0 603 case *icmpReasonHostUnreachable: 604 return header.ICMPv4DstUnreachable, header.ICMPv4HostUnreachable, sent.dstUnreachable, 0 605 case *icmpReasonFragmentationNeeded: 606 return header.ICMPv4DstUnreachable, header.ICMPv4FragmentationNeeded, sent.dstUnreachable, 0 607 case *icmpReasonTTLExceeded: 608 return header.ICMPv4TimeExceeded, header.ICMPv4TTLExceeded, sent.timeExceeded, 0 609 case *icmpReasonReassemblyTimeout: 610 return header.ICMPv4TimeExceeded, header.ICMPv4ReassemblyTimeout, sent.timeExceeded, 0 611 case *icmpReasonParamProblem: 612 return header.ICMPv4ParamProblem, header.ICMPv4UnusedCode, sent.paramProblem, reason.pointer 613 default: 614 panic(fmt.Sprintf("unsupported ICMP type %T", reason)) 615 } 616 }() 617 618 if !p.allowICMPReply(icmpType, icmpCode) { 619 sent.rateLimited.Increment() 620 return nil 621 } 622 623 // Now work out how much of the triggering packet we should return. 624 // As per RFC 1812 Section 4.3.2.3 625 // 626 // ICMP datagram SHOULD contain as much of the original 627 // datagram as possible without the length of the ICMP 628 // datagram exceeding 576 bytes. 629 // 630 // NOTE: The above RFC referenced is different from the original 631 // recommendation in RFC 1122 and RFC 792 where it mentioned that at 632 // least 8 bytes of the payload must be included. Today linux and other 633 // systems implement the RFC 1812 definition and not the original 634 // requirement. We treat 8 bytes as the minimum but will try send more. 635 mtu := int(route.MTU()) 636 const maxIPData = header.IPv4MinimumProcessableDatagramSize - header.IPv4MinimumSize 637 if mtu > maxIPData { 638 mtu = maxIPData 639 } 640 available := mtu - header.ICMPv4MinimumSize 641 642 if available < len(origIPHdr)+header.ICMPv4MinimumErrorPayloadSize { 643 return nil 644 } 645 646 payloadLen := len(origIPHdr) + transportHeader.Size() + pkt.Data().Size() 647 if payloadLen > available { 648 payloadLen = available 649 } 650 651 // The buffers used by pkt may be used elsewhere in the system. 652 // For example, an AF_RAW or AF_PACKET socket may use what the transport 653 // protocol considers an unreachable destination. Thus we deep copy pkt to 654 // prevent multiple ownership and SR errors. The new copy is a vectorized 655 // view with the entire incoming IP packet reassembled and truncated as 656 // required. This is now the payload of the new ICMP packet and no longer 657 // considered a packet in its own right. 658 newHeader := append(buffer.View(nil), origIPHdr...) 659 newHeader = append(newHeader, transportHeader...) 660 payload := newHeader.ToVectorisedView() 661 if dataCap := payloadLen - payload.Size(); dataCap > 0 { 662 payload.AppendView(pkt.Data().AsRange().Capped(dataCap).ToOwnedView()) 663 } else { 664 payload.CapLength(payloadLen) 665 } 666 667 icmpPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 668 ReserveHeaderBytes: int(route.MaxHeaderLength()) + header.ICMPv4MinimumSize, 669 Data: payload, 670 }) 671 defer icmpPkt.DecRef() 672 673 icmpPkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber 674 675 icmpHdr := header.ICMPv4(icmpPkt.TransportHeader().Push(header.ICMPv4MinimumSize)) 676 icmpHdr.SetCode(icmpCode) 677 icmpHdr.SetType(icmpType) 678 icmpHdr.SetPointer(pointer) 679 icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data().AsRange().Checksum())) 680 681 if err := route.WritePacket( 682 stack.NetworkHeaderParams{ 683 Protocol: header.ICMPv4ProtocolNumber, 684 TTL: route.DefaultTTL(), 685 TOS: stack.DefaultTOS, 686 }, 687 icmpPkt, 688 ); err != nil { 689 sent.dropped.Increment() 690 return err 691 } 692 counter.Increment() 693 return nil 694 } 695 696 // OnReassemblyTimeout implements fragmentation.TimeoutHandler. 697 func (p *protocol) OnReassemblyTimeout(pkt *stack.PacketBuffer) { 698 // OnReassemblyTimeout sends a Time Exceeded Message, as per RFC 792: 699 // 700 // If a host reassembling a fragmented datagram cannot complete the 701 // reassembly due to missing fragments within its time limit it discards the 702 // datagram, and it may send a time exceeded message. 703 // 704 // If fragment zero is not available then no time exceeded need be sent at 705 // all. 706 if pkt != nil { 707 p.returnError(&icmpReasonReassemblyTimeout{}, pkt) 708 } 709 }