summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/tcpip/network/ipv6/icmp.go29
-rw-r--r--pkg/tcpip/network/ipv6/ipv6.go70
2 files changed, 67 insertions, 32 deletions
diff --git a/pkg/tcpip/network/ipv6/icmp.go b/pkg/tcpip/network/ipv6/icmp.go
index 2690644d6..5f44ab317 100644
--- a/pkg/tcpip/network/ipv6/icmp.go
+++ b/pkg/tcpip/network/ipv6/icmp.go
@@ -260,12 +260,31 @@ func getTargetLinkAddr(it header.NDPOptionIterator) (tcpip.LinkAddress, bool) {
})
}
-func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool) {
+func isMLDValid(pkt *stack.PacketBuffer, iph header.IPv6, routerAlert *header.IPv6RouterAlertOption) bool {
+ // As per RFC 2710 section 3:
+ // All MLD messages described in this document are sent with a link-local
+ // IPv6 Source Address, an IPv6 Hop Limit of 1, and an IPv6 Router Alert
+ // option in a Hop-by-Hop Options header.
+ if routerAlert == nil || routerAlert.Value != header.IPv6RouterAlertMLD {
+ return false
+ }
+ if pkt.Data.Size() < header.ICMPv6HeaderSize+header.MLDMinimumSize {
+ return false
+ }
+ if iph.HopLimit() != header.MLDHopLimit {
+ return false
+ }
+ if !header.IsV6LinkLocalAddress(iph.SourceAddress()) {
+ return false
+ }
+ return true
+}
+
+func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, routerAlert *header.IPv6RouterAlertOption) {
sent := e.stats.icmp.packetsSent
received := e.stats.icmp.packetsReceived
- // TODO(gvisor.dev/issue/170): ICMP packets don't have their
- // TransportHeader fields set. See icmp/protocol.go:protocol.Parse for a
- // full explanation.
+ // TODO(gvisor.dev/issue/170): ICMP packets don't have their TransportHeader
+ // fields set. See icmp/protocol.go:protocol.Parse for a full explanation.
v, ok := pkt.Data.PullUp(header.ICMPv6HeaderSize)
if !ok {
received.invalid.Increment()
@@ -823,7 +842,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool) {
panic(fmt.Sprintf("unrecognized MLD message = %d", icmpType))
}
- if pkt.Data.Size()-header.ICMPv6HeaderSize < header.MLDMinimumSize {
+ if !isMLDValid(pkt, iph, routerAlert) {
received.invalid.Increment()
return
}
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go
index b16a2d322..7638ade35 100644
--- a/pkg/tcpip/network/ipv6/ipv6.go
+++ b/pkg/tcpip/network/ipv6/ipv6.go
@@ -1001,7 +1001,6 @@ func (e *endpoint) handlePacket(pkt *stack.PacketBuffer) {
vv.AppendView(pkt.TransportHeader().View())
vv.Append(pkt.Data)
it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(h.NextHeader()), vv)
- hasFragmentHeader := false
// iptables filtering. All packets that reach here are intended for
// this machine and need not be forwarded.
@@ -1012,6 +1011,11 @@ func (e *endpoint) handlePacket(pkt *stack.PacketBuffer) {
return
}
+ var (
+ hasFragmentHeader bool
+ routerAlert *header.IPv6RouterAlertOption
+ )
+
for {
// Keep track of the start of the previous header so we can report the
// special case of a Hop by Hop at a location other than at the start.
@@ -1049,34 +1053,46 @@ func (e *endpoint) handlePacket(pkt *stack.PacketBuffer) {
break
}
- // We currently do not support any IPv6 Hop By Hop extension header
- // options.
- switch opt.UnknownAction() {
- case header.IPv6OptionUnknownActionSkip:
- case header.IPv6OptionUnknownActionDiscard:
- return
- case header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest:
- if header.IsV6MulticastAddress(dstAddr) {
+ switch opt := opt.(type) {
+ case *header.IPv6RouterAlertOption:
+ if routerAlert != nil {
+ // As per RFC 2711 section 3, there should be at most one Router
+ // Alert option per packet.
+ //
+ // There MUST only be one option of this type, regardless of
+ // value, per Hop-by-Hop header.
+ stats.MalformedPacketsReceived.Increment()
return
}
- fallthrough
- case header.IPv6OptionUnknownActionDiscardSendICMP:
- // This case satisfies a requirement of RFC 8200 section 4.2
- // which states that an unknown option starting with bits [10] should:
- //
- // discard the packet and, regardless of whether or not the
- // packet's Destination Address was a multicast address, send an
- // ICMP Parameter Problem, Code 2, message to the packet's
- // Source Address, pointing to the unrecognized Option Type.
- //
- _ = e.protocol.returnError(&icmpReasonParameterProblem{
- code: header.ICMPv6UnknownOption,
- pointer: it.ParseOffset() + optsIt.OptionOffset(),
- respondToMulticast: true,
- }, pkt)
- return
+ routerAlert = opt
+ stats.OptionRouterAlertReceived.Increment()
default:
- panic(fmt.Sprintf("unrecognized action for an unrecognized Hop By Hop extension header option = %d", opt))
+ switch opt.UnknownAction() {
+ case header.IPv6OptionUnknownActionSkip:
+ case header.IPv6OptionUnknownActionDiscard:
+ return
+ case header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest:
+ if header.IsV6MulticastAddress(dstAddr) {
+ return
+ }
+ fallthrough
+ case header.IPv6OptionUnknownActionDiscardSendICMP:
+ // This case satisfies a requirement of RFC 8200 section 4.2 which
+ // states that an unknown option starting with bits [10] should:
+ //
+ // discard the packet and, regardless of whether or not the
+ // packet's Destination Address was a multicast address, send an
+ // ICMP Parameter Problem, Code 2, message to the packet's
+ // Source Address, pointing to the unrecognized Option Type.
+ _ = e.protocol.returnError(&icmpReasonParameterProblem{
+ code: header.ICMPv6UnknownOption,
+ pointer: it.ParseOffset() + optsIt.OptionOffset(),
+ respondToMulticast: true,
+ }, pkt)
+ return
+ default:
+ panic(fmt.Sprintf("unrecognized action for an unrecognized Hop By Hop extension header option = %d", opt))
+ }
}
}
@@ -1303,7 +1319,7 @@ func (e *endpoint) handlePacket(pkt *stack.PacketBuffer) {
stats.PacketsDelivered.Increment()
if p := tcpip.TransportProtocolNumber(extHdr.Identifier); p == header.ICMPv6ProtocolNumber {
pkt.TransportProtocolNumber = p
- e.handleICMP(pkt, hasFragmentHeader)
+ e.handleICMP(pkt, hasFragmentHeader, routerAlert)
} else {
stats.PacketsDelivered.Increment()
switch res := e.dispatcher.DeliverTransportPacket(p, pkt); res {