dialParameters.go 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946
  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. "context"
  23. "crypto/md5"
  24. "encoding/binary"
  25. "fmt"
  26. "net"
  27. "net/http"
  28. "strconv"
  29. "strings"
  30. "sync/atomic"
  31. "time"
  32. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  33. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  34. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/fragmentor"
  35. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/obfuscator"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
  37. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
  38. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  39. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/regen"
  40. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/resolver"
  41. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/transforms"
  42. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
  43. lrucache "github.com/cognusion/go-cache-lru"
  44. "golang.org/x/net/bpf"
  45. )
  46. // DialParameters represents a selected protocol and all the related selected
  47. // protocol attributes, many chosen at random, for a tunnel dial attempt.
  48. //
  49. // DialParameters is used:
  50. // - to configure dialers
  51. // - as a persistent record to store successful dial parameters for replay
  52. // - to report dial stats in notices and Psiphon API calls.
  53. //
  54. // MeekResolvedIPAddress is set asynchronously, as it is not known until the
  55. // dial process has begun. The atomic.Value will contain a string, initialized
  56. // to "", and set to the resolved IP address once that part of the dial
  57. // process has completed.
  58. //
  59. // DialParameters is not safe for concurrent use.
  60. type DialParameters struct {
  61. ServerEntry *protocol.ServerEntry `json:"-"`
  62. NetworkID string `json:"-"`
  63. IsReplay bool `json:"-"`
  64. CandidateNumber int `json:"-"`
  65. EstablishedTunnelsCount int `json:"-"`
  66. IsExchanged bool
  67. LastUsedTimestamp time.Time
  68. LastUsedConfigStateHash []byte
  69. LastUsedServerEntryHash []byte
  70. NetworkLatencyMultiplier float64
  71. TunnelProtocol string
  72. DirectDialAddress string
  73. DialPortNumber string
  74. UpstreamProxyType string `json:"-"`
  75. UpstreamProxyCustomHeaderNames []string `json:"-"`
  76. BPFProgramName string
  77. BPFProgramInstructions []bpf.RawInstruction
  78. SelectedSSHClientVersion bool
  79. SSHClientVersion string
  80. SSHKEXSeed *prng.Seed
  81. ObfuscatorPaddingSeed *prng.Seed
  82. OSSHObfuscatorSeedTransformerParameters *transforms.ObfuscatorSeedTransformerParameters
  83. OSSHPrefixSpec *obfuscator.OSSHPrefixSpec
  84. OSSHPrefixSplitConfig *obfuscator.OSSHPrefixSplitConfig
  85. FragmentorSeed *prng.Seed
  86. FrontingProviderID string
  87. MeekFrontingDialAddress string
  88. MeekFrontingHost string
  89. MeekDialAddress string
  90. MeekTransformedHostName bool
  91. MeekSNIServerName string
  92. MeekVerifyServerName string
  93. MeekVerifyPins []string
  94. MeekHostHeader string
  95. MeekObfuscatorPaddingSeed *prng.Seed
  96. MeekTLSPaddingSize int
  97. MeekResolvedIPAddress atomic.Value `json:"-"`
  98. TLSOSSHTransformedSNIServerName bool
  99. TLSOSSHSNIServerName string
  100. TLSOSSHObfuscatorPaddingSeed *prng.Seed
  101. SelectedUserAgent bool
  102. UserAgent string
  103. SelectedTLSProfile bool
  104. TLSProfile string
  105. NoDefaultTLSSessionID bool
  106. TLSVersion string
  107. RandomizedTLSProfileSeed *prng.Seed
  108. TLSFragmentClientHello bool
  109. QUICVersion string
  110. QUICDialSNIAddress string
  111. QUICClientHelloSeed *prng.Seed
  112. ObfuscatedQUICPaddingSeed *prng.Seed
  113. ObfuscatedQUICNonceTransformerParameters *transforms.ObfuscatorSeedTransformerParameters
  114. QUICDisablePathMTUDiscovery bool
  115. ConjureCachedRegistrationTTL time.Duration
  116. ConjureAPIRegistration bool
  117. ConjureAPIRegistrarBidirectionalURL string
  118. ConjureAPIRegistrarDelay time.Duration
  119. ConjureDecoyRegistration bool
  120. ConjureDecoyRegistrarDelay time.Duration
  121. ConjureDecoyRegistrarWidth int
  122. ConjureTransport string
  123. ConjureSTUNServerAddress string
  124. ConjureDTLSEmptyInitialPacket bool
  125. LivenessTestSeed *prng.Seed
  126. APIRequestPaddingSeed *prng.Seed
  127. HoldOffTunnelDuration time.Duration
  128. DialConnMetrics common.MetricsSource `json:"-"`
  129. DialConnNoticeMetrics common.NoticeMetricsSource `json:"-"`
  130. ObfuscatedSSHConnMetrics common.MetricsSource `json:"-"`
  131. DialDuration time.Duration `json:"-"`
  132. resolver *resolver.Resolver `json:"-"`
  133. ResolveParameters *resolver.ResolveParameters
  134. HTTPTransformerParameters *transforms.HTTPTransformerParameters
  135. SteeringIP string
  136. steeringIPCache *lrucache.Cache `json:"-"`
  137. steeringIPCacheKey string `json:"-"`
  138. dialConfig *DialConfig `json:"-"`
  139. meekConfig *MeekConfig `json:"-"`
  140. }
  141. // MakeDialParameters creates a new DialParameters for the candidate server
  142. // entry, including selecting a protocol and all the various protocol
  143. // attributes. The input selectProtocol is used to comply with any active
  144. // protocol selection constraints.
  145. //
  146. // When stored dial parameters are available and may be used,
  147. // MakeDialParameters may replay previous dial parameters in an effort to
  148. // leverage "known working" values instead of always chosing at random from a
  149. // large space.
  150. //
  151. // MakeDialParameters will return nil/nil in cases where the candidate server
  152. // entry should be skipped.
  153. //
  154. // To support replay, the caller must call DialParameters.Succeeded when a
  155. // successful tunnel is established with the returned DialParameters; and must
  156. // call DialParameters.Failed when a tunnel dial or activation fails, except
  157. // when establishment is cancelled.
  158. func MakeDialParameters(
  159. config *Config,
  160. steeringIPCache *lrucache.Cache,
  161. upstreamProxyErrorCallback func(error),
  162. canReplay func(serverEntry *protocol.ServerEntry, replayProtocol string) bool,
  163. selectProtocol func(serverEntry *protocol.ServerEntry) (string, bool),
  164. serverEntry *protocol.ServerEntry,
  165. isTactics bool,
  166. candidateNumber int,
  167. establishedTunnelsCount int) (*DialParameters, error) {
  168. networkID := config.GetNetworkID()
  169. p := config.GetParameters().Get()
  170. ttl := p.Duration(parameters.ReplayDialParametersTTL)
  171. replayIgnoreChangedConfigState := p.Bool(parameters.ReplayIgnoreChangedConfigState)
  172. replayBPF := p.Bool(parameters.ReplayBPF)
  173. replaySSH := p.Bool(parameters.ReplaySSH)
  174. replayObfuscatorPadding := p.Bool(parameters.ReplayObfuscatorPadding)
  175. replayFragmentor := p.Bool(parameters.ReplayFragmentor)
  176. replayTLSProfile := p.Bool(parameters.ReplayTLSProfile)
  177. replayTLSFragmentClientHello := p.Bool(parameters.ReplayTLSFragmentClientHello)
  178. replayFronting := p.Bool(parameters.ReplayFronting)
  179. replayHostname := p.Bool(parameters.ReplayHostname)
  180. replayQUICVersion := p.Bool(parameters.ReplayQUICVersion)
  181. replayObfuscatedQUIC := p.Bool(parameters.ReplayObfuscatedQUIC)
  182. replayObfuscatedQUICNonceTransformer := p.Bool(parameters.ReplayObfuscatedQUICNonceTransformer)
  183. replayConjureRegistration := p.Bool(parameters.ReplayConjureRegistration)
  184. replayConjureTransport := p.Bool(parameters.ReplayConjureTransport)
  185. replayLivenessTest := p.Bool(parameters.ReplayLivenessTest)
  186. replayUserAgent := p.Bool(parameters.ReplayUserAgent)
  187. replayAPIRequestPadding := p.Bool(parameters.ReplayAPIRequestPadding)
  188. replayHoldOffTunnel := p.Bool(parameters.ReplayHoldOffTunnel)
  189. replayResolveParameters := p.Bool(parameters.ReplayResolveParameters)
  190. replayHTTPTransformerParameters := p.Bool(parameters.ReplayHTTPTransformerParameters)
  191. replayOSSHSeedTransformerParameters := p.Bool(parameters.ReplayOSSHSeedTransformerParameters)
  192. replayOSSHPrefix := p.Bool(parameters.ReplayOSSHPrefix)
  193. // Check for existing dial parameters for this server/network ID.
  194. dialParams, err := GetDialParameters(
  195. config, serverEntry.IpAddress, networkID)
  196. if err != nil {
  197. NoticeWarning("GetDialParameters failed: %s", err)
  198. dialParams = nil
  199. // Proceed, without existing dial parameters.
  200. }
  201. // Check if replay is permitted:
  202. // - TTL must be > 0 and existing dial parameters must not have expired
  203. // as indicated by LastUsedTimestamp + TTL.
  204. // - Config/tactics/server entry values must be unchanged from when
  205. // previous dial parameters were established.
  206. // - The protocol selection constraints must permit replay, as indicated
  207. // by canReplay.
  208. // - Must not be using an obsolete TLS profile that is no longer supported.
  209. // - Must be using the latest Conjure API URL.
  210. //
  211. // When existing dial parameters don't meet these conditions, dialParams
  212. // is reset to nil and new dial parameters will be generated.
  213. var currentTimestamp time.Time
  214. var configStateHash []byte
  215. var serverEntryHash []byte
  216. // When TTL is 0, replay is disabled; the timestamp remains 0 and the
  217. // output DialParameters will not be stored by Success.
  218. if ttl > 0 {
  219. currentTimestamp = time.Now()
  220. configStateHash, serverEntryHash = getDialStateHashes(config, p, serverEntry)
  221. }
  222. if dialParams != nil &&
  223. (ttl <= 0 ||
  224. dialParams.LastUsedTimestamp.Before(currentTimestamp.Add(-ttl)) ||
  225. // Replay is disabled when the current config state hash -- config
  226. // dial parameters and the current tactics tag -- have changed
  227. // since the last dial. This prioritizes applying any potential
  228. // tactics change over redialing with parameters that may have
  229. // changed in tactics.
  230. //
  231. // Because of this, frequent tactics changes may degrade replay
  232. // effectiveness. When ReplayIgnoreChangedConfigState is set,
  233. // differences in the config state hash are ignored.
  234. //
  235. // Limitation: some code which previously assumed that replay
  236. // always implied unchanged tactics parameters may now use newer
  237. // tactics parameters in replay cases when
  238. // ReplayIgnoreChangedConfigState is set. One case is the call
  239. // below to fragmentor.NewUpstreamConfig, made when initializing
  240. // dialParams.dialConfig.
  241. (!replayIgnoreChangedConfigState && !bytes.Equal(dialParams.LastUsedConfigStateHash, configStateHash)) ||
  242. // Replay is disabled when the server entry has changed.
  243. !bytes.Equal(dialParams.LastUsedServerEntryHash, serverEntryHash) ||
  244. (dialParams.TLSProfile != "" &&
  245. !common.Contains(protocol.SupportedTLSProfiles, dialParams.TLSProfile)) ||
  246. (dialParams.QUICVersion != "" &&
  247. !common.Contains(protocol.SupportedQUICVersions, dialParams.QUICVersion)) ||
  248. // Legacy clients use ConjureAPIRegistrarURL with
  249. // gotapdance.tapdance.APIRegistrar and new clients use
  250. // ConjureAPIRegistrarBidirectionalURL with
  251. // gotapdance.tapdance.APIRegistrarBidirectional. Updated clients
  252. // may have replay dial parameters with the old
  253. // ConjureAPIRegistrarURL field, which is now ignored. In this
  254. // case, ConjureAPIRegistrarBidirectionalURL will be blank. Reset
  255. // this replay.
  256. (dialParams.ConjureAPIRegistration && dialParams.ConjureAPIRegistrarBidirectionalURL == "")) {
  257. // In these cases, existing dial parameters are expired or no longer
  258. // match the config state and so are cleared to avoid rechecking them.
  259. err = DeleteDialParameters(serverEntry.IpAddress, networkID)
  260. if err != nil {
  261. NoticeWarning("DeleteDialParameters failed: %s", err)
  262. }
  263. dialParams = nil
  264. }
  265. if dialParams != nil {
  266. if config.DisableReplay ||
  267. !canReplay(serverEntry, dialParams.TunnelProtocol) {
  268. // In these ephemeral cases, existing dial parameters may still be valid
  269. // and used in future establishment phases, and so are retained.
  270. dialParams = nil
  271. }
  272. }
  273. // IsExchanged:
  274. //
  275. // Dial parameters received via client-to-client exchange are partially
  276. // initialized. Only the exchange fields are retained, and all other dial
  277. // parameters fields must be initialized. This is not considered or logged as
  278. // a replay. The exchange case is identified by the IsExchanged flag.
  279. //
  280. // When previously stored, IsExchanged dial parameters will have set the same
  281. // timestamp and state hash used for regular dial parameters and the same
  282. // logic above should invalidate expired or invalid exchanged dial
  283. // parameters.
  284. //
  285. // Limitation: metrics will indicate when an exchanged server entry is used
  286. // (source "EXCHANGED") but will not indicate when exchanged dial parameters
  287. // are used vs. a redial after discarding dial parameters.
  288. isReplay := (dialParams != nil)
  289. isExchanged := isReplay && dialParams.IsExchanged
  290. if !isReplay {
  291. dialParams = &DialParameters{}
  292. }
  293. if isExchanged {
  294. // Set isReplay to false to cause all non-exchanged values to be
  295. // initialized; this also causes the exchange case to not log as replay.
  296. isReplay = false
  297. }
  298. // Set IsExchanged such that full dial parameters are stored and replayed
  299. // upon success.
  300. dialParams.IsExchanged = false
  301. // Point to the current resolver to be used in dials.
  302. dialParams.resolver = config.GetResolver()
  303. if dialParams.resolver == nil {
  304. return nil, errors.TraceNew("missing resolver")
  305. }
  306. dialParams.steeringIPCache = steeringIPCache
  307. dialParams.ServerEntry = serverEntry
  308. dialParams.NetworkID = networkID
  309. dialParams.IsReplay = isReplay
  310. dialParams.CandidateNumber = candidateNumber
  311. dialParams.EstablishedTunnelsCount = establishedTunnelsCount
  312. // Even when replaying, LastUsedTimestamp is updated to extend the TTL of
  313. // replayed dial parameters which will be updated in the datastore upon
  314. // success.
  315. dialParams.LastUsedTimestamp = currentTimestamp
  316. dialParams.LastUsedConfigStateHash = configStateHash
  317. dialParams.LastUsedServerEntryHash = serverEntryHash
  318. // Initialize dial parameters.
  319. //
  320. // When not replaying, all required parameters are initialized. When
  321. // replaying, existing parameters are retained, subject to the replay-X
  322. // tactics flags.
  323. // Select a network latency multiplier for this dial. This allows clients to
  324. // explore and discover timeout values appropriate for the current network.
  325. // The selection applies per tunnel, to avoid delaying all establishment
  326. // candidates due to excessive timeouts. The random selection is bounded by a
  327. // min/max set in tactics and an exponential distribution is used so as to
  328. // heavily favor values close to the min, which should be set to the
  329. // singleton NetworkLatencyMultiplier tactics value.
  330. //
  331. // For NetworkLatencyMultiplierLambda close to 2.0, values near min are
  332. // very approximately 10x more likely to be selected than values near
  333. // max, while for NetworkLatencyMultiplierLambda close to 0.1, the
  334. // distribution is close to uniform.
  335. //
  336. // Not all existing, persisted DialParameters will have a custom
  337. // NetworkLatencyMultiplier value. Its zero value will cause the singleton
  338. // NetworkLatencyMultiplier tactics value to be used instead, which is
  339. // consistent with the pre-custom multiplier behavior in the older client
  340. // version which persisted that DialParameters.
  341. networkLatencyMultiplierMin := p.Float(parameters.NetworkLatencyMultiplierMin)
  342. networkLatencyMultiplierMax := p.Float(parameters.NetworkLatencyMultiplierMax)
  343. if !isReplay ||
  344. // Was selected...
  345. (dialParams.NetworkLatencyMultiplier != 0.0 &&
  346. // But is now outside tactics range...
  347. (dialParams.NetworkLatencyMultiplier < networkLatencyMultiplierMin ||
  348. dialParams.NetworkLatencyMultiplier > networkLatencyMultiplierMax)) {
  349. dialParams.NetworkLatencyMultiplier = prng.ExpFloat64Range(
  350. networkLatencyMultiplierMin,
  351. networkLatencyMultiplierMax,
  352. p.Float(parameters.NetworkLatencyMultiplierLambda))
  353. }
  354. // After this point, any tactics parameters that apply the network latency
  355. // multiplier will use this selected value.
  356. p = config.GetParameters().GetCustom(dialParams.NetworkLatencyMultiplier)
  357. if !isReplay && !isExchanged {
  358. // TODO: should there be a pre-check of selectProtocol before incurring
  359. // overhead of unmarshaling dial parameters? In may be that a server entry
  360. // is fully incapable of satisfying the current protocol selection
  361. // constraints.
  362. selectedProtocol, ok := selectProtocol(serverEntry)
  363. if !ok {
  364. return nil, nil
  365. }
  366. dialParams.TunnelProtocol = selectedProtocol
  367. }
  368. // Skip this candidate when the clients tactics restrict usage of the
  369. // provider ID. See the corresponding server-side enforcement comments in
  370. // server.TacticsListener.accept.
  371. if protocol.TunnelProtocolIsDirect(dialParams.TunnelProtocol) &&
  372. (common.Contains(
  373. p.Strings(parameters.RestrictDirectProviderIDs),
  374. dialParams.ServerEntry.ProviderID) ||
  375. common.ContainsAny(
  376. p.KeyStrings(parameters.RestrictDirectProviderRegions, dialParams.ServerEntry.ProviderID), []string{"", serverEntry.Region})) {
  377. if p.WeightedCoinFlip(
  378. parameters.RestrictDirectProviderIDsClientProbability) {
  379. // When skipping, return nil/nil as no error should be logged.
  380. // NoticeSkipServerEntry emits each skip reason, regardless
  381. // of server entry, at most once per session.
  382. NoticeSkipServerEntry(
  383. "restricted provider ID: %s",
  384. dialParams.ServerEntry.ProviderID)
  385. return nil, nil
  386. }
  387. }
  388. // Skip this candidate when the clients tactics restrict usage of the
  389. // fronting provider ID. See the corresponding server-side enforcement
  390. // comments in server.MeekServer.getSessionOrEndpoint.
  391. if protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) &&
  392. common.Contains(
  393. p.Strings(parameters.RestrictFrontingProviderIDs),
  394. dialParams.ServerEntry.FrontingProviderID) {
  395. if p.WeightedCoinFlip(
  396. parameters.RestrictFrontingProviderIDsClientProbability) {
  397. // When skipping, return nil/nil as no error should be logged.
  398. // NoticeSkipServerEntry emits each skip reason, regardless
  399. // of server entry, at most once per session.
  400. NoticeSkipServerEntry(
  401. "restricted fronting provider ID: %s",
  402. dialParams.ServerEntry.FrontingProviderID)
  403. return nil, nil
  404. }
  405. }
  406. if config.UseUpstreamProxy() {
  407. // When UpstreamProxy is configured, ServerEntry.GetSupportedProtocols, when
  408. // called via selectProtocol, will filter out protocols such that will not
  409. // select a protocol incompatible with UpstreamProxy. This additional check
  410. // will catch cases where selectProtocol does not apply this filter.
  411. if !protocol.TunnelProtocolSupportsUpstreamProxy(dialParams.TunnelProtocol) {
  412. NoticeSkipServerEntry(
  413. "protocol does not support upstream proxy: %s",
  414. dialParams.TunnelProtocol)
  415. return nil, nil
  416. }
  417. // Skip this candidate when the server entry is not to be used with an
  418. // upstream proxy. By not exposing servers from sources that are
  419. // relatively hard to enumerate, this mechanism mitigates the risk of
  420. // a malicious upstream proxy enumerating Psiphon servers. Populate
  421. // the allowed sources with fronted servers to provide greater
  422. // blocking resistence for clients using upstream proxy clients that
  423. // are subject to blocking.
  424. source := dialParams.ServerEntry.LocalSource
  425. if !protocol.AllowServerEntrySourceWithUpstreamProxy(source) &&
  426. !p.Bool(parameters.UpstreamProxyAllowAllServerEntrySources) {
  427. NoticeSkipServerEntry(
  428. "server entry source disallowed with upstream proxy: %s",
  429. source)
  430. return nil, nil
  431. }
  432. }
  433. if (!isReplay || !replayBPF) &&
  434. ClientBPFEnabled() &&
  435. protocol.TunnelProtocolUsesTCP(dialParams.TunnelProtocol) {
  436. if p.WeightedCoinFlip(parameters.BPFClientTCPProbability) {
  437. dialParams.BPFProgramName = ""
  438. dialParams.BPFProgramInstructions = nil
  439. ok, name, rawInstructions := p.BPFProgram(parameters.BPFClientTCPProgram)
  440. if ok {
  441. dialParams.BPFProgramName = name
  442. dialParams.BPFProgramInstructions = rawInstructions
  443. }
  444. }
  445. }
  446. if !isReplay || !replaySSH {
  447. dialParams.SelectedSSHClientVersion = true
  448. dialParams.SSHClientVersion = values.GetSSHClientVersion()
  449. dialParams.SSHKEXSeed, err = prng.NewSeed()
  450. if err != nil {
  451. return nil, errors.Trace(err)
  452. }
  453. }
  454. if !isReplay || !replayObfuscatorPadding {
  455. dialParams.ObfuscatorPaddingSeed, err = prng.NewSeed()
  456. if err != nil {
  457. return nil, errors.Trace(err)
  458. }
  459. if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) {
  460. dialParams.MeekObfuscatorPaddingSeed, err = prng.NewSeed()
  461. if err != nil {
  462. return nil, errors.Trace(err)
  463. }
  464. } else if protocol.TunnelProtocolUsesTLSOSSH(dialParams.TunnelProtocol) {
  465. dialParams.TLSOSSHObfuscatorPaddingSeed, err = prng.NewSeed()
  466. if err != nil {
  467. return nil, errors.Trace(err)
  468. }
  469. }
  470. }
  471. if !isReplay || !replayFragmentor {
  472. dialParams.FragmentorSeed, err = prng.NewSeed()
  473. if err != nil {
  474. return nil, errors.Trace(err)
  475. }
  476. }
  477. if (!isReplay || !replayConjureRegistration) &&
  478. protocol.TunnelProtocolUsesConjure(dialParams.TunnelProtocol) {
  479. dialParams.ConjureCachedRegistrationTTL = p.Duration(parameters.ConjureCachedRegistrationTTL)
  480. apiURL := p.String(parameters.ConjureAPIRegistrarBidirectionalURL)
  481. decoyWidth := p.Int(parameters.ConjureDecoyRegistrarWidth)
  482. dialParams.ConjureAPIRegistration = apiURL != ""
  483. dialParams.ConjureDecoyRegistration = decoyWidth != 0
  484. // We select only one of API or decoy registration. When both are enabled,
  485. // ConjureDecoyRegistrarProbability determines the probability of using
  486. // decoy registration.
  487. //
  488. // In general, we disable retries in gotapdance and rely on Psiphon
  489. // establishment to try/retry different registration schemes. This allows us
  490. // to control the proportion of registration types attempted. And, in good
  491. // network conditions, individual candidates are most likely to be cancelled
  492. // before they exhaust their retry options.
  493. if dialParams.ConjureAPIRegistration && dialParams.ConjureDecoyRegistration {
  494. if p.WeightedCoinFlip(parameters.ConjureDecoyRegistrarProbability) {
  495. dialParams.ConjureAPIRegistration = false
  496. }
  497. }
  498. if dialParams.ConjureAPIRegistration {
  499. // While Conjure API registration uses MeekConn and specifies common meek
  500. // parameters, the meek address and SNI configuration is implemented in this
  501. // code block and not in common code blocks below. The exception is TLS
  502. // configuration.
  503. //
  504. // Accordingly, replayFronting/replayHostname have no effect on Conjure API
  505. // registration replay.
  506. dialParams.ConjureAPIRegistrarBidirectionalURL = apiURL
  507. frontingSpecs := p.FrontingSpecs(parameters.ConjureAPIRegistrarFrontingSpecs)
  508. dialParams.FrontingProviderID,
  509. dialParams.MeekFrontingDialAddress,
  510. dialParams.MeekSNIServerName,
  511. dialParams.MeekVerifyServerName,
  512. dialParams.MeekVerifyPins,
  513. dialParams.MeekFrontingHost,
  514. err = frontingSpecs.SelectParameters()
  515. if err != nil {
  516. return nil, errors.Trace(err)
  517. }
  518. if config.DisableSystemRootCAs {
  519. return nil, errors.TraceNew("TLS certificates must be verified in Conjure API registration")
  520. }
  521. dialParams.MeekDialAddress = net.JoinHostPort(dialParams.MeekFrontingDialAddress, "443")
  522. dialParams.MeekHostHeader = dialParams.MeekFrontingHost
  523. // For a FrontingSpec, an SNI value of "" indicates to disable/omit SNI, so
  524. // never transform in that case.
  525. if dialParams.MeekSNIServerName != "" {
  526. if p.WeightedCoinFlip(parameters.TransformHostNameProbability) {
  527. dialParams.MeekSNIServerName = selectHostName(dialParams.TunnelProtocol, p)
  528. dialParams.MeekTransformedHostName = true
  529. }
  530. }
  531. // The minimum delay value is determined by the Conjure station, which
  532. // performs an asynchronous "liveness test" against the selected phantom
  533. // IPs. The min/max range allows us to introduce some jitter so that we
  534. // don't present a trivial inter-flow fingerprint: CDN connection, fixed
  535. // delay, phantom dial.
  536. minDelay := p.Duration(parameters.ConjureAPIRegistrarMinDelay)
  537. maxDelay := p.Duration(parameters.ConjureAPIRegistrarMaxDelay)
  538. dialParams.ConjureAPIRegistrarDelay = prng.Period(minDelay, maxDelay)
  539. } else if dialParams.ConjureDecoyRegistration {
  540. dialParams.ConjureDecoyRegistrarWidth = decoyWidth
  541. minDelay := p.Duration(parameters.ConjureDecoyRegistrarMinDelay)
  542. maxDelay := p.Duration(parameters.ConjureDecoyRegistrarMaxDelay)
  543. dialParams.ConjureAPIRegistrarDelay = prng.Period(minDelay, maxDelay)
  544. } else {
  545. return nil, errors.TraceNew("no Conjure registrar configured")
  546. }
  547. }
  548. if (!isReplay || !replayConjureTransport) &&
  549. protocol.TunnelProtocolUsesConjure(dialParams.TunnelProtocol) {
  550. // None of ConjureEnableIPv6Dials, ConjureEnablePortRandomization, or
  551. // ConjureEnableRegistrationOverrides are set here for replay. The
  552. // current value of these flag parameters is always applied.
  553. dialParams.ConjureTransport = selectConjureTransport(p)
  554. if protocol.ConjureTransportUsesSTUN(dialParams.ConjureTransport) {
  555. stunServerAddresses := p.Strings(parameters.ConjureSTUNServerAddresses)
  556. if len(stunServerAddresses) == 0 {
  557. return nil, errors.Tracef(
  558. "no Conjure STUN servers addresses configured for transport %s", dialParams.ConjureTransport)
  559. }
  560. dialParams.ConjureSTUNServerAddress = stunServerAddresses[prng.Intn(len(stunServerAddresses))]
  561. dialParams.ConjureDTLSEmptyInitialPacket = p.WeightedCoinFlip(
  562. parameters.ConjureDTLSEmptyInitialPacketProbability)
  563. }
  564. }
  565. usingTLS := protocol.TunnelProtocolUsesMeekHTTPS(dialParams.TunnelProtocol) ||
  566. protocol.TunnelProtocolUsesTLSOSSH(dialParams.TunnelProtocol) ||
  567. dialParams.ConjureAPIRegistration
  568. if (!isReplay || !replayTLSProfile) && usingTLS {
  569. dialParams.SelectedTLSProfile = true
  570. requireTLS12SessionTickets := protocol.TunnelProtocolRequiresTLS12SessionTickets(
  571. dialParams.TunnelProtocol)
  572. requireTLS13Support := protocol.TunnelProtocolRequiresTLS13Support(dialParams.TunnelProtocol)
  573. isFronted := protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) ||
  574. dialParams.ConjureAPIRegistration
  575. dialParams.TLSProfile, dialParams.TLSVersion, dialParams.RandomizedTLSProfileSeed, err = SelectTLSProfile(
  576. requireTLS12SessionTickets, requireTLS13Support, isFronted, serverEntry.FrontingProviderID, p)
  577. if err != nil {
  578. return nil, errors.Trace(err)
  579. }
  580. if dialParams.TLSProfile == "" && (requireTLS12SessionTickets || requireTLS13Support) {
  581. return nil, errors.TraceNew("required TLS profile not found")
  582. }
  583. dialParams.NoDefaultTLSSessionID = p.WeightedCoinFlip(
  584. parameters.NoDefaultTLSSessionIDProbability)
  585. }
  586. if (!isReplay || !replayFronting) &&
  587. protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) {
  588. dialParams.FrontingProviderID = serverEntry.FrontingProviderID
  589. dialParams.MeekFrontingDialAddress, dialParams.MeekFrontingHost, err =
  590. selectFrontingParameters(serverEntry)
  591. if err != nil {
  592. return nil, errors.Trace(err)
  593. }
  594. }
  595. if !isReplay || !replayHostname {
  596. // Any MeekHostHeader selections made here will be overridden below,
  597. // as required, for fronting cases.
  598. if protocol.TunnelProtocolUsesMeekHTTPS(dialParams.TunnelProtocol) ||
  599. protocol.TunnelProtocolUsesFrontedMeekQUIC(dialParams.TunnelProtocol) {
  600. dialParams.MeekSNIServerName = ""
  601. hostname := ""
  602. if p.WeightedCoinFlip(parameters.TransformHostNameProbability) {
  603. dialParams.MeekSNIServerName = selectHostName(dialParams.TunnelProtocol, p)
  604. hostname = dialParams.MeekSNIServerName
  605. dialParams.MeekTransformedHostName = true
  606. } else {
  607. // Always select a hostname for the Host header in this case.
  608. // Unlike HTTP, the Host header isn't plaintext on the wire,
  609. // and so there's no anti-fingerprint benefit from presenting
  610. // the server IP address in the Host header. Omitting the
  611. // server IP here can prevent exposing it in certain
  612. // scenarios where the traffic is rerouted and arrives at a
  613. // different HTTPS server.
  614. hostname = selectHostName(dialParams.TunnelProtocol, p)
  615. }
  616. if serverEntry.MeekServerPort == 443 {
  617. dialParams.MeekHostHeader = hostname
  618. } else {
  619. dialParams.MeekHostHeader = net.JoinHostPort(
  620. hostname, strconv.Itoa(serverEntry.MeekServerPort))
  621. }
  622. } else if protocol.TunnelProtocolUsesTLSOSSH(dialParams.TunnelProtocol) {
  623. dialParams.TLSOSSHSNIServerName = ""
  624. if p.WeightedCoinFlip(parameters.TransformHostNameProbability) {
  625. dialParams.TLSOSSHSNIServerName = selectHostName(dialParams.TunnelProtocol, p)
  626. dialParams.TLSOSSHTransformedSNIServerName = true
  627. }
  628. } else if protocol.TunnelProtocolUsesMeekHTTP(dialParams.TunnelProtocol) {
  629. dialParams.MeekHostHeader = ""
  630. hostname := serverEntry.IpAddress
  631. if p.WeightedCoinFlip(parameters.TransformHostNameProbability) {
  632. hostname = selectHostName(dialParams.TunnelProtocol, p)
  633. dialParams.MeekTransformedHostName = true
  634. }
  635. if serverEntry.MeekServerPort == 80 {
  636. dialParams.MeekHostHeader = hostname
  637. } else {
  638. dialParams.MeekHostHeader = net.JoinHostPort(
  639. hostname, strconv.Itoa(serverEntry.MeekServerPort))
  640. }
  641. } else if protocol.TunnelProtocolUsesQUIC(dialParams.TunnelProtocol) {
  642. dialParams.QUICDialSNIAddress = selectHostName(dialParams.TunnelProtocol, p)
  643. }
  644. }
  645. if (!isReplay || !replayQUICVersion) &&
  646. protocol.TunnelProtocolUsesQUIC(dialParams.TunnelProtocol) {
  647. isFronted := protocol.TunnelProtocolUsesFrontedMeekQUIC(dialParams.TunnelProtocol)
  648. dialParams.QUICVersion = selectQUICVersion(isFronted, serverEntry, p)
  649. // Due to potential tactics configurations, it may be that no QUIC
  650. // version is selected. Abort immediately, with no error, as in the
  651. // selectProtocol case. quic.Dial and quic.NewQUICTransporter will
  652. // check for a missing QUIC version, but at that later stage an
  653. // unnecessary failed_tunnel can be logged in this scenario.
  654. if dialParams.QUICVersion == "" {
  655. return nil, nil
  656. }
  657. if protocol.QUICVersionHasRandomizedClientHello(dialParams.QUICVersion) {
  658. dialParams.QUICClientHelloSeed, err = prng.NewSeed()
  659. if err != nil {
  660. return nil, errors.Trace(err)
  661. }
  662. }
  663. dialParams.QUICDisablePathMTUDiscovery =
  664. protocol.QUICVersionUsesPathMTUDiscovery(dialParams.QUICVersion) &&
  665. p.WeightedCoinFlip(parameters.QUICDisableClientPathMTUDiscoveryProbability)
  666. }
  667. if (!isReplay || !replayObfuscatedQUIC) &&
  668. protocol.QUICVersionIsObfuscated(dialParams.QUICVersion) {
  669. dialParams.ObfuscatedQUICPaddingSeed, err = prng.NewSeed()
  670. if err != nil {
  671. return nil, errors.Trace(err)
  672. }
  673. }
  674. if protocol.QUICVersionIsObfuscated(dialParams.QUICVersion) {
  675. if serverEntry.DisableObfuscatedQUICTransforms {
  676. dialParams.ObfuscatedQUICNonceTransformerParameters = nil
  677. } else if !isReplay || !replayObfuscatedQUICNonceTransformer {
  678. params, err := makeSeedTransformerParameters(
  679. p,
  680. parameters.ObfuscatedQUICNonceTransformProbability,
  681. parameters.ObfuscatedQUICNonceTransformSpecs,
  682. parameters.ObfuscatedQUICNonceTransformScopedSpecNames)
  683. if err != nil {
  684. return nil, errors.Trace(err)
  685. }
  686. if params.TransformSpec != nil {
  687. dialParams.ObfuscatedQUICNonceTransformerParameters = params
  688. } else {
  689. dialParams.ObfuscatedQUICNonceTransformerParameters = nil
  690. }
  691. }
  692. }
  693. if !isReplay || !replayLivenessTest {
  694. // TODO: initialize only when LivenessTestMaxUp/DownstreamBytes > 0?
  695. dialParams.LivenessTestSeed, err = prng.NewSeed()
  696. if err != nil {
  697. return nil, errors.Trace(err)
  698. }
  699. }
  700. if !isReplay || !replayAPIRequestPadding {
  701. dialParams.APIRequestPaddingSeed, err = prng.NewSeed()
  702. if err != nil {
  703. return nil, errors.Trace(err)
  704. }
  705. }
  706. // Initialize dialParams.ResolveParameters for dials that will resolve
  707. // domain names, which currently includes fronted meek and Conjure API
  708. // registration, where the dial address is not an IP address.
  709. //
  710. // dialParams.ResolveParameters must be nil when the dial address is an IP
  711. // address to ensure that no DNS dial parameters are reported in metrics
  712. // or diagnostics when when no domain is resolved.
  713. useResolver := (protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) ||
  714. dialParams.ConjureAPIRegistration) &&
  715. net.ParseIP(dialParams.MeekFrontingDialAddress) == nil
  716. if (!isReplay || !replayResolveParameters) && useResolver {
  717. dialParams.ResolveParameters, err = dialParams.resolver.MakeResolveParameters(
  718. p, dialParams.FrontingProviderID, dialParams.MeekFrontingDialAddress)
  719. if err != nil {
  720. return nil, errors.Trace(err)
  721. }
  722. }
  723. if !isReplay || !replayHoldOffTunnel {
  724. var holdOffTunnelDuration time.Duration
  725. var holdOffDirectTunnelDuration time.Duration
  726. if common.Contains(
  727. p.TunnelProtocols(parameters.HoldOffTunnelProtocols), dialParams.TunnelProtocol) ||
  728. (protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) &&
  729. common.Contains(
  730. p.Strings(parameters.HoldOffTunnelFrontingProviderIDs),
  731. dialParams.FrontingProviderID)) {
  732. if p.WeightedCoinFlip(parameters.HoldOffTunnelProbability) {
  733. holdOffTunnelDuration = prng.Period(
  734. p.Duration(parameters.HoldOffTunnelMinDuration),
  735. p.Duration(parameters.HoldOffTunnelMaxDuration))
  736. }
  737. }
  738. if protocol.TunnelProtocolIsDirect(dialParams.TunnelProtocol) &&
  739. (common.Contains(
  740. p.Strings(parameters.HoldOffDirectServerEntryRegions), serverEntry.Region) ||
  741. common.ContainsAny(
  742. p.KeyStrings(parameters.HoldOffDirectServerEntryProviderRegions, dialParams.ServerEntry.ProviderID), []string{"", serverEntry.Region})) {
  743. if p.WeightedCoinFlip(parameters.HoldOffDirectTunnelProbability) {
  744. holdOffDirectTunnelDuration = prng.Period(
  745. p.Duration(parameters.HoldOffDirectTunnelMinDuration),
  746. p.Duration(parameters.HoldOffDirectTunnelMaxDuration))
  747. }
  748. }
  749. // Use the longest hold off duration
  750. if holdOffTunnelDuration >= holdOffDirectTunnelDuration {
  751. dialParams.HoldOffTunnelDuration = holdOffTunnelDuration
  752. } else {
  753. dialParams.HoldOffTunnelDuration = holdOffDirectTunnelDuration
  754. }
  755. }
  756. // OSSH prefix and seed transform are applied only to the OSSH tunnel protocol,
  757. // and not to any other protocol layered over OSSH.
  758. if dialParams.TunnelProtocol == protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH {
  759. if serverEntry.DisableOSSHTransforms {
  760. dialParams.OSSHObfuscatorSeedTransformerParameters = nil
  761. } else if !isReplay || !replayOSSHSeedTransformerParameters {
  762. params, err := makeSeedTransformerParameters(
  763. p,
  764. parameters.OSSHObfuscatorSeedTransformProbability,
  765. parameters.OSSHObfuscatorSeedTransformSpecs,
  766. parameters.OSSHObfuscatorSeedTransformScopedSpecNames)
  767. if err != nil {
  768. return nil, errors.Trace(err)
  769. }
  770. if params.TransformSpec != nil {
  771. dialParams.OSSHObfuscatorSeedTransformerParameters = params
  772. } else {
  773. dialParams.OSSHObfuscatorSeedTransformerParameters = nil
  774. }
  775. }
  776. if serverEntry.DisableOSSHPrefix {
  777. dialParams.OSSHPrefixSpec = nil
  778. dialParams.OSSHPrefixSplitConfig = nil
  779. } else if !isReplay || !replayOSSHPrefix {
  780. dialPortNumber, err := serverEntry.GetDialPortNumber(dialParams.TunnelProtocol)
  781. if err != nil {
  782. return nil, errors.Trace(err)
  783. }
  784. prefixSpec, err := makeOSSHPrefixSpecParameters(p, strconv.Itoa(dialPortNumber))
  785. if err != nil {
  786. return nil, errors.Trace(err)
  787. }
  788. splitConfig, err := makeOSSHPrefixSplitConfig(p)
  789. if err != nil {
  790. return nil, errors.Trace(err)
  791. }
  792. if prefixSpec.Spec != nil {
  793. dialParams.OSSHPrefixSpec = prefixSpec
  794. dialParams.OSSHPrefixSplitConfig = splitConfig
  795. } else {
  796. dialParams.OSSHPrefixSpec = nil
  797. dialParams.OSSHPrefixSplitConfig = nil
  798. }
  799. }
  800. // OSSHPrefix supersedes OSSHObfuscatorSeedTransform.
  801. // This ensures both tactics are not used simultaneously,
  802. // until OSSHObfuscatorSeedTransform is removed.
  803. if dialParams.OSSHPrefixSpec != nil {
  804. dialParams.OSSHObfuscatorSeedTransformerParameters = nil
  805. }
  806. }
  807. if protocol.TunnelProtocolUsesMeekHTTP(dialParams.TunnelProtocol) {
  808. if serverEntry.DisableHTTPTransforms {
  809. dialParams.HTTPTransformerParameters = nil
  810. } else if !isReplay || !replayHTTPTransformerParameters {
  811. isFronted := protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol)
  812. params, err := makeHTTPTransformerParameters(config.GetParameters().Get(), serverEntry.FrontingProviderID, isFronted)
  813. if err != nil {
  814. return nil, errors.Trace(err)
  815. }
  816. if params.ProtocolTransformSpec != nil {
  817. dialParams.HTTPTransformerParameters = params
  818. } else {
  819. dialParams.HTTPTransformerParameters = nil
  820. }
  821. }
  822. }
  823. // Set dial address fields. This portion of configuration is
  824. // deterministic, given the parameters established or replayed so far.
  825. dialPortNumber, err := serverEntry.GetDialPortNumber(dialParams.TunnelProtocol)
  826. if err != nil {
  827. return nil, errors.Trace(err)
  828. }
  829. dialParams.DialPortNumber = strconv.Itoa(dialPortNumber)
  830. switch dialParams.TunnelProtocol {
  831. case protocol.TUNNEL_PROTOCOL_SSH,
  832. protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH,
  833. protocol.TUNNEL_PROTOCOL_TAPDANCE_OBFUSCATED_SSH,
  834. protocol.TUNNEL_PROTOCOL_CONJURE_OBFUSCATED_SSH,
  835. protocol.TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH,
  836. protocol.TUNNEL_PROTOCOL_TLS_OBFUSCATED_SSH:
  837. dialParams.DirectDialAddress = net.JoinHostPort(serverEntry.IpAddress, dialParams.DialPortNumber)
  838. case protocol.TUNNEL_PROTOCOL_FRONTED_MEEK,
  839. protocol.TUNNEL_PROTOCOL_FRONTED_MEEK_QUIC_OBFUSCATED_SSH:
  840. dialParams.MeekDialAddress = net.JoinHostPort(dialParams.MeekFrontingDialAddress, dialParams.DialPortNumber)
  841. dialParams.MeekHostHeader = dialParams.MeekFrontingHost
  842. if serverEntry.MeekFrontingDisableSNI {
  843. dialParams.MeekSNIServerName = ""
  844. // When SNI is omitted, the transformed host name is not used.
  845. dialParams.MeekTransformedHostName = false
  846. } else if !dialParams.MeekTransformedHostName {
  847. dialParams.MeekSNIServerName = dialParams.MeekFrontingDialAddress
  848. }
  849. case protocol.TUNNEL_PROTOCOL_FRONTED_MEEK_HTTP:
  850. dialParams.MeekDialAddress = net.JoinHostPort(dialParams.MeekFrontingDialAddress, dialParams.DialPortNumber)
  851. dialParams.MeekHostHeader = dialParams.MeekFrontingHost
  852. // For FRONTED HTTP, the Host header cannot be transformed.
  853. dialParams.MeekTransformedHostName = false
  854. case protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK:
  855. dialParams.MeekDialAddress = net.JoinHostPort(serverEntry.IpAddress, dialParams.DialPortNumber)
  856. case protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_HTTPS,
  857. protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET:
  858. dialParams.MeekDialAddress = net.JoinHostPort(serverEntry.IpAddress, dialParams.DialPortNumber)
  859. if !dialParams.MeekTransformedHostName {
  860. // Note: IP address in SNI field will be omitted.
  861. dialParams.MeekSNIServerName = serverEntry.IpAddress
  862. }
  863. default:
  864. return nil, errors.Tracef(
  865. "unknown tunnel protocol: %s", dialParams.TunnelProtocol)
  866. }
  867. if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) {
  868. host, _, _ := net.SplitHostPort(dialParams.MeekDialAddress)
  869. if p.Bool(parameters.MeekDialDomainsOnly) {
  870. if net.ParseIP(host) != nil {
  871. // No error, as this is a "not supported" case.
  872. return nil, nil
  873. }
  874. }
  875. // The underlying TLS implementation will automatically omit SNI for
  876. // IP address server name values; we have this explicit check here so
  877. // we record the correct value for stats.
  878. if net.ParseIP(dialParams.MeekSNIServerName) != nil {
  879. dialParams.MeekSNIServerName = ""
  880. }
  881. }
  882. // TLS ClientHello fragmentation is applied only after the state
  883. // of SNI is determined above.
  884. if (!isReplay || !replayTLSFragmentClientHello) && usingTLS {
  885. limitProtocols := p.TunnelProtocols(parameters.TLSFragmentClientHelloLimitProtocols)
  886. if len(limitProtocols) == 0 || common.Contains(limitProtocols, dialParams.TunnelProtocol) {
  887. // Note: The TLS stack automatically drops the SNI extension when
  888. // the host is an IP address.
  889. usingSNI := false
  890. if dialParams.TLSOSSHSNIServerName != "" {
  891. usingSNI = net.ParseIP(dialParams.TLSOSSHSNIServerName) == nil
  892. } else if dialParams.MeekSNIServerName != "" {
  893. usingSNI = net.ParseIP(dialParams.MeekSNIServerName) == nil
  894. }
  895. // TLS ClientHello fragmentor expects SNI to be present.
  896. if usingSNI {
  897. dialParams.TLSFragmentClientHello = p.WeightedCoinFlip(
  898. parameters.TLSFragmentClientHelloProbability)
  899. }
  900. }
  901. }
  902. // Initialize/replay User-Agent header for HTTP upstream proxy and meek protocols.
  903. if config.UseUpstreamProxy() {
  904. // Note: UpstreamProxyURL will be validated in the dial
  905. proxyURL, err := common.SafeParseURL(config.UpstreamProxyURL)
  906. if err == nil {
  907. dialParams.UpstreamProxyType = proxyURL.Scheme
  908. }
  909. }
  910. dialCustomHeaders := makeDialCustomHeaders(config, p)
  911. if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) ||
  912. dialParams.UpstreamProxyType == "http" ||
  913. dialParams.ConjureAPIRegistration {
  914. if !isReplay || !replayUserAgent {
  915. dialParams.SelectedUserAgent, dialParams.UserAgent = selectUserAgentIfUnset(p, dialCustomHeaders)
  916. }
  917. if dialParams.SelectedUserAgent {
  918. dialCustomHeaders.Set("User-Agent", dialParams.UserAgent)
  919. }
  920. }
  921. // UpstreamProxyCustomHeaderNames is a reported metric. Just the names and
  922. // not the values are reported, in case the values are identifying.
  923. if len(config.CustomHeaders) > 0 {
  924. dialParams.UpstreamProxyCustomHeaderNames = make([]string, 0)
  925. for name := range dialCustomHeaders {
  926. if name == "User-Agent" && dialParams.SelectedUserAgent {
  927. continue
  928. }
  929. dialParams.UpstreamProxyCustomHeaderNames = append(dialParams.UpstreamProxyCustomHeaderNames, name)
  930. }
  931. }
  932. // Initialize Dial/MeekConfigs to be passed to the corresponding dialers.
  933. var resolveIP func(ctx context.Context, hostname string) ([]net.IP, error)
  934. // Determine whether to use a steering IP, and whether to indicate that
  935. // this dial remains a replay or not.
  936. //
  937. // Steering IPs are used only for fronted tunnels and not lower-traffic
  938. // tactics requests and signalling steps such as Conjure registration.
  939. //
  940. // The scope of the steering IP, and the corresponding cache key, is the
  941. // fronting provider, tunnel protocol, and the current network ID.
  942. //
  943. // Currently, steering IPs are obtained and cached in the Psiphon API
  944. // handshake response. A modest TTL is applied to cache entries, and, in
  945. // the case of a failed tunnel, any corresponding cached steering IP is
  946. // removed.
  947. //
  948. // DialParameters.SteeringIP is set and persisted, but is not used to dial
  949. // in a replay case; it's used to determine whether this dial should be
  950. // classified as a replay or not. A replay dial remains classified as
  951. // replay if a steering IP is not used and no steering IP was used
  952. // before; or when a steering IP is used and the same steering IP was
  953. // used before.
  954. //
  955. // When a steering IP is used and none was used before, or vice versa,
  956. // DialParameters.IsReplay is cleared so that is_replay is reported as
  957. // false, since the dial may be very different in nature: using a
  958. // different POP; skipping DNS; etc. Even if DialParameters.IsReplay was
  959. // true and is cleared, this MakeDialParameters will have wired up all
  960. // other dial parameters with replay values, so the benefit of those
  961. // values is not lost.
  962. var previousSteeringIP, currentSteeringIP string
  963. if isReplay {
  964. previousSteeringIP = dialParams.SteeringIP
  965. }
  966. dialParams.SteeringIP = ""
  967. if !isTactics &&
  968. protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) &&
  969. dialParams.ServerEntry.FrontingProviderID != "" {
  970. dialParams.steeringIPCacheKey = fmt.Sprintf("%s %s %s",
  971. dialParams.NetworkID,
  972. dialParams.ServerEntry.FrontingProviderID,
  973. dialParams.TunnelProtocol)
  974. steeringIPValue, ok := dialParams.steeringIPCache.Get(
  975. dialParams.steeringIPCacheKey)
  976. if ok {
  977. currentSteeringIP = steeringIPValue.(string)
  978. }
  979. // A steering IP probability is applied and may be used to gradually
  980. // apply steering IPs. The coin flip is made only to decide to start
  981. // using a steering IP, avoiding flip flopping between dials. For any
  982. // probability > 0.0, a long enough continuous session will
  983. // eventually flip to true and then keep using steering IPs as long
  984. // as they remain in the cache.
  985. if previousSteeringIP == "" && currentSteeringIP != "" &&
  986. !p.WeightedCoinFlip(parameters.SteeringIPProbability) {
  987. currentSteeringIP = ""
  988. }
  989. }
  990. if currentSteeringIP != "" {
  991. IP := net.ParseIP(currentSteeringIP)
  992. if IP == nil {
  993. return nil, errors.TraceNew("invalid steering IP")
  994. }
  995. // Since tcpDial and NewUDPConn invoke ResolveIP unconditionally, even
  996. // when the hostname is an IP address, a steering IP will be applied
  997. // even in that case.
  998. resolveIP = func(ctx context.Context, hostname string) ([]net.IP, error) {
  999. return []net.IP{IP}, nil
  1000. }
  1001. // dialParams.SteeringIP will be used as the "previous" steering IP in
  1002. // the next replay.
  1003. dialParams.SteeringIP = currentSteeringIP
  1004. }
  1005. if currentSteeringIP != previousSteeringIP {
  1006. dialParams.IsReplay = false
  1007. }
  1008. // Custom ResolveParameters are set only when useResolver is true, but
  1009. // DialConfig.ResolveIP is required and wired up unconditionally. Any
  1010. // misconfigured or miscoded domain dial cases will use default
  1011. // ResolveParameters.
  1012. //
  1013. // ResolveIP will use the networkID obtained above, as it will be used
  1014. // almost immediately, instead of incurring the overhead of calling
  1015. // GetNetworkID again.
  1016. if resolveIP == nil {
  1017. resolveIP = func(ctx context.Context, hostname string) ([]net.IP, error) {
  1018. IPs, err := dialParams.resolver.ResolveIP(
  1019. ctx,
  1020. networkID,
  1021. dialParams.ResolveParameters,
  1022. hostname)
  1023. if err != nil {
  1024. return nil, errors.Trace(err)
  1025. }
  1026. return IPs, nil
  1027. }
  1028. }
  1029. // Fragmentor configuration.
  1030. // Note: fragmentorConfig is nil if fragmentor is disabled for prefixed OSSH.
  1031. //
  1032. // Limitation: when replaying and with ReplayIgnoreChangedConfigState set,
  1033. // fragmentor.NewUpstreamConfig may select a config using newer tactics
  1034. // parameters.
  1035. fragmentorConfig := fragmentor.NewUpstreamConfig(p, dialParams.TunnelProtocol, dialParams.FragmentorSeed)
  1036. if !p.Bool(parameters.OSSHPrefixEnableFragmentor) && dialParams.OSSHPrefixSpec != nil {
  1037. fragmentorConfig = nil
  1038. }
  1039. dialParams.dialConfig = &DialConfig{
  1040. DiagnosticID: serverEntry.GetDiagnosticID(),
  1041. UpstreamProxyURL: config.UpstreamProxyURL,
  1042. CustomHeaders: dialCustomHeaders,
  1043. BPFProgramInstructions: dialParams.BPFProgramInstructions,
  1044. DeviceBinder: config.deviceBinder,
  1045. IPv6Synthesizer: config.IPv6Synthesizer,
  1046. ResolveIP: resolveIP,
  1047. TrustedCACertificatesFilename: config.TrustedCACertificatesFilename,
  1048. FragmentorConfig: fragmentorConfig,
  1049. UpstreamProxyErrorCallback: upstreamProxyErrorCallback,
  1050. }
  1051. // Unconditionally initialize MeekResolvedIPAddress, so a valid string can
  1052. // always be read.
  1053. dialParams.MeekResolvedIPAddress.Store("")
  1054. if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) ||
  1055. dialParams.ConjureAPIRegistration {
  1056. // For tactics requests, AddPsiphonFrontingHeader is set when set for
  1057. // the related tunnel protocol. E.g., FRONTED-OSSH-MEEK for
  1058. // FRONTED-MEEK-TACTICS. AddPsiphonFrontingHeader is not replayed.
  1059. addPsiphonFrontingHeader := false
  1060. if dialParams.FrontingProviderID != "" {
  1061. addPsiphonFrontingHeader = common.Contains(
  1062. p.LabeledTunnelProtocols(
  1063. parameters.AddFrontingProviderPsiphonFrontingHeader, dialParams.FrontingProviderID),
  1064. dialParams.TunnelProtocol)
  1065. }
  1066. dialParams.meekConfig = &MeekConfig{
  1067. DiagnosticID: serverEntry.GetDiagnosticID(),
  1068. Parameters: config.GetParameters(),
  1069. DialAddress: dialParams.MeekDialAddress,
  1070. UseQUIC: protocol.TunnelProtocolUsesFrontedMeekQUIC(dialParams.TunnelProtocol),
  1071. QUICVersion: dialParams.QUICVersion,
  1072. QUICClientHelloSeed: dialParams.QUICClientHelloSeed,
  1073. QUICDisablePathMTUDiscovery: dialParams.QUICDisablePathMTUDiscovery,
  1074. UseHTTPS: usingTLS,
  1075. TLSProfile: dialParams.TLSProfile,
  1076. TLSFragmentClientHello: dialParams.TLSFragmentClientHello,
  1077. LegacyPassthrough: serverEntry.ProtocolUsesLegacyPassthrough(dialParams.TunnelProtocol),
  1078. NoDefaultTLSSessionID: dialParams.NoDefaultTLSSessionID,
  1079. RandomizedTLSProfileSeed: dialParams.RandomizedTLSProfileSeed,
  1080. UseObfuscatedSessionTickets: dialParams.TunnelProtocol == protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET,
  1081. SNIServerName: dialParams.MeekSNIServerName,
  1082. AddPsiphonFrontingHeader: addPsiphonFrontingHeader,
  1083. VerifyServerName: dialParams.MeekVerifyServerName,
  1084. VerifyPins: dialParams.MeekVerifyPins,
  1085. DisableSystemRootCAs: config.DisableSystemRootCAs,
  1086. HostHeader: dialParams.MeekHostHeader,
  1087. TransformedHostName: dialParams.MeekTransformedHostName,
  1088. ClientTunnelProtocol: dialParams.TunnelProtocol,
  1089. MeekCookieEncryptionPublicKey: serverEntry.MeekCookieEncryptionPublicKey,
  1090. MeekObfuscatedKey: serverEntry.MeekObfuscatedKey,
  1091. MeekObfuscatorPaddingSeed: dialParams.MeekObfuscatorPaddingSeed,
  1092. NetworkLatencyMultiplier: dialParams.NetworkLatencyMultiplier,
  1093. HTTPTransformerParameters: dialParams.HTTPTransformerParameters,
  1094. AdditionalHeaders: config.MeekAdditionalHeaders,
  1095. }
  1096. // Use an asynchronous callback to record the resolved IP address when
  1097. // dialing a domain name. Note that DialMeek doesn't immediately
  1098. // establish any HTTP connections, so the resolved IP address won't be
  1099. // reported in all cases until after SSH traffic is relayed or a
  1100. // endpoint request is made over the meek connection.
  1101. dialParams.dialConfig.ResolvedIPCallback = func(IPAddress string) {
  1102. dialParams.MeekResolvedIPAddress.Store(IPAddress)
  1103. }
  1104. if isTactics {
  1105. dialParams.meekConfig.Mode = MeekModeObfuscatedRoundTrip
  1106. } else if dialParams.ConjureAPIRegistration {
  1107. dialParams.meekConfig.Mode = MeekModePlaintextRoundTrip
  1108. } else {
  1109. dialParams.meekConfig.Mode = MeekModeRelay
  1110. }
  1111. }
  1112. return dialParams, nil
  1113. }
  1114. func (dialParams *DialParameters) GetDialConfig() *DialConfig {
  1115. return dialParams.dialConfig
  1116. }
  1117. func (dialParams *DialParameters) GetTLSOSSHConfig(config *Config) *TLSTunnelConfig {
  1118. return &TLSTunnelConfig{
  1119. CustomTLSConfig: &CustomTLSConfig{
  1120. Parameters: config.GetParameters(),
  1121. DialAddr: dialParams.DirectDialAddress,
  1122. SNIServerName: dialParams.TLSOSSHSNIServerName,
  1123. SkipVerify: true,
  1124. VerifyServerName: "",
  1125. VerifyPins: nil,
  1126. TLSProfile: dialParams.TLSProfile,
  1127. NoDefaultTLSSessionID: &dialParams.NoDefaultTLSSessionID,
  1128. RandomizedTLSProfileSeed: dialParams.RandomizedTLSProfileSeed,
  1129. FragmentClientHello: dialParams.TLSFragmentClientHello,
  1130. },
  1131. // Obfuscated session tickets are not used because TLS-OSSH uses TLS 1.3.
  1132. UseObfuscatedSessionTickets: false,
  1133. // Meek obfuscated key used to allow clients with legacy unfronted
  1134. // meek-https server entries, that have the passthrough capability, to
  1135. // connect with TLS-OSSH to the servers corresponding to those server
  1136. // entries, which now support TLS-OSSH by demultiplexing meek-https and
  1137. // TLS-OSSH over the meek-https port.
  1138. ObfuscatedKey: dialParams.ServerEntry.MeekObfuscatedKey,
  1139. ObfuscatorPaddingSeed: dialParams.TLSOSSHObfuscatorPaddingSeed,
  1140. }
  1141. }
  1142. func (dialParams *DialParameters) GetMeekConfig() *MeekConfig {
  1143. return dialParams.meekConfig
  1144. }
  1145. // GetNetworkType returns a network type name, suitable for metrics, which is
  1146. // derived from the network ID.
  1147. func (dialParams *DialParameters) GetNetworkType() string {
  1148. // Unlike the logic in loggingNetworkIDGetter.GetNetworkID, we don't take the
  1149. // arbitrary text before the first "-" since some platforms without network
  1150. // detection support stub in random values to enable tactics. Instead we
  1151. // check for and use the common network type prefixes currently used in
  1152. // NetworkIDGetter implementations.
  1153. if strings.HasPrefix(dialParams.NetworkID, "VPN") {
  1154. return "VPN"
  1155. }
  1156. if strings.HasPrefix(dialParams.NetworkID, "WIFI") {
  1157. return "WIFI"
  1158. }
  1159. if strings.HasPrefix(dialParams.NetworkID, "MOBILE") {
  1160. return "MOBILE"
  1161. }
  1162. return "UNKNOWN"
  1163. }
  1164. func (dialParams *DialParameters) Succeeded() {
  1165. // When TTL is 0, don't store dial parameters.
  1166. if dialParams.LastUsedTimestamp.IsZero() {
  1167. return
  1168. }
  1169. NoticeInfo("Set dial parameters for %s", dialParams.ServerEntry.GetDiagnosticID())
  1170. err := SetDialParameters(dialParams.ServerEntry.IpAddress, dialParams.NetworkID, dialParams)
  1171. if err != nil {
  1172. NoticeWarning("SetDialParameters failed: %s", err)
  1173. }
  1174. }
  1175. func (dialParams *DialParameters) Failed(config *Config) {
  1176. // When a tunnel fails, and the dial is a replay, clear the stored dial
  1177. // parameters which are now presumed to be blocked, impaired or otherwise
  1178. // no longer effective.
  1179. //
  1180. // It may be the case that a dial is not using stored dial parameters
  1181. // (!IsReplay), and in this case we retain those dial parameters since they
  1182. // were not exercised and may still be effective.
  1183. //
  1184. // Failed tunnel dial parameters may be retained with a configurable
  1185. // probability; this is intended to help mitigate false positive failures due
  1186. // to, e.g., temporary network disruptions or server load limiting.
  1187. if dialParams.IsReplay &&
  1188. !config.GetParameters().Get().WeightedCoinFlip(
  1189. parameters.ReplayRetainFailedProbability) {
  1190. NoticeInfo("Delete dial parameters for %s", dialParams.ServerEntry.GetDiagnosticID())
  1191. err := DeleteDialParameters(dialParams.ServerEntry.IpAddress, dialParams.NetworkID)
  1192. if err != nil {
  1193. NoticeWarning("DeleteDialParameters failed: %s", err)
  1194. }
  1195. }
  1196. // When a failed tunnel dialed with steering IP, remove the corresponding
  1197. // cache entry to avoid continuously redialing a potentially blocked or
  1198. // degraded POP.
  1199. //
  1200. // TODO: don't remove, but reduce the TTL to allow for one more dial?
  1201. if dialParams.steeringIPCacheKey != "" {
  1202. dialParams.steeringIPCache.Delete(dialParams.steeringIPCacheKey)
  1203. }
  1204. }
  1205. func (dialParams *DialParameters) GetTLSVersionForMetrics() string {
  1206. return getTLSVersionForMetrics(dialParams.TLSVersion, dialParams.NoDefaultTLSSessionID)
  1207. }
  1208. func getTLSVersionForMetrics(tlsVersion string, noDefaultTLSSessionID bool) string {
  1209. version := tlsVersion
  1210. if noDefaultTLSSessionID {
  1211. version += "-no_def_id"
  1212. }
  1213. return version
  1214. }
  1215. // ExchangedDialParameters represents the subset of DialParameters that is
  1216. // shared in a client-to-client exchange of server connection info.
  1217. //
  1218. // The purpose of client-to-client exchange if for one user that can connect
  1219. // to help another user that cannot connect by sharing their connected
  1220. // configuration, including the server entry and dial parameters.
  1221. //
  1222. // There are two concerns regarding which dial parameter fields are safe to
  1223. // exchange:
  1224. //
  1225. // - Unlike signed server entries, there's no independent trust anchor
  1226. // that can certify that the exchange data is valid.
  1227. //
  1228. // - While users should only perform the exchange with trusted peers,
  1229. // the user's trust in their peer may be misplaced.
  1230. //
  1231. // This presents the possibility of attack such as the peer sending dial
  1232. // parameters that could be used to trace/monitor/flag the importer; or
  1233. // sending dial parameters, including dial address and SNI, to cause the peer
  1234. // to appear to connect to a banned service.
  1235. //
  1236. // To mitigate these risks, only a subset of dial parameters are exchanged.
  1237. // When exchanged dial parameters and imported and used, all unexchanged
  1238. // parameters are generated locally. At this time, only the tunnel protocol is
  1239. // exchanged. We consider tunnel protocol selection one of the key connection
  1240. // success factors.
  1241. //
  1242. // In addition, the exchange peers may not be on the same network with the
  1243. // same blocking and circumvention characteristics, which is another reason
  1244. // to limit exchanged dial parameter values to broadly applicable fields.
  1245. //
  1246. // Unlike the exchanged (and otherwise acquired) server entry,
  1247. // ExchangedDialParameters does not use the ServerEntry_Fields_ representation
  1248. // which allows older clients to receive and store new, unknown fields. Such a
  1249. // facility is less useful in this case, since exchanged dial parameters and
  1250. // used immediately and have a short lifespan.
  1251. //
  1252. // TODO: exchange more dial parameters, such as TLS profile, QUIC version, etc.
  1253. type ExchangedDialParameters struct {
  1254. TunnelProtocol string
  1255. }
  1256. // NewExchangedDialParameters creates a new ExchangedDialParameters from a
  1257. // DialParameters, including only the exchanged values.
  1258. // NewExchangedDialParameters assumes the input DialParameters has been
  1259. // initialized and populated by MakeDialParameters.
  1260. func NewExchangedDialParameters(dialParams *DialParameters) *ExchangedDialParameters {
  1261. return &ExchangedDialParameters{
  1262. TunnelProtocol: dialParams.TunnelProtocol,
  1263. }
  1264. }
  1265. // Validate checks that the ExchangedDialParameters contains only valid values
  1266. // and is compatible with the specified server entry.
  1267. func (dialParams *ExchangedDialParameters) Validate(serverEntry *protocol.ServerEntry) error {
  1268. if !common.Contains(protocol.SupportedTunnelProtocols, dialParams.TunnelProtocol) {
  1269. return errors.Tracef("unknown tunnel protocol: %s", dialParams.TunnelProtocol)
  1270. }
  1271. if !serverEntry.SupportsProtocol(dialParams.TunnelProtocol) {
  1272. return errors.Tracef("unsupported tunnel protocol: %s", dialParams.TunnelProtocol)
  1273. }
  1274. return nil
  1275. }
  1276. // MakeDialParameters creates a new, partially intitialized DialParameters
  1277. // from the values in ExchangedDialParameters. The returned DialParameters
  1278. // must not be used directly for dialing. It is intended to be stored, and
  1279. // then later fully initialized by MakeDialParameters.
  1280. func (dialParams *ExchangedDialParameters) MakeDialParameters(
  1281. config *Config,
  1282. p parameters.ParametersAccessor,
  1283. serverEntry *protocol.ServerEntry) *DialParameters {
  1284. configStateHash, serverEntryHash := getDialStateHashes(config, p, serverEntry)
  1285. return &DialParameters{
  1286. IsExchanged: true,
  1287. LastUsedTimestamp: time.Now(),
  1288. LastUsedConfigStateHash: configStateHash,
  1289. LastUsedServerEntryHash: serverEntryHash,
  1290. TunnelProtocol: dialParams.TunnelProtocol,
  1291. }
  1292. }
  1293. // getDialStateHashes returns two hashes: the config state hash reflects the
  1294. // config dial parameters and tactics tag used for a dial; and the server
  1295. // entry hash relects the server entry used for a dial.
  1296. //
  1297. // These hashes change if the input values change in a way that invalidates
  1298. // any stored dial parameters.
  1299. func getDialStateHashes(
  1300. config *Config,
  1301. p parameters.ParametersAccessor,
  1302. serverEntry *protocol.ServerEntry) ([]byte, []byte) {
  1303. // MD5 hash is used solely as a data checksum and not for any security
  1304. // purpose.
  1305. hash := md5.New()
  1306. // Add a hash of relevant dial parameter config fields. Config fields
  1307. // that change due to user preference changes, such as selected egress
  1308. // region, are not to be included in config.dialParametersHash.
  1309. //
  1310. // Limitation: the config hash may change even when tactics will override the
  1311. // changed config field.
  1312. hash.Write(config.dialParametersHash)
  1313. // Add the active tactics tag.
  1314. hash.Write([]byte(p.Tag()))
  1315. clientStateHash := hash.Sum(nil)
  1316. hash = md5.New()
  1317. // Add the server entry version and local timestamp, both of which should
  1318. // change when the server entry contents change and/or a new local copy is
  1319. // imported.
  1320. // TODO: marshal entire server entry?
  1321. var serverEntryConfigurationVersion [8]byte
  1322. binary.BigEndian.PutUint64(
  1323. serverEntryConfigurationVersion[:],
  1324. uint64(serverEntry.ConfigurationVersion))
  1325. hash.Write(serverEntryConfigurationVersion[:])
  1326. hash.Write([]byte(serverEntry.LocalTimestamp))
  1327. serverEntryHash := hash.Sum(nil)
  1328. return clientStateHash, serverEntryHash
  1329. }
  1330. func selectFrontingParameters(
  1331. serverEntry *protocol.ServerEntry) (string, string, error) {
  1332. frontingDialHost := ""
  1333. frontingHost := ""
  1334. if len(serverEntry.MeekFrontingAddressesRegex) > 0 {
  1335. // Generate a front address based on the regex.
  1336. var err error
  1337. frontingDialHost, err = regen.GenerateString(serverEntry.MeekFrontingAddressesRegex)
  1338. if err != nil {
  1339. return "", "", errors.Trace(err)
  1340. }
  1341. } else {
  1342. // Randomly select, for this connection attempt, one front address for
  1343. // fronting-capable servers.
  1344. if len(serverEntry.MeekFrontingAddresses) == 0 {
  1345. return "", "", errors.TraceNew("MeekFrontingAddresses is empty")
  1346. }
  1347. index := prng.Intn(len(serverEntry.MeekFrontingAddresses))
  1348. frontingDialHost = serverEntry.MeekFrontingAddresses[index]
  1349. }
  1350. if len(serverEntry.MeekFrontingHosts) > 0 {
  1351. index := prng.Intn(len(serverEntry.MeekFrontingHosts))
  1352. frontingHost = serverEntry.MeekFrontingHosts[index]
  1353. } else {
  1354. // Backwards compatibility case
  1355. frontingHost = serverEntry.MeekFrontingHost
  1356. }
  1357. return frontingDialHost, frontingHost, nil
  1358. }
  1359. func selectQUICVersion(
  1360. isFronted bool,
  1361. serverEntry *protocol.ServerEntry,
  1362. p parameters.ParametersAccessor) string {
  1363. limitQUICVersions := p.QUICVersions(parameters.LimitQUICVersions)
  1364. var disableQUICVersions protocol.QUICVersions
  1365. if isFronted {
  1366. if serverEntry.FrontingProviderID == "" {
  1367. // Legacy server entry case
  1368. disableQUICVersions = protocol.QUICVersions{
  1369. protocol.QUIC_VERSION_V1,
  1370. protocol.QUIC_VERSION_RANDOMIZED_V1,
  1371. protocol.QUIC_VERSION_OBFUSCATED_V1,
  1372. protocol.QUIC_VERSION_DECOY_V1,
  1373. }
  1374. } else {
  1375. disableQUICVersions = p.LabeledQUICVersions(
  1376. parameters.DisableFrontingProviderQUICVersions,
  1377. serverEntry.FrontingProviderID)
  1378. }
  1379. }
  1380. quicVersions := make([]string, 0)
  1381. // Don't use gQUIC versions when the server entry specifies QUICv1-only.
  1382. supportedQUICVersions := protocol.SupportedQUICVersions
  1383. if serverEntry.SupportsOnlyQUICv1() {
  1384. supportedQUICVersions = protocol.SupportedQUICv1Versions
  1385. }
  1386. for _, quicVersion := range supportedQUICVersions {
  1387. if len(limitQUICVersions) > 0 &&
  1388. !common.Contains(limitQUICVersions, quicVersion) {
  1389. continue
  1390. }
  1391. // Both tactics and the server entry can specify LimitQUICVersions. In
  1392. // tactics, the parameter is intended to direct certain clients to
  1393. // use a successful protocol variant. In the server entry, the
  1394. // parameter may be used to direct all clients to send
  1395. // consistent-looking protocol variants to a particular server; e.g.,
  1396. // only regular QUIC, or only obfuscated QUIC.
  1397. //
  1398. // The isFronted/QUICVersionIsObfuscated logic predates
  1399. // ServerEntry.LimitQUICVersions; ServerEntry.LimitQUICVersions could
  1400. // now be used to achieve a similar outcome.
  1401. if len(serverEntry.LimitQUICVersions) > 0 &&
  1402. !common.Contains(serverEntry.LimitQUICVersions, quicVersion) {
  1403. continue
  1404. }
  1405. if isFronted &&
  1406. protocol.QUICVersionIsObfuscated(quicVersion) {
  1407. continue
  1408. }
  1409. if common.Contains(disableQUICVersions, quicVersion) {
  1410. continue
  1411. }
  1412. quicVersions = append(quicVersions, quicVersion)
  1413. }
  1414. if len(quicVersions) == 0 {
  1415. return ""
  1416. }
  1417. choice := prng.Intn(len(quicVersions))
  1418. return quicVersions[choice]
  1419. }
  1420. // selectUserAgentIfUnset selects a User-Agent header if one is not set.
  1421. func selectUserAgentIfUnset(
  1422. p parameters.ParametersAccessor, headers http.Header) (bool, string) {
  1423. if _, ok := headers["User-Agent"]; !ok {
  1424. userAgent := ""
  1425. if p.WeightedCoinFlip(parameters.PickUserAgentProbability) {
  1426. userAgent = values.GetUserAgent()
  1427. }
  1428. return true, userAgent
  1429. }
  1430. return false, ""
  1431. }
  1432. func makeDialCustomHeaders(
  1433. config *Config,
  1434. p parameters.ParametersAccessor) http.Header {
  1435. dialCustomHeaders := make(http.Header)
  1436. if config.CustomHeaders != nil {
  1437. for k, v := range config.CustomHeaders {
  1438. dialCustomHeaders[k] = make([]string, len(v))
  1439. copy(dialCustomHeaders[k], v)
  1440. }
  1441. }
  1442. additionalCustomHeaders := p.HTTPHeaders(parameters.AdditionalCustomHeaders)
  1443. for k, v := range additionalCustomHeaders {
  1444. dialCustomHeaders[k] = make([]string, len(v))
  1445. copy(dialCustomHeaders[k], v)
  1446. }
  1447. return dialCustomHeaders
  1448. }
  1449. func selectHostName(
  1450. tunnelProtocol string, p parameters.ParametersAccessor) string {
  1451. limitProtocols := p.TunnelProtocols(parameters.CustomHostNameLimitProtocols)
  1452. if len(limitProtocols) > 0 && !common.Contains(limitProtocols, tunnelProtocol) {
  1453. return values.GetHostName()
  1454. }
  1455. if !p.WeightedCoinFlip(parameters.CustomHostNameProbability) {
  1456. return values.GetHostName()
  1457. }
  1458. regexStrings := p.RegexStrings(parameters.CustomHostNameRegexes)
  1459. if len(regexStrings) == 0 {
  1460. return values.GetHostName()
  1461. }
  1462. choice := prng.Intn(len(regexStrings))
  1463. hostName, err := regen.GenerateString(regexStrings[choice])
  1464. if err != nil {
  1465. NoticeWarning("selectHostName: regen.Generate failed: %v", errors.Trace(err))
  1466. return values.GetHostName()
  1467. }
  1468. return hostName
  1469. }
  1470. // makeHTTPTransformerParameters generates HTTPTransformerParameters using the
  1471. // input tactics parameters and optional frontingProviderID context.
  1472. func makeHTTPTransformerParameters(p parameters.ParametersAccessor,
  1473. frontingProviderID string, isFronted bool) (*transforms.HTTPTransformerParameters, error) {
  1474. params := transforms.HTTPTransformerParameters{}
  1475. // Select an HTTP transform. If the request is fronted, HTTP request
  1476. // transforms are "scoped" by fronting provider ID. Otherwise, a transform
  1477. // from the default scope (transforms.SCOPE_ANY == "") is selected.
  1478. var specsKey string
  1479. var scopedSpecsNamesKey string
  1480. useTransform := false
  1481. scope := transforms.SCOPE_ANY
  1482. if isFronted {
  1483. if p.WeightedCoinFlip(parameters.FrontedHTTPProtocolTransformProbability) {
  1484. useTransform = true
  1485. scope = frontingProviderID
  1486. specsKey = parameters.FrontedHTTPProtocolTransformSpecs
  1487. scopedSpecsNamesKey = parameters.FrontedHTTPProtocolTransformScopedSpecNames
  1488. }
  1489. } else {
  1490. // unfronted
  1491. if p.WeightedCoinFlip(parameters.DirectHTTPProtocolTransformProbability) {
  1492. useTransform = true
  1493. specsKey = parameters.DirectHTTPProtocolTransformSpecs
  1494. scopedSpecsNamesKey = parameters.DirectHTTPProtocolTransformScopedSpecNames
  1495. }
  1496. }
  1497. if useTransform {
  1498. specs := p.ProtocolTransformSpecs(
  1499. specsKey)
  1500. scopedSpecNames := p.ProtocolTransformScopedSpecNames(
  1501. scopedSpecsNamesKey)
  1502. name, spec := specs.Select(scope, scopedSpecNames)
  1503. if spec != nil {
  1504. params.ProtocolTransformName = name
  1505. params.ProtocolTransformSpec = spec
  1506. var err error
  1507. // transform seed generated
  1508. params.ProtocolTransformSeed, err = prng.NewSeed()
  1509. if err != nil {
  1510. return nil, errors.Trace(err)
  1511. }
  1512. }
  1513. }
  1514. return &params, nil
  1515. }
  1516. // makeSeedTransformerParameters generates ObfuscatorSeedTransformerParameters
  1517. // using the input tactics parameters.
  1518. func makeSeedTransformerParameters(p parameters.ParametersAccessor,
  1519. probabilityFieldName, specsKey, scopedSpecsKey string) (*transforms.ObfuscatorSeedTransformerParameters, error) {
  1520. if !p.WeightedCoinFlip(probabilityFieldName) {
  1521. return &transforms.ObfuscatorSeedTransformerParameters{}, nil
  1522. }
  1523. seed, err := prng.NewSeed()
  1524. if err != nil {
  1525. return nil, errors.Trace(err)
  1526. }
  1527. specs := p.ProtocolTransformSpecs(specsKey)
  1528. scopedSpecNames := p.ProtocolTransformScopedSpecNames(scopedSpecsKey)
  1529. name, spec := specs.Select(transforms.SCOPE_ANY, scopedSpecNames)
  1530. if spec == nil {
  1531. return &transforms.ObfuscatorSeedTransformerParameters{}, nil
  1532. } else {
  1533. return &transforms.ObfuscatorSeedTransformerParameters{
  1534. TransformName: name,
  1535. TransformSpec: spec,
  1536. TransformSeed: seed,
  1537. }, nil
  1538. }
  1539. }
  1540. func makeOSSHPrefixSpecParameters(
  1541. p parameters.ParametersAccessor,
  1542. dialPortNumber string) (*obfuscator.OSSHPrefixSpec, error) {
  1543. if !p.WeightedCoinFlip(parameters.OSSHPrefixProbability) {
  1544. return &obfuscator.OSSHPrefixSpec{}, nil
  1545. }
  1546. specs := p.ProtocolTransformSpecs(parameters.OSSHPrefixSpecs)
  1547. scopedSpecNames := p.ProtocolTransformScopedSpecNames(parameters.OSSHPrefixScopedSpecNames)
  1548. name, spec := specs.Select(dialPortNumber, scopedSpecNames)
  1549. if spec == nil {
  1550. return &obfuscator.OSSHPrefixSpec{}, nil
  1551. } else {
  1552. seed, err := prng.NewSeed()
  1553. if err != nil {
  1554. return nil, errors.Trace(err)
  1555. }
  1556. return &obfuscator.OSSHPrefixSpec{
  1557. Name: name,
  1558. Spec: spec,
  1559. Seed: seed,
  1560. }, nil
  1561. }
  1562. }
  1563. func makeOSSHPrefixSplitConfig(p parameters.ParametersAccessor) (*obfuscator.OSSHPrefixSplitConfig, error) {
  1564. minDelay := p.Duration(parameters.OSSHPrefixSplitMinDelay)
  1565. maxDelay := p.Duration(parameters.OSSHPrefixSplitMaxDelay)
  1566. seed, err := prng.NewSeed()
  1567. if err != nil {
  1568. return nil, errors.Trace(err)
  1569. }
  1570. return &obfuscator.OSSHPrefixSplitConfig{
  1571. Seed: seed,
  1572. MinDelay: minDelay,
  1573. MaxDelay: maxDelay,
  1574. }, nil
  1575. }
  1576. func selectConjureTransport(
  1577. p parameters.ParametersAccessor) string {
  1578. limitConjureTransports := p.ConjureTransports(parameters.ConjureLimitTransports)
  1579. transports := make([]string, 0)
  1580. for _, transport := range protocol.SupportedConjureTransports {
  1581. if len(limitConjureTransports) > 0 &&
  1582. !common.Contains(limitConjureTransports, transport) {
  1583. continue
  1584. }
  1585. transports = append(transports, transport)
  1586. }
  1587. if len(transports) == 0 {
  1588. return ""
  1589. }
  1590. choice := prng.Intn(len(transports))
  1591. return transports[choice]
  1592. }