2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-07-09 21:03:03 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-04-29 01:09:34 +00:00
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
package header_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|