diff options
Diffstat (limited to 'pkg/tcpip/header/tcp_test.go')
-rw-r--r-- | pkg/tcpip/header/tcp_test.go | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/pkg/tcpip/header/tcp_test.go b/pkg/tcpip/header/tcp_test.go new file mode 100644 index 000000000..27d43479a --- /dev/null +++ b/pkg/tcpip/header/tcp_test.go @@ -0,0 +1,134 @@ +package header_test + +import ( + "reflect" + "testing" + + "gvisor.googlesource.com/gvisor/pkg/tcpip/header" +) + +func TestEncodeSACKBlocks(t *testing.T) { + testCases := []struct { + sackBlocks []header.SACKBlock + want []header.SACKBlock + bufSize int + }{ + { + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}}, + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}}, + 40, + }, + { + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}}, + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}}, + 30, + }, + { + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}}, + []header.SACKBlock{{10, 20}, {22, 30}}, + 20, + }, + { + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}}, + []header.SACKBlock{{10, 20}}, + 10, + }, + { + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}}, + nil, + 8, + }, + { + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}}, + []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}}, + 60, + }, + } + for _, tc := range testCases { + b := make([]byte, tc.bufSize) + t.Logf("testing: %v", tc) + header.EncodeSACKBlocks(tc.sackBlocks, b) + opts := header.ParseTCPOptions(b) + if got, want := opts.SACKBlocks, tc.want; !reflect.DeepEqual(got, want) { + t.Errorf("header.EncodeSACKBlocks(%v, %v), encoded blocks got: %v, want: %v", tc.sackBlocks, b, got, want) + } + } +} + +func TestTCPParseOptions(t *testing.T) { + type tsOption struct { + tsVal uint32 + tsEcr uint32 + } + + generateOptions := func(tsOpt *tsOption, sackBlocks []header.SACKBlock) []byte { + l := 0 + if tsOpt != nil { + l += 10 + } + if len(sackBlocks) != 0 { + l += len(sackBlocks)*8 + 2 + } + b := make([]byte, l) + offset := 0 + if tsOpt != nil { + offset = header.EncodeTSOption(tsOpt.tsVal, tsOpt.tsEcr, b) + } + header.EncodeSACKBlocks(sackBlocks, b[offset:]) + return b + } + + testCases := []struct { + b []byte + want header.TCPOptions + }{ + // Trivial cases. + {nil, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionNOP}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionNOP, header.TCPOptionNOP}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionEOL}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionNOP, header.TCPOptionEOL, header.TCPOptionTS, 10, 1, 1}, header.TCPOptions{false, 0, 0, nil}}, + + // Test timestamp parsing. + {[]byte{header.TCPOptionNOP, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}}, + {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}}, + + // Test malformed timestamp option. + {[]byte{header.TCPOptionTS, 8, 1, 1}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionNOP, header.TCPOptionTS, 8, 1, 1}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionNOP, header.TCPOptionTS, 8, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}}, + + // Test SACKBlock parsing. + {[]byte{header.TCPOptionSACK, 10, 0, 0, 0, 1, 0, 0, 0, 10}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{1, 10}}}}, + {[]byte{header.TCPOptionSACK, 18, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{1, 10}, {11, 12}}}}, + + // Test malformed SACK option. + {[]byte{header.TCPOptionSACK, 0}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionSACK, 8, 0, 0, 0, 1, 0, 0, 0, 10}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionSACK, 11, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionSACK, 17, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionSACK}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionSACK, 10}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionSACK, 10, 0, 0, 0, 1, 0, 0, 0}, header.TCPOptions{false, 0, 0, nil}}, + + // Test Timestamp + SACK block parsing. + {generateOptions(&tsOption{1, 1}, []header.SACKBlock{{1, 10}, {11, 12}}), header.TCPOptions{true, 1, 1, []header.SACKBlock{{1, 10}, {11, 12}}}}, + {generateOptions(&tsOption{1, 2}, []header.SACKBlock{{1, 10}, {11, 12}}), header.TCPOptions{true, 1, 2, []header.SACKBlock{{1, 10}, {11, 12}}}}, + {generateOptions(&tsOption{1, 3}, []header.SACKBlock{{1, 10}, {11, 12}, {13, 14}, {14, 15}, {15, 16}}), header.TCPOptions{true, 1, 3, []header.SACKBlock{{1, 10}, {11, 12}, {13, 14}, {14, 15}}}}, + + // Test valid timestamp + malformed SACK block parsing. + {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK}, header.TCPOptions{true, 1, 1, nil}}, + {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 10}, header.TCPOptions{true, 1, 1, nil}}, + {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 10, 0, 0, 0}, header.TCPOptions{true, 1, 1, nil}}, + {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 11, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}}, + {[]byte{header.TCPOptionSACK, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}}, + {[]byte{header.TCPOptionSACK, 10, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{134873088, 65536}}}}, + {[]byte{header.TCPOptionSACK, 10, 0, 0, 0, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{8, 167772160}}}}, + {[]byte{header.TCPOptionSACK, 11, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}}, + } + for _, tc := range testCases { + if got, want := header.ParseTCPOptions(tc.b), tc.want; !reflect.DeepEqual(got, want) { + t.Errorf("ParseTCPOptions(%v) = %v, want: %v", tc.b, got, tc.want) + } + } +} |