mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Use common parsing utilities when sniffing
Extract parsing utilities so they can be used by the sniffer. Fixes #3930 PiperOrigin-RevId: 332401880
This commit is contained in:
committed by
gVisor bot
parent
07d832dbb5
commit
360006d894
@@ -0,0 +1,15 @@
|
|||||||
|
load("//tools:defs.bzl", "go_library")
|
||||||
|
|
||||||
|
package(licenses = ["notice"])
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "parse",
|
||||||
|
srcs = ["parse.go"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/tcpip",
|
||||||
|
"//pkg/tcpip/buffer",
|
||||||
|
"//pkg/tcpip/header",
|
||||||
|
"//pkg/tcpip/stack",
|
||||||
|
],
|
||||||
|
)
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Package parse provides utilities to parse packets.
|
||||||
|
package parse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ARP populates pkt's network header with an ARP header found in
|
||||||
|
// pkt.Data.
|
||||||
|
//
|
||||||
|
// Returns true if the header was successfully parsed.
|
||||||
|
func ARP(pkt *stack.PacketBuffer) bool {
|
||||||
|
_, ok := pkt.NetworkHeader().Consume(header.ARPSize)
|
||||||
|
if ok {
|
||||||
|
pkt.NetworkProtocolNumber = header.ARPProtocolNumber
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPv4 parses an IPv4 packet found in pkt.Data and populates pkt's network
|
||||||
|
// header with the IPv4 header.
|
||||||
|
//
|
||||||
|
// Returns true if the header was successfully parsed.
|
||||||
|
func IPv4(pkt *stack.PacketBuffer) bool {
|
||||||
|
hdr, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ipHdr := header.IPv4(hdr)
|
||||||
|
|
||||||
|
// Header may have options, determine the true header length.
|
||||||
|
headerLen := int(ipHdr.HeaderLength())
|
||||||
|
if headerLen < header.IPv4MinimumSize {
|
||||||
|
// TODO(gvisor.dev/issue/2404): Per RFC 791, IHL needs to be at least 5 in
|
||||||
|
// order for the packet to be valid. Figure out if we want to reject this
|
||||||
|
// case.
|
||||||
|
headerLen = header.IPv4MinimumSize
|
||||||
|
}
|
||||||
|
hdr, ok = pkt.NetworkHeader().Consume(headerLen)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ipHdr = header.IPv4(hdr)
|
||||||
|
|
||||||
|
pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber
|
||||||
|
pkt.Data.CapLength(int(ipHdr.TotalLength()) - len(hdr))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPv6 parses an IPv6 packet found in pkt.Data and populates pkt's network
|
||||||
|
// header with the IPv6 header.
|
||||||
|
func IPv6(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, fragID uint32, fragOffset uint16, fragMore bool, ok bool) {
|
||||||
|
hdr, ok := pkt.Data.PullUp(header.IPv6MinimumSize)
|
||||||
|
if !ok {
|
||||||
|
return 0, 0, 0, false, false
|
||||||
|
}
|
||||||
|
ipHdr := header.IPv6(hdr)
|
||||||
|
|
||||||
|
// dataClone consists of:
|
||||||
|
// - Any IPv6 header bytes after the first 40 (i.e. extensions).
|
||||||
|
// - The transport header, if present.
|
||||||
|
// - Any other payload data.
|
||||||
|
views := [8]buffer.View{}
|
||||||
|
dataClone := pkt.Data.Clone(views[:])
|
||||||
|
dataClone.TrimFront(header.IPv6MinimumSize)
|
||||||
|
it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(ipHdr.NextHeader()), dataClone)
|
||||||
|
|
||||||
|
// Iterate over the IPv6 extensions to find their length.
|
||||||
|
var nextHdr tcpip.TransportProtocolNumber
|
||||||
|
var extensionsSize int
|
||||||
|
|
||||||
|
traverseExtensions:
|
||||||
|
for {
|
||||||
|
extHdr, done, err := it.Next()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we exhaust the extension list, the entire packet is the IPv6 header
|
||||||
|
// and (possibly) extensions.
|
||||||
|
if done {
|
||||||
|
extensionsSize = dataClone.Size()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extHdr := extHdr.(type) {
|
||||||
|
case header.IPv6FragmentExtHdr:
|
||||||
|
if fragID == 0 && fragOffset == 0 && !fragMore {
|
||||||
|
fragID = extHdr.ID()
|
||||||
|
fragOffset = extHdr.FragmentOffset()
|
||||||
|
fragMore = extHdr.More()
|
||||||
|
}
|
||||||
|
|
||||||
|
case header.IPv6RawPayloadHeader:
|
||||||
|
// We've found the payload after any extensions.
|
||||||
|
extensionsSize = dataClone.Size() - extHdr.Buf.Size()
|
||||||
|
nextHdr = tcpip.TransportProtocolNumber(extHdr.Identifier)
|
||||||
|
break traverseExtensions
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Any other extension is a no-op, keep looping until we find the payload.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the IPv6 header with extensions in pkt.NetworkHeader().
|
||||||
|
hdr, ok = pkt.NetworkHeader().Consume(header.IPv6MinimumSize + extensionsSize)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("pkt.Data should have at least %d bytes, but only has %d.", header.IPv6MinimumSize+extensionsSize, pkt.Data.Size()))
|
||||||
|
}
|
||||||
|
ipHdr = header.IPv6(hdr)
|
||||||
|
pkt.Data.CapLength(int(ipHdr.PayloadLength()))
|
||||||
|
pkt.NetworkProtocolNumber = header.IPv6ProtocolNumber
|
||||||
|
|
||||||
|
return nextHdr, fragID, fragOffset, fragMore, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// UDP parses a UDP packet found in pkt.Data and populates pkt's transport
|
||||||
|
// header with the UDP header.
|
||||||
|
//
|
||||||
|
// Returns true if the header was successfully parsed.
|
||||||
|
func UDP(pkt *stack.PacketBuffer) bool {
|
||||||
|
_, ok := pkt.TransportHeader().Consume(header.UDPMinimumSize)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// TCP parses a TCP packet found in pkt.Data and populates pkt's transport
|
||||||
|
// header with the TCP header.
|
||||||
|
//
|
||||||
|
// Returns true if the header was successfully parsed.
|
||||||
|
func TCP(pkt *stack.PacketBuffer) bool {
|
||||||
|
// TCP header is variable length, peek at it first.
|
||||||
|
hdrLen := header.TCPMinimumSize
|
||||||
|
hdr, ok := pkt.Data.PullUp(hdrLen)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the header has options, pull those up as well.
|
||||||
|
if offset := int(header.TCP(hdr).DataOffset()); offset > header.TCPMinimumSize && offset <= pkt.Data.Size() {
|
||||||
|
// TODO(gvisor.dev/issue/2404): Figure out whether to reject this kind of
|
||||||
|
// packets.
|
||||||
|
hdrLen = offset
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = pkt.TransportHeader().Consume(hdrLen)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ go_library(
|
|||||||
"//pkg/tcpip",
|
"//pkg/tcpip",
|
||||||
"//pkg/tcpip/buffer",
|
"//pkg/tcpip/buffer",
|
||||||
"//pkg/tcpip/header",
|
"//pkg/tcpip/header",
|
||||||
|
"//pkg/tcpip/header/parse",
|
||||||
"//pkg/tcpip/link/nested",
|
"//pkg/tcpip/link/nested",
|
||||||
"//pkg/tcpip/stack",
|
"//pkg/tcpip/stack",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header/parse"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/link/nested"
|
"gvisor.dev/gvisor/pkg/tcpip/link/nested"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
)
|
)
|
||||||
@@ -195,49 +196,52 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
|
|||||||
var transProto uint8
|
var transProto uint8
|
||||||
src := tcpip.Address("unknown")
|
src := tcpip.Address("unknown")
|
||||||
dst := tcpip.Address("unknown")
|
dst := tcpip.Address("unknown")
|
||||||
id := 0
|
var size uint16
|
||||||
size := uint16(0)
|
var id uint32
|
||||||
var fragmentOffset uint16
|
var fragmentOffset uint16
|
||||||
var moreFragments bool
|
var moreFragments bool
|
||||||
|
|
||||||
// Examine the packet using a new VV. Backing storage must not be written.
|
// Clone the packet buffer to not modify the original.
|
||||||
vv := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
|
//
|
||||||
|
// We don't clone the original packet buffer so that the new packet buffer
|
||||||
|
// does not have any of its headers set.
|
||||||
|
pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Data: buffer.NewVectorisedView(pkt.Size(), pkt.Views())})
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case header.IPv4ProtocolNumber:
|
case header.IPv4ProtocolNumber:
|
||||||
hdr, ok := vv.PullUp(header.IPv4MinimumSize)
|
if ok := parse.IPv4(pkt); !ok {
|
||||||
if !ok {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ipv4 := header.IPv4(hdr)
|
|
||||||
|
ipv4 := header.IPv4(pkt.NetworkHeader().View())
|
||||||
fragmentOffset = ipv4.FragmentOffset()
|
fragmentOffset = ipv4.FragmentOffset()
|
||||||
moreFragments = ipv4.Flags()&header.IPv4FlagMoreFragments == header.IPv4FlagMoreFragments
|
moreFragments = ipv4.Flags()&header.IPv4FlagMoreFragments == header.IPv4FlagMoreFragments
|
||||||
src = ipv4.SourceAddress()
|
src = ipv4.SourceAddress()
|
||||||
dst = ipv4.DestinationAddress()
|
dst = ipv4.DestinationAddress()
|
||||||
transProto = ipv4.Protocol()
|
transProto = ipv4.Protocol()
|
||||||
size = ipv4.TotalLength() - uint16(ipv4.HeaderLength())
|
size = ipv4.TotalLength() - uint16(ipv4.HeaderLength())
|
||||||
vv.TrimFront(int(ipv4.HeaderLength()))
|
id = uint32(ipv4.ID())
|
||||||
id = int(ipv4.ID())
|
|
||||||
|
|
||||||
case header.IPv6ProtocolNumber:
|
case header.IPv6ProtocolNumber:
|
||||||
hdr, ok := vv.PullUp(header.IPv6MinimumSize)
|
proto, fragID, fragOffset, fragMore, ok := parse.IPv6(pkt)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ipv6 := header.IPv6(hdr)
|
|
||||||
|
ipv6 := header.IPv6(pkt.NetworkHeader().View())
|
||||||
src = ipv6.SourceAddress()
|
src = ipv6.SourceAddress()
|
||||||
dst = ipv6.DestinationAddress()
|
dst = ipv6.DestinationAddress()
|
||||||
transProto = ipv6.NextHeader()
|
transProto = uint8(proto)
|
||||||
size = ipv6.PayloadLength()
|
size = ipv6.PayloadLength()
|
||||||
vv.TrimFront(header.IPv6MinimumSize)
|
id = fragID
|
||||||
|
moreFragments = fragMore
|
||||||
|
fragmentOffset = fragOffset
|
||||||
|
|
||||||
case header.ARPProtocolNumber:
|
case header.ARPProtocolNumber:
|
||||||
hdr, ok := vv.PullUp(header.ARPSize)
|
if parse.ARP(pkt) {
|
||||||
if !ok {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vv.TrimFront(header.ARPSize)
|
|
||||||
arp := header.ARP(hdr)
|
arp := header.ARP(pkt.NetworkHeader().View())
|
||||||
log.Infof(
|
log.Infof(
|
||||||
"%s arp %s (%s) -> %s (%s) valid:%t",
|
"%s arp %s (%s) -> %s (%s) valid:%t",
|
||||||
prefix,
|
prefix,
|
||||||
@@ -259,7 +263,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
|
|||||||
switch tcpip.TransportProtocolNumber(transProto) {
|
switch tcpip.TransportProtocolNumber(transProto) {
|
||||||
case header.ICMPv4ProtocolNumber:
|
case header.ICMPv4ProtocolNumber:
|
||||||
transName = "icmp"
|
transName = "icmp"
|
||||||
hdr, ok := vv.PullUp(header.ICMPv4MinimumSize)
|
hdr, ok := pkt.Data.PullUp(header.ICMPv4MinimumSize)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -296,7 +300,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
|
|||||||
|
|
||||||
case header.ICMPv6ProtocolNumber:
|
case header.ICMPv6ProtocolNumber:
|
||||||
transName = "icmp"
|
transName = "icmp"
|
||||||
hdr, ok := vv.PullUp(header.ICMPv6MinimumSize)
|
hdr, ok := pkt.Data.PullUp(header.ICMPv6MinimumSize)
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -331,11 +335,11 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
|
|||||||
|
|
||||||
case header.UDPProtocolNumber:
|
case header.UDPProtocolNumber:
|
||||||
transName = "udp"
|
transName = "udp"
|
||||||
hdr, ok := vv.PullUp(header.UDPMinimumSize)
|
if ok := parse.UDP(pkt); !ok {
|
||||||
if !ok {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
udp := header.UDP(hdr)
|
|
||||||
|
udp := header.UDP(pkt.TransportHeader().View())
|
||||||
if fragmentOffset == 0 {
|
if fragmentOffset == 0 {
|
||||||
srcPort = udp.SourcePort()
|
srcPort = udp.SourcePort()
|
||||||
dstPort = udp.DestinationPort()
|
dstPort = udp.DestinationPort()
|
||||||
@@ -345,19 +349,19 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
|
|||||||
|
|
||||||
case header.TCPProtocolNumber:
|
case header.TCPProtocolNumber:
|
||||||
transName = "tcp"
|
transName = "tcp"
|
||||||
hdr, ok := vv.PullUp(header.TCPMinimumSize)
|
if ok := parse.TCP(pkt); !ok {
|
||||||
if !ok {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
tcp := header.TCP(hdr)
|
|
||||||
|
tcp := header.TCP(pkt.TransportHeader().View())
|
||||||
if fragmentOffset == 0 {
|
if fragmentOffset == 0 {
|
||||||
offset := int(tcp.DataOffset())
|
offset := int(tcp.DataOffset())
|
||||||
if offset < header.TCPMinimumSize {
|
if offset < header.TCPMinimumSize {
|
||||||
details += fmt.Sprintf("invalid packet: tcp data offset too small %d", offset)
|
details += fmt.Sprintf("invalid packet: tcp data offset too small %d", offset)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if offset > vv.Size() && !moreFragments {
|
if size := pkt.Data.Size() + len(tcp); offset > size && !moreFragments {
|
||||||
details += fmt.Sprintf("invalid packet: tcp data offset %d larger than packet buffer length %d", offset, vv.Size())
|
details += fmt.Sprintf("invalid packet: tcp data offset %d larger than tcp packet length %d", offset, size)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ go_library(
|
|||||||
"//pkg/tcpip",
|
"//pkg/tcpip",
|
||||||
"//pkg/tcpip/buffer",
|
"//pkg/tcpip/buffer",
|
||||||
"//pkg/tcpip/header",
|
"//pkg/tcpip/header",
|
||||||
|
"//pkg/tcpip/header/parse",
|
||||||
"//pkg/tcpip/stack",
|
"//pkg/tcpip/stack",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header/parse"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -234,11 +235,7 @@ func (*protocol) Wait() {}
|
|||||||
|
|
||||||
// Parse implements stack.NetworkProtocol.Parse.
|
// Parse implements stack.NetworkProtocol.Parse.
|
||||||
func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
|
func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
|
||||||
_, ok = pkt.NetworkHeader().Consume(header.ARPSize)
|
return 0, false, parse.ARP(pkt)
|
||||||
if !ok {
|
|
||||||
return 0, false, false
|
|
||||||
}
|
|
||||||
return 0, false, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProtocol returns an ARP network protocol.
|
// NewProtocol returns an ARP network protocol.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ go_library(
|
|||||||
"//pkg/tcpip",
|
"//pkg/tcpip",
|
||||||
"//pkg/tcpip/buffer",
|
"//pkg/tcpip/buffer",
|
||||||
"//pkg/tcpip/header",
|
"//pkg/tcpip/header",
|
||||||
|
"//pkg/tcpip/header/parse",
|
||||||
"//pkg/tcpip/network/fragmentation",
|
"//pkg/tcpip/network/fragmentation",
|
||||||
"//pkg/tcpip/network/hash",
|
"//pkg/tcpip/network/hash",
|
||||||
"//pkg/tcpip/stack",
|
"//pkg/tcpip/stack",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header/parse"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/fragmentation"
|
"gvisor.dev/gvisor/pkg/tcpip/network/fragmentation"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/hash"
|
"gvisor.dev/gvisor/pkg/tcpip/network/hash"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
@@ -529,37 +530,14 @@ func (*protocol) Close() {}
|
|||||||
// Wait implements stack.TransportProtocol.Wait.
|
// Wait implements stack.TransportProtocol.Wait.
|
||||||
func (*protocol) Wait() {}
|
func (*protocol) Wait() {}
|
||||||
|
|
||||||
// Parse implements stack.TransportProtocol.Parse.
|
// Parse implements stack.NetworkProtocol.Parse.
|
||||||
func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
|
func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
|
||||||
hdr, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
|
if ok := parse.IPv4(pkt); !ok {
|
||||||
if !ok {
|
|
||||||
return 0, false, false
|
return 0, false, false
|
||||||
}
|
}
|
||||||
ipHdr := header.IPv4(hdr)
|
|
||||||
|
|
||||||
// Header may have options, determine the true header length.
|
ipHdr := header.IPv4(pkt.NetworkHeader().View())
|
||||||
headerLen := int(ipHdr.HeaderLength())
|
return ipHdr.TransportProtocol(), !ipHdr.More() && ipHdr.FragmentOffset() == 0, true
|
||||||
if headerLen < header.IPv4MinimumSize {
|
|
||||||
// TODO(gvisor.dev/issue/2404): Per RFC 791, IHL needs to be at least 5 in
|
|
||||||
// order for the packet to be valid. Figure out if we want to reject this
|
|
||||||
// case.
|
|
||||||
headerLen = header.IPv4MinimumSize
|
|
||||||
}
|
|
||||||
hdr, ok = pkt.NetworkHeader().Consume(headerLen)
|
|
||||||
if !ok {
|
|
||||||
return 0, false, false
|
|
||||||
}
|
|
||||||
ipHdr = header.IPv4(hdr)
|
|
||||||
|
|
||||||
// If this is a fragment, don't bother parsing the transport header.
|
|
||||||
parseTransportHeader := true
|
|
||||||
if ipHdr.More() || ipHdr.FragmentOffset() != 0 {
|
|
||||||
parseTransportHeader = false
|
|
||||||
}
|
|
||||||
|
|
||||||
pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber
|
|
||||||
pkt.Data.CapLength(int(ipHdr.TotalLength()) - len(hdr))
|
|
||||||
return ipHdr.TransportProtocol(), parseTransportHeader, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateMTU calculates the network-layer payload MTU based on the link-layer
|
// calculateMTU calculates the network-layer payload MTU based on the link-layer
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ go_library(
|
|||||||
"//pkg/tcpip",
|
"//pkg/tcpip",
|
||||||
"//pkg/tcpip/buffer",
|
"//pkg/tcpip/buffer",
|
||||||
"//pkg/tcpip/header",
|
"//pkg/tcpip/header",
|
||||||
|
"//pkg/tcpip/header/parse",
|
||||||
"//pkg/tcpip/network/fragmentation",
|
"//pkg/tcpip/network/fragmentation",
|
||||||
"//pkg/tcpip/stack",
|
"//pkg/tcpip/stack",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header/parse"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/fragmentation"
|
"gvisor.dev/gvisor/pkg/tcpip/network/fragmentation"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
)
|
)
|
||||||
@@ -574,75 +575,14 @@ func (*protocol) Close() {}
|
|||||||
// Wait implements stack.TransportProtocol.Wait.
|
// Wait implements stack.TransportProtocol.Wait.
|
||||||
func (*protocol) Wait() {}
|
func (*protocol) Wait() {}
|
||||||
|
|
||||||
// Parse implements stack.TransportProtocol.Parse.
|
// Parse implements stack.NetworkProtocol.Parse.
|
||||||
func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
|
func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
|
||||||
hdr, ok := pkt.Data.PullUp(header.IPv6MinimumSize)
|
proto, _, fragOffset, fragMore, ok := parse.IPv6(pkt)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, false, false
|
return 0, false, false
|
||||||
}
|
}
|
||||||
ipHdr := header.IPv6(hdr)
|
|
||||||
|
|
||||||
// dataClone consists of:
|
return proto, !fragMore && fragOffset == 0, true
|
||||||
// - Any IPv6 header bytes after the first 40 (i.e. extensions).
|
|
||||||
// - The transport header, if present.
|
|
||||||
// - Any other payload data.
|
|
||||||
views := [8]buffer.View{}
|
|
||||||
dataClone := pkt.Data.Clone(views[:])
|
|
||||||
dataClone.TrimFront(header.IPv6MinimumSize)
|
|
||||||
it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(ipHdr.NextHeader()), dataClone)
|
|
||||||
|
|
||||||
// Iterate over the IPv6 extensions to find their length.
|
|
||||||
//
|
|
||||||
// Parsing occurs again in HandlePacket because we don't track the
|
|
||||||
// extensions in PacketBuffer. Unfortunately, that means HandlePacket
|
|
||||||
// has to do the parsing work again.
|
|
||||||
var nextHdr tcpip.TransportProtocolNumber
|
|
||||||
foundNext := true
|
|
||||||
extensionsSize := 0
|
|
||||||
traverseExtensions:
|
|
||||||
for extHdr, done, err := it.Next(); ; extHdr, done, err = it.Next() {
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// If we exhaust the extension list, the entire packet is the IPv6 header
|
|
||||||
// and (possibly) extensions.
|
|
||||||
if done {
|
|
||||||
extensionsSize = dataClone.Size()
|
|
||||||
foundNext = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
switch extHdr := extHdr.(type) {
|
|
||||||
case header.IPv6FragmentExtHdr:
|
|
||||||
// If this is an atomic fragment, we don't have to treat it specially.
|
|
||||||
if !extHdr.More() && extHdr.FragmentOffset() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// This is a non-atomic fragment and has to be re-assembled before we can
|
|
||||||
// examine the payload for a transport header.
|
|
||||||
foundNext = false
|
|
||||||
|
|
||||||
case header.IPv6RawPayloadHeader:
|
|
||||||
// We've found the payload after any extensions.
|
|
||||||
extensionsSize = dataClone.Size() - extHdr.Buf.Size()
|
|
||||||
nextHdr = tcpip.TransportProtocolNumber(extHdr.Identifier)
|
|
||||||
break traverseExtensions
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Any other extension is a no-op, keep looping until we find the payload.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the IPv6 header with extensions in pkt.NetworkHeader().
|
|
||||||
hdr, ok = pkt.NetworkHeader().Consume(header.IPv6MinimumSize + extensionsSize)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("pkt.Data should have at least %d bytes, but only has %d.", header.IPv6MinimumSize+extensionsSize, pkt.Data.Size()))
|
|
||||||
}
|
|
||||||
ipHdr = header.IPv6(hdr)
|
|
||||||
pkt.Data.CapLength(int(ipHdr.PayloadLength()))
|
|
||||||
pkt.NetworkProtocolNumber = header.IPv6ProtocolNumber
|
|
||||||
|
|
||||||
return nextHdr, foundNext, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateMTU calculates the network-layer payload MTU based on the link-layer
|
// calculateMTU calculates the network-layer payload MTU based on the link-layer
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ go_library(
|
|||||||
"//pkg/tcpip/buffer",
|
"//pkg/tcpip/buffer",
|
||||||
"//pkg/tcpip/hash/jenkins",
|
"//pkg/tcpip/hash/jenkins",
|
||||||
"//pkg/tcpip/header",
|
"//pkg/tcpip/header",
|
||||||
|
"//pkg/tcpip/header/parse",
|
||||||
"//pkg/tcpip/ports",
|
"//pkg/tcpip/ports",
|
||||||
"//pkg/tcpip/seqnum",
|
"//pkg/tcpip/seqnum",
|
||||||
"//pkg/tcpip/stack",
|
"//pkg/tcpip/stack",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header/parse"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
|
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/transport/raw"
|
"gvisor.dev/gvisor/pkg/tcpip/transport/raw"
|
||||||
@@ -506,22 +507,7 @@ func (p *protocol) SynRcvdCounter() *synRcvdCounter {
|
|||||||
|
|
||||||
// Parse implements stack.TransportProtocol.Parse.
|
// Parse implements stack.TransportProtocol.Parse.
|
||||||
func (*protocol) Parse(pkt *stack.PacketBuffer) bool {
|
func (*protocol) Parse(pkt *stack.PacketBuffer) bool {
|
||||||
// TCP header is variable length, peek at it first.
|
return parse.TCP(pkt)
|
||||||
hdrLen := header.TCPMinimumSize
|
|
||||||
hdr, ok := pkt.Data.PullUp(hdrLen)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the header has options, pull those up as well.
|
|
||||||
if offset := int(header.TCP(hdr).DataOffset()); offset > header.TCPMinimumSize && offset <= pkt.Data.Size() {
|
|
||||||
// TODO(gvisor.dev/issue/2404): Figure out whether to reject this kind of
|
|
||||||
// packets.
|
|
||||||
hdrLen = offset
|
|
||||||
}
|
|
||||||
|
|
||||||
_, ok = pkt.TransportHeader().Consume(hdrLen)
|
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProtocol returns a TCP transport protocol.
|
// NewProtocol returns a TCP transport protocol.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ go_library(
|
|||||||
"//pkg/tcpip",
|
"//pkg/tcpip",
|
||||||
"//pkg/tcpip/buffer",
|
"//pkg/tcpip/buffer",
|
||||||
"//pkg/tcpip/header",
|
"//pkg/tcpip/header",
|
||||||
|
"//pkg/tcpip/header/parse",
|
||||||
"//pkg/tcpip/ports",
|
"//pkg/tcpip/ports",
|
||||||
"//pkg/tcpip/stack",
|
"//pkg/tcpip/stack",
|
||||||
"//pkg/tcpip/transport/raw",
|
"//pkg/tcpip/transport/raw",
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header/parse"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/transport/raw"
|
"gvisor.dev/gvisor/pkg/tcpip/transport/raw"
|
||||||
"gvisor.dev/gvisor/pkg/waiter"
|
"gvisor.dev/gvisor/pkg/waiter"
|
||||||
@@ -219,8 +220,7 @@ func (*protocol) Wait() {}
|
|||||||
|
|
||||||
// Parse implements stack.TransportProtocol.Parse.
|
// Parse implements stack.TransportProtocol.Parse.
|
||||||
func (*protocol) Parse(pkt *stack.PacketBuffer) bool {
|
func (*protocol) Parse(pkt *stack.PacketBuffer) bool {
|
||||||
_, ok := pkt.TransportHeader().Consume(header.UDPMinimumSize)
|
return parse.UDP(pkt)
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProtocol returns a UDP transport protocol.
|
// NewProtocol returns a UDP transport protocol.
|
||||||
|
|||||||
Reference in New Issue
Block a user