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