gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/ipv6/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 ipv6 16 17 import ( 18 "fmt" 19 20 "gvisor.dev/gvisor/pkg/buffer" 21 "gvisor.dev/gvisor/pkg/tcpip" 22 "gvisor.dev/gvisor/pkg/tcpip/header" 23 "gvisor.dev/gvisor/pkg/tcpip/stack" 24 ) 25 26 // icmpv6DestinationUnreachableSockError is a general ICMPv6 Destination 27 // Unreachable error. 28 // 29 // +stateify savable 30 type icmpv6DestinationUnreachableSockError struct{} 31 32 // Origin implements tcpip.SockErrorCause. 33 func (*icmpv6DestinationUnreachableSockError) Origin() tcpip.SockErrOrigin { 34 return tcpip.SockExtErrorOriginICMP6 35 } 36 37 // Type implements tcpip.SockErrorCause. 38 func (*icmpv6DestinationUnreachableSockError) Type() uint8 { 39 return uint8(header.ICMPv6DstUnreachable) 40 } 41 42 // Info implements tcpip.SockErrorCause. 43 func (*icmpv6DestinationUnreachableSockError) Info() uint32 { 44 return 0 45 } 46 47 var _ stack.TransportError = (*icmpv6DestinationNetworkUnreachableSockError)(nil) 48 49 // icmpv6DestinationNetworkUnreachableSockError is an ICMPv6 Destination Network 50 // Unreachable error. 51 // 52 // It indicates that the destination network is unreachable. 53 // 54 // +stateify savable 55 type icmpv6DestinationNetworkUnreachableSockError struct { 56 icmpv6DestinationUnreachableSockError 57 } 58 59 // Code implements tcpip.SockErrorCause. 60 func (*icmpv6DestinationNetworkUnreachableSockError) Code() uint8 { 61 return uint8(header.ICMPv6NetworkUnreachable) 62 } 63 64 // Kind implements stack.TransportError. 65 func (*icmpv6DestinationNetworkUnreachableSockError) Kind() stack.TransportErrorKind { 66 return stack.DestinationNetworkUnreachableTransportError 67 } 68 69 var _ stack.TransportError = (*icmpv6DestinationPortUnreachableSockError)(nil) 70 71 // icmpv6DestinationPortUnreachableSockError is an ICMPv6 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 icmpv6DestinationPortUnreachableSockError struct { 79 icmpv6DestinationUnreachableSockError 80 } 81 82 // Code implements tcpip.SockErrorCause. 83 func (*icmpv6DestinationPortUnreachableSockError) Code() uint8 { 84 return uint8(header.ICMPv6PortUnreachable) 85 } 86 87 // Kind implements stack.TransportError. 88 func (*icmpv6DestinationPortUnreachableSockError) Kind() stack.TransportErrorKind { 89 return stack.DestinationPortUnreachableTransportError 90 } 91 92 var _ stack.TransportError = (*icmpv6DestinationAddressUnreachableSockError)(nil) 93 94 // icmpv6DestinationAddressUnreachableSockError is an ICMPv6 Destination Address 95 // Unreachable error. 96 // 97 // It indicates that a packet was not able to reach the destination. 98 // 99 // +stateify savable 100 type icmpv6DestinationAddressUnreachableSockError struct { 101 icmpv6DestinationUnreachableSockError 102 } 103 104 // Code implements tcpip.SockErrorCause. 105 func (*icmpv6DestinationAddressUnreachableSockError) Code() uint8 { 106 return uint8(header.ICMPv6AddressUnreachable) 107 } 108 109 // Kind implements stack.TransportError. 110 func (*icmpv6DestinationAddressUnreachableSockError) Kind() stack.TransportErrorKind { 111 return stack.DestinationHostUnreachableTransportError 112 } 113 114 var _ stack.TransportError = (*icmpv6PacketTooBigSockError)(nil) 115 116 // icmpv6PacketTooBigSockError is an ICMPv6 Packet Too Big error. 117 // 118 // It indicates that a link exists on the path to the destination with an MTU 119 // that is too small to carry the packet. 120 // 121 // +stateify savable 122 type icmpv6PacketTooBigSockError struct { 123 mtu uint32 124 } 125 126 // Origin implements tcpip.SockErrorCause. 127 func (*icmpv6PacketTooBigSockError) Origin() tcpip.SockErrOrigin { 128 return tcpip.SockExtErrorOriginICMP6 129 } 130 131 // Type implements tcpip.SockErrorCause. 132 func (*icmpv6PacketTooBigSockError) Type() uint8 { 133 return uint8(header.ICMPv6PacketTooBig) 134 } 135 136 // Code implements tcpip.SockErrorCause. 137 func (*icmpv6PacketTooBigSockError) Code() uint8 { 138 return uint8(header.ICMPv6UnusedCode) 139 } 140 141 // Info implements tcpip.SockErrorCause. 142 func (e *icmpv6PacketTooBigSockError) Info() uint32 { 143 return e.mtu 144 } 145 146 // Kind implements stack.TransportError. 147 func (*icmpv6PacketTooBigSockError) Kind() stack.TransportErrorKind { 148 return stack.PacketTooBigTransportError 149 } 150 151 func (e *endpoint) checkLocalAddress(addr tcpip.Address) bool { 152 if e.nic.Spoofing() { 153 return true 154 } 155 156 if addressEndpoint := e.AcquireAssignedAddress(addr, false, stack.NeverPrimaryEndpoint, true /* readOnly */); addressEndpoint != nil { 157 return true 158 } 159 return false 160 } 161 162 // handleControl handles the case when an ICMP packet contains the headers of 163 // the original packet that caused the ICMP one to be sent. This information is 164 // used to find out which transport endpoint must be notified about the ICMP 165 // packet. 166 func (e *endpoint) handleControl(transErr stack.TransportError, pkt *stack.PacketBuffer) { 167 h, ok := pkt.Data().PullUp(header.IPv6MinimumSize) 168 if !ok { 169 return 170 } 171 hdr := header.IPv6(h) 172 173 // We don't use IsValid() here because ICMP only requires that up to 174 // 1280 bytes of the original packet be included. So it's likely that it 175 // is truncated, which would cause IsValid to return false. 176 // 177 // Drop packet if it doesn't have the basic IPv6 header or if the 178 // original source address doesn't match an address we own. 179 srcAddr := hdr.SourceAddress() 180 if !e.checkLocalAddress(srcAddr) { 181 return 182 } 183 184 // Keep needed information before trimming header. 185 p := hdr.TransportProtocol() 186 dstAddr := hdr.DestinationAddress() 187 188 // Skip the IP header, then handle the fragmentation header if there 189 // is one. 190 if _, ok := pkt.Data().Consume(header.IPv6MinimumSize); !ok { 191 panic("could not consume IPv6MinimumSize bytes") 192 } 193 if p == header.IPv6FragmentHeader { 194 f, ok := pkt.Data().PullUp(header.IPv6FragmentHeaderSize) 195 if !ok { 196 return 197 } 198 fragHdr := header.IPv6Fragment(f) 199 if !fragHdr.IsValid() || fragHdr.FragmentOffset() != 0 { 200 // We can't handle fragments that aren't at offset 0 201 // because they don't have the transport headers. 202 return 203 } 204 p = fragHdr.TransportProtocol() 205 206 // Skip fragmentation header and find out the actual protocol 207 // number. 208 if _, ok := pkt.Data().Consume(header.IPv6FragmentHeaderSize); !ok { 209 panic("could not consume IPv6FragmentHeaderSize bytes") 210 } 211 } 212 213 e.dispatcher.DeliverTransportError(srcAddr, dstAddr, ProtocolNumber, p, transErr, pkt) 214 } 215 216 // getLinkAddrOption searches NDP options for a given link address option using 217 // the provided getAddr function as a filter. Returns the link address if 218 // found; otherwise, returns the zero link address value. Also returns true if 219 // the options are valid as per the wire format, false otherwise. 220 func getLinkAddrOption(it header.NDPOptionIterator, getAddr func(header.NDPOption) tcpip.LinkAddress) (tcpip.LinkAddress, bool) { 221 var linkAddr tcpip.LinkAddress 222 for { 223 opt, done, err := it.Next() 224 if err != nil { 225 return "", false 226 } 227 if done { 228 break 229 } 230 if addr := getAddr(opt); len(addr) != 0 { 231 // No RFCs define what to do when an NDP message has multiple Link-Layer 232 // Address options. Since no interface can have multiple link-layer 233 // addresses, we consider such messages invalid. 234 if len(linkAddr) != 0 { 235 return "", false 236 } 237 linkAddr = addr 238 } 239 } 240 return linkAddr, true 241 } 242 243 // getSourceLinkAddr searches NDP options for the source link address option. 244 // Returns the link address if found; otherwise, returns the zero link address 245 // value. Also returns true if the options are valid as per the wire format, 246 // false otherwise. 247 func getSourceLinkAddr(it header.NDPOptionIterator) (tcpip.LinkAddress, bool) { 248 return getLinkAddrOption(it, func(opt header.NDPOption) tcpip.LinkAddress { 249 if src, ok := opt.(header.NDPSourceLinkLayerAddressOption); ok { 250 return src.EthernetAddress() 251 } 252 return "" 253 }) 254 } 255 256 // getTargetLinkAddr searches NDP options for the target link address option. 257 // Returns the link address if found; otherwise, returns the zero link address 258 // value. Also returns true if the options are valid as per the wire format, 259 // false otherwise. 260 func getTargetLinkAddr(it header.NDPOptionIterator) (tcpip.LinkAddress, bool) { 261 return getLinkAddrOption(it, func(opt header.NDPOption) tcpip.LinkAddress { 262 if dst, ok := opt.(header.NDPTargetLinkLayerAddressOption); ok { 263 return dst.EthernetAddress() 264 } 265 return "" 266 }) 267 } 268 269 func isMLDValid(pkt *stack.PacketBuffer, iph header.IPv6, routerAlert *header.IPv6RouterAlertOption) bool { 270 // As per RFC 2710 section 3: 271 // All MLD messages described in this document are sent with a link-local 272 // IPv6 Source Address, an IPv6 Hop Limit of 1, and an IPv6 Router Alert 273 // option in a Hop-by-Hop Options header. 274 if routerAlert == nil || routerAlert.Value != header.IPv6RouterAlertMLD { 275 return false 276 } 277 if len(pkt.TransportHeader().Slice()) < header.ICMPv6HeaderSize+header.MLDMinimumSize { 278 return false 279 } 280 if iph.HopLimit() != header.MLDHopLimit { 281 return false 282 } 283 if !header.IsV6LinkLocalUnicastAddress(iph.SourceAddress()) { 284 return false 285 } 286 return true 287 } 288 289 func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, routerAlert *header.IPv6RouterAlertOption) { 290 sent := e.stats.icmp.packetsSent 291 received := e.stats.icmp.packetsReceived 292 h := header.ICMPv6(pkt.TransportHeader().Slice()) 293 if len(h) < header.ICMPv6MinimumSize { 294 received.invalid.Increment() 295 return 296 } 297 iph := header.IPv6(pkt.NetworkHeader().Slice()) 298 srcAddr := iph.SourceAddress() 299 dstAddr := iph.DestinationAddress() 300 301 // Validate ICMPv6 checksum before processing the packet. 302 payload := pkt.Data() 303 if got, want := h.Checksum(), header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 304 Header: h, 305 Src: srcAddr, 306 Dst: dstAddr, 307 PayloadCsum: payload.Checksum(), 308 PayloadLen: payload.Size(), 309 }); got != want { 310 received.invalid.Increment() 311 return 312 } 313 314 isNDPValid := func() bool { 315 // As per RFC 4861 sections 4.1 - 4.5, 6.1.1, 6.1.2, 7.1.1, 7.1.2 and 316 // 8.1, nodes MUST silently drop NDP packets where the Hop Limit field 317 // in the IPv6 header is not set to 255, or the ICMPv6 Code field is not 318 // set to 0. 319 // 320 // As per RFC 6980 section 5, nodes MUST silently drop NDP messages if the 321 // packet includes a fragmentation header. 322 return !hasFragmentHeader && iph.HopLimit() == header.NDPHopLimit && h.Code() == 0 323 } 324 325 // TODO(b/112892170): Meaningfully handle all ICMP types. 326 switch icmpType := h.Type(); icmpType { 327 case header.ICMPv6PacketTooBig: 328 received.packetTooBig.Increment() 329 networkMTU, err := calculateNetworkMTU(h.MTU(), header.IPv6MinimumSize) 330 if err != nil { 331 networkMTU = 0 332 } 333 e.handleControl(&icmpv6PacketTooBigSockError{mtu: networkMTU}, pkt) 334 335 case header.ICMPv6DstUnreachable: 336 received.dstUnreachable.Increment() 337 switch h.Code() { 338 case header.ICMPv6NetworkUnreachable: 339 e.handleControl(&icmpv6DestinationNetworkUnreachableSockError{}, pkt) 340 case header.ICMPv6PortUnreachable: 341 e.handleControl(&icmpv6DestinationPortUnreachableSockError{}, pkt) 342 } 343 case header.ICMPv6NeighborSolicit: 344 received.neighborSolicit.Increment() 345 if !isNDPValid() || len(h) < header.ICMPv6NeighborSolicitMinimumSize { 346 received.invalid.Increment() 347 return 348 } 349 350 ns := header.NDPNeighborSolicit(h.MessageBody()) 351 targetAddr := ns.TargetAddress() 352 353 // As per RFC 4861 section 4.3, the Target Address MUST NOT be a multicast 354 // address. 355 if header.IsV6MulticastAddress(targetAddr) { 356 received.invalid.Increment() 357 return 358 } 359 360 var it header.NDPOptionIterator 361 { 362 var err error 363 it, err = ns.Options().Iter(false /* check */) 364 if err != nil { 365 // Options are not valid as per the wire format, silently drop the 366 // packet. 367 received.invalid.Increment() 368 return 369 } 370 } 371 372 if e.hasTentativeAddr(targetAddr) { 373 // If the target address is tentative and the source of the packet is a 374 // unicast (specified) address, then the source of the packet is 375 // attempting to perform address resolution on the target. In this case, 376 // the solicitation is silently ignored, as per RFC 4862 section 5.4.3. 377 // 378 // If the target address is tentative and the source of the packet is the 379 // unspecified address (::), then we know another node is also performing 380 // DAD for the same address (since the target address is tentative for us, 381 // we know we are also performing DAD on it). In this case we let the 382 // stack know so it can handle such a scenario and do nothing further with 383 // the NS. 384 if srcAddr == header.IPv6Any { 385 var nonce []byte 386 for { 387 opt, done, err := it.Next() 388 if err != nil { 389 received.invalid.Increment() 390 return 391 } 392 if done { 393 break 394 } 395 if n, ok := opt.(header.NDPNonceOption); ok { 396 nonce = n.Nonce() 397 break 398 } 399 } 400 401 // Since this is a DAD message we know the sender does not actually hold 402 // the target address so there is no "holder". 403 var holderLinkAddress tcpip.LinkAddress 404 405 // We would get an error if the address no longer exists or the address 406 // is no longer tentative (DAD resolved between the call to 407 // hasTentativeAddr and this point). Both of these are valid scenarios: 408 // 1) An address may be removed at any time. 409 // 2) As per RFC 4862 section 5.4, DAD is not a perfect: 410 // "Note that the method for detecting duplicates 411 // is not completely reliable, and it is possible that duplicate 412 // addresses will still exist" 413 // 414 // TODO(gvisor.dev/issue/4046): Handle the scenario when a duplicate 415 // address is detected for an assigned address. 416 switch err := e.dupTentativeAddrDetected(targetAddr, holderLinkAddress, nonce); err.(type) { 417 case nil, *tcpip.ErrBadAddress, *tcpip.ErrInvalidEndpointState: 418 default: 419 panic(fmt.Sprintf("unexpected error handling duplicate tentative address: %s", err)) 420 } 421 } 422 423 // Do not handle neighbor solicitations targeted to an address that is 424 // tentative on the NIC any further. 425 return 426 } 427 428 // At this point we know that the target address is not tentative on the NIC 429 // so the packet is processed as defined in RFC 4861, as per RFC 4862 430 // section 5.4.3. 431 432 // Is the NS targeting us? 433 if !e.checkLocalAddress(targetAddr) { 434 return 435 } 436 437 sourceLinkAddr, ok := getSourceLinkAddr(it) 438 if !ok { 439 received.invalid.Increment() 440 return 441 } 442 443 // As per RFC 4861 section 4.3, the Source Link-Layer Address Option MUST 444 // NOT be included when the source IP address is the unspecified address. 445 // Otherwise, on link layers that have addresses this option MUST be 446 // included in multicast solicitations and SHOULD be included in unicast 447 // solicitations. 448 unspecifiedSource := srcAddr == header.IPv6Any 449 if len(sourceLinkAddr) == 0 { 450 if header.IsV6MulticastAddress(dstAddr) && !unspecifiedSource { 451 received.invalid.Increment() 452 return 453 } 454 } else if unspecifiedSource { 455 received.invalid.Increment() 456 return 457 } else { 458 switch err := e.nic.HandleNeighborProbe(ProtocolNumber, srcAddr, sourceLinkAddr); err.(type) { 459 case nil: 460 case *tcpip.ErrNotSupported: 461 // The stack may support ICMPv6 but the NIC may not need link resolution. 462 default: 463 panic(fmt.Sprintf("unexpected error when informing NIC of neighbor probe message: %s", err)) 464 } 465 } 466 467 // As per RFC 4861 section 7.1.1: 468 // A node MUST silently discard any received Neighbor Solicitation 469 // messages that do not satisfy all of the following validity checks: 470 // ... 471 // - If the IP source address is the unspecified address, the IP 472 // destination address is a solicited-node multicast address. 473 if unspecifiedSource && !header.IsSolicitedNodeAddr(dstAddr) { 474 received.invalid.Increment() 475 return 476 } 477 478 // As per RFC 4861 section 7.2.4: 479 // 480 // If the source of the solicitation is the unspecified address, the node 481 // MUST [...] and multicast the advertisement to the all-nodes address. 482 // 483 remoteAddr := srcAddr 484 if unspecifiedSource { 485 remoteAddr = header.IPv6AllNodesMulticastAddress 486 } 487 488 // Even if we were able to receive a packet from some remote, we may not 489 // have a route to it - the remote may be blocked via routing rules. We must 490 // always consult our routing table and find a route to the remote before 491 // sending any packet. 492 r, err := e.protocol.stack.FindRoute(e.nic.ID(), targetAddr, remoteAddr, ProtocolNumber, false /* multicastLoop */) 493 if err != nil { 494 // If we cannot find a route to the destination, silently drop the packet. 495 return 496 } 497 defer r.Release() 498 499 // If the NS has a source link-layer option, resolve the route immediately 500 // to avoid querying the neighbor table when the neighbor entry was updated 501 // as probing the neighbor table for a link address will transition the 502 // entry's state from stale to delay. 503 // 504 // Note, if the source link address is unspecified and this is a unicast 505 // solicitation, we may need to perform neighbor discovery to send the 506 // neighbor advertisement response. This is expected as per RFC 4861 section 507 // 7.2.4: 508 // 509 // Because unicast Neighbor Solicitations are not required to include a 510 // Source Link-Layer Address, it is possible that a node sending a 511 // solicited Neighbor Advertisement does not have a corresponding link- 512 // layer address for its neighbor in its Neighbor Cache. In such 513 // situations, a node will first have to use Neighbor Discovery to 514 // determine the link-layer address of its neighbor (i.e., send out a 515 // multicast Neighbor Solicitation). 516 // 517 if len(sourceLinkAddr) != 0 { 518 r.ResolveWith(sourceLinkAddr) 519 } 520 521 optsSerializer := header.NDPOptionsSerializer{ 522 header.NDPTargetLinkLayerAddressOption(e.nic.LinkAddress()), 523 } 524 neighborAdvertSize := header.ICMPv6NeighborAdvertMinimumSize + optsSerializer.Length() 525 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 526 ReserveHeaderBytes: int(r.MaxHeaderLength()) + neighborAdvertSize, 527 }) 528 defer pkt.DecRef() 529 pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber 530 packet := header.ICMPv6(pkt.TransportHeader().Push(neighborAdvertSize)) 531 packet.SetType(header.ICMPv6NeighborAdvert) 532 na := header.NDPNeighborAdvert(packet.MessageBody()) 533 534 // As per RFC 4861 section 7.2.4: 535 // 536 // If the source of the solicitation is the unspecified address, the node 537 // MUST set the Solicited flag to zero and [..]. Otherwise, the node MUST 538 // set the Solicited flag to one and [..]. 539 // 540 na.SetSolicitedFlag(!unspecifiedSource) 541 na.SetOverrideFlag(true) 542 na.SetRouterFlag(e.Forwarding()) 543 na.SetTargetAddress(targetAddr) 544 na.Options().Serialize(optsSerializer) 545 packet.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 546 Header: packet, 547 Src: r.LocalAddress(), 548 Dst: r.RemoteAddress(), 549 })) 550 551 // RFC 4861 Neighbor Discovery for IP version 6 (IPv6) 552 // 553 // 7.1.2. Validation of Neighbor Advertisements 554 // 555 // The IP Hop Limit field has a value of 255, i.e., the packet 556 // could not possibly have been forwarded by a router. 557 if err := r.WritePacket(stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: header.NDPHopLimit, TOS: stack.DefaultTOS}, pkt); err != nil { 558 sent.dropped.Increment() 559 return 560 } 561 sent.neighborAdvert.Increment() 562 563 case header.ICMPv6NeighborAdvert: 564 received.neighborAdvert.Increment() 565 if !isNDPValid() || len(h) < header.ICMPv6NeighborAdvertMinimumSize { 566 received.invalid.Increment() 567 return 568 } 569 570 na := header.NDPNeighborAdvert(h.MessageBody()) 571 572 it, err := na.Options().Iter(false /* check */) 573 if err != nil { 574 // If we have a malformed NDP NA option, drop the packet. 575 received.invalid.Increment() 576 return 577 } 578 579 targetLinkAddr, ok := getTargetLinkAddr(it) 580 if !ok { 581 received.invalid.Increment() 582 return 583 } 584 585 targetAddr := na.TargetAddress() 586 587 e.dad.mu.Lock() 588 e.dad.mu.dad.StopLocked(targetAddr, &stack.DADDupAddrDetected{HolderLinkAddress: targetLinkAddr}) 589 e.dad.mu.Unlock() 590 591 if e.hasTentativeAddr(targetAddr) { 592 // We only send a nonce value in DAD messages to check for loopedback 593 // messages so we use the empty nonce value here. 594 var nonce []byte 595 596 // We just got an NA from a node that owns an address we are performing 597 // DAD on, implying the address is not unique. In this case we let the 598 // stack know so it can handle such a scenario and do nothing further with 599 // the NDP NA. 600 // 601 // We would get an error if the address no longer exists or the address 602 // is no longer tentative (DAD resolved between the call to 603 // hasTentativeAddr and this point). Both of these are valid scenarios: 604 // 1) An address may be removed at any time. 605 // 2) As per RFC 4862 section 5.4, DAD is not a perfect: 606 // "Note that the method for detecting duplicates 607 // is not completely reliable, and it is possible that duplicate 608 // addresses will still exist" 609 // 610 // TODO(gvisor.dev/issue/4046): Handle the scenario when a duplicate 611 // address is detected for an assigned address. 612 switch err := e.dupTentativeAddrDetected(targetAddr, targetLinkAddr, nonce); err.(type) { 613 case nil, *tcpip.ErrBadAddress, *tcpip.ErrInvalidEndpointState: 614 return 615 default: 616 panic(fmt.Sprintf("unexpected error handling duplicate tentative address: %s", err)) 617 } 618 } 619 620 // At this point we know that the target address is not tentative on the 621 // NIC. However, the target address may still be assigned to the NIC but not 622 // tentative (it could be permanent). Such a scenario is beyond the scope of 623 // RFC 4862. As such, we simply ignore such a scenario for now and proceed 624 // as normal. 625 // 626 // TODO(b/143147598): Handle the scenario described above. Also inform the 627 // netstack integration that a duplicate address was detected outside of 628 // DAD. 629 630 // As per RFC 4861 section 7.1.2: 631 // A node MUST silently discard any received Neighbor Advertisement 632 // messages that do not satisfy all of the following validity checks: 633 // ... 634 // - If the IP Destination Address is a multicast address the 635 // Solicited flag is zero. 636 if header.IsV6MulticastAddress(dstAddr) && na.SolicitedFlag() { 637 received.invalid.Increment() 638 return 639 } 640 641 // If the NA message has the target link layer option, update the link 642 // address cache with the link address for the target of the message. 643 switch err := e.nic.HandleNeighborConfirmation(ProtocolNumber, targetAddr, targetLinkAddr, stack.ReachabilityConfirmationFlags{ 644 Solicited: na.SolicitedFlag(), 645 Override: na.OverrideFlag(), 646 IsRouter: na.RouterFlag(), 647 }); err.(type) { 648 case nil: 649 case *tcpip.ErrNotSupported: 650 // The stack may support ICMPv6 but the NIC may not need link resolution. 651 default: 652 panic(fmt.Sprintf("unexpected error when informing NIC of neighbor confirmation message: %s", err)) 653 } 654 655 case header.ICMPv6EchoRequest: 656 received.echoRequest.Increment() 657 // As per RFC 4291 section 2.7, multicast addresses must not be used as 658 // source addresses in IPv6 packets. 659 localAddr := dstAddr 660 if header.IsV6MulticastAddress(dstAddr) { 661 localAddr = tcpip.Address{} 662 } 663 664 r, err := e.protocol.stack.FindRoute(e.nic.ID(), localAddr, srcAddr, ProtocolNumber, false /* multicastLoop */) 665 if err != nil { 666 // If we cannot find a route to the destination, silently drop the packet. 667 return 668 } 669 defer r.Release() 670 671 if !e.protocol.allowICMPReply(header.ICMPv6EchoReply) { 672 sent.rateLimited.Increment() 673 return 674 } 675 676 replyPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 677 ReserveHeaderBytes: int(r.MaxHeaderLength()) + header.ICMPv6EchoMinimumSize, 678 Payload: pkt.Data().ToBuffer(), 679 }) 680 defer replyPkt.DecRef() 681 icmp := header.ICMPv6(replyPkt.TransportHeader().Push(header.ICMPv6EchoMinimumSize)) 682 replyPkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber 683 copy(icmp, h) 684 icmp.SetType(header.ICMPv6EchoReply) 685 replyData := replyPkt.Data() 686 icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 687 Header: icmp, 688 Src: r.LocalAddress(), 689 Dst: r.RemoteAddress(), 690 PayloadCsum: replyData.Checksum(), 691 PayloadLen: replyData.Size(), 692 })) 693 replyTClass, _ := iph.TOS() 694 if err := r.WritePacket(stack.NetworkHeaderParams{ 695 Protocol: header.ICMPv6ProtocolNumber, 696 TTL: r.DefaultTTL(), 697 // Even though RFC 4443 does not mention anything about it, Linux uses the 698 // TrafficClass of the received echo request when replying. 699 // https://github.com/torvalds/linux/blob/0280e3c58f9/net/ipv6/icmp.c#L797 700 TOS: replyTClass, 701 }, replyPkt); err != nil { 702 sent.dropped.Increment() 703 return 704 } 705 sent.echoReply.Increment() 706 707 case header.ICMPv6EchoReply: 708 received.echoReply.Increment() 709 if len(h) < header.ICMPv6EchoMinimumSize { 710 received.invalid.Increment() 711 return 712 } 713 e.dispatcher.DeliverTransportPacket(header.ICMPv6ProtocolNumber, pkt) 714 715 case header.ICMPv6TimeExceeded: 716 received.timeExceeded.Increment() 717 718 case header.ICMPv6ParamProblem: 719 received.paramProblem.Increment() 720 721 case header.ICMPv6RouterSolicit: 722 received.routerSolicit.Increment() 723 724 // 725 // Validate the RS as per RFC 4861 section 6.1.1. 726 // 727 728 // Is the NDP payload of sufficient size to hold a Router Solictation? 729 if !isNDPValid() || len(h)-header.ICMPv6HeaderSize < header.NDPRSMinimumSize { 730 received.invalid.Increment() 731 return 732 } 733 734 if !e.Forwarding() { 735 received.routerOnlyPacketsDroppedByHost.Increment() 736 return 737 } 738 739 rs := header.NDPRouterSolicit(h.MessageBody()) 740 it, err := rs.Options().Iter(false /* check */) 741 if err != nil { 742 // Options are not valid as per the wire format, silently drop the packet. 743 received.invalid.Increment() 744 return 745 } 746 747 sourceLinkAddr, ok := getSourceLinkAddr(it) 748 if !ok { 749 received.invalid.Increment() 750 return 751 } 752 753 // If the RS message has the source link layer option, update the link 754 // address cache with the link address for the source of the message. 755 if len(sourceLinkAddr) != 0 { 756 // As per RFC 4861 section 4.1, the Source Link-Layer Address Option MUST 757 // NOT be included when the source IP address is the unspecified address. 758 // Otherwise, it SHOULD be included on link layers that have addresses. 759 if srcAddr == header.IPv6Any { 760 received.invalid.Increment() 761 return 762 } 763 764 // A RS with a specified source IP address modifies the neighbor table 765 // in the same way a regular probe would. 766 switch err := e.nic.HandleNeighborProbe(ProtocolNumber, srcAddr, sourceLinkAddr); err.(type) { 767 case nil: 768 case *tcpip.ErrNotSupported: 769 // The stack may support ICMPv6 but the NIC may not need link resolution. 770 default: 771 panic(fmt.Sprintf("unexpected error when informing NIC of neighbor probe message: %s", err)) 772 } 773 } 774 775 case header.ICMPv6RouterAdvert: 776 received.routerAdvert.Increment() 777 778 // 779 // Validate the RA as per RFC 4861 section 6.1.2. 780 // 781 782 // Is the NDP payload of sufficient size to hold a Router Advertisement? 783 if !isNDPValid() || len(h)-header.ICMPv6HeaderSize < header.NDPRAMinimumSize { 784 received.invalid.Increment() 785 return 786 } 787 788 routerAddr := srcAddr 789 790 // Is the IP Source Address a link-local address? 791 if !header.IsV6LinkLocalUnicastAddress(routerAddr) { 792 // ...No, silently drop the packet. 793 received.invalid.Increment() 794 return 795 } 796 797 ra := header.NDPRouterAdvert(h.MessageBody()) 798 it, err := ra.Options().Iter(false /* check */) 799 if err != nil { 800 // Options are not valid as per the wire format, silently drop the packet. 801 received.invalid.Increment() 802 return 803 } 804 805 sourceLinkAddr, ok := getSourceLinkAddr(it) 806 if !ok { 807 received.invalid.Increment() 808 return 809 } 810 811 // 812 // At this point, we have a valid Router Advertisement, as far 813 // as RFC 4861 section 6.1.2 is concerned. 814 // 815 816 // If the RA has the source link layer option, update the link address 817 // cache with the link address for the advertised router. 818 if len(sourceLinkAddr) != 0 { 819 switch err := e.nic.HandleNeighborProbe(ProtocolNumber, routerAddr, sourceLinkAddr); err.(type) { 820 case nil: 821 case *tcpip.ErrNotSupported: 822 // The stack may support ICMPv6 but the NIC may not need link resolution. 823 default: 824 panic(fmt.Sprintf("unexpected error when informing NIC of neighbor probe message: %s", err)) 825 } 826 } 827 828 e.mu.Lock() 829 e.mu.ndp.handleRA(routerAddr, ra) 830 e.mu.Unlock() 831 832 case header.ICMPv6RedirectMsg: 833 // TODO(gvisor.dev/issue/2285): Call `e.nud.HandleProbe` after validating 834 // this redirect message, as per RFC 4871 section 7.3.3: 835 // 836 // "A Neighbor Cache entry enters the STALE state when created as a 837 // result of receiving packets other than solicited Neighbor 838 // Advertisements (i.e., Router Solicitations, Router Advertisements, 839 // Redirects, and Neighbor Solicitations). These packets contain the 840 // link-layer address of either the sender or, in the case of Redirect, 841 // the redirection target. However, receipt of these link-layer 842 // addresses does not confirm reachability of the forward-direction path 843 // to that node. Placing a newly created Neighbor Cache entry for which 844 // the link-layer address is known in the STALE state provides assurance 845 // that path failures are detected quickly. In addition, should a cached 846 // link-layer address be modified due to receiving one of the above 847 // messages, the state SHOULD also be set to STALE to provide prompt 848 // verification that the path to the new link-layer address is working." 849 received.redirectMsg.Increment() 850 if !isNDPValid() { 851 received.invalid.Increment() 852 return 853 } 854 855 case header.ICMPv6MulticastListenerQuery, 856 header.ICMPv6MulticastListenerReport, 857 header.ICMPv6MulticastListenerV2Report, 858 header.ICMPv6MulticastListenerDone: 859 icmpBody := h.MessageBody() 860 switch icmpType { 861 case header.ICMPv6MulticastListenerQuery: 862 received.multicastListenerQuery.Increment() 863 case header.ICMPv6MulticastListenerReport: 864 received.multicastListenerReport.Increment() 865 case header.ICMPv6MulticastListenerV2Report: 866 received.multicastListenerReportV2.Increment() 867 case header.ICMPv6MulticastListenerDone: 868 received.multicastListenerDone.Increment() 869 default: 870 panic(fmt.Sprintf("unrecognized MLD message = %d", icmpType)) 871 } 872 873 if !isMLDValid(pkt, iph, routerAlert) { 874 received.invalid.Increment() 875 return 876 } 877 878 switch icmpType { 879 case header.ICMPv6MulticastListenerQuery: 880 e.mu.Lock() 881 if len(icmpBody) >= header.MLDv2QueryMinimumSize { 882 e.mu.mld.handleMulticastListenerQueryV2(header.MLDv2Query(icmpBody)) 883 } else { 884 e.mu.mld.handleMulticastListenerQuery(header.MLD(icmpBody)) 885 } 886 e.mu.Unlock() 887 case header.ICMPv6MulticastListenerReport: 888 e.mu.Lock() 889 e.mu.mld.handleMulticastListenerReport(header.MLD(icmpBody)) 890 e.mu.Unlock() 891 case header.ICMPv6MulticastListenerDone, header.ICMPv6MulticastListenerV2Report: 892 default: 893 panic(fmt.Sprintf("unrecognized MLD message = %d", icmpType)) 894 } 895 896 default: 897 received.unrecognized.Increment() 898 } 899 } 900 901 // LinkAddressProtocol implements stack.LinkAddressResolver. 902 func (*endpoint) LinkAddressProtocol() tcpip.NetworkProtocolNumber { 903 return header.IPv6ProtocolNumber 904 } 905 906 // LinkAddressRequest implements stack.LinkAddressResolver. 907 func (e *endpoint) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) tcpip.Error { 908 remoteAddr := targetAddr 909 if len(remoteLinkAddr) == 0 { 910 remoteAddr = header.SolicitedNodeAddr(targetAddr) 911 remoteLinkAddr = header.EthernetAddressFromMulticastIPv6Address(remoteAddr) 912 } 913 914 if localAddr.BitLen() == 0 { 915 // Find an address that we can use as our source address. 916 addressEndpoint := e.AcquireOutgoingPrimaryAddress(remoteAddr, tcpip.Address{} /* srcHint */, false /* allowExpired */) 917 if addressEndpoint == nil { 918 return &tcpip.ErrNetworkUnreachable{} 919 } 920 921 localAddr = addressEndpoint.AddressWithPrefix().Address 922 addressEndpoint.DecRef() 923 } else if !e.checkLocalAddress(localAddr) { 924 // The provided local address is not assigned to us. 925 return &tcpip.ErrBadLocalAddress{} 926 } 927 928 return e.sendNDPNS(localAddr, remoteAddr, targetAddr, remoteLinkAddr, header.NDPOptionsSerializer{ 929 header.NDPSourceLinkLayerAddressOption(e.nic.LinkAddress()), 930 }) 931 } 932 933 // ResolveStaticAddress implements stack.LinkAddressResolver. 934 func (*endpoint) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bool) { 935 if header.IsV6MulticastAddress(addr) { 936 return header.EthernetAddressFromMulticastIPv6Address(addr), true 937 } 938 return tcpip.LinkAddress([]byte(nil)), false 939 } 940 941 // ======= ICMP Error packet generation ========= 942 943 // icmpReason is a marker interface for IPv6 specific ICMP errors. 944 type icmpReason interface { 945 isICMPReason() 946 // respondToMulticast indicates whether this error falls under the exception 947 // outlined by RFC 4443 section 2.4 point e.3 exception 2: 948 // 949 // (e.3) A packet destined to an IPv6 multicast address. (There are two 950 // exceptions to this rule: (1) the Packet Too Big Message (Section 3.2) to 951 // allow Path MTU discovery to work for IPv6 multicast, and (2) the Parameter 952 // Problem Message, Code 2 (Section 3.4) reporting an unrecognized IPv6 953 // option (see Section 4.2 of [IPv6]) that has the Option Type highest- 954 // order two bits set to 10). 955 respondsToMulticast() bool 956 } 957 958 // icmpReasonParameterProblem is an error during processing of extension headers 959 // or the fixed header defined in RFC 4443 section 3.4. 960 type icmpReasonParameterProblem struct { 961 code header.ICMPv6Code 962 963 // pointer is defined in the RFC 4443 section 3.4 which reads: 964 // 965 // Pointer Identifies the octet offset within the invoking packet 966 // where the error was detected. 967 // 968 // The pointer will point beyond the end of the ICMPv6 969 // packet if the field in error is beyond what can fit 970 // in the maximum size of an ICMPv6 error message. 971 pointer uint32 972 973 respondToMulticast bool 974 } 975 976 func (*icmpReasonParameterProblem) isICMPReason() {} 977 978 func (p *icmpReasonParameterProblem) respondsToMulticast() bool { 979 return p.respondToMulticast 980 } 981 982 // icmpReasonAdministrativelyProhibited is an error where the destination is 983 // administratively prohibited. 984 type icmpReasonAdministrativelyProhibited struct{} 985 986 func (*icmpReasonAdministrativelyProhibited) isICMPReason() {} 987 988 func (*icmpReasonAdministrativelyProhibited) respondsToMulticast() bool { 989 return false 990 } 991 992 // icmpReasonPortUnreachable is an error where the transport protocol has no 993 // listener and no alternative means to inform the sender. 994 type icmpReasonPortUnreachable struct{} 995 996 func (*icmpReasonPortUnreachable) isICMPReason() {} 997 998 func (*icmpReasonPortUnreachable) respondsToMulticast() bool { 999 return false 1000 } 1001 1002 // icmpReasonNetUnreachable is an error where no route can be found to the 1003 // network of the final destination. 1004 type icmpReasonNetUnreachable struct{} 1005 1006 func (*icmpReasonNetUnreachable) isICMPReason() {} 1007 1008 func (*icmpReasonNetUnreachable) respondsToMulticast() bool { 1009 return false 1010 } 1011 1012 // icmpReasonHostUnreachable is an error in which the host specified in the 1013 // internet destination field of the datagram is unreachable. 1014 type icmpReasonHostUnreachable struct{} 1015 1016 func (*icmpReasonHostUnreachable) isICMPReason() {} 1017 1018 func (*icmpReasonHostUnreachable) respondsToMulticast() bool { 1019 return false 1020 } 1021 1022 // icmpReasonFragmentationNeeded is an error where a packet is to big to be sent 1023 // out through the outgoing MTU, as per RFC 4443 page 9, Packet Too Big Message. 1024 type icmpReasonPacketTooBig struct{} 1025 1026 func (*icmpReasonPacketTooBig) isICMPReason() {} 1027 1028 func (*icmpReasonPacketTooBig) respondsToMulticast() bool { 1029 return true 1030 } 1031 1032 // icmpReasonHopLimitExceeded is an error where a packet's hop limit exceeded in 1033 // transit to its final destination, as per RFC 4443 section 3.3. 1034 type icmpReasonHopLimitExceeded struct{} 1035 1036 func (*icmpReasonHopLimitExceeded) isICMPReason() {} 1037 1038 func (*icmpReasonHopLimitExceeded) respondsToMulticast() bool { 1039 return false 1040 } 1041 1042 // icmpReasonReassemblyTimeout is an error where insufficient fragments are 1043 // received to complete reassembly of a packet within a configured time after 1044 // the reception of the first-arriving fragment of that packet. 1045 type icmpReasonReassemblyTimeout struct{} 1046 1047 func (*icmpReasonReassemblyTimeout) isICMPReason() {} 1048 1049 func (*icmpReasonReassemblyTimeout) respondsToMulticast() bool { 1050 return false 1051 } 1052 1053 // returnError takes an error descriptor and generates the appropriate ICMP 1054 // error packet for IPv6 and sends it. 1055 func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliveredLocally bool) tcpip.Error { 1056 origIPHdr := header.IPv6(pkt.NetworkHeader().Slice()) 1057 origIPHdrSrc := origIPHdr.SourceAddress() 1058 origIPHdrDst := origIPHdr.DestinationAddress() 1059 1060 // Only send ICMP error if the address is not a multicast v6 1061 // address and the source is not the unspecified address. 1062 // 1063 // There are exceptions to this rule. 1064 // See: point e.3) RFC 4443 section-2.4 1065 // 1066 // (e) An ICMPv6 error message MUST NOT be originated as a result of 1067 // receiving the following: 1068 // 1069 // (e.1) An ICMPv6 error message. 1070 // 1071 // (e.2) An ICMPv6 redirect message [IPv6-DISC]. 1072 // 1073 // (e.3) A packet destined to an IPv6 multicast address. (There are 1074 // two exceptions to this rule: (1) the Packet Too Big Message 1075 // (Section 3.2) to allow Path MTU discovery to work for IPv6 1076 // multicast, and (2) the Parameter Problem Message, Code 2 1077 // (Section 3.4) reporting an unrecognized IPv6 option (see 1078 // Section 4.2 of [IPv6]) that has the Option Type highest- 1079 // order two bits set to 10). 1080 // 1081 allowResponseToMulticast := reason.respondsToMulticast() 1082 isOrigDstMulticast := header.IsV6MulticastAddress(origIPHdrDst) 1083 if (!allowResponseToMulticast && isOrigDstMulticast) || origIPHdrSrc == header.IPv6Any { 1084 return nil 1085 } 1086 1087 // If the packet wasn't delivered locally, do not use the packet's destination 1088 // address as the response's source address as we should not own the 1089 // destination address of a packet we are forwarding. 1090 // 1091 // If the packet was originally destined to a multicast address, then do not 1092 // use the packet's destination address as the source for the response ICMP 1093 // packet as "multicast addresses must not be used as source addresses in IPv6 1094 // packets", as per RFC 4291 section 2.7. 1095 localAddr := origIPHdrDst 1096 if !deliveredLocally || isOrigDstMulticast { 1097 localAddr = tcpip.Address{} 1098 } 1099 // Even if we were able to receive a packet from some remote, we may not have 1100 // a route to it - the remote may be blocked via routing rules. We must always 1101 // consult our routing table and find a route to the remote before sending any 1102 // packet. 1103 route, err := p.stack.FindRoute(pkt.NICID, localAddr, origIPHdrSrc, ProtocolNumber, false /* multicastLoop */) 1104 if err != nil { 1105 return err 1106 } 1107 defer route.Release() 1108 1109 p.mu.Lock() 1110 // We retrieve an endpoint using the newly constructed route's NICID rather 1111 // than the packet's NICID. The packet's NICID corresponds to the NIC on 1112 // which it arrived, which isn't necessarily the same as the NIC on which it 1113 // will be transmitted. On the other hand, the route's NIC *is* guaranteed 1114 // to be the NIC on which the packet will be transmitted. 1115 netEP, ok := p.mu.eps[route.NICID()] 1116 p.mu.Unlock() 1117 if !ok { 1118 return &tcpip.ErrNotConnected{} 1119 } 1120 1121 if pkt.TransportProtocolNumber == header.ICMPv6ProtocolNumber { 1122 if typ := header.ICMPv6(pkt.TransportHeader().Slice()).Type(); typ.IsErrorType() || typ == header.ICMPv6RedirectMsg { 1123 return nil 1124 } 1125 } 1126 1127 sent := netEP.stats.icmp.packetsSent 1128 icmpType, icmpCode, counter, typeSpecific := func() (header.ICMPv6Type, header.ICMPv6Code, tcpip.MultiCounterStat, uint32) { 1129 switch reason := reason.(type) { 1130 case *icmpReasonParameterProblem: 1131 return header.ICMPv6ParamProblem, reason.code, sent.paramProblem, reason.pointer 1132 case *icmpReasonAdministrativelyProhibited: 1133 return header.ICMPv6DstUnreachable, header.ICMPv6Prohibited, sent.dstUnreachable, 0 1134 case *icmpReasonPortUnreachable: 1135 return header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, sent.dstUnreachable, 0 1136 case *icmpReasonNetUnreachable: 1137 return header.ICMPv6DstUnreachable, header.ICMPv6NetworkUnreachable, sent.dstUnreachable, 0 1138 case *icmpReasonHostUnreachable: 1139 return header.ICMPv6DstUnreachable, header.ICMPv6AddressUnreachable, sent.dstUnreachable, 0 1140 case *icmpReasonPacketTooBig: 1141 return header.ICMPv6PacketTooBig, header.ICMPv6UnusedCode, sent.packetTooBig, 0 1142 case *icmpReasonHopLimitExceeded: 1143 return header.ICMPv6TimeExceeded, header.ICMPv6HopLimitExceeded, sent.timeExceeded, 0 1144 case *icmpReasonReassemblyTimeout: 1145 return header.ICMPv6TimeExceeded, header.ICMPv6ReassemblyTimeout, sent.timeExceeded, 0 1146 default: 1147 panic(fmt.Sprintf("unsupported ICMP type %T", reason)) 1148 } 1149 }() 1150 1151 if !p.allowICMPReply(icmpType) { 1152 sent.rateLimited.Increment() 1153 return nil 1154 } 1155 1156 network, transport := pkt.NetworkHeader().View(), pkt.TransportHeader().View() 1157 1158 // As per RFC 4443 section 2.4 1159 // 1160 // (c) Every ICMPv6 error message (type < 128) MUST include 1161 // as much of the IPv6 offending (invoking) packet (the 1162 // packet that caused the error) as possible without making 1163 // the error message packet exceed the minimum IPv6 MTU 1164 // [IPv6]. 1165 mtu := int(route.MTU()) 1166 const maxIPv6Data = header.IPv6MinimumMTU - header.IPv6FixedHeaderSize 1167 if mtu > maxIPv6Data { 1168 mtu = maxIPv6Data 1169 } 1170 available := mtu - header.ICMPv6ErrorHeaderSize 1171 if available < header.IPv6MinimumSize { 1172 return nil 1173 } 1174 payloadLen := network.Size() + transport.Size() + pkt.Data().Size() 1175 if payloadLen > available { 1176 payloadLen = available 1177 } 1178 payload := buffer.MakeWithView(network) 1179 payload.Append(transport) 1180 dataBuf := pkt.Data().ToBuffer() 1181 payload.Merge(&dataBuf) 1182 payload.Truncate(int64(payloadLen)) 1183 1184 newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1185 ReserveHeaderBytes: int(route.MaxHeaderLength()) + header.ICMPv6ErrorHeaderSize, 1186 Payload: payload, 1187 }) 1188 defer newPkt.DecRef() 1189 newPkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber 1190 1191 icmpHdr := header.ICMPv6(newPkt.TransportHeader().Push(header.ICMPv6DstUnreachableMinimumSize)) 1192 icmpHdr.SetType(icmpType) 1193 icmpHdr.SetCode(icmpCode) 1194 icmpHdr.SetTypeSpecific(typeSpecific) 1195 1196 pktData := newPkt.Data() 1197 icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1198 Header: icmpHdr, 1199 Src: route.LocalAddress(), 1200 Dst: route.RemoteAddress(), 1201 PayloadCsum: pktData.Checksum(), 1202 PayloadLen: pktData.Size(), 1203 })) 1204 if err := route.WritePacket( 1205 stack.NetworkHeaderParams{ 1206 Protocol: header.ICMPv6ProtocolNumber, 1207 TTL: route.DefaultTTL(), 1208 TOS: stack.DefaultTOS, 1209 }, 1210 newPkt, 1211 ); err != nil { 1212 sent.dropped.Increment() 1213 return err 1214 } 1215 counter.Increment() 1216 return nil 1217 } 1218 1219 // OnReassemblyTimeout implements fragmentation.TimeoutHandler. 1220 func (p *protocol) OnReassemblyTimeout(pkt *stack.PacketBuffer) { 1221 // OnReassemblyTimeout sends a Time Exceeded Message as per RFC 2460 Section 1222 // 4.5: 1223 // 1224 // If the first fragment (i.e., the one with a Fragment Offset of zero) has 1225 // been received, an ICMP Time Exceeded -- Fragment Reassembly Time Exceeded 1226 // message should be sent to the source of that fragment. 1227 if pkt != nil { 1228 p.returnError(&icmpReasonReassemblyTimeout{}, pkt, true /* deliveredLocally */) 1229 } 1230 }