golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/transport_params_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.21 6 7 package quic 8 9 import ( 10 "bytes" 11 "math" 12 "net/netip" 13 "reflect" 14 "testing" 15 "time" 16 ) 17 18 func TestTransportParametersMarshalUnmarshal(t *testing.T) { 19 for _, test := range []struct { 20 params func(p *transportParameters) 21 enc []byte 22 }{{ 23 params: func(p *transportParameters) { 24 p.originalDstConnID = []byte("connid") 25 }, 26 enc: []byte{ 27 0x00, // original_destination_connection_id 28 byte(len("connid")), 29 'c', 'o', 'n', 'n', 'i', 'd', 30 }, 31 }, { 32 params: func(p *transportParameters) { 33 p.maxIdleTimeout = 10 * time.Millisecond 34 }, 35 enc: []byte{ 36 0x01, // max_idle_timeout 37 1, // length 38 10, // varint msecs 39 }, 40 }, { 41 params: func(p *transportParameters) { 42 p.statelessResetToken = []byte("0123456789abcdef") 43 }, 44 enc: []byte{ 45 0x02, // stateless_reset_token 46 16, // length 47 '0', '1', '2', '3', '4', '5', '6', '7', 48 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', // reset token 49 }, 50 }, { 51 params: func(p *transportParameters) { 52 p.maxUDPPayloadSize = 1200 53 }, 54 enc: []byte{ 55 0x03, // max_udp_payload_size 56 2, // length 57 0x44, 0xb0, // varint value 58 }, 59 }, { 60 params: func(p *transportParameters) { 61 p.initialMaxData = 10 62 }, 63 enc: []byte{ 64 0x04, // initial_max_data 65 1, // length 66 10, // varint value 67 }, 68 }, { 69 params: func(p *transportParameters) { 70 p.initialMaxStreamDataBidiLocal = 10 71 }, 72 enc: []byte{ 73 0x05, // initial_max_stream_data_bidi_local 74 1, // length 75 10, // varint value 76 }, 77 }, { 78 params: func(p *transportParameters) { 79 p.initialMaxStreamDataBidiRemote = 10 80 }, 81 enc: []byte{ 82 0x06, // initial_max_stream_data_bidi_remote 83 1, // length 84 10, // varint value 85 }, 86 }, { 87 params: func(p *transportParameters) { 88 p.initialMaxStreamDataUni = 10 89 }, 90 enc: []byte{ 91 0x07, // initial_max_stream_data_uni 92 1, // length 93 10, // varint value 94 }, 95 }, { 96 params: func(p *transportParameters) { 97 p.initialMaxStreamsBidi = 10 98 }, 99 enc: []byte{ 100 0x08, // initial_max_streams_bidi 101 1, // length 102 10, // varint value 103 }, 104 }, { 105 params: func(p *transportParameters) { 106 p.initialMaxStreamsUni = 10 107 }, 108 enc: []byte{ 109 0x09, // initial_max_streams_uni 110 1, // length 111 10, // varint value 112 }, 113 }, { 114 params: func(p *transportParameters) { 115 p.ackDelayExponent = 4 116 }, 117 enc: []byte{ 118 0x0a, // ack_delay_exponent 119 1, // length 120 4, // varint value 121 }, 122 }, { 123 params: func(p *transportParameters) { 124 p.maxAckDelay = 10 * time.Millisecond 125 }, 126 enc: []byte{ 127 0x0b, // max_ack_delay 128 1, // length 129 10, // varint value 130 }, 131 }, { 132 params: func(p *transportParameters) { 133 p.disableActiveMigration = true 134 }, 135 enc: []byte{ 136 0x0c, // disable_active_migration 137 0, // length 138 }, 139 }, { 140 params: func(p *transportParameters) { 141 p.preferredAddrV4 = netip.MustParseAddrPort("127.0.0.1:80") 142 p.preferredAddrV6 = netip.MustParseAddrPort("[fe80::1]:1024") 143 p.preferredAddrConnID = []byte("connid") 144 p.preferredAddrResetToken = []byte("0123456789abcdef") 145 }, 146 enc: []byte{ 147 0x0d, // preferred_address 148 byte(4 + 2 + 16 + 2 + 1 + len("connid") + 16), // length 149 127, 0, 0, 1, // v4 address 150 0, 80, // v4 port 151 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // v6 address 152 0x04, 0x00, // v6 port, 153 6, // connection id length 154 'c', 'o', 'n', 'n', 'i', 'd', // connection id 155 '0', '1', '2', '3', '4', '5', '6', '7', 156 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', // reset token 157 }, 158 }, { 159 params: func(p *transportParameters) { 160 p.activeConnIDLimit = 10 161 }, 162 enc: []byte{ 163 0x0e, // active_connection_id_limit 164 1, // length 165 10, // varint value 166 }, 167 }, { 168 params: func(p *transportParameters) { 169 p.initialSrcConnID = []byte("connid") 170 }, 171 enc: []byte{ 172 0x0f, // initial_source_connection_id 173 byte(len("connid")), 174 'c', 'o', 'n', 'n', 'i', 'd', 175 }, 176 }, { 177 params: func(p *transportParameters) { 178 p.retrySrcConnID = []byte("connid") 179 }, 180 enc: []byte{ 181 0x10, // retry_source_connection_id 182 byte(len("connid")), 183 'c', 'o', 'n', 'n', 'i', 'd', 184 }, 185 }} { 186 wantParams := defaultTransportParameters() 187 test.params(&wantParams) 188 gotBytes := marshalTransportParameters(wantParams) 189 if !bytes.Equal(gotBytes, test.enc) { 190 t.Errorf("marshalTransportParameters(%#v):\n got: %x\nwant: %x", wantParams, gotBytes, test.enc) 191 } 192 gotParams, err := unmarshalTransportParams(test.enc) 193 if err != nil { 194 t.Errorf("unmarshalTransportParams(%x): unexpected error: %v", test.enc, err) 195 } else if !reflect.DeepEqual(gotParams, wantParams) { 196 t.Errorf("unmarshalTransportParams(%x):\n got: %#v\nwant: %#v", test.enc, gotParams, wantParams) 197 } 198 } 199 } 200 201 func TestTransportParametersErrors(t *testing.T) { 202 for _, test := range []struct { 203 desc string 204 enc []byte 205 }{{ 206 desc: "invalid id", 207 enc: []byte{ 208 0x40, // too short 209 }, 210 }, { 211 desc: "parameter too short", 212 enc: []byte{ 213 0x00, // original_destination_connection_id 214 0x04, // length 215 1, 2, 3, // not enough data 216 }, 217 }, { 218 desc: "extra data in parameter", 219 enc: []byte{ 220 0x01, // max_idle_timeout 221 2, // length 222 10, // varint msecs 223 0, // extra junk 224 }, 225 }, { 226 desc: "invalid varint in parameter", 227 enc: []byte{ 228 0x01, // max_idle_timeout 229 1, // length 230 0x40, // incomplete varint 231 }, 232 }, { 233 desc: "stateless_reset_token not 16 bytes", 234 enc: []byte{ 235 0x02, // stateless_reset_token, 236 15, // length 237 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 238 }, 239 }, { 240 desc: "initial_max_streams_bidi is too large", 241 enc: []byte{ 242 0x08, // initial_max_streams_bidi, 243 8, // length, 244 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 245 }, 246 }, { 247 desc: "initial_max_streams_uni is too large", 248 enc: []byte{ 249 0x08, // initial_max_streams_uni, 250 9, // length, 251 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 252 }, 253 }, { 254 desc: "preferred_address is too short", 255 enc: []byte{ 256 0x0d, // preferred_address 257 byte(3), 258 127, 0, 0, 259 }, 260 }, { 261 desc: "preferred_address reset token too short", 262 enc: []byte{ 263 0x0d, // preferred_address 264 byte(4 + 2 + 16 + 2 + 1 + len("connid") + 15), // length 265 127, 0, 0, 1, // v4 address 266 0, 80, // v4 port 267 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // v6 address 268 0x04, 0x00, // v6 port, 269 6, // connection id length 270 'c', 'o', 'n', 'n', 'i', 'd', // connection id 271 '0', '1', '2', '3', '4', '5', '6', '7', 272 '8', '9', 'a', 'b', 'c', 'd', 'e', // reset token, one byte too short 273 274 }, 275 }, { 276 desc: "preferred_address conn id too long", 277 enc: []byte{ 278 0x0d, // preferred_address 279 byte(4 + 2 + 16 + 2 + 1 + len("connid") + 16), // length 280 127, 0, 0, 1, // v4 address 281 0, 80, // v4 port 282 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // v6 address 283 0x04, 0x00, // v6 port, 284 byte(len("connid")) + 16 + 1, // connection id length, too long 285 'c', 'o', 'n', 'n', 'i', 'd', // connection id 286 '0', '1', '2', '3', '4', '5', '6', '7', 287 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', // reset token 288 289 }, 290 }} { 291 _, err := unmarshalTransportParams(test.enc) 292 if err == nil { 293 t.Errorf("%v:\nunmarshalTransportParams(%x): unexpectedly succeeded", test.desc, test.enc) 294 } 295 } 296 } 297 298 func TestTransportParametersRangeErrors(t *testing.T) { 299 for _, test := range []struct { 300 desc string 301 params func(p *transportParameters) 302 }{{ 303 desc: "max_udp_payload_size < 1200", 304 params: func(p *transportParameters) { 305 p.maxUDPPayloadSize = 1199 306 }, 307 }, { 308 desc: "ack_delay_exponent > 20", 309 params: func(p *transportParameters) { 310 p.ackDelayExponent = 21 311 }, 312 }, { 313 desc: "max_ack_delay > 1^14 ms", 314 params: func(p *transportParameters) { 315 p.maxAckDelay = (1 << 14) * time.Millisecond 316 }, 317 }, { 318 desc: "active_connection_id_limit < 2", 319 params: func(p *transportParameters) { 320 p.activeConnIDLimit = 1 321 }, 322 }} { 323 p := defaultTransportParameters() 324 test.params(&p) 325 enc := marshalTransportParameters(p) 326 _, err := unmarshalTransportParams(enc) 327 if err == nil { 328 t.Errorf("%v: unmarshalTransportParams unexpectedly succeeded", test.desc) 329 } 330 } 331 } 332 333 func TestTransportParameterMaxIdleTimeoutOverflowsDuration(t *testing.T) { 334 tooManyMS := 1 + (math.MaxInt64 / uint64(time.Millisecond)) 335 336 var enc []byte 337 enc = appendVarint(enc, paramMaxIdleTimeout) 338 enc = appendVarint(enc, uint64(sizeVarint(tooManyMS))) 339 enc = appendVarint(enc, uint64(tooManyMS)) 340 341 dec, err := unmarshalTransportParams(enc) 342 if err != nil { 343 t.Fatalf("unmarshalTransportParameters(enc) = %v", err) 344 } 345 if got, want := dec.maxIdleTimeout, time.Duration(0); got != want { 346 t.Errorf("max_idle_timeout=%v, got maxIdleTimeout=%v; want %v", tooManyMS, got, want) 347 } 348 } 349 350 func TestTransportParametersSkipUnknownParameters(t *testing.T) { 351 enc := []byte{ 352 0x20, // unknown transport parameter 353 1, // length 354 0, // varint value 355 356 0x04, // initial_max_data 357 1, // length 358 10, // varint value 359 360 0x21, // unknown transport parameter 361 1, // length 362 0, // varint value 363 } 364 dec, err := unmarshalTransportParams(enc) 365 if err != nil { 366 t.Fatalf("unmarshalTransportParameters(enc) = %v", err) 367 } 368 if got, want := dec.initialMaxData, int64(10); got != want { 369 t.Errorf("got initial_max_data=%v; want %v", got, want) 370 } 371 } 372 373 func FuzzTransportParametersMarshalUnmarshal(f *testing.F) { 374 f.Fuzz(func(t *testing.T, in []byte) { 375 p1, err := unmarshalTransportParams(in) 376 if err != nil { 377 return 378 } 379 out := marshalTransportParameters(p1) 380 p2, err := unmarshalTransportParams(out) 381 if err != nil { 382 t.Fatalf("round trip unmarshal/remarshal: unmarshal error: %v\n%x", err, in) 383 } 384 if !reflect.DeepEqual(p1, p2) { 385 t.Fatalf("round trip unmarshal/remarshal: parameters differ:\n%x\n%#v\n%#v", in, p1, p2) 386 } 387 }) 388 }