mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Support TCP options for packetimpact
PiperOrigin-RevId: 312119730
This commit is contained in:
@@ -39,6 +39,7 @@ go_test(
|
||||
library = ":testbench",
|
||||
deps = [
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/header",
|
||||
"@com_github_mohae_deepcopy//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user