dialParameters_test.go 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  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/transforms"
  34. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
  35. )
  36. func TestDialParametersAndReplay(t *testing.T) {
  37. for _, tunnelProtocol := range protocol.SupportedTunnelProtocols {
  38. if !common.Contains(protocol.DefaultDisabledTunnelProtocols, tunnelProtocol) {
  39. runDialParametersAndReplay(t, tunnelProtocol)
  40. }
  41. }
  42. }
  43. var testNetworkID = prng.HexString(8)
  44. type testNetworkGetter struct {
  45. }
  46. func (t *testNetworkGetter) GetNetworkID() string {
  47. return testNetworkID
  48. }
  49. func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
  50. t.Logf("Test %s...", tunnelProtocol)
  51. testDataDirName, err := ioutil.TempDir("", "psiphon-dial-parameters-test")
  52. if err != nil {
  53. t.Fatalf("TempDir failed: %s", err)
  54. }
  55. defer os.RemoveAll(testDataDirName)
  56. SetNoticeWriter(ioutil.Discard)
  57. clientConfig := &Config{
  58. PropagationChannelId: "0",
  59. SponsorId: "0",
  60. DataRootDirectory: testDataDirName,
  61. NetworkIDGetter: new(testNetworkGetter),
  62. }
  63. err = clientConfig.Commit(false)
  64. if err != nil {
  65. t.Fatalf("error committing configuration file: %s", err)
  66. }
  67. holdOffTunnelProtocols := protocol.TunnelProtocols{protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH}
  68. providerID := prng.HexString(8)
  69. frontingProviderID := prng.HexString(8)
  70. var holdOffDirectServerEntryRegions []string
  71. if tunnelProtocol == protocol.TUNNEL_PROTOCOL_TLS_OBFUSCATED_SSH {
  72. holdOffDirectServerEntryRegions = []string{"CA"}
  73. }
  74. var holdOffDirectServerEntryProviderRegions parameters.KeyStrings
  75. if tunnelProtocol == protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK {
  76. holdOffDirectServerEntryProviderRegions = map[string][]string{providerID: {""}}
  77. }
  78. applyParameters := make(map[string]interface{})
  79. applyParameters[parameters.TransformHostNameProbability] = 1.0
  80. applyParameters[parameters.PickUserAgentProbability] = 1.0
  81. applyParameters[parameters.HoldOffTunnelMinDuration] = "1ms"
  82. applyParameters[parameters.HoldOffTunnelMaxDuration] = "10ms"
  83. applyParameters[parameters.HoldOffTunnelProtocols] = holdOffTunnelProtocols
  84. applyParameters[parameters.HoldOffTunnelFrontingProviderIDs] = []string{frontingProviderID}
  85. applyParameters[parameters.HoldOffTunnelProbability] = 1.0
  86. applyParameters[parameters.HoldOffDirectTunnelMinDuration] = "1ms"
  87. applyParameters[parameters.HoldOffDirectTunnelMaxDuration] = "10ms"
  88. applyParameters[parameters.HoldOffDirectServerEntryRegions] = holdOffDirectServerEntryRegions
  89. applyParameters[parameters.HoldOffDirectServerEntryProviderRegions] = holdOffDirectServerEntryProviderRegions
  90. applyParameters[parameters.HoldOffDirectTunnelProbability] = 1.0
  91. applyParameters[parameters.DNSResolverAlternateServers] = []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}
  92. applyParameters[parameters.DirectHTTPProtocolTransformProbability] = 1.0
  93. applyParameters[parameters.DirectHTTPProtocolTransformSpecs] = transforms.Specs{"spec": transforms.Spec{{"", ""}}}
  94. applyParameters[parameters.DirectHTTPProtocolTransformScopedSpecNames] = transforms.ScopedSpecNames{"": {"spec"}}
  95. applyParameters[parameters.OSSHObfuscatorSeedTransformProbability] = 1.0
  96. applyParameters[parameters.OSSHObfuscatorSeedTransformSpecs] = transforms.Specs{"spec": transforms.Spec{{"", ""}}}
  97. applyParameters[parameters.OSSHObfuscatorSeedTransformScopedSpecNames] = transforms.ScopedSpecNames{"": {"spec"}}
  98. applyParameters[parameters.ObfuscatedQUICNonceTransformProbability] = 1.0
  99. applyParameters[parameters.ObfuscatedQUICNonceTransformSpecs] = transforms.Specs{"spec": transforms.Spec{{"", ""}}}
  100. applyParameters[parameters.ObfuscatedQUICNonceTransformScopedSpecNames] = transforms.ScopedSpecNames{"": {"spec"}}
  101. err = clientConfig.SetParameters("tag1", false, applyParameters)
  102. if err != nil {
  103. t.Fatalf("SetParameters failed: %s", err)
  104. }
  105. resolver := NewResolver(clientConfig, true)
  106. defer resolver.Stop()
  107. clientConfig.SetResolver(resolver)
  108. err = OpenDataStore(clientConfig)
  109. if err != nil {
  110. t.Fatalf("error initializing client datastore: %s", err)
  111. }
  112. defer CloseDataStore()
  113. serverEntries := makeMockServerEntries(tunnelProtocol, "CA", providerID, frontingProviderID, 100)
  114. canReplay := func(serverEntry *protocol.ServerEntry, replayProtocol string) bool {
  115. return replayProtocol == tunnelProtocol
  116. }
  117. selectProtocol := func(serverEntry *protocol.ServerEntry) (string, bool) {
  118. return tunnelProtocol, true
  119. }
  120. values.SetSSHClientVersionsSpec(
  121. values.NewPickOneSpec([]string{"SSH-2.0-A", "SSH-2.0-B", "SSH-2.0-C"}))
  122. values.SetUserAgentsSpec(
  123. values.NewPickOneSpec([]string{"ua1", "ua2", "ua3"}))
  124. // Test: expected dial parameter fields set
  125. upstreamProxyErrorCallback := func(_ error) {}
  126. dialParams, err := MakeDialParameters(
  127. clientConfig, upstreamProxyErrorCallback, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  128. if err != nil {
  129. t.Fatalf("MakeDialParameters failed: %s", err)
  130. }
  131. if dialParams.ServerEntry != serverEntries[0] {
  132. t.Fatalf("unexpected server entry")
  133. }
  134. if dialParams.NetworkID != testNetworkID {
  135. t.Fatalf("unexpected network ID")
  136. }
  137. if dialParams.IsReplay {
  138. t.Fatalf("unexpected replay")
  139. }
  140. if dialParams.TunnelProtocol != tunnelProtocol {
  141. t.Fatalf("unexpected tunnel protocol")
  142. }
  143. if !protocol.TunnelProtocolUsesMeek(tunnelProtocol) &&
  144. dialParams.DirectDialAddress == "" {
  145. t.Fatalf("missing direct dial fields")
  146. }
  147. if dialParams.DialPortNumber == "" {
  148. t.Fatalf("missing port number fields")
  149. }
  150. if !dialParams.SelectedSSHClientVersion || dialParams.SSHClientVersion == "" || dialParams.SSHKEXSeed == nil {
  151. t.Fatalf("missing SSH fields")
  152. }
  153. if protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) &&
  154. dialParams.ObfuscatorPaddingSeed == nil {
  155. t.Fatalf("missing obfuscator fields")
  156. }
  157. if dialParams.FragmentorSeed == nil {
  158. t.Fatalf("missing fragmentor field")
  159. }
  160. if protocol.TunnelProtocolUsesMeek(tunnelProtocol) &&
  161. (dialParams.MeekDialAddress == "" ||
  162. dialParams.MeekHostHeader == "" ||
  163. dialParams.MeekObfuscatorPaddingSeed == nil) {
  164. t.Fatalf("missing meek fields")
  165. }
  166. if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) &&
  167. (dialParams.MeekFrontingDialAddress == "" ||
  168. dialParams.MeekFrontingHost == "" ||
  169. dialParams.ResolveParameters == nil) {
  170. t.Fatalf("missing meek fronting fields")
  171. }
  172. if protocol.TunnelProtocolUsesMeekHTTP(tunnelProtocol) &&
  173. dialParams.UserAgent == "" {
  174. t.Fatalf("missing meek HTTP fields")
  175. }
  176. if protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) &&
  177. (dialParams.MeekSNIServerName == "" ||
  178. !dialParams.SelectedTLSProfile ||
  179. dialParams.TLSProfile == "") {
  180. t.Fatalf("missing meek HTTPS fields")
  181. }
  182. if protocol.TunnelProtocolUsesQUIC(tunnelProtocol) {
  183. if dialParams.QUICVersion == "" {
  184. t.Fatalf("missing QUIC version field")
  185. }
  186. if protocol.TunnelProtocolUsesFrontedMeekQUIC(tunnelProtocol) {
  187. if dialParams.MeekFrontingDialAddress == "" ||
  188. dialParams.MeekFrontingHost == "" ||
  189. dialParams.MeekSNIServerName == "" {
  190. t.Fatalf("missing fronted QUIC fields")
  191. }
  192. } else {
  193. if dialParams.QUICDialSNIAddress == "" {
  194. t.Fatalf("missing QUIC SNI field")
  195. }
  196. }
  197. }
  198. if dialParams.LivenessTestSeed == nil {
  199. t.Fatalf("missing liveness test fields")
  200. }
  201. if dialParams.APIRequestPaddingSeed == nil {
  202. t.Fatalf("missing API request fields")
  203. }
  204. expectHoldOffTunnelProtocols := common.Contains(holdOffTunnelProtocols, tunnelProtocol)
  205. expectHoldOffTunnelFrontingProviderIDs := protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol)
  206. expectHoldOffDirectServerEntryRegions := protocol.TunnelProtocolIsDirect(tunnelProtocol) && common.Contains(holdOffDirectServerEntryRegions, dialParams.ServerEntry.Region)
  207. expectHoldOffDirectServerEntryProviderRegion := protocol.TunnelProtocolIsDirect(tunnelProtocol) && common.ContainsAny(holdOffDirectServerEntryProviderRegions[dialParams.ServerEntry.ProviderID], []string{"", dialParams.ServerEntry.Region})
  208. if expectHoldOffTunnelProtocols ||
  209. expectHoldOffTunnelFrontingProviderIDs ||
  210. expectHoldOffDirectServerEntryRegions ||
  211. expectHoldOffDirectServerEntryProviderRegion {
  212. if dialParams.HoldOffTunnelDuration < 1*time.Millisecond ||
  213. dialParams.HoldOffTunnelDuration > 10*time.Millisecond {
  214. t.Fatalf("unexpected hold-off duration: %v", dialParams.HoldOffTunnelDuration)
  215. }
  216. } else {
  217. if dialParams.HoldOffTunnelDuration != 0 {
  218. t.Fatalf("unexpected hold-off duration: %v", dialParams.HoldOffTunnelDuration)
  219. }
  220. }
  221. dialConfig := dialParams.GetDialConfig()
  222. if dialConfig.UpstreamProxyErrorCallback == nil {
  223. t.Fatalf("missing upstreamProxyErrorCallback")
  224. }
  225. // Test: no replay after dial reported to fail
  226. dialParams.Failed(clientConfig)
  227. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  228. if err != nil {
  229. t.Fatalf("MakeDialParameters failed: %s", err)
  230. }
  231. if dialParams.IsReplay {
  232. t.Fatalf("unexpected replay")
  233. }
  234. // Test: no replay after network ID changes
  235. dialParams.Succeeded()
  236. testNetworkID = prng.HexString(8)
  237. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  238. if err != nil {
  239. t.Fatalf("MakeDialParameters failed: %s", err)
  240. }
  241. if dialParams.NetworkID != testNetworkID {
  242. t.Fatalf("unexpected network ID")
  243. }
  244. if dialParams.IsReplay {
  245. t.Fatalf("unexpected replay")
  246. }
  247. // Test: replay after dial reported to succeed, and replay fields match previous dial parameters
  248. dialParams.Succeeded()
  249. replayDialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  250. if err != nil {
  251. t.Fatalf("MakeDialParameters failed: %s", err)
  252. }
  253. if !replayDialParams.IsReplay {
  254. t.Fatalf("unexpected non-replay")
  255. }
  256. if !replayDialParams.LastUsedTimestamp.After(dialParams.LastUsedTimestamp) {
  257. t.Fatalf("unexpected non-updated timestamp")
  258. }
  259. if replayDialParams.TunnelProtocol != dialParams.TunnelProtocol {
  260. t.Fatalf("mismatching tunnel protocol")
  261. }
  262. if replayDialParams.DirectDialAddress != dialParams.DirectDialAddress ||
  263. replayDialParams.DialPortNumber != dialParams.DialPortNumber {
  264. t.Fatalf("mismatching dial fields")
  265. }
  266. identicalSeeds := func(seed1, seed2 *prng.Seed) bool {
  267. if seed1 == nil {
  268. return seed2 == nil
  269. }
  270. return bytes.Equal(seed1[:], seed2[:])
  271. }
  272. if replayDialParams.SelectedSSHClientVersion != dialParams.SelectedSSHClientVersion ||
  273. replayDialParams.SSHClientVersion != dialParams.SSHClientVersion ||
  274. !identicalSeeds(replayDialParams.SSHKEXSeed, dialParams.SSHKEXSeed) {
  275. t.Fatalf("mismatching SSH fields")
  276. }
  277. if !identicalSeeds(replayDialParams.ObfuscatorPaddingSeed, dialParams.ObfuscatorPaddingSeed) {
  278. t.Fatalf("mismatching obfuscator fields")
  279. }
  280. if !identicalSeeds(replayDialParams.FragmentorSeed, dialParams.FragmentorSeed) {
  281. t.Fatalf("mismatching fragmentor fields")
  282. }
  283. if replayDialParams.MeekFrontingDialAddress != dialParams.MeekFrontingDialAddress ||
  284. replayDialParams.MeekFrontingHost != dialParams.MeekFrontingHost ||
  285. replayDialParams.MeekDialAddress != dialParams.MeekDialAddress ||
  286. replayDialParams.MeekTransformedHostName != dialParams.MeekTransformedHostName ||
  287. replayDialParams.MeekSNIServerName != dialParams.MeekSNIServerName ||
  288. replayDialParams.MeekHostHeader != dialParams.MeekHostHeader ||
  289. !identicalSeeds(replayDialParams.MeekObfuscatorPaddingSeed, dialParams.MeekObfuscatorPaddingSeed) {
  290. t.Fatalf("mismatching meek fields")
  291. }
  292. if replayDialParams.SelectedUserAgent != dialParams.SelectedUserAgent ||
  293. replayDialParams.UserAgent != dialParams.UserAgent {
  294. t.Fatalf("mismatching user agent fields")
  295. }
  296. if replayDialParams.SelectedTLSProfile != dialParams.SelectedTLSProfile ||
  297. replayDialParams.TLSProfile != dialParams.TLSProfile ||
  298. !identicalSeeds(replayDialParams.RandomizedTLSProfileSeed, dialParams.RandomizedTLSProfileSeed) {
  299. t.Fatalf("mismatching TLS fields")
  300. }
  301. if replayDialParams.QUICVersion != dialParams.QUICVersion ||
  302. replayDialParams.QUICDialSNIAddress != dialParams.QUICDialSNIAddress ||
  303. !identicalSeeds(replayDialParams.ObfuscatedQUICPaddingSeed, dialParams.ObfuscatedQUICPaddingSeed) {
  304. t.Fatalf("mismatching QUIC fields")
  305. }
  306. if !identicalSeeds(replayDialParams.LivenessTestSeed, dialParams.LivenessTestSeed) {
  307. t.Fatalf("mismatching liveness test fields")
  308. }
  309. if !identicalSeeds(replayDialParams.APIRequestPaddingSeed, dialParams.APIRequestPaddingSeed) {
  310. t.Fatalf("mismatching API request fields")
  311. }
  312. if (replayDialParams.ResolveParameters == nil) != (dialParams.ResolveParameters == nil) ||
  313. (replayDialParams.ResolveParameters != nil &&
  314. !reflect.DeepEqual(replayDialParams.ResolveParameters, dialParams.ResolveParameters)) {
  315. t.Fatalf("mismatching ResolveParameters fields")
  316. }
  317. if (replayDialParams.HTTPTransformerParameters == nil) != (dialParams.HTTPTransformerParameters == nil) ||
  318. (replayDialParams.HTTPTransformerParameters != nil &&
  319. !reflect.DeepEqual(replayDialParams.HTTPTransformerParameters, dialParams.HTTPTransformerParameters)) {
  320. t.Fatalf("mismatching HTTPTransformerParameters fields")
  321. }
  322. if (replayDialParams.OSSHObfuscatorSeedTransformerParameters == nil) != (dialParams.OSSHObfuscatorSeedTransformerParameters == nil) ||
  323. (replayDialParams.OSSHObfuscatorSeedTransformerParameters != nil &&
  324. !reflect.DeepEqual(replayDialParams.OSSHObfuscatorSeedTransformerParameters, dialParams.OSSHObfuscatorSeedTransformerParameters)) {
  325. t.Fatalf("mismatching ObfuscatorSeedTransformerParameters fields")
  326. }
  327. if (replayDialParams.ObfuscatedQUICNonceTransformerParameters == nil) != (dialParams.ObfuscatedQUICNonceTransformerParameters == nil) ||
  328. (replayDialParams.ObfuscatedQUICNonceTransformerParameters != nil &&
  329. !reflect.DeepEqual(replayDialParams.ObfuscatedQUICNonceTransformerParameters, dialParams.ObfuscatedQUICNonceTransformerParameters)) {
  330. t.Fatalf("mismatching ObfuscatedQUICNonceTransformerParameters fields")
  331. }
  332. // Test: replay after change tactics, with ReplayIgnoreChangedClientState = true
  333. applyParameters[parameters.ReplayDialParametersTTL] = "1s"
  334. applyParameters[parameters.ReplayIgnoreChangedConfigState] = true
  335. err = clientConfig.SetParameters("tag2a", false, applyParameters)
  336. if err != nil {
  337. t.Fatalf("SetParameters failed: %s", err)
  338. }
  339. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  340. if err != nil {
  341. t.Fatalf("MakeDialParameters failed: %s", err)
  342. }
  343. if !replayDialParams.IsReplay {
  344. t.Fatalf("unexpected non-replay")
  345. }
  346. // Test: no replay after change tactics
  347. applyParameters[parameters.ReplayDialParametersTTL] = "1s"
  348. applyParameters[parameters.ReplayIgnoreChangedConfigState] = false
  349. err = clientConfig.SetParameters("tag2", false, applyParameters)
  350. if err != nil {
  351. t.Fatalf("SetParameters failed: %s", err)
  352. }
  353. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  354. if err != nil {
  355. t.Fatalf("MakeDialParameters failed: %s", err)
  356. }
  357. if dialParams.IsReplay {
  358. t.Fatalf("unexpected replay")
  359. }
  360. // Test: no replay after dial parameters expired
  361. dialParams.Succeeded()
  362. time.Sleep(1 * time.Second)
  363. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  364. if err != nil {
  365. t.Fatalf("MakeDialParameters failed: %s", err)
  366. }
  367. if dialParams.IsReplay {
  368. t.Fatalf("unexpected replay")
  369. }
  370. // Test: no replay after server entry changes
  371. dialParams.Succeeded()
  372. serverEntries[0].ConfigurationVersion += 1
  373. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  374. if err != nil {
  375. t.Fatalf("MakeDialParameters failed: %s", err)
  376. }
  377. if dialParams.IsReplay {
  378. t.Fatalf("unexpected replay")
  379. }
  380. // Test: disable replay elements (partial coverage)
  381. applyParameters[parameters.ReplayDialParametersTTL] = "24h"
  382. applyParameters[parameters.ReplaySSH] = false
  383. applyParameters[parameters.ReplayObfuscatorPadding] = false
  384. applyParameters[parameters.ReplayFragmentor] = false
  385. applyParameters[parameters.ReplayObfuscatedQUIC] = false
  386. applyParameters[parameters.ReplayLivenessTest] = false
  387. applyParameters[parameters.ReplayAPIRequestPadding] = false
  388. err = clientConfig.SetParameters("tag3", false, applyParameters)
  389. if err != nil {
  390. t.Fatalf("SetParameters failed: %s", err)
  391. }
  392. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  393. if err != nil {
  394. t.Fatalf("MakeDialParameters failed: %s", err)
  395. }
  396. dialParams.Succeeded()
  397. replayDialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  398. if err != nil {
  399. t.Fatalf("MakeDialParameters failed: %s", err)
  400. }
  401. if !replayDialParams.IsReplay {
  402. t.Fatalf("unexpected non-replay")
  403. }
  404. if identicalSeeds(replayDialParams.SSHKEXSeed, dialParams.SSHKEXSeed) ||
  405. (protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) &&
  406. identicalSeeds(replayDialParams.ObfuscatorPaddingSeed, dialParams.ObfuscatorPaddingSeed)) ||
  407. identicalSeeds(replayDialParams.FragmentorSeed, dialParams.FragmentorSeed) ||
  408. (protocol.TunnelProtocolUsesMeek(tunnelProtocol) &&
  409. identicalSeeds(replayDialParams.MeekObfuscatorPaddingSeed, dialParams.MeekObfuscatorPaddingSeed)) ||
  410. (protocol.TunnelProtocolUsesQUIC(tunnelProtocol) &&
  411. identicalSeeds(replayDialParams.ObfuscatedQUICPaddingSeed, dialParams.ObfuscatedQUICPaddingSeed) &&
  412. replayDialParams.ObfuscatedQUICPaddingSeed != nil) ||
  413. identicalSeeds(replayDialParams.LivenessTestSeed, dialParams.LivenessTestSeed) ||
  414. identicalSeeds(replayDialParams.APIRequestPaddingSeed, dialParams.APIRequestPaddingSeed) {
  415. t.Fatalf("unexpected replayed fields")
  416. }
  417. // Test: client-side restrict fronting provider ID
  418. applyParameters[parameters.RestrictFrontingProviderIDs] = []string{frontingProviderID}
  419. applyParameters[parameters.RestrictFrontingProviderIDsClientProbability] = 1.0
  420. err = clientConfig.SetParameters("tag4", false, applyParameters)
  421. if err != nil {
  422. t.Fatalf("SetParameters failed: %s", err)
  423. }
  424. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  425. if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
  426. if err == nil {
  427. if dialParams != nil {
  428. t.Fatalf("unexpected MakeDialParameters success")
  429. }
  430. }
  431. } else {
  432. if err != nil {
  433. t.Fatalf("MakeDialParameters failed: %s", err)
  434. }
  435. }
  436. applyParameters[parameters.RestrictFrontingProviderIDsClientProbability] = 0.0
  437. err = clientConfig.SetParameters("tag5", false, applyParameters)
  438. if err != nil {
  439. t.Fatalf("SetParameters failed: %s", err)
  440. }
  441. // Test: client-side restrict provider ID
  442. applyParameters[parameters.RestrictDirectProviderIDs] = []string{providerID}
  443. applyParameters[parameters.RestrictDirectProviderIDsClientProbability] = 1.0
  444. err = clientConfig.SetParameters("tag6", false, applyParameters)
  445. if err != nil {
  446. t.Fatalf("SetParameters failed: %s", err)
  447. }
  448. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  449. if protocol.TunnelProtocolIsDirect(tunnelProtocol) {
  450. if err == nil {
  451. if dialParams != nil {
  452. t.Fatalf("unexpected MakeDialParameters success")
  453. }
  454. }
  455. } else {
  456. if err != nil {
  457. t.Fatalf("MakeDialParameters failed: %s", err)
  458. }
  459. }
  460. applyParameters[parameters.RestrictDirectProviderIDs] = []string{}
  461. applyParameters[parameters.RestrictDirectProviderIDsClientProbability] = 0.0
  462. err = clientConfig.SetParameters("tag7", false, applyParameters)
  463. if err != nil {
  464. t.Fatalf("SetParameters failed: %s", err)
  465. }
  466. // Test: client-side restrict provider ID by region
  467. applyParameters[parameters.RestrictDirectProviderRegions] = map[string][]string{providerID: {"CA"}}
  468. applyParameters[parameters.RestrictDirectProviderIDsClientProbability] = 1.0
  469. err = clientConfig.SetParameters("tag6", false, applyParameters)
  470. if err != nil {
  471. t.Fatalf("SetParameters failed: %s", err)
  472. }
  473. dialParams, err = MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
  474. if protocol.TunnelProtocolIsDirect(tunnelProtocol) {
  475. if err == nil {
  476. if dialParams != nil {
  477. t.Fatalf("unexpected MakeDialParameters success")
  478. }
  479. }
  480. } else {
  481. if err != nil {
  482. t.Fatalf("MakeDialParameters failed: %s", err)
  483. }
  484. }
  485. applyParameters[parameters.RestrictDirectProviderRegions] = map[string][]string{}
  486. applyParameters[parameters.RestrictDirectProviderIDsClientProbability] = 0.0
  487. err = clientConfig.SetParameters("tag7", false, applyParameters)
  488. if err != nil {
  489. t.Fatalf("SetParameters failed: %s", err)
  490. }
  491. // Test: iterator shuffles
  492. for i, serverEntry := range serverEntries {
  493. data, err := json.Marshal(serverEntry)
  494. if err != nil {
  495. t.Fatalf("json.Marshal failed: %s", err)
  496. }
  497. var serverEntryFields protocol.ServerEntryFields
  498. err = json.Unmarshal(data, &serverEntryFields)
  499. if err != nil {
  500. t.Fatalf("json.Unmarshal failed: %s", err)
  501. }
  502. err = StoreServerEntry(serverEntryFields, false)
  503. if err != nil {
  504. t.Fatalf("StoreServerEntry failed: %s", err)
  505. }
  506. if i%10 == 0 {
  507. dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
  508. if err != nil {
  509. t.Fatalf("MakeDialParameters failed: %s", err)
  510. }
  511. dialParams.Succeeded()
  512. }
  513. }
  514. for i := 0; i < 5; i++ {
  515. hasAffinity, iterator, err := NewServerEntryIterator(clientConfig)
  516. if err != nil {
  517. t.Fatalf("NewServerEntryIterator failed: %s", err)
  518. }
  519. if hasAffinity {
  520. t.Fatalf("unexpected affinity server")
  521. }
  522. // Test: the first shuffle should move the replay candidates to the front
  523. for j := 0; j < 10; j++ {
  524. serverEntry, err := iterator.Next()
  525. if err != nil {
  526. t.Fatalf("ServerEntryIterator.Next failed: %s", err)
  527. }
  528. dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
  529. if err != nil {
  530. t.Fatalf("MakeDialParameters failed: %s", err)
  531. }
  532. if !dialParams.IsReplay {
  533. t.Fatalf("unexpected non-replay")
  534. }
  535. }
  536. iterator.Reset()
  537. // Test: subsequent shuffles should not move the replay candidates
  538. allReplay := true
  539. for j := 0; j < 10; j++ {
  540. serverEntry, err := iterator.Next()
  541. if err != nil {
  542. t.Fatalf("ServerEntryIterator.Next failed: %s", err)
  543. }
  544. dialParams, err := MakeDialParameters(clientConfig, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
  545. if err != nil {
  546. t.Fatalf("MakeDialParameters failed: %s", err)
  547. }
  548. if !dialParams.IsReplay {
  549. allReplay = false
  550. }
  551. }
  552. if allReplay {
  553. t.Fatalf("unexpected all replay")
  554. }
  555. iterator.Close()
  556. }
  557. }
  558. func TestLimitTunnelDialPortNumbers(t *testing.T) {
  559. testDataDirName, err := ioutil.TempDir("", "psiphon-limit-tunnel-dial-port-numbers-test")
  560. if err != nil {
  561. t.Fatalf("TempDir failed: %s", err)
  562. }
  563. defer os.RemoveAll(testDataDirName)
  564. SetNoticeWriter(ioutil.Discard)
  565. clientConfig := &Config{
  566. PropagationChannelId: "0",
  567. SponsorId: "0",
  568. DataRootDirectory: testDataDirName,
  569. NetworkIDGetter: new(testNetworkGetter),
  570. }
  571. err = clientConfig.Commit(false)
  572. if err != nil {
  573. t.Fatalf("error committing configuration file: %s", err)
  574. }
  575. jsonLimitDialPortNumbers := `
  576. {
  577. "SSH" : [[10,11]],
  578. "OSSH" : [[20,21]],
  579. "QUIC-OSSH" : [[30,31]],
  580. "TAPDANCE-OSSH" : [[40,41]],
  581. "CONJURE-OSSH" : [[50,51]],
  582. "All" : [[60,61],80,443]
  583. }
  584. `
  585. var limitTunnelDialPortNumbers parameters.TunnelProtocolPortLists
  586. err = json.Unmarshal([]byte(jsonLimitDialPortNumbers), &limitTunnelDialPortNumbers)
  587. if err != nil {
  588. t.Fatalf("Unmarshal failed: %s", err)
  589. }
  590. applyParameters := make(map[string]interface{})
  591. applyParameters[parameters.LimitTunnelDialPortNumbers] = limitTunnelDialPortNumbers
  592. applyParameters[parameters.LimitTunnelDialPortNumbersProbability] = 1.0
  593. err = clientConfig.SetParameters("tag1", false, applyParameters)
  594. if err != nil {
  595. t.Fatalf("SetParameters failed: %s", err)
  596. }
  597. constraints := &protocolSelectionConstraints{
  598. limitTunnelDialPortNumbers: protocol.TunnelProtocolPortLists(
  599. clientConfig.GetParameters().Get().TunnelProtocolPortLists(parameters.LimitTunnelDialPortNumbers)),
  600. }
  601. selectProtocol := func(serverEntry *protocol.ServerEntry) (string, bool) {
  602. return constraints.selectProtocol(0, false, serverEntry)
  603. }
  604. for _, tunnelProtocol := range protocol.SupportedTunnelProtocols {
  605. if common.Contains(protocol.DefaultDisabledTunnelProtocols, tunnelProtocol) {
  606. continue
  607. }
  608. serverEntries := makeMockServerEntries(tunnelProtocol, "", "", "", 100)
  609. selected := false
  610. skipped := false
  611. for _, serverEntry := range serverEntries {
  612. selectedProtocol, ok := selectProtocol(serverEntry)
  613. if ok {
  614. if selectedProtocol != tunnelProtocol {
  615. t.Fatalf("unexpected selected protocol: %s", selectedProtocol)
  616. }
  617. port, err := serverEntry.GetDialPortNumber(selectedProtocol)
  618. if err != nil {
  619. t.Fatalf("GetDialPortNumber failed: %s", err)
  620. }
  621. if port%10 != 0 && port%10 != 1 && !protocol.TunnelProtocolUsesFrontedMeek(selectedProtocol) {
  622. t.Fatalf("unexpected dial port number: %d", port)
  623. }
  624. selected = true
  625. } else {
  626. skipped = true
  627. }
  628. }
  629. if !selected {
  630. t.Fatalf("expected at least one selected server entry: %s", tunnelProtocol)
  631. }
  632. if !skipped && !protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
  633. t.Fatalf("expected at least one skipped server entry: %s", tunnelProtocol)
  634. }
  635. }
  636. }
  637. func makeMockServerEntries(
  638. tunnelProtocol string,
  639. region string,
  640. providerID string,
  641. frontingProviderID string,
  642. count int) []*protocol.ServerEntry {
  643. serverEntries := make([]*protocol.ServerEntry, count)
  644. for i := 0; i < count; i++ {
  645. serverEntries[i] = &protocol.ServerEntry{
  646. IpAddress: fmt.Sprintf("192.168.0.%d", i),
  647. SshPort: prng.Range(10, 19),
  648. SshObfuscatedPort: prng.Range(20, 29),
  649. SshObfuscatedQUICPort: prng.Range(30, 39),
  650. SshObfuscatedTapDancePort: prng.Range(40, 49),
  651. SshObfuscatedConjurePort: prng.Range(50, 59),
  652. MeekServerPort: prng.Range(60, 69),
  653. MeekFrontingHosts: []string{"www1.example.org", "www2.example.org", "www3.example.org"},
  654. MeekFrontingAddressesRegex: "[a-z0-9]{1,64}.example.org",
  655. Region: region,
  656. ProviderID: providerID,
  657. FrontingProviderID: frontingProviderID,
  658. LocalSource: protocol.SERVER_ENTRY_SOURCE_EMBEDDED,
  659. LocalTimestamp: common.TruncateTimestampToHour(common.GetCurrentTimestamp()),
  660. Capabilities: []string{protocol.GetCapability(tunnelProtocol)},
  661. }
  662. }
  663. return serverEntries
  664. }
  665. func TestMakeHTTPTransformerParameters(t *testing.T) {
  666. type test struct {
  667. name string
  668. frontingProviderID string
  669. isFronted bool
  670. paramValues map[string]interface{}
  671. expectedTransformName string
  672. expectedTransformSpec transforms.Spec
  673. }
  674. tests := []test{
  675. {
  676. name: "unfronted",
  677. frontingProviderID: "",
  678. isFronted: false,
  679. paramValues: map[string]interface{}{
  680. "DirectHTTPProtocolTransformProbability": 1,
  681. "DirectHTTPProtocolTransformSpecs": transforms.Specs{
  682. "spec1": {{"A", "B"}},
  683. },
  684. "DirectHTTPProtocolTransformScopedSpecNames": transforms.ScopedSpecNames{
  685. "": {"spec1"},
  686. },
  687. },
  688. expectedTransformName: "spec1",
  689. expectedTransformSpec: [][2]string{{"A", "B"}},
  690. },
  691. {
  692. name: "fronted",
  693. frontingProviderID: "frontingProvider",
  694. isFronted: true,
  695. paramValues: map[string]interface{}{
  696. "FrontedHTTPProtocolTransformProbability": 1,
  697. "FrontedHTTPProtocolTransformSpecs": transforms.Specs{
  698. "spec1": {{"A", "B"}},
  699. },
  700. "FrontedHTTPProtocolTransformScopedSpecNames": transforms.ScopedSpecNames{
  701. "frontingProvider": {"spec1"},
  702. },
  703. },
  704. expectedTransformName: "spec1",
  705. expectedTransformSpec: [][2]string{{"A", "B"}},
  706. },
  707. {
  708. name: "no transform, coinflip false",
  709. frontingProviderID: "frontingProvider",
  710. isFronted: false,
  711. paramValues: map[string]interface{}{
  712. "DirectHTTPProtocolTransformProbability": 0,
  713. "DirectHTTPProtocolTransformSpecs": transforms.Specs{
  714. "spec1": {{"A", "B"}},
  715. },
  716. "DirectHTTPProtocolTransformScopedSpecNames": transforms.ScopedSpecNames{
  717. "frontingProvider": {"spec1"},
  718. },
  719. },
  720. expectedTransformName: "",
  721. expectedTransformSpec: nil,
  722. },
  723. }
  724. for _, tt := range tests {
  725. t.Run(tt.name, func(t *testing.T) {
  726. params, err := parameters.NewParameters(nil)
  727. if err != nil {
  728. t.Fatalf("parameters.NewParameters failed %v", err)
  729. }
  730. _, err = params.Set("", false, tt.paramValues)
  731. if err != nil {
  732. t.Fatalf("params.Set failed %v", err)
  733. }
  734. httpTransformerParams, err := makeHTTPTransformerParameters(params.Get(), tt.frontingProviderID, tt.isFronted)
  735. if err != nil {
  736. t.Fatalf("MakeHTTPTransformerParameters failed %v", err)
  737. }
  738. if httpTransformerParams.ProtocolTransformName != tt.expectedTransformName {
  739. t.Fatalf("expected ProtocolTransformName \"%s\" but got \"%s\"", tt.expectedTransformName, httpTransformerParams.ProtocolTransformName)
  740. }
  741. if !reflect.DeepEqual(httpTransformerParams.ProtocolTransformSpec, tt.expectedTransformSpec) {
  742. t.Fatalf("expected ProtocolTransformSpec %v but got %v", tt.expectedTransformSpec, httpTransformerParams.ProtocolTransformSpec)
  743. }
  744. if httpTransformerParams.ProtocolTransformSpec != nil {
  745. if httpTransformerParams.ProtocolTransformSeed == nil {
  746. t.Fatalf("expected non-nil seed")
  747. }
  748. }
  749. })
  750. }
  751. }
  752. func TestMakeOSSHObfuscatorSeedTranformerParameters(t *testing.T) {
  753. type test struct {
  754. name string
  755. paramValues map[string]interface{}
  756. expectedTransformName string
  757. expectedTransformSpec transforms.Spec
  758. }
  759. tests := []test{
  760. {
  761. name: "transform",
  762. paramValues: map[string]interface{}{
  763. "OSSHObfuscatorSeedTransformProbability": 1,
  764. "OSSHObfuscatorSeedTransformSpecs": transforms.Specs{
  765. "spec1": {{"A", "B"}},
  766. },
  767. "OSSHObfuscatorSeedTransformScopedSpecNames": transforms.ScopedSpecNames{
  768. "": {"spec1"},
  769. },
  770. },
  771. expectedTransformName: "spec1",
  772. expectedTransformSpec: [][2]string{{"A", "B"}},
  773. },
  774. {
  775. name: "no transform, coinflip false",
  776. paramValues: map[string]interface{}{
  777. "OSSHObfuscatorSeedTransformProbability": 0,
  778. "OSSHObfuscatorSeedTransformSpecs": transforms.Specs{
  779. "spec1": {{"A", "B"}},
  780. },
  781. "OSSHObfuscatorSeedTransformScopedSpecNames": transforms.ScopedSpecNames{
  782. "": {"spec1"},
  783. },
  784. },
  785. expectedTransformName: "",
  786. expectedTransformSpec: nil,
  787. },
  788. }
  789. for _, tt := range tests {
  790. t.Run(tt.name, func(t *testing.T) {
  791. params, err := parameters.NewParameters(nil)
  792. if err != nil {
  793. t.Fatalf("parameters.NewParameters failed: %v", err)
  794. }
  795. _, err = params.Set("", false, tt.paramValues)
  796. if err != nil {
  797. t.Fatalf("params.Set failed: %v", err)
  798. }
  799. transformerParams, err := makeSeedTransformerParameters(
  800. params.Get(),
  801. parameters.OSSHObfuscatorSeedTransformProbability,
  802. parameters.OSSHObfuscatorSeedTransformSpecs,
  803. parameters.OSSHObfuscatorSeedTransformScopedSpecNames)
  804. if err != nil {
  805. t.Fatalf("makeSeedTransformerParameters failed: %v", err)
  806. }
  807. if transformerParams.TransformName != tt.expectedTransformName {
  808. t.Fatalf("expected TransformName \"%s\" but got \"%s\"", tt.expectedTransformName, transformerParams.TransformName)
  809. }
  810. if !reflect.DeepEqual(transformerParams.TransformSpec, tt.expectedTransformSpec) {
  811. t.Fatalf("expected TransformSpec %v but got %v", tt.expectedTransformSpec, transformerParams.TransformSpec)
  812. }
  813. if transformerParams.TransformSpec != nil {
  814. if transformerParams.TransformSeed == nil {
  815. t.Fatalf("expected non-nil seed")
  816. }
  817. }
  818. })
  819. }
  820. }