dialParameters.go 64 KB

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