Automated rollback of changelist 308163542

PiperOrigin-RevId: 308674219
This commit is contained in:
gVisor bot
2020-04-27 12:26:32 -07:00
parent 292f3f99b7
commit 55f0c3316a
28 changed files with 149 additions and 458 deletions
+2 -3
View File
@@ -121,13 +121,12 @@ func (tm *TCPMatcher) Match(hook stack.Hook, pkt stack.PacketBuffer, interfaceNa
tcpHeader = header.TCP(pkt.TransportHeader)
} else {
// The TCP header hasn't been parsed yet. We have to do it here.
hdr, ok := pkt.Data.PullUp(header.TCPMinimumSize)
if !ok {
if len(pkt.Data.First()) < header.TCPMinimumSize {
// There's no valid TCP header here, so we hotdrop the
// packet.
return false, true
}
tcpHeader = header.TCP(hdr)
tcpHeader = header.TCP(pkt.Data.First())
}
// Check whether the source and destination ports are within the
+2 -3
View File
@@ -120,13 +120,12 @@ func (um *UDPMatcher) Match(hook stack.Hook, pkt stack.PacketBuffer, interfaceNa
udpHeader = header.UDP(pkt.TransportHeader)
} else {
// The UDP header hasn't been parsed yet. We have to do it here.
hdr, ok := pkt.Data.PullUp(header.UDPMinimumSize)
if !ok {
if len(pkt.Data.First()) < header.UDPMinimumSize {
// There's no valid UDP header here, so we hotdrop the
// packet.
return false, true
}
udpHeader = header.UDP(hdr)
udpHeader = header.UDP(pkt.Data.First())
}
// Check whether the source and destination ports are within the
+16 -39
View File
@@ -77,8 +77,7 @@ func NewVectorisedView(size int, views []View) VectorisedView {
return VectorisedView{views: views, size: size}
}
// TrimFront removes the first "count" bytes of the vectorised view. It panics
// if count > vv.Size().
// TrimFront removes the first "count" bytes of the vectorised view.
func (vv *VectorisedView) TrimFront(count int) {
for count > 0 && len(vv.views) > 0 {
if count < len(vv.views[0]) {
@@ -87,7 +86,7 @@ func (vv *VectorisedView) TrimFront(count int) {
return
}
count -= len(vv.views[0])
vv.removeFirst()
vv.RemoveFirst()
}
}
@@ -105,7 +104,7 @@ func (vv *VectorisedView) Read(v View) (copied int, err error) {
count -= len(vv.views[0])
copy(v[copied:], vv.views[0])
copied += len(vv.views[0])
vv.removeFirst()
vv.RemoveFirst()
}
if copied == 0 {
return 0, io.EOF
@@ -127,7 +126,7 @@ func (vv *VectorisedView) ReadToVV(dstVV *VectorisedView, count int) (copied int
count -= len(vv.views[0])
dstVV.AppendView(vv.views[0])
copied += len(vv.views[0])
vv.removeFirst()
vv.RemoveFirst()
}
return copied
}
@@ -163,37 +162,22 @@ func (vv *VectorisedView) Clone(buffer []View) VectorisedView {
return VectorisedView{views: append(buffer[:0], vv.views...), size: vv.size}
}
// PullUp returns the first "count" bytes of the vectorised view. If those
// bytes aren't already contiguous inside the vectorised view, PullUp will
// reallocate as needed to make them contiguous. PullUp fails and returns false
// when count > vv.Size().
func (vv *VectorisedView) PullUp(count int) (View, bool) {
// First returns the first view of the vectorised view.
func (vv *VectorisedView) First() View {
if len(vv.views) == 0 {
return nil, count == 0
}
if count <= len(vv.views[0]) {
return vv.views[0][:count], true
}
if count > vv.size {
return nil, false
return nil
}
return vv.views[0]
}
newFirst := NewView(count)
i := 0
for offset := 0; offset < count; i++ {
copy(newFirst[offset:], vv.views[i])
if count-offset < len(vv.views[i]) {
vv.views[i].TrimFront(count - offset)
break
}
offset += len(vv.views[i])
vv.views[i] = nil
// RemoveFirst removes the first view of the vectorised view.
func (vv *VectorisedView) RemoveFirst() {
if len(vv.views) == 0 {
return
}
// We're guaranteed that i > 0, since count is too large for the first
// view.
vv.views[i-1] = newFirst
vv.views = vv.views[i-1:]
return newFirst, true
vv.size -= len(vv.views[0])
vv.views[0] = nil
vv.views = vv.views[1:]
}
// Size returns the size in bytes of the entire content stored in the vectorised view.
@@ -241,10 +225,3 @@ func (vv *VectorisedView) Readers() []bytes.Reader {
}
return readers
}
// removeFirst panics when len(vv.views) < 1.
func (vv *VectorisedView) removeFirst() {
vv.size -= len(vv.views[0])
vv.views[0] = nil
vv.views = vv.views[1:]
}
-113
View File
@@ -16,7 +16,6 @@
package buffer
import (
"bytes"
"reflect"
"testing"
)
@@ -371,115 +370,3 @@ func TestVVRead(t *testing.T) {
})
}
}
var pullUpTestCases = []struct {
comment string
in VectorisedView
count int
want []byte
result VectorisedView
ok bool
}{
{
comment: "simple case",
in: vv(2, "12"),
count: 1,
want: []byte("1"),
result: vv(2, "12"),
ok: true,
},
{
comment: "entire View",
in: vv(2, "1", "2"),
count: 1,
want: []byte("1"),
result: vv(2, "1", "2"),
ok: true,
},
{
comment: "spanning across two Views",
in: vv(3, "1", "23"),
count: 2,
want: []byte("12"),
result: vv(3, "12", "3"),
ok: true,
},
{
comment: "spanning across all Views",
in: vv(5, "1", "23", "45"),
count: 5,
want: []byte("12345"),
result: vv(5, "12345"),
ok: true,
},
{
comment: "count = 0",
in: vv(1, "1"),
count: 0,
want: []byte{},
result: vv(1, "1"),
ok: true,
},
{
comment: "count = size",
in: vv(1, "1"),
count: 1,
want: []byte("1"),
result: vv(1, "1"),
ok: true,
},
{
comment: "count too large",
in: vv(3, "1", "23"),
count: 4,
want: nil,
result: vv(3, "1", "23"),
ok: false,
},
{
comment: "empty vv",
in: vv(0, ""),
count: 1,
want: nil,
result: vv(0, ""),
ok: false,
},
{
comment: "empty vv, count = 0",
in: vv(0, ""),
count: 0,
want: nil,
result: vv(0, ""),
ok: true,
},
{
comment: "empty views",
in: vv(3, "", "1", "", "23"),
count: 2,
want: []byte("12"),
result: vv(3, "12", "3"),
ok: true,
},
}
func TestPullUp(t *testing.T) {
for _, c := range pullUpTestCases {
got, ok := c.in.PullUp(c.count)
// Is the return value right?
if ok != c.ok {
t.Errorf("Test %q failed when calling PullUp(%d) on %v. Got an ok of %t. Want %t",
c.comment, c.count, c.in, ok, c.ok)
}
if bytes.Compare(got, View(c.want)) != 0 {
t.Errorf("Test %q failed when calling PullUp(%d) on %v. Got %v. Want %v",
c.comment, c.count, c.in, got, c.want)
}
// Is the underlying structure right?
if !reflect.DeepEqual(c.in, c.result) {
t.Errorf("Test %q failed when calling PullUp(%d). Got vv with structure %v. Wanted %v",
c.comment, c.count, c.in, c.result)
}
}
}
+5 -5
View File
@@ -98,13 +98,13 @@ func (e *endpoint) WritePackets(*stack.Route, *stack.GSO, stack.PacketBufferList
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
// There should be an ethernet header at the beginning of vv.
hdr, ok := vv.PullUp(header.EthernetMinimumSize)
if !ok {
// Reject the packet if it's shorter than an ethernet header.
// Reject the packet if it's shorter than an ethernet header.
if vv.Size() < header.EthernetMinimumSize {
return tcpip.ErrBadAddress
}
linkHeader := header.Ethernet(hdr)
// There should be an ethernet header at the beginning of vv.
linkHeader := header.Ethernet(vv.First()[:header.EthernetMinimumSize])
vv.TrimFront(len(linkHeader))
e.dispatcher.DeliverNetworkPacket(e, "" /* remote */, "" /* local */, linkHeader.Type(), stack.PacketBuffer{
Data: vv,
+1 -8
View File
@@ -1,4 +1,4 @@
load("//tools:defs.bzl", "go_library", "go_test")
load("//tools:defs.bzl", "go_library")
package(licenses = ["notice"])
@@ -18,10 +18,3 @@ go_library(
"@org_golang_x_sys//unix:go_default_library",
],
)
go_test(
name = "rawfile_test",
size = "small",
srcs = ["rawfile_test.go"],
library = ":rawfile",
)
-46
View File
@@ -1,46 +0,0 @@
// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux
package rawfile
import (
"syscall"
"testing"
)
func TestNonBlockingWrite3ZeroLength(t *testing.T) {
fd, err := syscall.Open("/dev/null", syscall.O_WRONLY, 0)
if err != nil {
t.Fatalf("failed to open /dev/null: %v", err)
}
defer syscall.Close(fd)
if err := NonBlockingWrite3(fd, []byte{}, []byte{0}, nil); err != nil {
t.Fatalf("failed to write: %v", err)
}
}
func TestNonBlockingWrite3Nil(t *testing.T) {
fd, err := syscall.Open("/dev/null", syscall.O_WRONLY, 0)
if err != nil {
t.Fatalf("failed to open /dev/null: %v", err)
}
defer syscall.Close(fd)
if err := NonBlockingWrite3(fd, nil, []byte{0}, nil); err != nil {
t.Fatalf("failed to write: %v", err)
}
}
+1 -5
View File
@@ -76,13 +76,9 @@ func NonBlockingWrite3(fd int, b1, b2, b3 []byte) *tcpip.Error {
// We have two buffers. Build the iovec that represents them and issue
// a writev syscall.
var base *byte
if len(b1) > 0 {
base = &b1[0]
}
iovec := [3]syscall.Iovec{
{
Base: base,
Base: &b1[0],
Len: uint64(len(b1)),
},
{
+1 -1
View File
@@ -674,7 +674,7 @@ func TestSimpleReceive(t *testing.T) {
// Wait for packet to be received, then check it.
c.waitForPackets(1, time.After(5*time.Second), "Timeout waiting for packet")
c.mu.Lock()
rcvd := []byte(c.packets[0].vv.ToView())
rcvd := []byte(c.packets[0].vv.First())
c.packets = c.packets[:0]
c.mu.Unlock()
+16 -49
View File
@@ -171,7 +171,11 @@ func (e *endpoint) GSOMaxSize() uint32 {
func (e *endpoint) dumpPacket(prefix string, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
writer := e.writer
if writer == nil && atomic.LoadUint32(&LogPackets) == 1 {
logPacket(prefix, protocol, pkt, gso)
first := pkt.Header.View()
if len(first) == 0 {
first = pkt.Data.First()
}
logPacket(prefix, protocol, first, gso)
}
if writer != nil && atomic.LoadUint32(&LogPacketsToPCAP) == 1 {
totalLength := pkt.Header.UsedLength() + pkt.Data.Size()
@@ -234,7 +238,7 @@ func (e *endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
// Wait implements stack.LinkEndpoint.Wait.
func (e *endpoint) Wait() { e.lower.Wait() }
func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer, gso *stack.GSO) {
func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.View, gso *stack.GSO) {
// Figure out the network layer info.
var transProto uint8
src := tcpip.Address("unknown")
@@ -243,49 +247,28 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
size := uint16(0)
var fragmentOffset uint16
var moreFragments bool
// Create a clone of pkt, including any headers if present. Avoid allocating
// backing memory for the clone.
views := [8]buffer.View{}
vv := buffer.NewVectorisedView(0, views[:0])
vv.AppendView(pkt.Header.View())
vv.Append(pkt.Data)
switch protocol {
case header.IPv4ProtocolNumber:
hdr, ok := vv.PullUp(header.IPv4MinimumSize)
if !ok {
return
}
ipv4 := header.IPv4(hdr)
ipv4 := header.IPv4(b)
fragmentOffset = ipv4.FragmentOffset()
moreFragments = ipv4.Flags()&header.IPv4FlagMoreFragments == header.IPv4FlagMoreFragments
src = ipv4.SourceAddress()
dst = ipv4.DestinationAddress()
transProto = ipv4.Protocol()
size = ipv4.TotalLength() - uint16(ipv4.HeaderLength())
vv.TrimFront(int(ipv4.HeaderLength()))
b = b[ipv4.HeaderLength():]
id = int(ipv4.ID())
case header.IPv6ProtocolNumber:
hdr, ok := vv.PullUp(header.IPv6MinimumSize)
if !ok {
return
}
ipv6 := header.IPv6(hdr)
ipv6 := header.IPv6(b)
src = ipv6.SourceAddress()
dst = ipv6.DestinationAddress()
transProto = ipv6.NextHeader()
size = ipv6.PayloadLength()
vv.TrimFront(header.IPv6MinimumSize)
b = b[header.IPv6MinimumSize:]
case header.ARPProtocolNumber:
hdr, ok := vv.PullUp(header.ARPSize)
if !ok {
return
}
vv.TrimFront(header.ARPSize)
arp := header.ARP(hdr)
arp := header.ARP(b)
log.Infof(
"%s arp %v (%v) -> %v (%v) valid:%v",
prefix,
@@ -301,7 +284,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
// We aren't guaranteed to have a transport header - it's possible for
// writes via raw endpoints to contain only network headers.
if minSize, ok := transportProtocolMinSizes[tcpip.TransportProtocolNumber(transProto)]; ok && vv.Size() < minSize {
if minSize, ok := transportProtocolMinSizes[tcpip.TransportProtocolNumber(transProto)]; ok && len(b) < minSize {
log.Infof("%s %v -> %v transport protocol: %d, but no transport header found (possible raw packet)", prefix, src, dst, transProto)
return
}
@@ -314,11 +297,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
switch tcpip.TransportProtocolNumber(transProto) {
case header.ICMPv4ProtocolNumber:
transName = "icmp"
hdr, ok := vv.PullUp(header.ICMPv4MinimumSize)
if !ok {
break
}
icmp := header.ICMPv4(hdr)
icmp := header.ICMPv4(b)
icmpType := "unknown"
if fragmentOffset == 0 {
switch icmp.Type() {
@@ -351,11 +330,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
case header.ICMPv6ProtocolNumber:
transName = "icmp"
hdr, ok := vv.PullUp(header.ICMPv6MinimumSize)
if !ok {
break
}
icmp := header.ICMPv6(hdr)
icmp := header.ICMPv6(b)
icmpType := "unknown"
switch icmp.Type() {
case header.ICMPv6DstUnreachable:
@@ -386,11 +361,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
case header.UDPProtocolNumber:
transName = "udp"
hdr, ok := vv.PullUp(header.UDPMinimumSize)
if !ok {
break
}
udp := header.UDP(hdr)
udp := header.UDP(b)
if fragmentOffset == 0 && len(udp) >= header.UDPMinimumSize {
srcPort = udp.SourcePort()
dstPort = udp.DestinationPort()
@@ -400,11 +371,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
case header.TCPProtocolNumber:
transName = "tcp"
hdr, ok := vv.PullUp(header.TCPMinimumSize)
if !ok {
break
}
tcp := header.TCP(hdr)
tcp := header.TCP(b)
if fragmentOffset == 0 && len(tcp) >= header.TCPMinimumSize {
offset := int(tcp.DataOffset())
if offset < header.TCPMinimumSize {
+1 -4
View File
@@ -93,10 +93,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt stack.PacketBuf
}
func (e *endpoint) HandlePacket(r *stack.Route, pkt stack.PacketBuffer) {
v, ok := pkt.Data.PullUp(header.ARPSize)
if !ok {
return
}
v := pkt.Data.First()
h := header.ARP(v)
if !h.IsValid() {
return
+8 -12
View File
@@ -25,11 +25,7 @@ import (
// used to find out which transport endpoint must be notified about the ICMP
// packet.
func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt stack.PacketBuffer) {
h, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
if !ok {
return
}
hdr := header.IPv4(h)
h := header.IPv4(pkt.Data.First())
// We don't use IsValid() here because ICMP only requires that the IP
// header plus 8 bytes of the transport header be included. So it's
@@ -38,12 +34,12 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt stack.
//
// Drop packet if it doesn't have the basic IPv4 header or if the
// original source address doesn't match the endpoint's address.
if hdr.SourceAddress() != e.id.LocalAddress {
if len(h) < header.IPv4MinimumSize || h.SourceAddress() != e.id.LocalAddress {
return
}
hlen := int(hdr.HeaderLength())
if pkt.Data.Size() < hlen || hdr.FragmentOffset() != 0 {
hlen := int(h.HeaderLength())
if pkt.Data.Size() < hlen || h.FragmentOffset() != 0 {
// We won't be able to handle this if it doesn't contain the
// full IPv4 header, or if it's a fragment not at offset 0
// (because it won't have the transport header).
@@ -52,15 +48,15 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt stack.
// Skip the ip header, then deliver control message.
pkt.Data.TrimFront(hlen)
p := hdr.TransportProtocol()
e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, hdr.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
p := h.TransportProtocol()
e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, h.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
}
func (e *endpoint) handleICMP(r *stack.Route, pkt stack.PacketBuffer) {
stats := r.Stats()
received := stats.ICMP.V4PacketsReceived
v, ok := pkt.Data.PullUp(header.ICMPv4MinimumSize)
if !ok {
v := pkt.Data.First()
if len(v) < header.ICMPv4MinimumSize {
received.Invalid.Increment()
return
}
+2 -10
View File
@@ -328,11 +328,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt stack.PacketBuffer) *tcpip.Error {
// The packet already has an IP header, but there are a few required
// checks.
h, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
if !ok {
return tcpip.ErrInvalidOptionValue
}
ip := header.IPv4(h)
ip := header.IPv4(pkt.Data.First())
if !ip.IsValid(pkt.Data.Size()) {
return tcpip.ErrInvalidOptionValue
}
@@ -382,11 +378,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt stack.PacketBuf
// HandlePacket is called by the link layer when new ipv4 packets arrive for
// this endpoint.
func (e *endpoint) HandlePacket(r *stack.Route, pkt stack.PacketBuffer) {
headerView, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
if !ok {
r.Stats().IP.MalformedPacketsReceived.Increment()
return
}
headerView := pkt.Data.First()
h := header.IPv4(headerView)
if !h.IsValid(pkt.Data.Size()) {
r.Stats().IP.MalformedPacketsReceived.Increment()
+26 -48
View File
@@ -28,11 +28,7 @@ import (
// used to find out which transport endpoint must be notified about the ICMP
// packet.
func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt stack.PacketBuffer) {
h, ok := pkt.Data.PullUp(header.IPv6MinimumSize)
if !ok {
return
}
hdr := header.IPv6(h)
h := header.IPv6(pkt.Data.First())
// We don't use IsValid() here because ICMP only requires that up to
// 1280 bytes of the original packet be included. So it's likely that it
@@ -40,21 +36,17 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt stack.
//
// Drop packet if it doesn't have the basic IPv6 header or if the
// original source address doesn't match the endpoint's address.
if hdr.SourceAddress() != e.id.LocalAddress {
if len(h) < header.IPv6MinimumSize || h.SourceAddress() != e.id.LocalAddress {
return
}
// Skip the IP header, then handle the fragmentation header if there
// is one.
pkt.Data.TrimFront(header.IPv6MinimumSize)
p := hdr.TransportProtocol()
p := h.TransportProtocol()
if p == header.IPv6FragmentHeader {
f, ok := pkt.Data.PullUp(header.IPv6FragmentHeaderSize)
if !ok {
return
}
fragHdr := header.IPv6Fragment(f)
if !fragHdr.IsValid() || fragHdr.FragmentOffset() != 0 {
f := header.IPv6Fragment(pkt.Data.First())
if !f.IsValid() || f.FragmentOffset() != 0 {
// We can't handle fragments that aren't at offset 0
// because they don't have the transport headers.
return
@@ -63,19 +55,19 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt stack.
// Skip fragmentation header and find out the actual protocol
// number.
pkt.Data.TrimFront(header.IPv6FragmentHeaderSize)
p = fragHdr.TransportProtocol()
p = f.TransportProtocol()
}
// Deliver the control packet to the transport endpoint.
e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, hdr.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, h.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
}
func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.PacketBuffer, hasFragmentHeader bool) {
stats := r.Stats().ICMP
sent := stats.V6PacketsSent
received := stats.V6PacketsReceived
v, ok := pkt.Data.PullUp(header.ICMPv6HeaderSize)
if !ok {
v := pkt.Data.First()
if len(v) < header.ICMPv6MinimumSize {
received.Invalid.Increment()
return
}
@@ -84,9 +76,11 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.P
// Validate ICMPv6 checksum before processing the packet.
//
// Only the first view in vv is accounted for by h. To account for the
// rest of vv, a shallow copy is made and the first view is removed.
// This copy is used as extra payload during the checksum calculation.
payload := pkt.Data.Clone(nil)
payload.TrimFront(len(h))
payload.RemoveFirst()
if got, want := h.Checksum(), header.ICMPv6Checksum(h, iph.SourceAddress(), iph.DestinationAddress(), payload); got != want {
received.Invalid.Increment()
return
@@ -107,40 +101,34 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.P
switch h.Type() {
case header.ICMPv6PacketTooBig:
received.PacketTooBig.Increment()
hdr, ok := pkt.Data.PullUp(header.ICMPv6PacketTooBigMinimumSize)
if !ok {
if len(v) < header.ICMPv6PacketTooBigMinimumSize {
received.Invalid.Increment()
return
}
pkt.Data.TrimFront(header.ICMPv6PacketTooBigMinimumSize)
mtu := header.ICMPv6(hdr).MTU()
mtu := h.MTU()
e.handleControl(stack.ControlPacketTooBig, calculateMTU(mtu), pkt)
case header.ICMPv6DstUnreachable:
received.DstUnreachable.Increment()
hdr, ok := pkt.Data.PullUp(header.ICMPv6DstUnreachableMinimumSize)
if !ok {
if len(v) < header.ICMPv6DstUnreachableMinimumSize {
received.Invalid.Increment()
return
}
pkt.Data.TrimFront(header.ICMPv6DstUnreachableMinimumSize)
switch header.ICMPv6(hdr).Code() {
switch h.Code() {
case header.ICMPv6PortUnreachable:
e.handleControl(stack.ControlPortUnreachable, 0, pkt)
}
case header.ICMPv6NeighborSolicit:
received.NeighborSolicit.Increment()
if pkt.Data.Size() < header.ICMPv6NeighborSolicitMinimumSize || !isNDPValid() {
if len(v) < header.ICMPv6NeighborSolicitMinimumSize || !isNDPValid() {
received.Invalid.Increment()
return
}
// The remainder of payload must be only the neighbor solicitation, so
// payload.ToView() always returns the solicitation. Per RFC 6980 section 5,
// NDP messages cannot be fragmented. Also note that in the common case NDP
// datagrams are very small and ToView() will not incur allocations.
ns := header.NDPNeighborSolicit(payload.ToView())
ns := header.NDPNeighborSolicit(h.NDPPayload())
it, err := ns.Options().Iter(true)
if err != nil {
// If we have a malformed NDP NS option, drop the packet.
@@ -298,16 +286,12 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.P
case header.ICMPv6NeighborAdvert:
received.NeighborAdvert.Increment()
if pkt.Data.Size() < header.ICMPv6NeighborAdvertSize || !isNDPValid() {
if len(v) < header.ICMPv6NeighborAdvertSize || !isNDPValid() {
received.Invalid.Increment()
return
}
// The remainder of payload must be only the neighbor advertisement, so
// payload.ToView() always returns the advertisement. Per RFC 6980 section
// 5, NDP messages cannot be fragmented. Also note that in the common case
// NDP datagrams are very small and ToView() will not incur allocations.
na := header.NDPNeighborAdvert(payload.ToView())
na := header.NDPNeighborAdvert(h.NDPPayload())
it, err := na.Options().Iter(true)
if err != nil {
// If we have a malformed NDP NA option, drop the packet.
@@ -379,15 +363,14 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.P
case header.ICMPv6EchoRequest:
received.EchoRequest.Increment()
icmpHdr, ok := pkt.Data.PullUp(header.ICMPv6EchoMinimumSize)
if !ok {
if len(v) < header.ICMPv6EchoMinimumSize {
received.Invalid.Increment()
return
}
pkt.Data.TrimFront(header.ICMPv6EchoMinimumSize)
hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.ICMPv6EchoMinimumSize)
packet := header.ICMPv6(hdr.Prepend(header.ICMPv6EchoMinimumSize))
copy(packet, icmpHdr)
copy(packet, h)
packet.SetType(header.ICMPv6EchoReply)
packet.SetChecksum(header.ICMPv6Checksum(packet, r.LocalAddress, r.RemoteAddress, pkt.Data))
if err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: r.DefaultTTL(), TOS: stack.DefaultTOS}, stack.PacketBuffer{
@@ -401,7 +384,7 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.P
case header.ICMPv6EchoReply:
received.EchoReply.Increment()
if pkt.Data.Size() < header.ICMPv6EchoMinimumSize {
if len(v) < header.ICMPv6EchoMinimumSize {
received.Invalid.Increment()
return
}
@@ -423,9 +406,8 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.P
case header.ICMPv6RouterAdvert:
received.RouterAdvert.Increment()
// Is the NDP payload of sufficient size to hold a Router
// Advertisement?
if pkt.Data.Size()-header.ICMPv6HeaderSize < header.NDPRAMinimumSize || !isNDPValid() {
p := h.NDPPayload()
if len(p) < header.NDPRAMinimumSize || !isNDPValid() {
received.Invalid.Increment()
return
}
@@ -443,11 +425,7 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, pkt stack.P
return
}
// The remainder of payload must be only the router advertisement, so
// payload.ToView() always returns the advertisement. Per RFC 6980 section
// 5, NDP messages cannot be fragmented. Also note that in the common case
// NDP datagrams are very small and ToView() will not incur allocations.
ra := header.NDPRouterAdvert(payload.ToView())
ra := header.NDPRouterAdvert(p)
opts := ra.Options()
// Are options valid as per the wire format?
+1 -2
View File
@@ -166,8 +166,7 @@ func TestICMPCounts(t *testing.T) {
},
{
typ: header.ICMPv6NeighborSolicit,
size: header.ICMPv6NeighborSolicitMinimumSize,
},
size: header.ICMPv6NeighborSolicitMinimumSize},
{
typ: header.ICMPv6NeighborAdvert,
size: header.ICMPv6NeighborAdvertMinimumSize,
+1 -5
View File
@@ -171,11 +171,7 @@ func (*endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt stack.PacketBuffe
// HandlePacket is called by the link layer when new ipv6 packets arrive for
// this endpoint.
func (e *endpoint) HandlePacket(r *stack.Route, pkt stack.PacketBuffer) {
headerView, ok := pkt.Data.PullUp(header.IPv6MinimumSize)
if !ok {
r.Stats().IP.MalformedPacketsReceived.Increment()
return
}
headerView := pkt.Data.First()
h := header.IPv6(headerView)
if !h.IsValid(pkt.Data.Size()) {
r.Stats().IP.MalformedPacketsReceived.Increment()
+5 -8
View File
@@ -70,10 +70,7 @@ func (f *fwdTestNetworkEndpoint) ID() *NetworkEndpointID {
func (f *fwdTestNetworkEndpoint) HandlePacket(r *Route, pkt PacketBuffer) {
// Consume the network header.
b, ok := pkt.Data.PullUp(fwdTestNetHeaderLen)
if !ok {
return
}
b := pkt.Data.First()
pkt.Data.TrimFront(fwdTestNetHeaderLen)
// Dispatch the packet to the transport protocol.
@@ -476,7 +473,7 @@ func TestForwardingWithFakeResolverPartialTimeout(t *testing.T) {
t.Fatal("packet not forwarded")
}
b := p.Pkt.Data.ToView()
b := p.Pkt.Header.View()
if b[0] != 3 {
t.Fatalf("got b[0] = %d, want = 3", b[0])
}
@@ -520,7 +517,7 @@ func TestForwardingWithFakeResolverTwoPackets(t *testing.T) {
t.Fatal("packet not forwarded")
}
b := p.Pkt.Data.ToView()
b := p.Pkt.Header.View()
if b[0] != 3 {
t.Fatalf("got b[0] = %d, want = 3", b[0])
}
@@ -567,7 +564,7 @@ func TestForwardingWithFakeResolverManyPackets(t *testing.T) {
t.Fatal("packet not forwarded")
}
b := p.Pkt.Data.ToView()
b := p.Pkt.Header.View()
if b[0] != 3 {
t.Fatalf("got b[0] = %d, want = 3", b[0])
}
@@ -622,7 +619,7 @@ func TestForwardingWithFakeResolverManyResolutions(t *testing.T) {
// The first 5 packets (address 3 to 7) should not be forwarded
// because their address resolutions are interrupted.
b := p.Pkt.Data.ToView()
b := p.Pkt.Header.View()
if b[0] < 8 {
t.Fatalf("got b[0] = %d, want b[0] >= 8", b[0])
}
+4 -18
View File
@@ -212,11 +212,6 @@ func (it *IPTables) Check(hook Hook, pkt PacketBuffer) bool {
// CheckPackets runs pkts through the rules for hook and returns a map of packets that
// should not go forward.
//
// Precondition: pkt is a IPv4 packet of at least length header.IPv4MinimumSize.
//
// TODO(gvisor.dev/issue/170): pk.NetworkHeader will always be set as a
// precondition.
//
// NOTE: unlike the Check API the returned map contains packets that should be
// dropped.
func (it *IPTables) CheckPackets(hook Hook, pkts PacketBufferList) (drop map[*PacketBuffer]struct{}) {
@@ -231,9 +226,7 @@ func (it *IPTables) CheckPackets(hook Hook, pkts PacketBufferList) (drop map[*Pa
return drop
}
// Precondition: pkt is a IPv4 packet of at least length header.IPv4MinimumSize.
// TODO(gvisor.dev/issue/170): pk.NetworkHeader will always be set as a
// precondition.
// Precondition: pkt.NetworkHeader is set.
func (it *IPTables) checkChain(hook Hook, pkt PacketBuffer, table Table, ruleIdx int) chainVerdict {
// Start from ruleIdx and walk the list of rules until a rule gives us
// a verdict.
@@ -278,21 +271,14 @@ func (it *IPTables) checkChain(hook Hook, pkt PacketBuffer, table Table, ruleIdx
return chainDrop
}
// Precondition: pkt is a IPv4 packet of at least length header.IPv4MinimumSize.
// TODO(gvisor.dev/issue/170): pk.NetworkHeader will always be set as a
// precondition.
// Precondition: pk.NetworkHeader is set.
func (it *IPTables) checkRule(hook Hook, pkt PacketBuffer, table Table, ruleIdx int) (RuleVerdict, int) {
rule := table.Rules[ruleIdx]
// If pkt.NetworkHeader hasn't been set yet, it will be contained in
// pkt.Data.
// pkt.Data.First().
if pkt.NetworkHeader == nil {
var ok bool
pkt.NetworkHeader, ok = pkt.Data.PullUp(header.IPv4MinimumSize)
if !ok {
// Precondition has been violated.
panic(fmt.Sprintf("iptables checks require IPv4 headers of at least %d bytes", header.IPv4MinimumSize))
}
pkt.NetworkHeader = pkt.Data.First()
}
// Check whether the packet matches the IP header filter.
+6 -17
View File
@@ -96,12 +96,9 @@ func (rt RedirectTarget) Action(pkt PacketBuffer) (RuleVerdict, int) {
newPkt := pkt.Clone()
// Set network header.
headerView, ok := newPkt.Data.PullUp(header.IPv4MinimumSize)
if !ok {
return RuleDrop, 0
}
headerView := newPkt.Data.First()
netHeader := header.IPv4(headerView)
newPkt.NetworkHeader = headerView
newPkt.NetworkHeader = headerView[:header.IPv4MinimumSize]
hlen := int(netHeader.HeaderLength())
tlen := int(netHeader.TotalLength())
@@ -120,14 +117,10 @@ func (rt RedirectTarget) Action(pkt PacketBuffer) (RuleVerdict, int) {
if newPkt.TransportHeader != nil {
udpHeader = header.UDP(newPkt.TransportHeader)
} else {
if pkt.Data.Size() < header.UDPMinimumSize {
if len(pkt.Data.First()) < header.UDPMinimumSize {
return RuleDrop, 0
}
hdr, ok := newPkt.Data.PullUp(header.UDPMinimumSize)
if !ok {
return RuleDrop, 0
}
udpHeader = header.UDP(hdr)
udpHeader = header.UDP(newPkt.Data.First())
}
udpHeader.SetDestinationPort(rt.MinPort)
case header.TCPProtocolNumber:
@@ -135,14 +128,10 @@ func (rt RedirectTarget) Action(pkt PacketBuffer) (RuleVerdict, int) {
if newPkt.TransportHeader != nil {
tcpHeader = header.TCP(newPkt.TransportHeader)
} else {
if pkt.Data.Size() < header.TCPMinimumSize {
if len(pkt.Data.First()) < header.TCPMinimumSize {
return RuleDrop, 0
}
hdr, ok := newPkt.Data.PullUp(header.TCPMinimumSize)
if !ok {
return RuleDrop, 0
}
tcpHeader = header.TCP(hdr)
tcpHeader = header.TCP(newPkt.TransportHeader)
}
// TODO(gvisor.dev/issue/170): Need to recompute checksum
// and implement nat connection tracking to support TCP.
+23 -11
View File
@@ -1203,12 +1203,12 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remote, local tcpip.Link
n.stack.stats.IP.PacketsReceived.Increment()
}
netHeader, ok := pkt.Data.PullUp(netProto.MinimumPacketSize())
if !ok {
if len(pkt.Data.First()) < netProto.MinimumPacketSize() {
n.stack.stats.MalformedRcvdPackets.Increment()
return
}
src, dst := netProto.ParseAddresses(netHeader)
src, dst := netProto.ParseAddresses(pkt.Data.First())
if n.stack.handleLocal && !n.isLoopback() && n.getRef(protocol, src) != nil {
// The source address is one of our own, so we never should have gotten a
@@ -1289,8 +1289,22 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remote, local tcpip.Link
func (n *NIC) forwardPacket(r *Route, protocol tcpip.NetworkProtocolNumber, pkt PacketBuffer) {
// TODO(b/143425874) Decrease the TTL field in forwarded packets.
if linkHeaderLen := int(n.linkEP.MaxHeaderLength()); linkHeaderLen != 0 {
pkt.Header = buffer.NewPrependable(linkHeaderLen)
firstData := pkt.Data.First()
pkt.Data.RemoveFirst()
if linkHeaderLen := int(n.linkEP.MaxHeaderLength()); linkHeaderLen == 0 {
pkt.Header = buffer.NewPrependableFromView(firstData)
} else {
firstDataLen := len(firstData)
// pkt.Header should have enough capacity to hold n.linkEP's headers.
pkt.Header = buffer.NewPrependable(firstDataLen + linkHeaderLen)
// TODO(b/151227689): avoid copying the packet when forwarding
if n := copy(pkt.Header.Prepend(firstDataLen), firstData); n != firstDataLen {
panic(fmt.Sprintf("copied %d bytes, expected %d", n, firstDataLen))
}
}
if err := n.linkEP.WritePacket(r, nil /* gso */, protocol, pkt); err != nil {
@@ -1318,13 +1332,12 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN
// validly formed.
n.stack.demux.deliverRawPacket(r, protocol, pkt)
transHeader, ok := pkt.Data.PullUp(transProto.MinimumPacketSize())
if !ok {
if len(pkt.Data.First()) < transProto.MinimumPacketSize() {
n.stack.stats.MalformedRcvdPackets.Increment()
return
}
srcPort, dstPort, err := transProto.ParsePorts(transHeader)
srcPort, dstPort, err := transProto.ParsePorts(pkt.Data.First())
if err != nil {
n.stack.stats.MalformedRcvdPackets.Increment()
return
@@ -1362,12 +1375,11 @@ func (n *NIC) DeliverTransportControlPacket(local, remote tcpip.Address, net tcp
// ICMPv4 only guarantees that 8 bytes of the transport protocol will
// be present in the payload. We know that the ports are within the
// first 8 bytes for all known transport protocols.
transHeader, ok := pkt.Data.PullUp(8)
if !ok {
if len(pkt.Data.First()) < 8 {
return
}
srcPort, dstPort, err := transProto.ParsePorts(transHeader)
srcPort, dstPort, err := transProto.ParsePorts(pkt.Data.First())
if err != nil {
return
}

Some files were not shown because too many files have changed in this diff Show More