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