mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Ignore ethernet paddings in parsing
PacketImpact testbench did not take into account that ethernet frames can have paddings, which can cause test failures. PiperOrigin-RevId: 416127829
This commit is contained in:
@@ -215,23 +215,34 @@ func NetworkProtocolNumber(v tcpip.NetworkProtocolNumber) *tcpip.NetworkProtocol
|
||||
return &v
|
||||
}
|
||||
|
||||
// bodySizeHint describes num of bytes left to parse for the rest of layers.
|
||||
type bodySizeHint int
|
||||
|
||||
const bodySizeUnknown bodySizeHint = -1
|
||||
|
||||
// layerParser parses the input bytes and returns a Layer along with the next
|
||||
// layerParser to run. If there is no more parsing to do, the returned
|
||||
// layerParser is nil.
|
||||
type layerParser func([]byte) (Layer, layerParser)
|
||||
type layerParser func([]byte) (Layer, bodySizeHint, layerParser)
|
||||
|
||||
// parse parses bytes starting with the first layerParser and using successive
|
||||
// layerParsers until all the bytes are parsed.
|
||||
func parse(parser layerParser, b []byte) Layers {
|
||||
var layers Layers
|
||||
for {
|
||||
var layer Layer
|
||||
layer, parser = parser(b)
|
||||
layer, hint, next := parser(b)
|
||||
layers = append(layers, layer)
|
||||
if parser == nil {
|
||||
break
|
||||
}
|
||||
b = b[layer.length():]
|
||||
if hint != bodySizeUnknown {
|
||||
b = b[:hint]
|
||||
}
|
||||
if next == nil {
|
||||
break
|
||||
}
|
||||
parser = next
|
||||
}
|
||||
layers.linkLayers()
|
||||
return layers
|
||||
@@ -239,7 +250,7 @@ func parse(parser layerParser, b []byte) Layers {
|
||||
|
||||
// parseEther parses the bytes assuming that they start with an ethernet header
|
||||
// and continues parsing further encapsulations.
|
||||
func parseEther(b []byte) (Layer, layerParser) {
|
||||
func parseEther(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
h := header.Ethernet(b)
|
||||
ether := Ether{
|
||||
SrcAddr: LinkAddress(h.SourceAddress()),
|
||||
@@ -256,7 +267,7 @@ func parseEther(b []byte) (Layer, layerParser) {
|
||||
// Assume that the rest is a payload.
|
||||
nextParser = parsePayload
|
||||
}
|
||||
return ðer, nextParser
|
||||
return ðer, bodySizeUnknown, nextParser
|
||||
}
|
||||
|
||||
func (l *Ether) match(other Layer) bool {
|
||||
@@ -421,7 +432,7 @@ func Address(v tcpip.Address) *tcpip.Address {
|
||||
|
||||
// parseIPv4 parses the bytes assuming that they start with an ipv4 header and
|
||||
// continues parsing further encapsulations.
|
||||
func parseIPv4(b []byte) (Layer, layerParser) {
|
||||
func parseIPv4(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
h := header.IPv4(b)
|
||||
options := h.Options()
|
||||
tos, _ := h.TOS()
|
||||
@@ -442,7 +453,7 @@ func parseIPv4(b []byte) (Layer, layerParser) {
|
||||
var nextParser layerParser
|
||||
// If it is a fragment, don't treat it as having a transport protocol.
|
||||
if h.FragmentOffset() != 0 || h.More() {
|
||||
return &ipv4, parsePayload
|
||||
return &ipv4, bodySizeHint(h.PayloadLength()), parsePayload
|
||||
}
|
||||
switch h.TransportProtocol() {
|
||||
case header.TCPProtocolNumber:
|
||||
@@ -455,7 +466,7 @@ func parseIPv4(b []byte) (Layer, layerParser) {
|
||||
// Assume that the rest is a payload.
|
||||
nextParser = parsePayload
|
||||
}
|
||||
return &ipv4, nextParser
|
||||
return &ipv4, bodySizeHint(h.PayloadLength()), nextParser
|
||||
}
|
||||
|
||||
func (l *IPv4) match(other Layer) bool {
|
||||
@@ -555,7 +566,7 @@ func nextIPv6PayloadParser(nextHeader uint8) layerParser {
|
||||
|
||||
// parseIPv6 parses the bytes assuming that they start with an ipv6 header and
|
||||
// continues parsing further encapsulations.
|
||||
func parseIPv6(b []byte) (Layer, layerParser) {
|
||||
func parseIPv6(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
h := header.IPv6(b)
|
||||
tos, flowLabel := h.TOS()
|
||||
ipv6 := IPv6{
|
||||
@@ -568,7 +579,7 @@ func parseIPv6(b []byte) (Layer, layerParser) {
|
||||
DstAddr: Address(h.DestinationAddress()),
|
||||
}
|
||||
nextParser := nextIPv6PayloadParser(h.NextHeader())
|
||||
return &ipv6, nextParser
|
||||
return &ipv6, bodySizeHint(h.PayloadLength()), nextParser
|
||||
}
|
||||
|
||||
func (l *IPv6) match(other Layer) bool {
|
||||
@@ -727,16 +738,16 @@ func parseIPv6ExtHdr(b []byte) (header.IPv6ExtensionHeaderIdentifier, []byte, la
|
||||
|
||||
// parseIPv6HopByHopOptionsExtHdr parses the bytes assuming that they start
|
||||
// with an IPv6 HopByHop Options Extension Header.
|
||||
func parseIPv6HopByHopOptionsExtHdr(b []byte) (Layer, layerParser) {
|
||||
func parseIPv6HopByHopOptionsExtHdr(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
nextHeader, options, nextParser := parseIPv6ExtHdr(b)
|
||||
return &IPv6HopByHopOptionsExtHdr{NextHeader: &nextHeader, Options: options}, nextParser
|
||||
return &IPv6HopByHopOptionsExtHdr{NextHeader: &nextHeader, Options: options}, bodySizeUnknown, nextParser
|
||||
}
|
||||
|
||||
// parseIPv6DestinationOptionsExtHdr parses the bytes assuming that they start
|
||||
// with an IPv6 Destination Options Extension Header.
|
||||
func parseIPv6DestinationOptionsExtHdr(b []byte) (Layer, layerParser) {
|
||||
func parseIPv6DestinationOptionsExtHdr(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
nextHeader, options, nextParser := parseIPv6ExtHdr(b)
|
||||
return &IPv6DestinationOptionsExtHdr{NextHeader: &nextHeader, Options: options}, nextParser
|
||||
return &IPv6DestinationOptionsExtHdr{NextHeader: &nextHeader, Options: options}, bodySizeUnknown, nextParser
|
||||
}
|
||||
|
||||
// Bool is a helper routine that allocates a new
|
||||
@@ -747,7 +758,7 @@ func Bool(v bool) *bool {
|
||||
|
||||
// parseIPv6FragmentExtHdr parses the bytes assuming that they start
|
||||
// with an IPv6 Fragment Extension Header.
|
||||
func parseIPv6FragmentExtHdr(b []byte) (Layer, layerParser) {
|
||||
func parseIPv6FragmentExtHdr(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
nextHeader := b[0]
|
||||
var extHdr header.IPv6FragmentExtHdr
|
||||
copy(extHdr[:], b[2:])
|
||||
@@ -759,9 +770,9 @@ func parseIPv6FragmentExtHdr(b []byte) (Layer, layerParser) {
|
||||
}
|
||||
// If it is a fragment, we can't interpret it.
|
||||
if extHdr.FragmentOffset() != 0 || extHdr.More() {
|
||||
return &fragLayer, parsePayload
|
||||
return &fragLayer, bodySizeUnknown, parsePayload
|
||||
}
|
||||
return &fragLayer, nextIPv6PayloadParser(nextHeader)
|
||||
return &fragLayer, bodySizeUnknown, nextIPv6PayloadParser(nextHeader)
|
||||
}
|
||||
|
||||
func (l *IPv6HopByHopOptionsExtHdr) length() int {
|
||||
@@ -894,7 +905,7 @@ func ICMPv6Code(v header.ICMPv6Code) *header.ICMPv6Code {
|
||||
}
|
||||
|
||||
// parseICMPv6 parses the bytes assuming that they start with an ICMPv6 header.
|
||||
func parseICMPv6(b []byte) (Layer, layerParser) {
|
||||
func parseICMPv6(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
h := header.ICMPv6(b)
|
||||
msgType := h.Type()
|
||||
icmpv6 := ICMPv6{
|
||||
@@ -909,7 +920,7 @@ func parseICMPv6(b []byte) (Layer, layerParser) {
|
||||
case header.ICMPv6ParamProblem:
|
||||
icmpv6.Pointer = Uint32(h.TypeSpecific())
|
||||
}
|
||||
return &icmpv6, nil
|
||||
return &icmpv6, bodySizeUnknown, nil
|
||||
}
|
||||
|
||||
func (l *ICMPv6) match(other Layer) bool {
|
||||
@@ -995,7 +1006,7 @@ func (l *ICMPv4) ToBytes() ([]byte, error) {
|
||||
|
||||
// parseICMPv4 parses the bytes as an ICMPv4 header, returning a Layer and a
|
||||
// parser for the encapsulated payload.
|
||||
func parseICMPv4(b []byte) (Layer, layerParser) {
|
||||
func parseICMPv4(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
h := header.ICMPv4(b)
|
||||
|
||||
msgType := h.Type()
|
||||
@@ -1012,7 +1023,7 @@ func parseICMPv4(b []byte) (Layer, layerParser) {
|
||||
case header.ICMPv4ParamProblem:
|
||||
icmpv4.Pointer = Uint8(h.Pointer())
|
||||
}
|
||||
return &icmpv4, nil
|
||||
return &icmpv4, bodySizeUnknown, nil
|
||||
}
|
||||
|
||||
func (l *ICMPv4) match(other Layer) bool {
|
||||
@@ -1156,7 +1167,7 @@ func Uint32(v uint32) *uint32 {
|
||||
|
||||
// parseTCP parses the bytes assuming that they start with a tcp header and
|
||||
// continues parsing further encapsulations.
|
||||
func parseTCP(b []byte) (Layer, layerParser) {
|
||||
func parseTCP(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
h := header.TCP(b)
|
||||
tcp := TCP{
|
||||
SrcPort: Uint16(h.SourcePort()),
|
||||
@@ -1170,7 +1181,7 @@ func parseTCP(b []byte) (Layer, layerParser) {
|
||||
UrgentPointer: Uint16(h.UrgentPointer()),
|
||||
Options: b[header.TCPMinimumSize:h.DataOffset()],
|
||||
}
|
||||
return &tcp, parsePayload
|
||||
return &tcp, bodySizeUnknown, parsePayload
|
||||
}
|
||||
|
||||
func (l *TCP) match(other Layer) bool {
|
||||
@@ -1245,7 +1256,7 @@ func setUDPChecksum(h *header.UDP, udp *UDP) error {
|
||||
|
||||
// parseUDP parses the bytes assuming that they start with a udp header and
|
||||
// returns the parsed layer and the next parser to use.
|
||||
func parseUDP(b []byte) (Layer, layerParser) {
|
||||
func parseUDP(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
h := header.UDP(b)
|
||||
udp := UDP{
|
||||
SrcPort: Uint16(h.SourcePort()),
|
||||
@@ -1253,7 +1264,7 @@ func parseUDP(b []byte) (Layer, layerParser) {
|
||||
Length: Uint16(h.Length()),
|
||||
Checksum: Uint16(h.Checksum()),
|
||||
}
|
||||
return &udp, parsePayload
|
||||
return &udp, bodySizeUnknown, parsePayload
|
||||
}
|
||||
|
||||
func (l *UDP) match(other Layer) bool {
|
||||
@@ -1281,11 +1292,11 @@ func (l *Payload) String() string {
|
||||
|
||||
// parsePayload parses the bytes assuming that they start with a payload and
|
||||
// continue to the end. There can be no further encapsulations.
|
||||
func parsePayload(b []byte) (Layer, layerParser) {
|
||||
func parsePayload(b []byte) (Layer, bodySizeHint, layerParser) {
|
||||
payload := Payload{
|
||||
Bytes: b,
|
||||
}
|
||||
return &payload, nil
|
||||
return &payload, bodySizeUnknown, nil
|
||||
}
|
||||
|
||||
// ToBytes implements Layer.ToBytes.
|
||||
|
||||
@@ -16,6 +16,7 @@ package testbench
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
@@ -726,3 +727,52 @@ func TestIPv6ExtHdrOptions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthernetPadding(t *testing.T) {
|
||||
packet := []byte{
|
||||
0x3a, 0xd6, 0x90, 0x36, 0x18, 0xce, 0x64, 0x4f, 0x16, 0x3f,
|
||||
0x5f, 0x0f, 0x08, 0x00, 0x45, 0x00, 0x00, 0x2c, 0xf5, 0x0e,
|
||||
0x00, 0x00, 0x40, 0x06, 0x2d, 0xba, 0xac, 0x00, 0x00, 0x02,
|
||||
0xac, 0x00, 0x00, 0x01, 0x7c, 0x3e, 0xe3, 0x91, 0x2b, 0xe4,
|
||||
0xb0, 0xe7, 0x9a, 0xcb, 0x04, 0x43, 0x60, 0x12, 0x72, 0x00,
|
||||
0xf2, 0x67, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x00, 0x00,
|
||||
}
|
||||
parsed := parse(parseEther, packet)
|
||||
wanted := Layers{
|
||||
&Ether{
|
||||
SrcAddr: LinkAddress(tcpip.LinkAddress("\x64\x4f\x16\x3f\x5f\x0f")),
|
||||
DstAddr: LinkAddress(tcpip.LinkAddress("\x3a\xd6\x90\x36\x18\xce")),
|
||||
Type: NetworkProtocolNumber(header.IPv4ProtocolNumber),
|
||||
},
|
||||
&IPv4{
|
||||
IHL: Uint8(20),
|
||||
TOS: Uint8(0),
|
||||
TotalLength: Uint16(44),
|
||||
ID: Uint16(0xf50e),
|
||||
Flags: Uint8(0),
|
||||
FragmentOffset: Uint16(0),
|
||||
TTL: Uint8(64),
|
||||
Protocol: Uint8(uint8(header.TCPProtocolNumber)),
|
||||
Checksum: Uint16(0x2dba),
|
||||
SrcAddr: Address(tcpip.Address("\xac\x00\x00\x02")),
|
||||
DstAddr: Address(tcpip.Address("\xac\x00\x00\x01")),
|
||||
},
|
||||
&TCP{
|
||||
SrcPort: Uint16(31806),
|
||||
DstPort: Uint16(58257),
|
||||
SeqNum: Uint32(736407783),
|
||||
AckNum: Uint32(2596996163),
|
||||
DataOffset: Uint8(24),
|
||||
Flags: TCPFlags(header.TCPFlagSyn | header.TCPFlagAck),
|
||||
WindowSize: Uint16(29184),
|
||||
Checksum: Uint16(0xf267),
|
||||
UrgentPointer: Uint16(0),
|
||||
},
|
||||
&Payload{
|
||||
Bytes: []byte{},
|
||||
},
|
||||
}
|
||||
if !parsed.match(wanted) {
|
||||
t.Fatalf("parse(parseEther, %s) = %s, want %s)", hex.Dump(packet), parsed, wanted)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user