summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/network/ipv4/icmp.go
diff options
context:
space:
mode:
authorJulian Elischer <jrelis@google.com>2021-02-09 01:00:40 -0800
committergVisor bot <gvisor-bot@google.com>2021-02-09 01:02:43 -0800
commit3f802e7180cfe703ecb97d8f2b6ba32257cf6216 (patch)
treeda741ecec72e36a68b4e4868dbcb5b68a1ac3d5f /pkg/tcpip/network/ipv4/icmp.go
parent6671a42d605d681e6aa63b610617523ab632e95a (diff)
add IPv4 options processing for forwarding and reassembly
IPv4 forwarding and reassembly needs support for option processing and regular processing also needs options to be processed before being passed to the transport layer. This patch extends option processing to those cases and provides additional testing. A small change to the ICMP error generation API code was required to allow it to know when a packet was being forwarded or not. Updates #4586 PiperOrigin-RevId: 356446681
Diffstat (limited to 'pkg/tcpip/network/ipv4/icmp.go')
-rw-r--r--pkg/tcpip/network/ipv4/icmp.go53
1 files changed, 36 insertions, 17 deletions
diff --git a/pkg/tcpip/network/ipv4/icmp.go b/pkg/tcpip/network/ipv4/icmp.go
index 2b7bc0dd0..b44304cee 100644
--- a/pkg/tcpip/network/ipv4/icmp.go
+++ b/pkg/tcpip/network/ipv4/icmp.go
@@ -213,7 +213,8 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
} else {
op = &optionUsageReceive{}
}
- tmp, optProblem := e.processIPOptions(pkt, opts, op)
+ var optProblem *header.IPv4OptParameterProblem
+ newOptions, optProblem = e.processIPOptions(pkt, opts, op)
if optProblem != nil {
if optProblem.NeedICMP {
_ = e.protocol.returnError(&icmpReasonParamProblem{
@@ -224,7 +225,14 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
}
return
}
- newOptions = tmp
+ copied := copy(opts, newOptions)
+ if copied != len(newOptions) {
+ panic(fmt.Sprintf("copied %d bytes of new options, expected %d bytes", copied, len(newOptions)))
+ }
+ for i := copied; i < len(opts); i++ {
+ // Pad with 0 (EOL). RFC 791 page 23 says "The padding is zero".
+ opts[i] = byte(header.IPv4OptionListEndType)
+ }
}
// TODO(b/112892170): Meaningfully handle all ICMP types.
@@ -375,6 +383,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
// icmpReason is a marker interface for IPv4 specific ICMP errors.
type icmpReason interface {
isICMPReason()
+ isForwarding() bool
}
// icmpReasonPortUnreachable is an error where the transport protocol has no
@@ -382,12 +391,18 @@ type icmpReason interface {
type icmpReasonPortUnreachable struct{}
func (*icmpReasonPortUnreachable) isICMPReason() {}
+func (*icmpReasonPortUnreachable) isForwarding() bool {
+ return false
+}
// icmpReasonProtoUnreachable is an error where the transport protocol is
// not supported.
type icmpReasonProtoUnreachable struct{}
func (*icmpReasonProtoUnreachable) isICMPReason() {}
+func (*icmpReasonProtoUnreachable) isForwarding() bool {
+ return false
+}
// icmpReasonTTLExceeded is an error where a packet's time to live exceeded in
// transit to its final destination, as per RFC 792 page 6, Time Exceeded
@@ -395,6 +410,15 @@ func (*icmpReasonProtoUnreachable) isICMPReason() {}
type icmpReasonTTLExceeded struct{}
func (*icmpReasonTTLExceeded) isICMPReason() {}
+func (*icmpReasonTTLExceeded) isForwarding() bool {
+ // If we hit a TTL Exceeded error, then we know we are operating as a router.
+ // As per RFC 792 page 6, Time Exceeded Message,
+ //
+ // If the gateway processing a datagram finds the time to live field
+ // is zero it must discard the datagram. The gateway may also notify
+ // the source host via the time exceeded message.
+ return true
+}
// icmpReasonReassemblyTimeout is an error where insufficient fragments are
// received to complete reassembly of a packet within a configured time after
@@ -402,14 +426,21 @@ func (*icmpReasonTTLExceeded) isICMPReason() {}
type icmpReasonReassemblyTimeout struct{}
func (*icmpReasonReassemblyTimeout) isICMPReason() {}
+func (*icmpReasonReassemblyTimeout) isForwarding() bool {
+ return false
+}
// icmpReasonParamProblem is an error to use to request a Parameter Problem
// message to be sent.
type icmpReasonParamProblem struct {
- pointer byte
+ pointer byte
+ forwarding bool
}
func (*icmpReasonParamProblem) isICMPReason() {}
+func (r *icmpReasonParamProblem) isForwarding() bool {
+ return r.forwarding
+}
// returnError takes an error descriptor and generates the appropriate ICMP
// error packet for IPv4 and sends it back to the remote device that sent
@@ -448,26 +479,14 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer) tcpip
return nil
}
- // If we hit a TTL Exceeded error, then we know we are operating as a router.
- // As per RFC 792 page 6, Time Exceeded Message,
- //
- // If the gateway processing a datagram finds the time to live field
- // is zero it must discard the datagram. The gateway may also notify
- // the source host via the time exceeded message.
- //
- // ...
- //
- // Code 0 may be received from a gateway. ...
- //
- // Note, Code 0 is the TTL exceeded error.
- //
// If we are operating as a router/gateway, don't use the packet's destination
// address as the response's source address as we should not not own the
// destination address of a packet we are forwarding.
localAddr := origIPHdrDst
- if _, ok := reason.(*icmpReasonTTLExceeded); ok {
+ if reason.isForwarding() {
localAddr = ""
}
+
// Even if we were able to receive a packet from some remote, we may not have
// a route to it - the remote may be blocked via routing rules. We must always
// consult our routing table and find a route to the remote before sending any