dialParameters_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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. "bytes"
  22. "encoding/json"
  23. "fmt"
  24. "io/ioutil"
  25. "os"
  26. "reflect"
  27. "testing"
  28. "time"
  29. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  30. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
  31. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
  32. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  33. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
  34. )
  35. func TestDialParametersAndReplay(t *testing.T) {
  36. for _, tunnelProtocol := range protocol.SupportedTunnelProtocols {
  37. if !common.Contains(protocol.DefaultDisabledTunnelProtocols, tunnelProtocol) {
  38. runDialParametersAndReplay(t, tunnelProtocol)
  39. }
  40. }
  41. }
  42. var testNetworkID = prng.HexString(8)
  43. type testNetworkGetter struct {
  44. }
  45. func (t *testNetworkGetter) GetNetworkID() string {
  46. return testNetworkID
  47. }
  48. func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
  49. t.Logf("Test %s...", tunnelProtocol)
  50. testDataDirName, err := ioutil.TempDir("", "psiphon-dial-parameters-test")
  51. if err != nil {
  52. t.Fatalf("TempDir failed: %s", err)
  53. }
  54. defer os.RemoveAll(testDataDirName)
  55. SetNoticeWriter(ioutil.Discard)
  56. clientConfig := &Config{
  57. PropagationChannelId: "0",
  58. SponsorId: "0",
  59. DataRootDirectory: testDataDirName,
  60. NetworkIDGetter: new(testNetworkGetter),
  61. }
  62. err = clientConfig.Commit(false)
  63. if err != nil {
  64. t.Fatalf("error committing configuration file: %s", err)
  65. }
  66. holdOffTunnelProtocols := protocol.TunnelProtocols{protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH}
  67. frontingProviderID := prng.HexString(8)
  68. applyParameters := make(map[string]interface{})
  69. applyParameters[parameters.TransformHostNameProbability] = 1.0
  70. applyParameters[parameters.PickUserAgentProbability] = 1.0
  71. applyParameters[parameters.HoldOffTunnelMinDuration] = "1ms"
  72. applyParameters[parameters.HoldOffTunnelMaxDuration] = "10ms"
  73. applyParameters[parameters.HoldOffTunnelProtocols] = holdOffTunnelProtocols
  74. applyParameters[parameters.HoldOffTunnelFrontingProviderIDs] = []string{frontingProviderID}
  75. applyParameters[parameters.HoldOffTunnelProbability] = 1.0
  76. applyParameters[parameters.DNSResolverAlternateServers] = []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}
  77. err = clientConfig.SetParameters("tag1", false, applyParameters)
  78. if err != nil {
  79. t.Fatalf("SetParameters failed: %s", err)
  80. }
  81. resolver := NewResolver(clientConfig, true)
  82. defer resolver.Stop()
  83. clientConfig.SetResolver(resolver)
  84. err = OpenDataStore(clientConfig)
  85. if err != nil {
  86. t.Fatalf("error initializing client datastore: %s", err)
  87. }
  88. defer CloseDataStore()
  89. serverEntries := makeMockServerEntries(tunnelProtocol, frontingProviderID, 100)
  90. canReplay := func(serverEntry *protocol.ServerEntry, replayProtocol string) bool {
  91. return replayProtocol == tunnelProtocol
  92. }
  93. selectProtocol := func(serverEntry *protocol.ServerEntry) (string, bool) {
  94. return tunnelProtocol, true
  95. }
  96. values.SetSSHClientVersionsSpec(
  97. values.NewPickOneSpec([]string{"SSH-2.0-A", "SSH-2.0-B", "SSH-2.0-C"}))
  98. values.SetUserAgentsSpec(
  99. values.NewPickOneSpec([]string{"ua1", "ua2", "ua3"}))
  100. // Test: expected dial parameter fields set
  101. upstreamProxyErrorCallback := func(_ error) {}
  102. dialParams, err := MakeDialParameters(
  103. clientConfig, upstreamProxyErrorCallback, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  104. if err != nil {
  105. t.Fatalf("MakeDialParameters failed: %s", err)
  106. }
  107. if dialParams.ServerEntry != serverEntries[0] {
  108. t.Fatalf("unexpected server entry")
  109. }
  110. if dialParams.NetworkID != testNetworkID {
  111. t.Fatalf("unexpected network ID")
  112. }
  113. if dialParams.IsReplay {
  114. t.Fatalf("unexpected replay")
  115. }
  116. if dialParams.TunnelProtocol != tunnelProtocol {
  117. t.Fatalf("unexpected tunnel protocol")
  118. }
  119. if !protocol.TunnelProtocolUsesMeek(tunnelProtocol) &&
  120. dialParams.DirectDialAddress == "" {
  121. t.Fatalf("missing direct dial fields")
  122. }
  123. if dialParams.DialPortNumber == "" {
  124. t.Fatalf("missing port number fields")
  125. }
  126. if !dialParams.SelectedSSHClientVersion || dialParams.SSHClientVersion == "" || dialParams.SSHKEXSeed == nil {
  127. t.Fatalf("missing SSH fields")
  128. }
  129. if protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) &&
  130. dialParams.ObfuscatorPaddingSeed == nil {
  131. t.Fatalf("missing obfuscator fields")
  132. }
  133. if dialParams.FragmentorSeed == nil {
  134. t.Fatalf("missing fragmentor field")
  135. }
  136. if protocol.TunnelProtocolUsesMeek(tunnelProtocol) &&
  137. (dialParams.MeekDialAddress == "" ||
  138. dialParams.MeekHostHeader == "" ||
  139. dialParams.MeekObfuscatorPaddingSeed == nil) {
  140. t.Fatalf("missing meek fields")
  141. }
  142. if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) &&
  143. (dialParams.MeekFrontingDialAddress == "" ||
  144. dialParams.MeekFrontingHost == "" ||
  145. dialParams.ResolveParameters == nil) {
  146. t.Fatalf("missing meek fronting fields")
  147. }
  148. if protocol.TunnelProtocolUsesMeekHTTP(tunnelProtocol) &&
  149. dialParams.UserAgent == "" {
  150. t.Fatalf("missing meek HTTP fields")
  151. }
  152. if protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) &&
  153. (dialParams.MeekSNIServerName == "" ||
  154. !dialParams.SelectedTLSProfile ||
  155. dialParams.TLSProfile == "") {
  156. t.Fatalf("missing meek HTTPS fields")
  157. }
  158. if protocol.TunnelProtocolUsesQUIC(tunnelProtocol) {
  159. if dialParams.QUICVersion == "" {
  160. t.Fatalf("missing QUIC version field")
  161. }
  162. if protocol.TunnelProtocolUsesFrontedMeekQUIC(tunnelProtocol) {
  163. if dialParams.MeekFrontingDialAddress == "" ||
  164. dialParams.MeekFrontingHost == "" ||
  165. dialParams.MeekSNIServerName == "" {
  166. t.Fatalf("missing fronted QUIC fields")
  167. }
  168. } else {
  169. if dialParams.QUICDialSNIAddress == "" {
  170. t.Fatalf("missing QUIC SNI field")
  171. }
  172. }
  173. }
  174. if dialParams.LivenessTestSeed == nil {
  175. t.Fatalf("missing liveness test fields")
  176. }
  177. if dialParams.APIRequestPaddingSeed == nil {
  178. t.Fatalf("missing API request fields")
  179. }
  180. if common.Contains(holdOffTunnelProtocols, tunnelProtocol) ||
  181. protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
  182. if dialParams.HoldOffTunnelDuration < 1*time.Millisecond ||
  183. dialParams.HoldOffTunnelDuration > 10*time.Millisecond {
  184. t.Fatalf("unexpected hold-off duration: %v", dialParams.HoldOffTunnelDuration)
  185. }
  186. } else {
  187. if dialParams.HoldOffTunnelDuration != 0 {
  188. t.Fatalf("unexpected hold-off duration: %v", dialParams.HoldOffTunnelDuration)
  189. }
  190. }
  191. dialConfig := dialParams.GetDialConfig()
  192. if dialConfig.UpstreamProxyErrorCallback == nil {
  193. t.Fatalf("missing upstreamProxyErrorCallback")
  194. }
  195. // Test: no replay after dial reported to fail
  196. dialParams.Failed(clientConfig)
  197. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  198. if err != nil {
  199. t.Fatalf("MakeDialParameters failed: %s", err)
  200. }
  201. if dialParams.IsReplay {
  202. t.Fatalf("unexpected replay")
  203. }
  204. // Test: no replay after network ID changes
  205. dialParams.Succeeded()
  206. testNetworkID = prng.HexString(8)
  207. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  208. if err != nil {
  209. t.Fatalf("MakeDialParameters failed: %s", err)
  210. }
  211. if dialParams.NetworkID != testNetworkID {
  212. t.Fatalf("unexpected network ID")
  213. }
  214. if dialParams.IsReplay {
  215. t.Fatalf("unexpected replay")
  216. }
  217. // Test: replay after dial reported to succeed, and replay fields match previous dial parameters
  218. dialParams.Succeeded()
  219. replayDialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  220. if err != nil {
  221. t.Fatalf("MakeDialParameters failed: %s", err)
  222. }
  223. if !replayDialParams.IsReplay {
  224. t.Fatalf("unexpected non-replay")
  225. }
  226. if !replayDialParams.LastUsedTimestamp.After(dialParams.LastUsedTimestamp) {
  227. t.Fatalf("unexpected non-updated timestamp")
  228. }
  229. if replayDialParams.TunnelProtocol != dialParams.TunnelProtocol {
  230. t.Fatalf("mismatching tunnel protocol")
  231. }
  232. if replayDialParams.DirectDialAddress != dialParams.DirectDialAddress ||
  233. replayDialParams.DialPortNumber != dialParams.DialPortNumber {
  234. t.Fatalf("mismatching dial fields")
  235. }
  236. identicalSeeds := func(seed1, seed2 *prng.Seed) bool {
  237. if seed1 == nil {
  238. return seed2 == nil
  239. }
  240. return bytes.Equal(seed1[:], seed2[:])
  241. }
  242. if replayDialParams.SelectedSSHClientVersion != dialParams.SelectedSSHClientVersion ||
  243. replayDialParams.SSHClientVersion != dialParams.SSHClientVersion ||
  244. !identicalSeeds(replayDialParams.SSHKEXSeed, dialParams.SSHKEXSeed) {
  245. t.Fatalf("mismatching SSH fields")
  246. }
  247. if !identicalSeeds(replayDialParams.ObfuscatorPaddingSeed, dialParams.ObfuscatorPaddingSeed) {
  248. t.Fatalf("mismatching obfuscator fields")
  249. }
  250. if !identicalSeeds(replayDialParams.FragmentorSeed, dialParams.FragmentorSeed) {
  251. t.Fatalf("mismatching fragmentor fields")
  252. }
  253. if replayDialParams.MeekFrontingDialAddress != dialParams.MeekFrontingDialAddress ||
  254. replayDialParams.MeekFrontingHost != dialParams.MeekFrontingHost ||
  255. replayDialParams.MeekDialAddress != dialParams.MeekDialAddress ||
  256. replayDialParams.MeekTransformedHostName != dialParams.MeekTransformedHostName ||
  257. replayDialParams.MeekSNIServerName != dialParams.MeekSNIServerName ||
  258. replayDialParams.MeekHostHeader != dialParams.MeekHostHeader ||
  259. !identicalSeeds(replayDialParams.MeekObfuscatorPaddingSeed, dialParams.MeekObfuscatorPaddingSeed) {
  260. t.Fatalf("mismatching meek fields")
  261. }
  262. if replayDialParams.SelectedUserAgent != dialParams.SelectedUserAgent ||
  263. replayDialParams.UserAgent != dialParams.UserAgent {
  264. t.Fatalf("mismatching user agent fields")
  265. }
  266. if replayDialParams.SelectedTLSProfile != dialParams.SelectedTLSProfile ||
  267. replayDialParams.TLSProfile != dialParams.TLSProfile ||
  268. !identicalSeeds(replayDialParams.RandomizedTLSProfileSeed, dialParams.RandomizedTLSProfileSeed) {
  269. t.Fatalf("mismatching TLS fields")
  270. }
  271. if replayDialParams.QUICVersion != dialParams.QUICVersion ||
  272. replayDialParams.QUICDialSNIAddress != dialParams.QUICDialSNIAddress ||
  273. !identicalSeeds(replayDialParams.ObfuscatedQUICPaddingSeed, dialParams.ObfuscatedQUICPaddingSeed) {
  274. t.Fatalf("mismatching QUIC fields")
  275. }
  276. if !identicalSeeds(replayDialParams.LivenessTestSeed, dialParams.LivenessTestSeed) {
  277. t.Fatalf("mismatching liveness test fields")
  278. }
  279. if !identicalSeeds(replayDialParams.APIRequestPaddingSeed, dialParams.APIRequestPaddingSeed) {
  280. t.Fatalf("mismatching API request fields")
  281. }
  282. if (replayDialParams.ResolveParameters == nil) != (dialParams.ResolveParameters == nil) ||
  283. (replayDialParams.ResolveParameters != nil &&
  284. !reflect.DeepEqual(replayDialParams.ResolveParameters, dialParams.ResolveParameters)) {
  285. t.Fatalf("mismatching ResolveParameters fields")
  286. }
  287. // Test: no replay after change tactics
  288. applyParameters[parameters.ReplayDialParametersTTL] = "1s"
  289. err = clientConfig.SetParameters("tag2", false, applyParameters)
  290. if err != nil {
  291. t.Fatalf("SetParameters failed: %s", err)
  292. }
  293. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  294. if err != nil {
  295. t.Fatalf("MakeDialParameters failed: %s", err)
  296. }
  297. if dialParams.IsReplay {
  298. t.Fatalf("unexpected replay")
  299. }
  300. // Test: no replay after dial parameters expired
  301. dialParams.Succeeded()
  302. time.Sleep(1 * time.Second)
  303. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  304. if err != nil {
  305. t.Fatalf("MakeDialParameters failed: %s", err)
  306. }
  307. if dialParams.IsReplay {
  308. t.Fatalf("unexpected replay")
  309. }
  310. // Test: no replay after server entry changes
  311. dialParams.Succeeded()
  312. serverEntries[0].ConfigurationVersion += 1
  313. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  314. if err != nil {
  315. t.Fatalf("MakeDialParameters failed: %s", err)
  316. }
  317. if dialParams.IsReplay {
  318. t.Fatalf("unexpected replay")
  319. }
  320. // Test: disable replay elements (partial coverage)
  321. applyParameters[parameters.ReplayDialParametersTTL] = "24h"
  322. applyParameters[parameters.ReplaySSH] = false
  323. applyParameters[parameters.ReplayObfuscatorPadding] = false
  324. applyParameters[parameters.ReplayFragmentor] = false
  325. applyParameters[parameters.ReplayRandomizedTLSProfile] = false
  326. applyParameters[parameters.ReplayObfuscatedQUIC] = false
  327. applyParameters[parameters.ReplayLivenessTest] = false
  328. applyParameters[parameters.ReplayAPIRequestPadding] = false
  329. err = clientConfig.SetParameters("tag3", false, applyParameters)
  330. if err != nil {
  331. t.Fatalf("SetParameters failed: %s", err)
  332. }
  333. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  334. if err != nil {
  335. t.Fatalf("MakeDialParameters failed: %s", err)
  336. }
  337. dialParams.Succeeded()
  338. replayDialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  339. if err != nil {
  340. t.Fatalf("MakeDialParameters failed: %s", err)
  341. }
  342. if !replayDialParams.IsReplay {
  343. t.Fatalf("unexpected non-replay")
  344. }
  345. if identicalSeeds(replayDialParams.SSHKEXSeed, dialParams.SSHKEXSeed) ||
  346. (protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) &&
  347. identicalSeeds(replayDialParams.ObfuscatorPaddingSeed, dialParams.ObfuscatorPaddingSeed)) ||
  348. identicalSeeds(replayDialParams.FragmentorSeed, dialParams.FragmentorSeed) ||
  349. (protocol.TunnelProtocolUsesMeek(tunnelProtocol) &&
  350. identicalSeeds(replayDialParams.MeekObfuscatorPaddingSeed, dialParams.MeekObfuscatorPaddingSeed)) ||
  351. (protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) &&
  352. identicalSeeds(replayDialParams.RandomizedTLSProfileSeed, dialParams.RandomizedTLSProfileSeed) &&
  353. replayDialParams.RandomizedTLSProfileSeed != nil) ||
  354. (protocol.TunnelProtocolUsesQUIC(tunnelProtocol) &&
  355. identicalSeeds(replayDialParams.ObfuscatedQUICPaddingSeed, dialParams.ObfuscatedQUICPaddingSeed) &&
  356. replayDialParams.ObfuscatedQUICPaddingSeed != nil) ||
  357. identicalSeeds(replayDialParams.LivenessTestSeed, dialParams.LivenessTestSeed) ||
  358. identicalSeeds(replayDialParams.APIRequestPaddingSeed, dialParams.APIRequestPaddingSeed) {
  359. t.Fatalf("unexpected replayed fields")
  360. }
  361. // Test: client-side restrict fronting provider ID
  362. applyParameters[parameters.RestrictFrontingProviderIDs] = []string{frontingProviderID}
  363. applyParameters[parameters.RestrictFrontingProviderIDsClientProbability] = 1.0
  364. err = clientConfig.SetParameters("tag4", false, applyParameters)
  365. if err != nil {
  366. t.Fatalf("SetParameters failed: %s", err)
  367. }
  368. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  369. if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
  370. if err == nil {
  371. if dialParams != nil {
  372. t.Fatalf("unexpected MakeDialParameters success")
  373. }
  374. }
  375. } else {
  376. if err != nil {
  377. t.Fatalf("MakeDialParameters failed: %s", err)
  378. }
  379. }
  380. applyParameters[parameters.RestrictFrontingProviderIDsClientProbability] = 0.0
  381. err = clientConfig.SetParameters("tag5", false, applyParameters)
  382. if err != nil {
  383. t.Fatalf("SetParameters failed: %s", err)
  384. }
  385. // Test: iterator shuffles
  386. for i, serverEntry := range serverEntries {
  387. data, err := json.Marshal(serverEntry)
  388. if err != nil {
  389. t.Fatalf("json.Marshal failed: %s", err)
  390. }
  391. var serverEntryFields protocol.ServerEntryFields
  392. err = json.Unmarshal(data, &serverEntryFields)
  393. if err != nil {
  394. t.Fatalf("json.Unmarshal failed: %s", err)
  395. }
  396. err = StoreServerEntry(serverEntryFields, false)
  397. if err != nil {
  398. t.Fatalf("StoreServerEntry failed: %s", err)
  399. }
  400. if i%10 == 0 {
  401. dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
  402. if err != nil {
  403. t.Fatalf("MakeDialParameters failed: %s", err)
  404. }
  405. dialParams.Succeeded()
  406. }
  407. }
  408. for i := 0; i < 5; i++ {
  409. hasAffinity, iterator, err := NewServerEntryIterator(clientConfig)
  410. if err != nil {
  411. t.Fatalf("NewServerEntryIterator failed: %s", err)
  412. }
  413. if hasAffinity {
  414. t.Fatalf("unexpected affinity server")
  415. }
  416. // Test: the first shuffle should move the replay candidates to the front
  417. for j := 0; j < 10; j++ {
  418. serverEntry, err := iterator.Next()
  419. if err != nil {
  420. t.Fatalf("ServerEntryIterator.Next failed: %s", err)
  421. }
  422. dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
  423. if err != nil {
  424. t.Fatalf("MakeDialParameters failed: %s", err)
  425. }
  426. if !dialParams.IsReplay {
  427. t.Fatalf("unexpected non-replay")
  428. }
  429. }
  430. iterator.Reset()
  431. // Test: subsequent shuffles should not move the replay candidates
  432. allReplay := true
  433. for j := 0; j < 10; j++ {
  434. serverEntry, err := iterator.Next()
  435. if err != nil {
  436. t.Fatalf("ServerEntryIterator.Next failed: %s", err)
  437. }
  438. dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
  439. if err != nil {
  440. t.Fatalf("MakeDialParameters failed: %s", err)
  441. }
  442. if !dialParams.IsReplay {
  443. allReplay = false
  444. }
  445. }
  446. if allReplay {
  447. t.Fatalf("unexpected all replay")
  448. }
  449. iterator.Close()
  450. }
  451. }
  452. func TestLimitTunnelDialPortNumbers(t *testing.T) {
  453. testDataDirName, err := ioutil.TempDir("", "psiphon-limit-tunnel-dial-port-numbers-test")
  454. if err != nil {
  455. t.Fatalf("TempDir failed: %s", err)
  456. }
  457. defer os.RemoveAll(testDataDirName)
  458. SetNoticeWriter(ioutil.Discard)
  459. clientConfig := &Config{
  460. PropagationChannelId: "0",
  461. SponsorId: "0",
  462. DataRootDirectory: testDataDirName,
  463. NetworkIDGetter: new(testNetworkGetter),
  464. }
  465. err = clientConfig.Commit(false)
  466. if err != nil {
  467. t.Fatalf("error committing configuration file: %s", err)
  468. }
  469. jsonLimitDialPortNumbers := `
  470. {
  471. "SSH" : [[10,11]],
  472. "OSSH" : [[20,21]],
  473. "QUIC-OSSH" : [[30,31]],
  474. "TAPDANCE-OSSH" : [[40,41]],
  475. "CONJURE-OSSH" : [[50,51]],
  476. "All" : [[60,61],80,443]
  477. }
  478. `
  479. var limitTunnelDialPortNumbers parameters.TunnelProtocolPortLists
  480. err = json.Unmarshal([]byte(jsonLimitDialPortNumbers), &limitTunnelDialPortNumbers)
  481. if err != nil {
  482. t.Fatalf("Unmarshal failed: %s", err)
  483. }
  484. applyParameters := make(map[string]interface{})
  485. applyParameters[parameters.LimitTunnelDialPortNumbers] = limitTunnelDialPortNumbers
  486. applyParameters[parameters.LimitTunnelDialPortNumbersProbability] = 1.0
  487. err = clientConfig.SetParameters("tag1", false, applyParameters)
  488. if err != nil {
  489. t.Fatalf("SetParameters failed: %s", err)
  490. }
  491. constraints := &protocolSelectionConstraints{
  492. limitTunnelDialPortNumbers: protocol.TunnelProtocolPortLists(
  493. clientConfig.GetParameters().Get().TunnelProtocolPortLists(parameters.LimitTunnelDialPortNumbers)),
  494. }
  495. selectProtocol := func(serverEntry *protocol.ServerEntry) (string, bool) {
  496. return constraints.selectProtocol(0, false, serverEntry)
  497. }
  498. for _, tunnelProtocol := range protocol.SupportedTunnelProtocols {
  499. if common.Contains(protocol.DefaultDisabledTunnelProtocols, tunnelProtocol) {
  500. continue
  501. }
  502. serverEntries := makeMockServerEntries(tunnelProtocol, "", 100)
  503. selected := false
  504. skipped := false
  505. for _, serverEntry := range serverEntries {
  506. selectedProtocol, ok := selectProtocol(serverEntry)
  507. if ok {
  508. if selectedProtocol != tunnelProtocol {
  509. t.Fatalf("unexpected selected protocol: %s", selectedProtocol)
  510. }
  511. port, err := serverEntry.GetDialPortNumber(selectedProtocol)
  512. if err != nil {
  513. t.Fatalf("GetDialPortNumber failed: %s", err)
  514. }
  515. if port%10 != 0 && port%10 != 1 && !protocol.TunnelProtocolUsesFrontedMeek(selectedProtocol) {
  516. t.Fatalf("unexpected dial port number: %d", port)
  517. }
  518. selected = true
  519. } else {
  520. skipped = true
  521. }
  522. }
  523. if !selected {
  524. t.Fatalf("expected at least one selected server entry: %s", tunnelProtocol)
  525. }
  526. if !skipped && !protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
  527. t.Fatalf("expected at least one skipped server entry: %s", tunnelProtocol)
  528. }
  529. }
  530. }
  531. func makeMockServerEntries(
  532. tunnelProtocol string,
  533. frontingProviderID string,
  534. count int) []*protocol.ServerEntry {
  535. serverEntries := make([]*protocol.ServerEntry, count)
  536. for i := 0; i < count; i++ {
  537. serverEntries[i] = &protocol.ServerEntry{
  538. IpAddress: fmt.Sprintf("192.168.0.%d", i),
  539. SshPort: prng.Range(10, 19),
  540. SshObfuscatedPort: prng.Range(20, 29),
  541. SshObfuscatedQUICPort: prng.Range(30, 39),
  542. SshObfuscatedTapDancePort: prng.Range(40, 49),
  543. SshObfuscatedConjurePort: prng.Range(50, 59),
  544. MeekServerPort: prng.Range(60, 69),
  545. MeekFrontingHosts: []string{"www1.example.org", "www2.example.org", "www3.example.org"},
  546. MeekFrontingAddressesRegex: "[a-z0-9]{1,64}.example.org",
  547. FrontingProviderID: frontingProviderID,
  548. LocalSource: protocol.SERVER_ENTRY_SOURCE_EMBEDDED,
  549. LocalTimestamp: common.TruncateTimestampToHour(common.GetCurrentTimestamp()),
  550. Capabilities: []string{protocol.GetCapability(tunnelProtocol)},
  551. }
  552. }
  553. return serverEntries
  554. }