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:
Zeling Feng
2021-12-13 13:59:50 -08:00
committed by gVisor bot
parent 02f12a67bb
commit ef0119d3d0
2 changed files with 88 additions and 27 deletions
+38 -27
View File
@@ -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 &ether, nextParser
return &ether, 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)
}
}