inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/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 "inet.af/netstack/tcpip" 21 "inet.af/netstack/tcpip/header" 22 "inet.af/netstack/tcpip/stack" 23 ) 24 25 // icmpv6DestinationUnreachableSockError is a general ICMPv6 Destination 26 // Unreachable error. 27 // 28 // +stateify savable 29 type icmpv6DestinationUnreachableSockError struct{} 30 31 // Origin implements tcpip.SockErrorCause. 32 func (*icmpv6DestinationUnreachableSockError) Origin() tcpip.SockErrOrigin { 33 return tcpip.SockExtErrorOriginICMP6 34 } 35 36 // Type implements tcpip.SockErrorCause. 37 func (*icmpv6DestinationUnreachableSockError) Type() uint8 { 38 return uint8(header.ICMPv6DstUnreachable) 39 } 40 41 // Info implements tcpip.SockErrorCause. 42 func (*icmpv6DestinationUnreachableSockError) Info() uint32 { 43 return 0 44 } 45 46 var _ stack.TransportError = (*icmpv6DestinationNetworkUnreachableSockError)(nil) 47 48 // icmpv6DestinationNetworkUnreachableSockError is an ICMPv6 Destination Network 49 // Unreachable error. 50 // 51 // It indicates that the destination network is unreachable. 52 // 53 // +stateify savable 54 type icmpv6DestinationNetworkUnreachableSockError struct { 55 icmpv6DestinationUnreachableSockError 56 } 57 58 // Code implements tcpip.SockErrorCause. 59 func (*icmpv6DestinationNetworkUnreachableSockError) Code() uint8 { 60 return uint8(header.ICMPv6NetworkUnreachable) 61 } 62 63 // Kind implements stack.TransportError. 64 func (*icmpv6DestinationNetworkUnreachableSockError) Kind() stack.TransportErrorKind { 65 return stack.DestinationNetworkUnreachableTransportError 66 } 67 68 var _ stack.TransportError = (*icmpv6DestinationPortUnreachableSockError)(nil) 69 70 // icmpv6DestinationPortUnreachableSockError is an ICMPv6 Destination Port 71 // Unreachable error. 72 // 73 // It indicates that a packet reached the destination host, but the transport 74 // protocol was not active on the destination port. 75 // 76 // +stateify savable 77 type icmpv6DestinationPortUnreachableSockError struct { 78 icmpv6DestinationUnreachableSockError 79 } 80 81 // Code implements tcpip.SockErrorCause. 82 func (*icmpv6DestinationPortUnreachableSockError) Code() uint8 { 83 return uint8(header.ICMPv6PortUnreachable) 84 } 85 86 // Kind implements stack.TransportError. 87 func (*icmpv6DestinationPortUnreachableSockError) Kind() stack.TransportErrorKind { 88 return stack.DestinationPortUnreachableTransportError 89 } 90 91 var _ stack.TransportError = (*icmpv6DestinationAddressUnreachableSockError)(nil) 92 93 // icmpv6DestinationAddressUnreachableSockError is an ICMPv6 Destination Address 94 // Unreachable error. 95 // 96 // It indicates that a packet was not able to reach the destination. 97 // 98 // +stateify savable 99 type icmpv6DestinationAddressUnreachableSockError struct { 100 icmpv6DestinationUnreachableSockError 101 } 102 103 // Code implements tcpip.SockErrorCause. 104 func (*icmpv6DestinationAddressUnreachableSockError) Code() uint8 { 105 return uint8(header.ICMPv6AddressUnreachable) 106 } 107 108 // Kind implements stack.TransportError. 109 func (*icmpv6DestinationAddressUnreachableSockError) Kind() stack.TransportErrorKind { 110 return stack.DestinationHostUnreachableTransportError 111 } 112 113 var _ stack.TransportError = (*icmpv6PacketTooBigSockError)(nil) 114 115 // icmpv6PacketTooBigSockError is an ICMPv6 Packet Too Big error. 116 // 117 // It indicates that a link exists on the path to the destination with an MTU 118 // that is too small to carry the packet. 119 // 120 // +stateify savable 121 type icmpv6PacketTooBigSockError struct { 122 mtu uint32 123 } 124 125 // Origin implements tcpip.SockErrorCause. 126 func (*icmpv6PacketTooBigSockError) Origin() tcpip.SockErrOrigin { 127 return tcpip.SockExtErrorOriginICMP6 128 } 129 130 // Type implements tcpip.SockErrorCause. 131 func (*icmpv6PacketTooBigSockError) Type() uint8 { 132 return uint8(header.ICMPv6PacketTooBig) 133 } 134 135 // Code implements tcpip.SockErrorCause. 136 func (*icmpv6PacketTooBigSockError) Code() uint8 { 137 return uint8(header.ICMPv6UnusedCode) 138 } 139 140 // Info implements tcpip.SockErrorCause. 141 func (e *icmpv6PacketTooBigSockError) Info() uint32 { 142 return e.mtu 143 } 144 145 // Kind implements stack.TransportError. 146 func (*icmpv6PacketTooBigSockError) Kind() stack.TransportErrorKind { 147 return stack.PacketTooBigTransportError 148 } 149 150 func (e *endpoint) checkLocalAddress(addr tcpip.Address) bool { 151 if e.nic.Spoofing() { 152 return true 153 } 154 155 if addressEndpoint := e.AcquireAssignedAddress(addr, false, stack.NeverPrimaryEndpoint); addressEndpoint != nil { 156 addressEndpoint.DecRef() 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 pkt.TransportHeader().View().Size() < 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().View()) 293 if len(h) < header.ICMPv6MinimumSize { 294 received.invalid.Increment() 295 return 296 } 297 iph := header.IPv6(pkt.NetworkHeader().View()) 298 srcAddr := iph.SourceAddress() 299 dstAddr := iph.DestinationAddress() 300 301 // Validate ICMPv6 checksum before processing the packet. 302 payload := pkt.Data().AsRange() 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.SetTargetAddress(targetAddr) 543 na.Options().Serialize(optsSerializer) 544 packet.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 545 Header: packet, 546 Src: r.LocalAddress(), 547 Dst: r.RemoteAddress(), 548 })) 549 550 // RFC 4861 Neighbor Discovery for IP version 6 (IPv6) 551 // 552 // 7.1.2. Validation of Neighbor Advertisements 553 // 554 // The IP Hop Limit field has a value of 255, i.e., the packet 555 // could not possibly have been forwarded by a router. 556 if err := r.WritePacket(stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: header.NDPHopLimit, TOS: stack.DefaultTOS}, pkt); err != nil { 557 sent.dropped.Increment() 558 return 559 } 560 sent.neighborAdvert.Increment() 561 562 case header.ICMPv6NeighborAdvert: 563 received.neighborAdvert.Increment() 564 if !isNDPValid() || len(h) < header.ICMPv6NeighborAdvertMinimumSize { 565 received.invalid.Increment() 566 return 567 } 568 569 na := header.NDPNeighborAdvert(h.MessageBody()) 570 571 it, err := na.Options().Iter(false /* check */) 572 if err != nil { 573 // If we have a malformed NDP NA option, drop the packet. 574 received.invalid.Increment() 575 return 576 } 577 578 targetLinkAddr, ok := getTargetLinkAddr(it) 579 if !ok { 580 received.invalid.Increment() 581 return 582 } 583 584 targetAddr := na.TargetAddress() 585 586 e.dad.mu.Lock() 587 e.dad.mu.dad.StopLocked(targetAddr, &stack.DADDupAddrDetected{HolderLinkAddress: targetLinkAddr}) 588 e.dad.mu.Unlock() 589 590 if e.hasTentativeAddr(targetAddr) { 591 // We only send a nonce value in DAD messages to check for loopedback 592 // messages so we use the empty nonce value here. 593 var nonce []byte 594 595 // We just got an NA from a node that owns an address we are performing 596 // DAD on, implying the address is not unique. In this case we let the 597 // stack know so it can handle such a scenario and do nothing furthur with 598 // the NDP NA. 599 // 600 // We would get an error if the address no longer exists or the address 601 // is no longer tentative (DAD resolved between the call to 602 // hasTentativeAddr and this point). Both of these are valid scenarios: 603 // 1) An address may be removed at any time. 604 // 2) As per RFC 4862 section 5.4, DAD is not a perfect: 605 // "Note that the method for detecting duplicates 606 // is not completely reliable, and it is possible that duplicate 607 // addresses will still exist" 608 // 609 // TODO(gvisor.dev/issue/4046): Handle the scenario when a duplicate 610 // address is detected for an assigned address. 611 switch err := e.dupTentativeAddrDetected(targetAddr, targetLinkAddr, nonce); err.(type) { 612 case nil, *tcpip.ErrBadAddress, *tcpip.ErrInvalidEndpointState: 613 return 614 default: 615 panic(fmt.Sprintf("unexpected error handling duplicate tentative address: %s", err)) 616 } 617 } 618 619 // At this point we know that the target address is not tentative on the 620 // NIC. However, the target address may still be assigned to the NIC but not 621 // tentative (it could be permanent). Such a scenario is beyond the scope of 622 // RFC 4862. As such, we simply ignore such a scenario for now and proceed 623 // as normal. 624 // 625 // TODO(b/143147598): Handle the scenario described above. Also inform the 626 // netstack integration that a duplicate address was detected outside of 627 // DAD. 628 629 // As per RFC 4861 section 7.1.2: 630 // A node MUST silently discard any received Neighbor Advertisement 631 // messages that do not satisfy all of the following validity checks: 632 // ... 633 // - If the IP Destination Address is a multicast address the 634 // Solicited flag is zero. 635 if header.IsV6MulticastAddress(dstAddr) && na.SolicitedFlag() { 636 received.invalid.Increment() 637 return 638 } 639 640 // If the NA message has the target link layer option, update the link 641 // address cache with the link address for the target of the message. 642 switch err := e.nic.HandleNeighborConfirmation(ProtocolNumber, targetAddr, targetLinkAddr, stack.ReachabilityConfirmationFlags{ 643 Solicited: na.SolicitedFlag(), 644 Override: na.OverrideFlag(), 645 IsRouter: na.RouterFlag(), 646 }); err.(type) { 647 case nil: 648 case *tcpip.ErrNotSupported: 649 // The stack may support ICMPv6 but the NIC may not need link resolution. 650 default: 651 panic(fmt.Sprintf("unexpected error when informing NIC of neighbor confirmation message: %s", err)) 652 } 653 654 case header.ICMPv6EchoRequest: 655 received.echoRequest.Increment() 656 // As per RFC 4291 section 2.7, multicast addresses must not be used as 657 // source addresses in IPv6 packets. 658 localAddr := dstAddr 659 if header.IsV6MulticastAddress(dstAddr) { 660 localAddr = "" 661 } 662 663 r, err := e.protocol.stack.FindRoute(e.nic.ID(), localAddr, srcAddr, ProtocolNumber, false /* multicastLoop */) 664 if err != nil { 665 // If we cannot find a route to the destination, silently drop the packet. 666 return 667 } 668 defer r.Release() 669 670 if !e.protocol.allowICMPReply(header.ICMPv6EchoReply) { 671 sent.rateLimited.Increment() 672 return 673 } 674 675 replyPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 676 ReserveHeaderBytes: int(r.MaxHeaderLength()) + header.ICMPv6EchoMinimumSize, 677 Data: pkt.Data().ExtractVV(), 678 }) 679 defer replyPkt.DecRef() 680 icmp := header.ICMPv6(replyPkt.TransportHeader().Push(header.ICMPv6EchoMinimumSize)) 681 pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber 682 copy(icmp, h) 683 icmp.SetType(header.ICMPv6EchoReply) 684 dataRange := replyPkt.Data().AsRange() 685 icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 686 Header: icmp, 687 Src: r.LocalAddress(), 688 Dst: r.RemoteAddress(), 689 PayloadCsum: dataRange.Checksum(), 690 PayloadLen: dataRange.Size(), 691 })) 692 if err := r.WritePacket(stack.NetworkHeaderParams{ 693 Protocol: header.ICMPv6ProtocolNumber, 694 TTL: r.DefaultTTL(), 695 TOS: stack.DefaultTOS, 696 }, replyPkt); err != nil { 697 sent.dropped.Increment() 698 return 699 } 700 sent.echoReply.Increment() 701 702 case header.ICMPv6EchoReply: 703 received.echoReply.Increment() 704 if len(h) < header.ICMPv6EchoMinimumSize { 705 received.invalid.Increment() 706 return 707 } 708 e.dispatcher.DeliverTransportPacket(header.ICMPv6ProtocolNumber, pkt) 709 710 case header.ICMPv6TimeExceeded: 711 received.timeExceeded.Increment() 712 713 case header.ICMPv6ParamProblem: 714 received.paramProblem.Increment() 715 716 case header.ICMPv6RouterSolicit: 717 received.routerSolicit.Increment() 718 719 // 720 // Validate the RS as per RFC 4861 section 6.1.1. 721 // 722 723 // Is the NDP payload of sufficient size to hold a Router Solictation? 724 if !isNDPValid() || len(h)-header.ICMPv6HeaderSize < header.NDPRSMinimumSize { 725 received.invalid.Increment() 726 return 727 } 728 729 if !e.Forwarding() { 730 received.routerOnlyPacketsDroppedByHost.Increment() 731 return 732 } 733 734 rs := header.NDPRouterSolicit(h.MessageBody()) 735 it, err := rs.Options().Iter(false /* check */) 736 if err != nil { 737 // Options are not valid as per the wire format, silently drop the packet. 738 received.invalid.Increment() 739 return 740 } 741 742 sourceLinkAddr, ok := getSourceLinkAddr(it) 743 if !ok { 744 received.invalid.Increment() 745 return 746 } 747 748 // If the RS message has the source link layer option, update the link 749 // address cache with the link address for the source of the message. 750 if len(sourceLinkAddr) != 0 { 751 // As per RFC 4861 section 4.1, the Source Link-Layer Address Option MUST 752 // NOT be included when the source IP address is the unspecified address. 753 // Otherwise, it SHOULD be included on link layers that have addresses. 754 if srcAddr == header.IPv6Any { 755 received.invalid.Increment() 756 return 757 } 758 759 // A RS with a specified source IP address modifies the neighbor table 760 // in the same way a regular probe would. 761 switch err := e.nic.HandleNeighborProbe(ProtocolNumber, srcAddr, sourceLinkAddr); err.(type) { 762 case nil: 763 case *tcpip.ErrNotSupported: 764 // The stack may support ICMPv6 but the NIC may not need link resolution. 765 default: 766 panic(fmt.Sprintf("unexpected error when informing NIC of neighbor probe message: %s", err)) 767 } 768 } 769 770 case header.ICMPv6RouterAdvert: 771 received.routerAdvert.Increment() 772 773 // 774 // Validate the RA as per RFC 4861 section 6.1.2. 775 // 776 777 // Is the NDP payload of sufficient size to hold a Router Advertisement? 778 if !isNDPValid() || len(h)-header.ICMPv6HeaderSize < header.NDPRAMinimumSize { 779 received.invalid.Increment() 780 return 781 } 782 783 routerAddr := srcAddr 784 785 // Is the IP Source Address a link-local address? 786 if !header.IsV6LinkLocalUnicastAddress(routerAddr) { 787 // ...No, silently drop the packet. 788 received.invalid.Increment() 789 return 790 } 791 792 ra := header.NDPRouterAdvert(h.MessageBody()) 793 it, err := ra.Options().Iter(false /* check */) 794 if err != nil { 795 // Options are not valid as per the wire format, silently drop the packet. 796 received.invalid.Increment() 797 return 798 } 799 800 sourceLinkAddr, ok := getSourceLinkAddr(it) 801 if !ok { 802 received.invalid.Increment() 803 return 804 } 805 806 // 807 // At this point, we have a valid Router Advertisement, as far 808 // as RFC 4861 section 6.1.2 is concerned. 809 // 810 811 // If the RA has the source link layer option, update the link address 812 // cache with the link address for the advertised router. 813 if len(sourceLinkAddr) != 0 { 814 switch err := e.nic.HandleNeighborProbe(ProtocolNumber, routerAddr, sourceLinkAddr); err.(type) { 815 case nil: 816 case *tcpip.ErrNotSupported: 817 // The stack may support ICMPv6 but the NIC may not need link resolution. 818 default: 819 panic(fmt.Sprintf("unexpected error when informing NIC of neighbor probe message: %s", err)) 820 } 821 } 822 823 e.mu.Lock() 824 e.mu.ndp.handleRA(routerAddr, ra) 825 e.mu.Unlock() 826 827 case header.ICMPv6RedirectMsg: 828 // TODO(gvisor.dev/issue/2285): Call `e.nud.HandleProbe` after validating 829 // this redirect message, as per RFC 4871 section 7.3.3: 830 // 831 // "A Neighbor Cache entry enters the STALE state when created as a 832 // result of receiving packets other than solicited Neighbor 833 // Advertisements (i.e., Router Solicitations, Router Advertisements, 834 // Redirects, and Neighbor Solicitations). These packets contain the 835 // link-layer address of either the sender or, in the case of Redirect, 836 // the redirection target. However, receipt of these link-layer 837 // addresses does not confirm reachability of the forward-direction path 838 // to that node. Placing a newly created Neighbor Cache entry for which 839 // the link-layer address is known in the STALE state provides assurance 840 // that path failures are detected quickly. In addition, should a cached 841 // link-layer address be modified due to receiving one of the above 842 // messages, the state SHOULD also be set to STALE to provide prompt 843 // verification that the path to the new link-layer address is working." 844 received.redirectMsg.Increment() 845 if !isNDPValid() { 846 received.invalid.Increment() 847 return 848 } 849 850 case header.ICMPv6MulticastListenerQuery, header.ICMPv6MulticastListenerReport, header.ICMPv6MulticastListenerDone: 851 switch icmpType { 852 case header.ICMPv6MulticastListenerQuery: 853 received.multicastListenerQuery.Increment() 854 case header.ICMPv6MulticastListenerReport: 855 received.multicastListenerReport.Increment() 856 case header.ICMPv6MulticastListenerDone: 857 received.multicastListenerDone.Increment() 858 default: 859 panic(fmt.Sprintf("unrecognized MLD message = %d", icmpType)) 860 } 861 862 if !isMLDValid(pkt, iph, routerAlert) { 863 received.invalid.Increment() 864 return 865 } 866 867 switch icmpType { 868 case header.ICMPv6MulticastListenerQuery: 869 e.mu.Lock() 870 e.mu.mld.handleMulticastListenerQuery(header.MLD(h.MessageBody())) 871 e.mu.Unlock() 872 case header.ICMPv6MulticastListenerReport: 873 e.mu.Lock() 874 e.mu.mld.handleMulticastListenerReport(header.MLD(h.MessageBody())) 875 e.mu.Unlock() 876 case header.ICMPv6MulticastListenerDone: 877 default: 878 panic(fmt.Sprintf("unrecognized MLD message = %d", icmpType)) 879 } 880 881 default: 882 received.unrecognized.Increment() 883 } 884 } 885 886 // LinkAddressProtocol implements stack.LinkAddressResolver. 887 func (*endpoint) LinkAddressProtocol() tcpip.NetworkProtocolNumber { 888 return header.IPv6ProtocolNumber 889 } 890 891 // LinkAddressRequest implements stack.LinkAddressResolver. 892 func (e *endpoint) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) tcpip.Error { 893 remoteAddr := targetAddr 894 if len(remoteLinkAddr) == 0 { 895 remoteAddr = header.SolicitedNodeAddr(targetAddr) 896 remoteLinkAddr = header.EthernetAddressFromMulticastIPv6Address(remoteAddr) 897 } 898 899 if len(localAddr) == 0 { 900 // Find an address that we can use as our source address. 901 addressEndpoint := e.AcquireOutgoingPrimaryAddress(remoteAddr, false /* allowExpired */) 902 if addressEndpoint == nil { 903 return &tcpip.ErrNetworkUnreachable{} 904 } 905 906 localAddr = addressEndpoint.AddressWithPrefix().Address 907 addressEndpoint.DecRef() 908 } else if !e.checkLocalAddress(localAddr) { 909 // The provided local address is not assigned to us. 910 return &tcpip.ErrBadLocalAddress{} 911 } 912 913 return e.sendNDPNS(localAddr, remoteAddr, targetAddr, remoteLinkAddr, header.NDPOptionsSerializer{ 914 header.NDPSourceLinkLayerAddressOption(e.nic.LinkAddress()), 915 }) 916 } 917 918 // ResolveStaticAddress implements stack.LinkAddressResolver. 919 func (*endpoint) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bool) { 920 if header.IsV6MulticastAddress(addr) { 921 return header.EthernetAddressFromMulticastIPv6Address(addr), true 922 } 923 return tcpip.LinkAddress([]byte(nil)), false 924 } 925 926 // ======= ICMP Error packet generation ========= 927 928 // icmpReason is a marker interface for IPv6 specific ICMP errors. 929 type icmpReason interface { 930 isICMPReason() 931 // isForwarding indicates whether or not the error arose while attempting to 932 // forward a packet. 933 isForwarding() bool 934 // respondToMulticast indicates whether this error falls under the exception 935 // outlined by RFC 4443 section 2.4 point e.3 exception 2: 936 // 937 // (e.3) A packet destined to an IPv6 multicast address. (There are two 938 // exceptions to this rule: (1) the Packet Too Big Message (Section 3.2) to 939 // allow Path MTU discovery to work for IPv6 multicast, and (2) the Parameter 940 // Problem Message, Code 2 (Section 3.4) reporting an unrecognized IPv6 941 // option (see Section 4.2 of [IPv6]) that has the Option Type highest- 942 // order two bits set to 10). 943 respondsToMulticast() bool 944 } 945 946 // icmpReasonParameterProblem is an error during processing of extension headers 947 // or the fixed header defined in RFC 4443 section 3.4. 948 type icmpReasonParameterProblem struct { 949 code header.ICMPv6Code 950 951 // pointer is defined in the RFC 4443 setion 3.4 which reads: 952 // 953 // Pointer Identifies the octet offset within the invoking packet 954 // where the error was detected. 955 // 956 // The pointer will point beyond the end of the ICMPv6 957 // packet if the field in error is beyond what can fit 958 // in the maximum size of an ICMPv6 error message. 959 pointer uint32 960 961 forwarding bool 962 963 respondToMulticast bool 964 } 965 966 func (*icmpReasonParameterProblem) isICMPReason() {} 967 func (p *icmpReasonParameterProblem) isForwarding() bool { 968 return p.forwarding 969 } 970 971 func (p *icmpReasonParameterProblem) respondsToMulticast() bool { 972 return p.respondToMulticast 973 } 974 975 // icmpReasonPortUnreachable is an error where the transport protocol has no 976 // listener and no alternative means to inform the sender. 977 type icmpReasonPortUnreachable struct{} 978 979 func (*icmpReasonPortUnreachable) isICMPReason() {} 980 981 func (*icmpReasonPortUnreachable) isForwarding() bool { 982 return false 983 } 984 985 func (*icmpReasonPortUnreachable) respondsToMulticast() bool { 986 return false 987 } 988 989 // icmpReasonNetUnreachable is an error where no route can be found to the 990 // network of the final destination. 991 type icmpReasonNetUnreachable struct{} 992 993 func (*icmpReasonNetUnreachable) isICMPReason() {} 994 995 func (*icmpReasonNetUnreachable) isForwarding() bool { 996 // If we hit a Network Unreachable error, then we also know we are 997 // operating as a router. As per RFC 4443 section 3.1: 998 // 999 // If the reason for the failure to deliver is lack of a matching 1000 // entry in the forwarding node's routing table, the Code field is 1001 // set to 0 (Network Unreachable). 1002 return true 1003 } 1004 1005 func (*icmpReasonNetUnreachable) respondsToMulticast() bool { 1006 return false 1007 } 1008 1009 // icmpReasonHostUnreachable is an error in which the host specified in the 1010 // internet destination field of the datagram is unreachable. 1011 type icmpReasonHostUnreachable struct{} 1012 1013 func (*icmpReasonHostUnreachable) isICMPReason() {} 1014 func (*icmpReasonHostUnreachable) isForwarding() bool { 1015 // If we hit a Host Unreachable error, then we know we are operating as a 1016 // router. As per RFC 4443 page 8, Destination Unreachable Message, 1017 // 1018 // If the reason for the failure to deliver cannot be mapped to any of 1019 // other codes, the Code field is set to 3. Example of such cases are 1020 // an inability to resolve the IPv6 destination address into a 1021 // corresponding link address, or a link-specific problem of some sort. 1022 return true 1023 } 1024 1025 func (*icmpReasonHostUnreachable) respondsToMulticast() bool { 1026 return false 1027 } 1028 1029 // icmpReasonFragmentationNeeded is an error where a packet is to big to be sent 1030 // out through the outgoing MTU, as per RFC 4443 page 9, Packet Too Big Message. 1031 type icmpReasonPacketTooBig struct{} 1032 1033 func (*icmpReasonPacketTooBig) isICMPReason() {} 1034 1035 func (*icmpReasonPacketTooBig) isForwarding() bool { 1036 // If we hit a Packet Too Big error, then we know we are operating as a router. 1037 // As per RFC 4443 section 3.2: 1038 // 1039 // A Packet Too Big MUST be sent by a router in response to a packet that it 1040 // cannot forward because the packet is larger than the MTU of the outgoing 1041 // link. 1042 return true 1043 } 1044 1045 func (*icmpReasonPacketTooBig) respondsToMulticast() bool { 1046 return true 1047 } 1048 1049 // icmpReasonHopLimitExceeded is an error where a packet's hop limit exceeded in 1050 // transit to its final destination, as per RFC 4443 section 3.3. 1051 type icmpReasonHopLimitExceeded struct{} 1052 1053 func (*icmpReasonHopLimitExceeded) isICMPReason() {} 1054 1055 func (*icmpReasonHopLimitExceeded) isForwarding() bool { 1056 // If we hit a Hop Limit Exceeded error, then we know we are operating 1057 // as a router. As per RFC 4443 section 3.3: 1058 // 1059 // If a router receives a packet with a Hop Limit of zero, or if a 1060 // router decrements a packet's Hop Limit to zero, it MUST discard 1061 // the packet and originate an ICMPv6 Time Exceeded message with Code 1062 // 0 to the source of the packet. This indicates either a routing 1063 // loop or too small an initial Hop Limit value. 1064 return true 1065 } 1066 1067 func (*icmpReasonHopLimitExceeded) respondsToMulticast() bool { 1068 return false 1069 } 1070 1071 // icmpReasonReassemblyTimeout is an error where insufficient fragments are 1072 // received to complete reassembly of a packet within a configured time after 1073 // the reception of the first-arriving fragment of that packet. 1074 type icmpReasonReassemblyTimeout struct{} 1075 1076 func (*icmpReasonReassemblyTimeout) isICMPReason() {} 1077 1078 func (*icmpReasonReassemblyTimeout) isForwarding() bool { 1079 return false 1080 } 1081 1082 func (*icmpReasonReassemblyTimeout) respondsToMulticast() bool { 1083 return false 1084 } 1085 1086 // returnError takes an error descriptor and generates the appropriate ICMP 1087 // error packet for IPv6 and sends it. 1088 func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip.Error { 1089 origIPHdr := header.IPv6(pkt.NetworkHeader().View()) 1090 origIPHdrSrc := origIPHdr.SourceAddress() 1091 origIPHdrDst := origIPHdr.DestinationAddress() 1092 1093 // Only send ICMP error if the address is not a multicast v6 1094 // address and the source is not the unspecified address. 1095 // 1096 // There are exceptions to this rule. 1097 // See: point e.3) RFC 4443 section-2.4 1098 // 1099 // (e) An ICMPv6 error message MUST NOT be originated as a result of 1100 // receiving the following: 1101 // 1102 // (e.1) An ICMPv6 error message. 1103 // 1104 // (e.2) An ICMPv6 redirect message [IPv6-DISC]. 1105 // 1106 // (e.3) A packet destined to an IPv6 multicast address. (There are 1107 // two exceptions to this rule: (1) the Packet Too Big Message 1108 // (Section 3.2) to allow Path MTU discovery to work for IPv6 1109 // multicast, and (2) the Parameter Problem Message, Code 2 1110 // (Section 3.4) reporting an unrecognized IPv6 option (see 1111 // Section 4.2 of [IPv6]) that has the Option Type highest- 1112 // order two bits set to 10). 1113 // 1114 allowResponseToMulticast := reason.respondsToMulticast() 1115 isOrigDstMulticast := header.IsV6MulticastAddress(origIPHdrDst) 1116 if (!allowResponseToMulticast && isOrigDstMulticast) || origIPHdrSrc == header.IPv6Any { 1117 return nil 1118 } 1119 1120 // If we are operating as a router, do not use the packet's destination 1121 // address as the response's source address as we should not own the 1122 // destination address of a packet we are forwarding. 1123 // 1124 // If the packet was originally destined to a multicast address, then do not 1125 // use the packet's destination address as the source for the response ICMP 1126 // packet as "multicast addresses must not be used as source addresses in IPv6 1127 // packets", as per RFC 4291 section 2.7. 1128 localAddr := origIPHdrDst 1129 if reason.isForwarding() || isOrigDstMulticast { 1130 localAddr = "" 1131 } 1132 // Even if we were able to receive a packet from some remote, we may not have 1133 // a route to it - the remote may be blocked via routing rules. We must always 1134 // consult our routing table and find a route to the remote before sending any 1135 // packet. 1136 route, err := p.stack.FindRoute(pkt.NICID, localAddr, origIPHdrSrc, ProtocolNumber, false /* multicastLoop */) 1137 if err != nil { 1138 return err 1139 } 1140 defer route.Release() 1141 1142 p.mu.Lock() 1143 // We retrieve an endpoint using the newly constructed route's NICID rather 1144 // than the packet's NICID. The packet's NICID corresponds to the NIC on 1145 // which it arrived, which isn't necessarily the same as the NIC on which it 1146 // will be transmitted. On the other hand, the route's NIC *is* guaranteed 1147 // to be the NIC on which the packet will be transmitted. 1148 netEP, ok := p.mu.eps[route.NICID()] 1149 p.mu.Unlock() 1150 if !ok { 1151 return &tcpip.ErrNotConnected{} 1152 } 1153 1154 if pkt.TransportProtocolNumber == header.ICMPv6ProtocolNumber { 1155 if typ := header.ICMPv6(pkt.TransportHeader().View()).Type(); typ.IsErrorType() || typ == header.ICMPv6RedirectMsg { 1156 return nil 1157 } 1158 } 1159 1160 sent := netEP.stats.icmp.packetsSent 1161 icmpType, icmpCode, counter, typeSpecific := func() (header.ICMPv6Type, header.ICMPv6Code, tcpip.MultiCounterStat, uint32) { 1162 switch reason := reason.(type) { 1163 case *icmpReasonParameterProblem: 1164 return header.ICMPv6ParamProblem, reason.code, sent.paramProblem, reason.pointer 1165 case *icmpReasonPortUnreachable: 1166 return header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, sent.dstUnreachable, 0 1167 case *icmpReasonNetUnreachable: 1168 return header.ICMPv6DstUnreachable, header.ICMPv6NetworkUnreachable, sent.dstUnreachable, 0 1169 case *icmpReasonHostUnreachable: 1170 return header.ICMPv6DstUnreachable, header.ICMPv6AddressUnreachable, sent.dstUnreachable, 0 1171 case *icmpReasonPacketTooBig: 1172 return header.ICMPv6PacketTooBig, header.ICMPv6UnusedCode, sent.packetTooBig, 0 1173 case *icmpReasonHopLimitExceeded: 1174 return header.ICMPv6TimeExceeded, header.ICMPv6HopLimitExceeded, sent.timeExceeded, 0 1175 case *icmpReasonReassemblyTimeout: 1176 return header.ICMPv6TimeExceeded, header.ICMPv6ReassemblyTimeout, sent.timeExceeded, 0 1177 default: 1178 panic(fmt.Sprintf("unsupported ICMP type %T", reason)) 1179 } 1180 }() 1181 1182 if !p.allowICMPReply(icmpType) { 1183 sent.rateLimited.Increment() 1184 return nil 1185 } 1186 1187 network, transport := pkt.NetworkHeader().View(), pkt.TransportHeader().View() 1188 1189 // As per RFC 4443 section 2.4 1190 // 1191 // (c) Every ICMPv6 error message (type < 128) MUST include 1192 // as much of the IPv6 offending (invoking) packet (the 1193 // packet that caused the error) as possible without making 1194 // the error message packet exceed the minimum IPv6 MTU 1195 // [IPv6]. 1196 mtu := int(route.MTU()) 1197 const maxIPv6Data = header.IPv6MinimumMTU - header.IPv6FixedHeaderSize 1198 if mtu > maxIPv6Data { 1199 mtu = maxIPv6Data 1200 } 1201 available := mtu - header.ICMPv6ErrorHeaderSize 1202 if available < header.IPv6MinimumSize { 1203 return nil 1204 } 1205 payloadLen := network.Size() + transport.Size() + pkt.Data().Size() 1206 if payloadLen > available { 1207 payloadLen = available 1208 } 1209 payload := network.ToVectorisedView() 1210 payload.AppendView(transport) 1211 payload.Append(pkt.Data().ExtractVV()) 1212 payload.CapLength(payloadLen) 1213 1214 newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 1215 ReserveHeaderBytes: int(route.MaxHeaderLength()) + header.ICMPv6ErrorHeaderSize, 1216 Data: payload, 1217 }) 1218 defer newPkt.DecRef() 1219 newPkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber 1220 1221 icmpHdr := header.ICMPv6(newPkt.TransportHeader().Push(header.ICMPv6DstUnreachableMinimumSize)) 1222 icmpHdr.SetType(icmpType) 1223 icmpHdr.SetCode(icmpCode) 1224 icmpHdr.SetTypeSpecific(typeSpecific) 1225 1226 dataRange := newPkt.Data().AsRange() 1227 icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ 1228 Header: icmpHdr, 1229 Src: route.LocalAddress(), 1230 Dst: route.RemoteAddress(), 1231 PayloadCsum: dataRange.Checksum(), 1232 PayloadLen: dataRange.Size(), 1233 })) 1234 if err := route.WritePacket( 1235 stack.NetworkHeaderParams{ 1236 Protocol: header.ICMPv6ProtocolNumber, 1237 TTL: route.DefaultTTL(), 1238 TOS: stack.DefaultTOS, 1239 }, 1240 newPkt, 1241 ); err != nil { 1242 sent.dropped.Increment() 1243 return err 1244 } 1245 counter.Increment() 1246 return nil 1247 } 1248 1249 // OnReassemblyTimeout implements fragmentation.TimeoutHandler. 1250 func (p *protocol) OnReassemblyTimeout(pkt *stack.PacketBuffer) { 1251 // OnReassemblyTimeout sends a Time Exceeded Message as per RFC 2460 Section 1252 // 4.5: 1253 // 1254 // If the first fragment (i.e., the one with a Fragment Offset of zero) has 1255 // been received, an ICMP Time Exceeded -- Fragment Reassembly Time Exceeded 1256 // message should be sent to the source of that fragment. 1257 if pkt != nil { 1258 p.returnError(&icmpReasonReassemblyTimeout{}, pkt) 1259 } 1260 }