github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/dialParameters_test.go (about) 1 /* 2 * Copyright (c) 2018, Psiphon Inc. 3 * All rights reserved. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package psiphon 21 22 import ( 23 "bytes" 24 "encoding/json" 25 "fmt" 26 "io/ioutil" 27 "os" 28 "reflect" 29 "testing" 30 "time" 31 32 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 33 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters" 34 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" 35 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol" 36 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values" 37 ) 38 39 func TestDialParametersAndReplay(t *testing.T) { 40 for _, tunnelProtocol := range protocol.SupportedTunnelProtocols { 41 if !common.Contains(protocol.DefaultDisabledTunnelProtocols, tunnelProtocol) { 42 runDialParametersAndReplay(t, tunnelProtocol) 43 } 44 } 45 } 46 47 var testNetworkID = prng.HexString(8) 48 49 type testNetworkGetter struct { 50 } 51 52 func (t *testNetworkGetter) GetNetworkID() string { 53 return testNetworkID 54 } 55 56 func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) { 57 58 t.Logf("Test %s...", tunnelProtocol) 59 60 testDataDirName, err := ioutil.TempDir("", "psiphon-dial-parameters-test") 61 if err != nil { 62 t.Fatalf("TempDir failed: %s", err) 63 } 64 defer os.RemoveAll(testDataDirName) 65 66 SetNoticeWriter(ioutil.Discard) 67 68 clientConfig := &Config{ 69 PropagationChannelId: "0", 70 SponsorId: "0", 71 DataRootDirectory: testDataDirName, 72 NetworkIDGetter: new(testNetworkGetter), 73 } 74 75 err = clientConfig.Commit(false) 76 if err != nil { 77 t.Fatalf("error committing configuration file: %s", err) 78 } 79 80 holdOffTunnelProtocols := protocol.TunnelProtocols{protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH} 81 frontingProviderID := prng.HexString(8) 82 83 applyParameters := make(map[string]interface{}) 84 applyParameters[parameters.TransformHostNameProbability] = 1.0 85 applyParameters[parameters.PickUserAgentProbability] = 1.0 86 applyParameters[parameters.HoldOffTunnelMinDuration] = "1ms" 87 applyParameters[parameters.HoldOffTunnelMaxDuration] = "10ms" 88 applyParameters[parameters.HoldOffTunnelProtocols] = holdOffTunnelProtocols 89 applyParameters[parameters.HoldOffTunnelFrontingProviderIDs] = []string{frontingProviderID} 90 applyParameters[parameters.HoldOffTunnelProbability] = 1.0 91 applyParameters[parameters.DNSResolverAlternateServers] = []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"} 92 err = clientConfig.SetParameters("tag1", false, applyParameters) 93 if err != nil { 94 t.Fatalf("SetParameters failed: %s", err) 95 } 96 97 resolver := NewResolver(clientConfig, true) 98 defer resolver.Stop() 99 clientConfig.SetResolver(resolver) 100 101 err = OpenDataStore(clientConfig) 102 if err != nil { 103 t.Fatalf("error initializing client datastore: %s", err) 104 } 105 defer CloseDataStore() 106 107 serverEntries := makeMockServerEntries(tunnelProtocol, frontingProviderID, 100) 108 109 canReplay := func(serverEntry *protocol.ServerEntry, replayProtocol string) bool { 110 return replayProtocol == tunnelProtocol 111 } 112 113 selectProtocol := func(serverEntry *protocol.ServerEntry) (string, bool) { 114 return tunnelProtocol, true 115 } 116 117 values.SetSSHClientVersionsSpec( 118 values.NewPickOneSpec([]string{"SSH-2.0-A", "SSH-2.0-B", "SSH-2.0-C"})) 119 120 values.SetUserAgentsSpec( 121 values.NewPickOneSpec([]string{"ua1", "ua2", "ua3"})) 122 123 // Test: expected dial parameter fields set 124 125 upstreamProxyErrorCallback := func(_ error) {} 126 127 dialParams, err := MakeDialParameters( 128 clientConfig, upstreamProxyErrorCallback, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 129 if err != nil { 130 t.Fatalf("MakeDialParameters failed: %s", err) 131 } 132 133 if dialParams.ServerEntry != serverEntries[0] { 134 t.Fatalf("unexpected server entry") 135 } 136 137 if dialParams.NetworkID != testNetworkID { 138 t.Fatalf("unexpected network ID") 139 } 140 141 if dialParams.IsReplay { 142 t.Fatalf("unexpected replay") 143 } 144 145 if dialParams.TunnelProtocol != tunnelProtocol { 146 t.Fatalf("unexpected tunnel protocol") 147 } 148 149 if !protocol.TunnelProtocolUsesMeek(tunnelProtocol) && 150 dialParams.DirectDialAddress == "" { 151 t.Fatalf("missing direct dial fields") 152 } 153 154 if dialParams.DialPortNumber == "" { 155 t.Fatalf("missing port number fields") 156 } 157 158 if !dialParams.SelectedSSHClientVersion || dialParams.SSHClientVersion == "" || dialParams.SSHKEXSeed == nil { 159 t.Fatalf("missing SSH fields") 160 } 161 162 if protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) && 163 dialParams.ObfuscatorPaddingSeed == nil { 164 t.Fatalf("missing obfuscator fields") 165 } 166 167 if dialParams.FragmentorSeed == nil { 168 t.Fatalf("missing fragmentor field") 169 } 170 171 if protocol.TunnelProtocolUsesMeek(tunnelProtocol) && 172 (dialParams.MeekDialAddress == "" || 173 dialParams.MeekHostHeader == "" || 174 dialParams.MeekObfuscatorPaddingSeed == nil) { 175 t.Fatalf("missing meek fields") 176 } 177 178 if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) && 179 (dialParams.MeekFrontingDialAddress == "" || 180 dialParams.MeekFrontingHost == "" || 181 dialParams.ResolveParameters == nil) { 182 t.Fatalf("missing meek fronting fields") 183 } 184 185 if protocol.TunnelProtocolUsesMeekHTTP(tunnelProtocol) && 186 dialParams.UserAgent == "" { 187 t.Fatalf("missing meek HTTP fields") 188 } 189 190 if protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) && 191 (dialParams.MeekSNIServerName == "" || 192 !dialParams.SelectedTLSProfile || 193 dialParams.TLSProfile == "") { 194 t.Fatalf("missing meek HTTPS fields") 195 } 196 197 if protocol.TunnelProtocolUsesQUIC(tunnelProtocol) { 198 if dialParams.QUICVersion == "" { 199 t.Fatalf("missing QUIC version field") 200 } 201 if protocol.TunnelProtocolUsesFrontedMeekQUIC(tunnelProtocol) { 202 if dialParams.MeekFrontingDialAddress == "" || 203 dialParams.MeekFrontingHost == "" || 204 dialParams.MeekSNIServerName == "" { 205 t.Fatalf("missing fronted QUIC fields") 206 } 207 } else { 208 if dialParams.QUICDialSNIAddress == "" { 209 t.Fatalf("missing QUIC SNI field") 210 } 211 } 212 } 213 214 if dialParams.LivenessTestSeed == nil { 215 t.Fatalf("missing liveness test fields") 216 } 217 218 if dialParams.APIRequestPaddingSeed == nil { 219 t.Fatalf("missing API request fields") 220 } 221 222 if common.Contains(holdOffTunnelProtocols, tunnelProtocol) || 223 protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) { 224 if dialParams.HoldOffTunnelDuration < 1*time.Millisecond || 225 dialParams.HoldOffTunnelDuration > 10*time.Millisecond { 226 t.Fatalf("unexpected hold-off duration: %v", dialParams.HoldOffTunnelDuration) 227 } 228 } else { 229 if dialParams.HoldOffTunnelDuration != 0 { 230 t.Fatalf("unexpected hold-off duration: %v", dialParams.HoldOffTunnelDuration) 231 } 232 } 233 234 dialConfig := dialParams.GetDialConfig() 235 if dialConfig.UpstreamProxyErrorCallback == nil { 236 t.Fatalf("missing upstreamProxyErrorCallback") 237 } 238 239 // Test: no replay after dial reported to fail 240 241 dialParams.Failed(clientConfig) 242 243 dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 244 if err != nil { 245 t.Fatalf("MakeDialParameters failed: %s", err) 246 } 247 248 if dialParams.IsReplay { 249 t.Fatalf("unexpected replay") 250 } 251 252 // Test: no replay after network ID changes 253 254 dialParams.Succeeded() 255 256 testNetworkID = prng.HexString(8) 257 258 dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 259 if err != nil { 260 t.Fatalf("MakeDialParameters failed: %s", err) 261 } 262 263 if dialParams.NetworkID != testNetworkID { 264 t.Fatalf("unexpected network ID") 265 } 266 267 if dialParams.IsReplay { 268 t.Fatalf("unexpected replay") 269 } 270 271 // Test: replay after dial reported to succeed, and replay fields match previous dial parameters 272 273 dialParams.Succeeded() 274 275 replayDialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 276 if err != nil { 277 t.Fatalf("MakeDialParameters failed: %s", err) 278 } 279 280 if !replayDialParams.IsReplay { 281 t.Fatalf("unexpected non-replay") 282 } 283 284 if !replayDialParams.LastUsedTimestamp.After(dialParams.LastUsedTimestamp) { 285 t.Fatalf("unexpected non-updated timestamp") 286 } 287 288 if replayDialParams.TunnelProtocol != dialParams.TunnelProtocol { 289 t.Fatalf("mismatching tunnel protocol") 290 } 291 292 if replayDialParams.DirectDialAddress != dialParams.DirectDialAddress || 293 replayDialParams.DialPortNumber != dialParams.DialPortNumber { 294 t.Fatalf("mismatching dial fields") 295 } 296 297 identicalSeeds := func(seed1, seed2 *prng.Seed) bool { 298 if seed1 == nil { 299 return seed2 == nil 300 } 301 return bytes.Equal(seed1[:], seed2[:]) 302 } 303 304 if replayDialParams.SelectedSSHClientVersion != dialParams.SelectedSSHClientVersion || 305 replayDialParams.SSHClientVersion != dialParams.SSHClientVersion || 306 !identicalSeeds(replayDialParams.SSHKEXSeed, dialParams.SSHKEXSeed) { 307 t.Fatalf("mismatching SSH fields") 308 } 309 310 if !identicalSeeds(replayDialParams.ObfuscatorPaddingSeed, dialParams.ObfuscatorPaddingSeed) { 311 t.Fatalf("mismatching obfuscator fields") 312 } 313 314 if !identicalSeeds(replayDialParams.FragmentorSeed, dialParams.FragmentorSeed) { 315 t.Fatalf("mismatching fragmentor fields") 316 } 317 318 if replayDialParams.MeekFrontingDialAddress != dialParams.MeekFrontingDialAddress || 319 replayDialParams.MeekFrontingHost != dialParams.MeekFrontingHost || 320 replayDialParams.MeekDialAddress != dialParams.MeekDialAddress || 321 replayDialParams.MeekTransformedHostName != dialParams.MeekTransformedHostName || 322 replayDialParams.MeekSNIServerName != dialParams.MeekSNIServerName || 323 replayDialParams.MeekHostHeader != dialParams.MeekHostHeader || 324 !identicalSeeds(replayDialParams.MeekObfuscatorPaddingSeed, dialParams.MeekObfuscatorPaddingSeed) { 325 t.Fatalf("mismatching meek fields") 326 } 327 328 if replayDialParams.SelectedUserAgent != dialParams.SelectedUserAgent || 329 replayDialParams.UserAgent != dialParams.UserAgent { 330 t.Fatalf("mismatching user agent fields") 331 } 332 333 if replayDialParams.SelectedTLSProfile != dialParams.SelectedTLSProfile || 334 replayDialParams.TLSProfile != dialParams.TLSProfile || 335 !identicalSeeds(replayDialParams.RandomizedTLSProfileSeed, dialParams.RandomizedTLSProfileSeed) { 336 t.Fatalf("mismatching TLS fields") 337 } 338 339 if replayDialParams.QUICVersion != dialParams.QUICVersion || 340 replayDialParams.QUICDialSNIAddress != dialParams.QUICDialSNIAddress || 341 !identicalSeeds(replayDialParams.ObfuscatedQUICPaddingSeed, dialParams.ObfuscatedQUICPaddingSeed) { 342 t.Fatalf("mismatching QUIC fields") 343 } 344 345 if !identicalSeeds(replayDialParams.LivenessTestSeed, dialParams.LivenessTestSeed) { 346 t.Fatalf("mismatching liveness test fields") 347 } 348 349 if !identicalSeeds(replayDialParams.APIRequestPaddingSeed, dialParams.APIRequestPaddingSeed) { 350 t.Fatalf("mismatching API request fields") 351 } 352 353 if (replayDialParams.ResolveParameters == nil) != (dialParams.ResolveParameters == nil) || 354 (replayDialParams.ResolveParameters != nil && 355 !reflect.DeepEqual(replayDialParams.ResolveParameters, dialParams.ResolveParameters)) { 356 t.Fatalf("mismatching ResolveParameters fields") 357 } 358 359 // Test: no replay after change tactics 360 361 applyParameters[parameters.ReplayDialParametersTTL] = "1s" 362 err = clientConfig.SetParameters("tag2", false, applyParameters) 363 if err != nil { 364 t.Fatalf("SetParameters failed: %s", err) 365 } 366 367 dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 368 if err != nil { 369 t.Fatalf("MakeDialParameters failed: %s", err) 370 } 371 372 if dialParams.IsReplay { 373 t.Fatalf("unexpected replay") 374 } 375 376 // Test: no replay after dial parameters expired 377 378 dialParams.Succeeded() 379 380 time.Sleep(1 * time.Second) 381 382 dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 383 if err != nil { 384 t.Fatalf("MakeDialParameters failed: %s", err) 385 } 386 387 if dialParams.IsReplay { 388 t.Fatalf("unexpected replay") 389 } 390 391 // Test: no replay after server entry changes 392 393 dialParams.Succeeded() 394 395 serverEntries[0].ConfigurationVersion += 1 396 397 dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 398 if err != nil { 399 t.Fatalf("MakeDialParameters failed: %s", err) 400 } 401 402 if dialParams.IsReplay { 403 t.Fatalf("unexpected replay") 404 } 405 406 // Test: disable replay elements (partial coverage) 407 408 applyParameters[parameters.ReplayDialParametersTTL] = "24h" 409 applyParameters[parameters.ReplaySSH] = false 410 applyParameters[parameters.ReplayObfuscatorPadding] = false 411 applyParameters[parameters.ReplayFragmentor] = false 412 applyParameters[parameters.ReplayRandomizedTLSProfile] = false 413 applyParameters[parameters.ReplayObfuscatedQUIC] = false 414 applyParameters[parameters.ReplayLivenessTest] = false 415 applyParameters[parameters.ReplayAPIRequestPadding] = false 416 err = clientConfig.SetParameters("tag3", false, applyParameters) 417 if err != nil { 418 t.Fatalf("SetParameters failed: %s", err) 419 } 420 421 dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 422 if err != nil { 423 t.Fatalf("MakeDialParameters failed: %s", err) 424 } 425 426 dialParams.Succeeded() 427 428 replayDialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 429 if err != nil { 430 t.Fatalf("MakeDialParameters failed: %s", err) 431 } 432 433 if !replayDialParams.IsReplay { 434 t.Fatalf("unexpected non-replay") 435 } 436 437 if identicalSeeds(replayDialParams.SSHKEXSeed, dialParams.SSHKEXSeed) || 438 (protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) && 439 identicalSeeds(replayDialParams.ObfuscatorPaddingSeed, dialParams.ObfuscatorPaddingSeed)) || 440 identicalSeeds(replayDialParams.FragmentorSeed, dialParams.FragmentorSeed) || 441 (protocol.TunnelProtocolUsesMeek(tunnelProtocol) && 442 identicalSeeds(replayDialParams.MeekObfuscatorPaddingSeed, dialParams.MeekObfuscatorPaddingSeed)) || 443 (protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) && 444 identicalSeeds(replayDialParams.RandomizedTLSProfileSeed, dialParams.RandomizedTLSProfileSeed) && 445 replayDialParams.RandomizedTLSProfileSeed != nil) || 446 (protocol.TunnelProtocolUsesQUIC(tunnelProtocol) && 447 identicalSeeds(replayDialParams.ObfuscatedQUICPaddingSeed, dialParams.ObfuscatedQUICPaddingSeed) && 448 replayDialParams.ObfuscatedQUICPaddingSeed != nil) || 449 identicalSeeds(replayDialParams.LivenessTestSeed, dialParams.LivenessTestSeed) || 450 identicalSeeds(replayDialParams.APIRequestPaddingSeed, dialParams.APIRequestPaddingSeed) { 451 t.Fatalf("unexpected replayed fields") 452 } 453 454 // Test: client-side restrict fronting provider ID 455 456 applyParameters[parameters.RestrictFrontingProviderIDs] = []string{frontingProviderID} 457 applyParameters[parameters.RestrictFrontingProviderIDsClientProbability] = 1.0 458 err = clientConfig.SetParameters("tag4", false, applyParameters) 459 if err != nil { 460 t.Fatalf("SetParameters failed: %s", err) 461 } 462 463 dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0) 464 465 if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) { 466 if err == nil { 467 if dialParams != nil { 468 t.Fatalf("unexpected MakeDialParameters success") 469 } 470 } 471 } else { 472 if err != nil { 473 t.Fatalf("MakeDialParameters failed: %s", err) 474 } 475 } 476 477 applyParameters[parameters.RestrictFrontingProviderIDsClientProbability] = 0.0 478 err = clientConfig.SetParameters("tag5", false, applyParameters) 479 if err != nil { 480 t.Fatalf("SetParameters failed: %s", err) 481 } 482 483 // Test: iterator shuffles 484 485 for i, serverEntry := range serverEntries { 486 487 data, err := json.Marshal(serverEntry) 488 if err != nil { 489 t.Fatalf("json.Marshal failed: %s", err) 490 } 491 492 var serverEntryFields protocol.ServerEntryFields 493 err = json.Unmarshal(data, &serverEntryFields) 494 if err != nil { 495 t.Fatalf("json.Unmarshal failed: %s", err) 496 } 497 498 err = StoreServerEntry(serverEntryFields, false) 499 if err != nil { 500 t.Fatalf("StoreServerEntry failed: %s", err) 501 } 502 503 if i%10 == 0 { 504 505 dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0) 506 if err != nil { 507 t.Fatalf("MakeDialParameters failed: %s", err) 508 } 509 510 dialParams.Succeeded() 511 } 512 } 513 514 for i := 0; i < 5; i++ { 515 516 hasAffinity, iterator, err := NewServerEntryIterator(clientConfig) 517 if err != nil { 518 t.Fatalf("NewServerEntryIterator failed: %s", err) 519 } 520 521 if hasAffinity { 522 t.Fatalf("unexpected affinity server") 523 } 524 525 // Test: the first shuffle should move the replay candidates to the front 526 527 for j := 0; j < 10; j++ { 528 529 serverEntry, err := iterator.Next() 530 if err != nil { 531 t.Fatalf("ServerEntryIterator.Next failed: %s", err) 532 } 533 534 dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0) 535 if err != nil { 536 t.Fatalf("MakeDialParameters failed: %s", err) 537 } 538 539 if !dialParams.IsReplay { 540 t.Fatalf("unexpected non-replay") 541 } 542 } 543 544 iterator.Reset() 545 546 // Test: subsequent shuffles should not move the replay candidates 547 548 allReplay := true 549 for j := 0; j < 10; j++ { 550 551 serverEntry, err := iterator.Next() 552 if err != nil { 553 t.Fatalf("ServerEntryIterator.Next failed: %s", err) 554 } 555 556 dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0) 557 if err != nil { 558 t.Fatalf("MakeDialParameters failed: %s", err) 559 } 560 561 if !dialParams.IsReplay { 562 allReplay = false 563 } 564 } 565 566 if allReplay { 567 t.Fatalf("unexpected all replay") 568 } 569 570 iterator.Close() 571 } 572 } 573 574 func TestLimitTunnelDialPortNumbers(t *testing.T) { 575 576 testDataDirName, err := ioutil.TempDir("", "psiphon-limit-tunnel-dial-port-numbers-test") 577 if err != nil { 578 t.Fatalf("TempDir failed: %s", err) 579 } 580 defer os.RemoveAll(testDataDirName) 581 582 SetNoticeWriter(ioutil.Discard) 583 584 clientConfig := &Config{ 585 PropagationChannelId: "0", 586 SponsorId: "0", 587 DataRootDirectory: testDataDirName, 588 NetworkIDGetter: new(testNetworkGetter), 589 } 590 591 err = clientConfig.Commit(false) 592 if err != nil { 593 t.Fatalf("error committing configuration file: %s", err) 594 } 595 596 jsonLimitDialPortNumbers := ` 597 { 598 "SSH" : [[10,11]], 599 "OSSH" : [[20,21]], 600 "QUIC-OSSH" : [[30,31]], 601 "TAPDANCE-OSSH" : [[40,41]], 602 "CONJURE-OSSH" : [[50,51]], 603 "All" : [[60,61],80,443] 604 } 605 ` 606 607 var limitTunnelDialPortNumbers parameters.TunnelProtocolPortLists 608 err = json.Unmarshal([]byte(jsonLimitDialPortNumbers), &limitTunnelDialPortNumbers) 609 if err != nil { 610 t.Fatalf("Unmarshal failed: %s", err) 611 } 612 613 applyParameters := make(map[string]interface{}) 614 applyParameters[parameters.LimitTunnelDialPortNumbers] = limitTunnelDialPortNumbers 615 applyParameters[parameters.LimitTunnelDialPortNumbersProbability] = 1.0 616 err = clientConfig.SetParameters("tag1", false, applyParameters) 617 if err != nil { 618 t.Fatalf("SetParameters failed: %s", err) 619 } 620 621 constraints := &protocolSelectionConstraints{ 622 limitTunnelDialPortNumbers: protocol.TunnelProtocolPortLists( 623 clientConfig.GetParameters().Get().TunnelProtocolPortLists(parameters.LimitTunnelDialPortNumbers)), 624 } 625 626 selectProtocol := func(serverEntry *protocol.ServerEntry) (string, bool) { 627 return constraints.selectProtocol(0, false, serverEntry) 628 } 629 630 for _, tunnelProtocol := range protocol.SupportedTunnelProtocols { 631 632 if common.Contains(protocol.DefaultDisabledTunnelProtocols, tunnelProtocol) { 633 continue 634 } 635 636 serverEntries := makeMockServerEntries(tunnelProtocol, "", 100) 637 638 selected := false 639 skipped := false 640 641 for _, serverEntry := range serverEntries { 642 643 selectedProtocol, ok := selectProtocol(serverEntry) 644 645 if ok { 646 647 if selectedProtocol != tunnelProtocol { 648 t.Fatalf("unexpected selected protocol: %s", selectedProtocol) 649 } 650 651 port, err := serverEntry.GetDialPortNumber(selectedProtocol) 652 if err != nil { 653 t.Fatalf("GetDialPortNumber failed: %s", err) 654 } 655 656 if port%10 != 0 && port%10 != 1 && !protocol.TunnelProtocolUsesFrontedMeek(selectedProtocol) { 657 t.Fatalf("unexpected dial port number: %d", port) 658 } 659 660 selected = true 661 662 } else { 663 664 skipped = true 665 } 666 } 667 668 if !selected { 669 t.Fatalf("expected at least one selected server entry: %s", tunnelProtocol) 670 } 671 672 if !skipped && !protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) { 673 t.Fatalf("expected at least one skipped server entry: %s", tunnelProtocol) 674 } 675 } 676 } 677 678 func makeMockServerEntries( 679 tunnelProtocol string, 680 frontingProviderID string, 681 count int) []*protocol.ServerEntry { 682 683 serverEntries := make([]*protocol.ServerEntry, count) 684 685 for i := 0; i < count; i++ { 686 serverEntries[i] = &protocol.ServerEntry{ 687 IpAddress: fmt.Sprintf("192.168.0.%d", i), 688 SshPort: prng.Range(10, 19), 689 SshObfuscatedPort: prng.Range(20, 29), 690 SshObfuscatedQUICPort: prng.Range(30, 39), 691 SshObfuscatedTapDancePort: prng.Range(40, 49), 692 SshObfuscatedConjurePort: prng.Range(50, 59), 693 MeekServerPort: prng.Range(60, 69), 694 MeekFrontingHosts: []string{"www1.example.org", "www2.example.org", "www3.example.org"}, 695 MeekFrontingAddressesRegex: "[a-z0-9]{1,64}.example.org", 696 FrontingProviderID: frontingProviderID, 697 LocalSource: protocol.SERVER_ENTRY_SOURCE_EMBEDDED, 698 LocalTimestamp: common.TruncateTimestampToHour(common.GetCurrentTimestamp()), 699 Capabilities: []string{protocol.GetCapability(tunnelProtocol)}, 700 } 701 } 702 703 return serverEntries 704 }