github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/tcpip/header/tcp_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package header_test
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  
    21  	"github.com/google/netstack/tcpip/header"
    22  )
    23  
    24  func TestEncodeSACKBlocks(t *testing.T) {
    25  	testCases := []struct {
    26  		sackBlocks []header.SACKBlock
    27  		want       []header.SACKBlock
    28  		bufSize    int
    29  	}{
    30  		{
    31  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
    32  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}},
    33  			40,
    34  		},
    35  		{
    36  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
    37  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}},
    38  			30,
    39  		},
    40  		{
    41  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
    42  			[]header.SACKBlock{{10, 20}, {22, 30}},
    43  			20,
    44  		},
    45  		{
    46  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
    47  			[]header.SACKBlock{{10, 20}},
    48  			10,
    49  		},
    50  		{
    51  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
    52  			nil,
    53  			8,
    54  		},
    55  		{
    56  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
    57  			[]header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}},
    58  			60,
    59  		},
    60  	}
    61  	for _, tc := range testCases {
    62  		b := make([]byte, tc.bufSize)
    63  		t.Logf("testing: %v", tc)
    64  		header.EncodeSACKBlocks(tc.sackBlocks, b)
    65  		opts := header.ParseTCPOptions(b)
    66  		if got, want := opts.SACKBlocks, tc.want; !reflect.DeepEqual(got, want) {
    67  			t.Errorf("header.EncodeSACKBlocks(%v, %v), encoded blocks got: %v, want: %v", tc.sackBlocks, b, got, want)
    68  		}
    69  	}
    70  }
    71  
    72  func TestTCPParseOptions(t *testing.T) {
    73  	type tsOption struct {
    74  		tsVal uint32
    75  		tsEcr uint32
    76  	}
    77  
    78  	generateOptions := func(tsOpt *tsOption, sackBlocks []header.SACKBlock) []byte {
    79  		l := 0
    80  		if tsOpt != nil {
    81  			l += 10
    82  		}
    83  		if len(sackBlocks) != 0 {
    84  			l += len(sackBlocks)*8 + 2
    85  		}
    86  		b := make([]byte, l)
    87  		offset := 0
    88  		if tsOpt != nil {
    89  			offset = header.EncodeTSOption(tsOpt.tsVal, tsOpt.tsEcr, b)
    90  		}
    91  		header.EncodeSACKBlocks(sackBlocks, b[offset:])
    92  		return b
    93  	}
    94  
    95  	testCases := []struct {
    96  		b    []byte
    97  		want header.TCPOptions
    98  	}{
    99  		// Trivial cases.
   100  		{nil, header.TCPOptions{false, 0, 0, nil}},
   101  		{[]byte{header.TCPOptionNOP}, header.TCPOptions{false, 0, 0, nil}},
   102  		{[]byte{header.TCPOptionNOP, header.TCPOptionNOP}, header.TCPOptions{false, 0, 0, nil}},
   103  		{[]byte{header.TCPOptionEOL}, header.TCPOptions{false, 0, 0, nil}},
   104  		{[]byte{header.TCPOptionNOP, header.TCPOptionEOL, header.TCPOptionTS, 10, 1, 1}, header.TCPOptions{false, 0, 0, nil}},
   105  
   106  		// Test timestamp parsing.
   107  		{[]byte{header.TCPOptionNOP, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}},
   108  		{[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}},
   109  
   110  		// Test malformed timestamp option.
   111  		{[]byte{header.TCPOptionTS, 8, 1, 1}, header.TCPOptions{false, 0, 0, nil}},
   112  		{[]byte{header.TCPOptionNOP, header.TCPOptionTS, 8, 1, 1}, header.TCPOptions{false, 0, 0, nil}},
   113  		{[]byte{header.TCPOptionNOP, header.TCPOptionTS, 8, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}},
   114  
   115  		// Test SACKBlock parsing.
   116  		{[]byte{header.TCPOptionSACK, 10, 0, 0, 0, 1, 0, 0, 0, 10}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{1, 10}}}},
   117  		{[]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}}}},
   118  
   119  		// Test malformed SACK option.
   120  		{[]byte{header.TCPOptionSACK, 0}, header.TCPOptions{false, 0, 0, nil}},
   121  		{[]byte{header.TCPOptionSACK, 8, 0, 0, 0, 1, 0, 0, 0, 10}, header.TCPOptions{false, 0, 0, nil}},
   122  		{[]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}},
   123  		{[]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}},
   124  		{[]byte{header.TCPOptionSACK}, header.TCPOptions{false, 0, 0, nil}},
   125  		{[]byte{header.TCPOptionSACK, 10}, header.TCPOptions{false, 0, 0, nil}},
   126  		{[]byte{header.TCPOptionSACK, 10, 0, 0, 0, 1, 0, 0, 0}, header.TCPOptions{false, 0, 0, nil}},
   127  
   128  		// Test Timestamp + SACK block parsing.
   129  		{generateOptions(&tsOption{1, 1}, []header.SACKBlock{{1, 10}, {11, 12}}), header.TCPOptions{true, 1, 1, []header.SACKBlock{{1, 10}, {11, 12}}}},
   130  		{generateOptions(&tsOption{1, 2}, []header.SACKBlock{{1, 10}, {11, 12}}), header.TCPOptions{true, 1, 2, []header.SACKBlock{{1, 10}, {11, 12}}}},
   131  		{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}}}},
   132  
   133  		// Test valid timestamp + malformed SACK block parsing.
   134  		{[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK}, header.TCPOptions{true, 1, 1, nil}},
   135  		{[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 10}, header.TCPOptions{true, 1, 1, nil}},
   136  		{[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 10, 0, 0, 0}, header.TCPOptions{true, 1, 1, nil}},
   137  		{[]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}},
   138  		{[]byte{header.TCPOptionSACK, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}},
   139  		{[]byte{header.TCPOptionSACK, 10, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{134873088, 65536}}}},
   140  		{[]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}}}},
   141  		{[]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}},
   142  	}
   143  	for _, tc := range testCases {
   144  		if got, want := header.ParseTCPOptions(tc.b), tc.want; !reflect.DeepEqual(got, want) {
   145  			t.Errorf("ParseTCPOptions(%v) = %v, want: %v", tc.b, got, tc.want)
   146  		}
   147  	}
   148  }