dialParameters.go 86 KB

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