Skip to content

Commit

Permalink
Fixes for Geneve option flags/length field (#17)
Browse files Browse the repository at this point in the history
* Fix Geneve option flags/length field decoding

The option header length is 5 bits, not 4, so fix the bit shift for
decoding flags, and fix the mask for decoding the length. This also adds
a unit test for decoding a max length option (124 byte payload).

* Fix Geneve option flags/length field serialization

OR-assigning the flag bits into the byte offset for the Geneve option
header flags/length field produced corrupt packets because the buffer
returned by PrependBytes is not guaranteed to be zeroed out. Since this
is the first time that offset is touched, just assign instead.

---------

Co-authored-by: Simeon Miteff <simeon.miteff@corelight.com>
  • Loading branch information
simeonmiteff and Simeon Miteff committed Jun 27, 2023
1 parent 9e29b47 commit 4472aec
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 3 deletions.
6 changes: 3 additions & 3 deletions layers/geneve.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ func decodeGeneveOption(data []byte, gn *Geneve, df gopacket.DecodeFeedback) (*G

opt.Class = binary.BigEndian.Uint16(data[0:2])
opt.Type = data[2]
opt.Flags = data[3] >> 4
opt.Length = (data[3]&0xf)*4 + 4
opt.Flags = data[3] >> 5
opt.Length = (data[3]&0x1f)*4 + 4

if len(data) < int(opt.Length) {
df.SetTruncated()
Expand Down Expand Up @@ -181,7 +181,7 @@ func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.Serializ
bytes[offset] = o.Type

offset += 1
bytes[offset] |= o.Flags << 5
bytes[offset] = o.Flags << 5
bytes[offset] |= ((o.Length - 4) >> 2) & 0x1f

offset += 1
Expand Down
96 changes: 96 additions & 0 deletions layers/geneve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,66 @@ var testPacketGeneve3 = []byte{
0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
}

var testMaxSizeOption = []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b,
}

var testPacketGeneve4 = []byte{
0x00, 0x1b, 0x21, 0x3c, 0xac, 0x30, // dst mac
0x00, 0x1b, 0x21, 0x3c, 0xab, 0x64, // src mac
0x08, 0x00, // ethertype, len

// IPv4
0x45, 0x00,
0x01, 0x06, // total length
0xdf, 0xad, // identification
0x40, 0x00, // flags, fragment offset
0x40, // TTL
0x11, // proto UDP
0x32, 0xaf, // header checksum
0x14, 0x00, 0x00, 0x01, // src IP
0x14, 0x00, 0x00, 0x02, // dst IP

// UDP?
0x31, 0x4a, // src port
0x17, 0xc1, // dst port
0x00, 0xf2, // length
0x00, 0x00, // checksum

// Start of geneve header
0x20, // top 2 bits = version 0, bottom 6 bits = options.len = 32 = 0x20 (32 * 4 = 128 bytes)
0x40, 0x65, 0x58, 0x00, 0x00, 0x0a, 0x00,

// Start of geneve option header (4 bytes)
0x00, 0x00, 0x80, 0x1f, // option[0].len = 31 = 0x1f (31 * 4 = 124 bytes)

// Geneve option payload (124 bytes)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b,

// Remainder of packet
0xfe, 0x71, 0xd8, 0x83, 0x72, 0x4f,
0xb6, 0x9e, 0xd2, 0x49, 0x51, 0x48, 0x08, 0x00, 0x45, 0x00, 0x00, 0x54, 0xbd, 0xa2, 0x40, 0x00,
0x40, 0x01, 0x41, 0x04, 0x1e, 0x00, 0x00, 0x01, 0x1e, 0x00, 0x00, 0x02, 0x08, 0x00, 0x2c, 0x54,
0x29, 0x52, 0x00, 0x17, 0xf1, 0xa2, 0xce, 0x54, 0x00, 0x00, 0x00, 0x00, 0x17, 0x78, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
}

func TestDecodeGeneve1(t *testing.T) {
p := gopacket.NewPacket(testPacketGeneve1, LinkTypeLinuxSLL, gopacket.Default)
if p.ErrorLayer() != nil {
Expand Down Expand Up @@ -150,6 +210,42 @@ func TestDecodeGeneve3(t *testing.T) {
}
}

func TestDecodeGeneve4(t *testing.T) {
p := gopacket.NewPacket(testPacketGeneve4, LinkTypeEthernet, gopacket.Default)
if p.ErrorLayer() != nil {
t.Error("Failed to decode packet:", p.ErrorLayer().Error())
}
checkLayers(p, []gopacket.LayerType{
LayerTypeEthernet, LayerTypeIPv4, LayerTypeUDP, LayerTypeGeneve,
LayerTypeEthernet, LayerTypeIPv4, LayerTypeICMPv4, gopacket.LayerTypePayload,
}, t)
if got, ok := p.Layer(LayerTypeGeneve).(*Geneve); ok {
want := &Geneve{
BaseLayer: BaseLayer{
Contents: testPacketGeneve4[42:178],
Payload: testPacketGeneve4[178:276],
},
Version: 0x0,
OptionsLength: 124 + 4,
OAMPacket: false,
CriticalOption: true,
Protocol: EthernetTypeTransparentEthernetBridging,
VNI: 0xa,
Options: []*GeneveOption{
{
Class: 0x0,
Type: 0x80,
Length: 124 + 4,
Data: testMaxSizeOption,
},
},
}
if !reflect.DeepEqual(want, got) {
t.Errorf("Geneve layer mismatch, \nwant %#v\ngot %#v\n", want, got)
}
}
}

func BenchmarkDecodeGeneve1(b *testing.B) {
for i := 0; i < b.N; i++ {
gopacket.NewPacket(testPacketGeneve1, LinkTypeEthernet, gopacket.NoCopy)
Expand Down

0 comments on commit 4472aec

Please sign in to comment.