limitProtocols_test.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. package psiphon
  20. import (
  21. "context"
  22. "fmt"
  23. "io/ioutil"
  24. "os"
  25. "sync"
  26. "testing"
  27. "time"
  28. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  29. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
  30. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  31. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/server"
  32. )
  33. func TestLimitTunnelProtocols(t *testing.T) {
  34. testDataDirName, err := ioutil.TempDir("", "psiphon-limit-tunnel-protocols-test")
  35. if err != nil {
  36. t.Fatalf("TempDir failed: %s", err)
  37. }
  38. defer os.RemoveAll(testDataDirName)
  39. initialLimitTunnelProtocols := protocol.TunnelProtocols{"OSSH", "UNFRONTED-MEEK-HTTPS-OSSH"}
  40. initialLimitTunnelProtocolsCandidateCount := 100
  41. limitTunnelProtocols := protocol.TunnelProtocols{"SSH", "UNFRONTED-MEEK-OSSH"}
  42. initialConnectingCount := 0
  43. connectingCount := 0
  44. err = SetNoticeWriter(NewNoticeReceiver(
  45. func(notice []byte) {
  46. noticeType, payload, err := GetNotice(notice)
  47. if err != nil {
  48. return
  49. }
  50. if noticeType == "ConnectingServer" {
  51. connectingCount += 1
  52. protocolField := payload["protocol"]
  53. protocol := protocolField.(string)
  54. if common.Contains(initialLimitTunnelProtocols, protocol) {
  55. initialConnectingCount += 1
  56. }
  57. if common.Contains(limitTunnelProtocols, protocol) {
  58. connectingCount += 1
  59. }
  60. // At the end of the InitialLimit phase, the order of
  61. // ConnectingServer notices isn't strictly synchronized and
  62. // it's possible for a Limit candidate ConnectingServer notice
  63. // to arrive before the last InitialLimit notice. So strict
  64. // checking of notice order is performed only up to 90% of
  65. // InitialLimitTunnelProtocolsCandidateCount.
  66. if initialConnectingCount <= (initialLimitTunnelProtocolsCandidateCount*9)/10 {
  67. var expectedProtocols []string
  68. if connectingCount <= initialLimitTunnelProtocolsCandidateCount {
  69. expectedProtocols = initialLimitTunnelProtocols
  70. } else {
  71. expectedProtocols = limitTunnelProtocols
  72. }
  73. if !common.Contains(expectedProtocols, protocol) {
  74. t.Fatalf("unexpected protocol: %s (%d %+v)", protocol, connectingCount, expectedProtocols)
  75. }
  76. }
  77. }
  78. }))
  79. if err != nil {
  80. t.Fatalf("error setting notice writer: %s", err)
  81. }
  82. defer ResetNoticeWriter()
  83. clientConfigJSON := `
  84. {
  85. "ClientPlatform" : "Windows",
  86. "ClientVersion" : "0",
  87. "SponsorId" : "0000000000000000",
  88. "PropagationChannelId" : "0000000000000000",
  89. "DisableRemoteServerListFetcher" : true
  90. }`
  91. clientConfig, err := LoadConfig([]byte(clientConfigJSON))
  92. if err != nil {
  93. t.Fatalf("error processing configuration file: %s", err)
  94. }
  95. clientConfig.DataRootDirectory = testDataDirName
  96. err = clientConfig.Commit(false)
  97. if err != nil {
  98. t.Fatalf("error committing configuration file: %s", err)
  99. }
  100. applyParameters := make(map[string]interface{})
  101. applyParameters[parameters.ConnectionWorkerPoolSize] = initialLimitTunnelProtocolsCandidateCount / 2
  102. applyParameters[parameters.LimitIntensiveConnectionWorkers] = initialLimitTunnelProtocolsCandidateCount / 4
  103. applyParameters[parameters.TunnelConnectTimeout] = "1s"
  104. applyParameters[parameters.EstablishTunnelPausePeriod] = "1s"
  105. applyParameters[parameters.InitialLimitTunnelProtocols] = initialLimitTunnelProtocols
  106. applyParameters[parameters.InitialLimitTunnelProtocolsCandidateCount] = initialLimitTunnelProtocolsCandidateCount
  107. applyParameters[parameters.LimitTunnelProtocols] = limitTunnelProtocols
  108. err = clientConfig.SetParameters("", true, applyParameters)
  109. if err != nil {
  110. t.Fatalf("error setting client parameters: %s", err)
  111. }
  112. err = OpenDataStore(clientConfig)
  113. if err != nil {
  114. t.Fatalf("error initializing client datastore: %s", err)
  115. }
  116. defer CloseDataStore()
  117. if CountServerEntries() > 0 {
  118. t.Fatalf("unexpected server entries")
  119. }
  120. serverEntries := make([]map[string]interface{}, len(protocol.SupportedTunnelProtocols))
  121. for i, tunnelProtocol := range protocol.SupportedTunnelProtocols {
  122. _, _, _, _, encodedServerEntry, err := server.GenerateConfig(
  123. &server.GenerateConfigParams{
  124. ServerIPAddress: fmt.Sprintf("0.1.0.0"),
  125. TunnelProtocolPorts: map[string]int{tunnelProtocol: 4000},
  126. })
  127. if err != nil {
  128. t.Fatalf("error generating server config: %s", err)
  129. }
  130. serverEntryFields, err := protocol.DecodeServerEntryFields(
  131. string(encodedServerEntry),
  132. common.GetCurrentTimestamp(),
  133. protocol.SERVER_ENTRY_SOURCE_REMOTE)
  134. if err != nil {
  135. t.Fatalf("error decoding server entry: %s", err)
  136. }
  137. serverEntries[i] = serverEntryFields
  138. }
  139. for i := 0; i < 1000; i++ {
  140. serverEntryFields := serverEntries[i%len(protocol.SupportedTunnelProtocols)]
  141. serverEntryFields["ipAddress"] = fmt.Sprintf("0.1.%d.%d", (i>>8)&0xFF, i&0xFF)
  142. err = StoreServerEntry(serverEntryFields, true)
  143. if err != nil {
  144. t.Fatalf("error storing server entry: %s", err)
  145. }
  146. }
  147. controller, err := NewController(clientConfig)
  148. if err != nil {
  149. t.Fatalf("error creating client controller: %s", err)
  150. }
  151. ctx, cancelFunc := context.WithCancel(context.Background())
  152. controllerWaitGroup := new(sync.WaitGroup)
  153. controllerWaitGroup.Add(1)
  154. go func() {
  155. defer controllerWaitGroup.Done()
  156. controller.Run(ctx)
  157. }()
  158. time.Sleep(10 * time.Second)
  159. cancelFunc()
  160. controllerWaitGroup.Wait()
  161. t.Logf("initial-connecting and connecting count: %d/%d", initialConnectingCount, connectingCount)
  162. if initialConnectingCount != initialLimitTunnelProtocolsCandidateCount {
  163. t.Fatalf("unexpected initial-connecting count")
  164. }
  165. if connectingCount < 3*initialLimitTunnelProtocolsCandidateCount {
  166. t.Fatalf("unexpected connecting count")
  167. }
  168. }