summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/network/ipv6
diff options
context:
space:
mode:
authorNick Brown <nickbrow@google.com>2021-05-19 12:09:54 -0700
committergVisor bot <gvisor-bot@google.com>2021-05-19 12:13:09 -0700
commitb8b43f70c898861a6fd642ded069dd33d35f17f9 (patch)
treecc78171174e81454a2d761cec23f0812f95d56ee /pkg/tcpip/network/ipv6
parent2f3eda37a4dd64f1202fac1c69ab819fb0bd7a5e (diff)
Send ICMP errors when link address resolution fails
Before this change, we would silently drop packets when link resolution failed. This change brings us into line with RFC 792 (IPv4) and RFC 4443 (IPv6), both of which specify that gateways should return an ICMP error to the sender when link resolution fails. PiperOrigin-RevId: 374699789
Diffstat (limited to 'pkg/tcpip/network/ipv6')
-rw-r--r--pkg/tcpip/network/ipv6/icmp.go31
-rw-r--r--pkg/tcpip/network/ipv6/ipv6.go10
2 files changed, 40 insertions, 1 deletions
diff --git a/pkg/tcpip/network/ipv6/icmp.go b/pkg/tcpip/network/ipv6/icmp.go
index 307e1972d..23fc94303 100644
--- a/pkg/tcpip/network/ipv6/icmp.go
+++ b/pkg/tcpip/network/ipv6/icmp.go
@@ -1029,6 +1029,26 @@ func (*icmpReasonNetUnreachable) respondsToMulticast() bool {
return false
}
+// icmpReasonHostUnreachable is an error in which the host specified in the
+// internet destination field of the datagram is unreachable.
+type icmpReasonHostUnreachable struct{}
+
+func (*icmpReasonHostUnreachable) isICMPReason() {}
+func (*icmpReasonHostUnreachable) isForwarding() bool {
+ // If we hit a Host Unreachable error, then we know we are operating as a
+ // router. As per RFC 4443 page 8, Destination Unreachable Message,
+ //
+ // If the reason for the failure to deliver cannot be mapped to any of
+ // other codes, the Code field is set to 3. Example of such cases are
+ // an inability to resolve the IPv6 destination address into a
+ // corresponding link address, or a link-specific problem of some sort.
+ return true
+}
+
+func (*icmpReasonHostUnreachable) respondsToMulticast() bool {
+ return false
+}
+
// icmpReasonFragmentationNeeded is an error where a packet is to big to be sent
// out through the outgoing MTU, as per RFC 4443 page 9, Packet Too Big Message.
type icmpReasonPacketTooBig struct{}
@@ -1143,7 +1163,12 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip
defer route.Release()
p.mu.Lock()
- netEP, ok := p.mu.eps[pkt.NICID]
+ // We retrieve an endpoint using the newly constructed route's NICID rather
+ // than the packet's NICID. The packet's NICID corresponds to the NIC on
+ // which it arrived, which isn't necessarily the same as the NIC on which it
+ // will be transmitted. On the other hand, the route's NIC *is* guaranteed
+ // to be the NIC on which the packet will be transmitted.
+ netEP, ok := p.mu.eps[route.NICID()]
p.mu.Unlock()
if !ok {
return &tcpip.ErrNotConnected{}
@@ -1222,6 +1247,10 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip
icmpHdr.SetType(header.ICMPv6DstUnreachable)
icmpHdr.SetCode(header.ICMPv6NetworkUnreachable)
counter = sent.dstUnreachable
+ case *icmpReasonHostUnreachable:
+ icmpHdr.SetType(header.ICMPv6DstUnreachable)
+ icmpHdr.SetCode(header.ICMPv6AddressUnreachable)
+ counter = sent.dstUnreachable
case *icmpReasonPacketTooBig:
icmpHdr.SetType(header.ICMPv6PacketTooBig)
icmpHdr.SetCode(header.ICMPv6UnusedCode)
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go
index 95e11ac51..68f8308f2 100644
--- a/pkg/tcpip/network/ipv6/ipv6.go
+++ b/pkg/tcpip/network/ipv6/ipv6.go
@@ -282,6 +282,16 @@ func (*endpoint) DuplicateAddressProtocol() tcpip.NetworkProtocolNumber {
// HandleLinkResolutionFailure implements stack.LinkResolvableNetworkEndpoint.
func (e *endpoint) HandleLinkResolutionFailure(pkt *stack.PacketBuffer) {
+ // If we are operating as a router, we should return an ICMP error to the
+ // original packet's sender.
+ if pkt.NetworkPacketInfo.IsForwardedPacket {
+ // TODO(gvisor.dev/issue/6005): Propagate asynchronously generated ICMP
+ // errors to local endpoints.
+ e.protocol.returnError(&icmpReasonHostUnreachable{}, pkt)
+ e.stats.ip.Forwarding.Errors.Increment()
+ e.stats.ip.Forwarding.HostUnreachable.Increment()
+ return
+ }
// handleControl expects the entire offending packet to be in the packet
// buffer's data field.
pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{