Support TCP options for packetimpact

PiperOrigin-RevId: 312119730
This commit is contained in:
Zeling Feng
2020-05-18 11:31:38 -07:00
committed by gVisor bot
parent 32ab382c80
commit 99a18ec8b4
3 changed files with 124 additions and 2 deletions
+1
View File
@@ -39,6 +39,7 @@ go_test(
library = ":testbench",
deps = [
"//pkg/tcpip",
"//pkg/tcpip/header",
"@com_github_mohae_deepcopy//:go_default_library",
],
)
+11 -2
View File
@@ -689,6 +689,7 @@ type TCP struct {
WindowSize *uint16
Checksum *uint16
UrgentPointer *uint16
Options []byte
}
func (l *TCP) String() string {
@@ -697,7 +698,7 @@ func (l *TCP) String() string {
// ToBytes implements Layer.ToBytes.
func (l *TCP) ToBytes() ([]byte, error) {
b := make([]byte, header.TCPMinimumSize)
b := make([]byte, l.length())
h := header.TCP(b)
if l.SrcPort != nil {
h.SetSourcePort(*l.SrcPort)
@@ -727,6 +728,8 @@ func (l *TCP) ToBytes() ([]byte, error) {
if l.UrgentPointer != nil {
h.SetUrgentPoiner(*l.UrgentPointer)
}
copy(b[header.TCPMinimumSize:], l.Options)
header.AddTCPOptionPadding(b[header.TCPMinimumSize:], len(l.Options))
if l.Checksum != nil {
h.SetChecksum(*l.Checksum)
return h, nil
@@ -811,6 +814,7 @@ func parseTCP(b []byte) (Layer, layerParser) {
WindowSize: Uint16(h.WindowSize()),
Checksum: Uint16(h.Checksum()),
UrgentPointer: Uint16(h.UrgentPointer()),
Options: b[header.TCPMinimumSize:h.DataOffset()],
}
return &tcp, parsePayload
}
@@ -821,7 +825,12 @@ func (l *TCP) match(other Layer) bool {
func (l *TCP) length() int {
if l.DataOffset == nil {
return header.TCPMinimumSize
// TCP header including the options must end on a 32-bit
// boundary; the user could potentially give us a slice
// whose length is not a multiple of 4 bytes, so we have
// to do the alignment here.
optlen := (len(l.Options) + 3) & ^3
return header.TCPMinimumSize + optlen
}
return int(*l.DataOffset)
}
+112
View File
@@ -15,10 +15,13 @@
package testbench
import (
"bytes"
"net"
"testing"
"github.com/mohae/deepcopy"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
)
func TestLayerMatch(t *testing.T) {
@@ -393,3 +396,112 @@ func TestLayersDiff(t *testing.T) {
}
}
}
func TestTCPOptions(t *testing.T) {
for _, tt := range []struct {
description string
wantBytes []byte
wantLayers Layers
}{
{
description: "without payload",
wantBytes: []byte{
// IPv4 Header
0x45, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
0xf9, 0x77, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01,
// TCP Header
0x30, 0x39, 0xd4, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x02, 0x20, 0x00, 0xf5, 0x1c, 0x00, 0x00,
// WindowScale Option
0x03, 0x03, 0x02,
// NOP Option
0x00,
},
wantLayers: []Layer{
&IPv4{
IHL: Uint8(20),
TOS: Uint8(0),
TotalLength: Uint16(44),
ID: Uint16(1),
Flags: Uint8(0),
FragmentOffset: Uint16(0),
TTL: Uint8(64),
Protocol: Uint8(uint8(header.TCPProtocolNumber)),
Checksum: Uint16(0xf977),
SrcAddr: Address(tcpip.Address(net.ParseIP("192.168.0.2").To4())),
DstAddr: Address(tcpip.Address(net.ParseIP("192.168.0.1").To4())),
},
&TCP{
SrcPort: Uint16(12345),
DstPort: Uint16(54321),
SeqNum: Uint32(0),
AckNum: Uint32(0),
Flags: Uint8(header.TCPFlagSyn),
WindowSize: Uint16(8192),
Checksum: Uint16(0xf51c),
UrgentPointer: Uint16(0),
Options: []byte{3, 3, 2, 0},
},
&Payload{Bytes: nil},
},
},
{
description: "with payload",
wantBytes: []byte{
// IPv4 header
0x45, 0x00, 0x00, 0x37, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
0xf9, 0x6c, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01,
// TCP header
0x30, 0x39, 0xd4, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x02, 0x20, 0x00, 0xe5, 0x21, 0x00, 0x00,
// WindowScale Option
0x03, 0x03, 0x02,
// NOP Option
0x00,
// Payload: "Sample Data"
0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61,
},
wantLayers: []Layer{
&IPv4{
IHL: Uint8(20),
TOS: Uint8(0),
TotalLength: Uint16(55),
ID: Uint16(1),
Flags: Uint8(0),
FragmentOffset: Uint16(0),
TTL: Uint8(64),
Protocol: Uint8(uint8(header.TCPProtocolNumber)),
Checksum: Uint16(0xf96c),
SrcAddr: Address(tcpip.Address(net.ParseIP("192.168.0.2").To4())),
DstAddr: Address(tcpip.Address(net.ParseIP("192.168.0.1").To4())),
},
&TCP{
SrcPort: Uint16(12345),
DstPort: Uint16(54321),
SeqNum: Uint32(0),
AckNum: Uint32(0),
Flags: Uint8(header.TCPFlagSyn),
WindowSize: Uint16(8192),
Checksum: Uint16(0xe521),
UrgentPointer: Uint16(0),
Options: []byte{3, 3, 2, 0},
},
&Payload{Bytes: []byte("Sample Data")},
},
},
} {
t.Run(tt.description, func(t *testing.T) {
layers := parse(parseIPv4, tt.wantBytes)
if !layers.match(tt.wantLayers) {
t.Fatalf("match failed with diff: %s", layers.diff(tt.wantLayers))
}
gotBytes, err := layers.ToBytes()
if err != nil {
t.Fatalf("ToBytes() failed on %s: %s", &layers, err)
}
if !bytes.Equal(tt.wantBytes, gotBytes) {
t.Fatalf("mismatching bytes, gotBytes: %x, wantBytes: %x", gotBytes, tt.wantBytes)
}
})
}
}