github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/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/FlowerWrong/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 }