config.go 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926
  1. /*
  2. * Copyright (c) 2015, 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. "crypto/md5"
  22. "encoding/base64"
  23. "encoding/binary"
  24. "encoding/json"
  25. "fmt"
  26. "io/ioutil"
  27. "net/http"
  28. "os"
  29. "path/filepath"
  30. "regexp"
  31. "strconv"
  32. "strings"
  33. "sync"
  34. "unicode"
  35. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  37. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
  38. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  39. )
  40. const (
  41. TUNNEL_POOL_SIZE = 1
  42. // Psiphon data directory name, relative to config.DataRootDirectory.
  43. // See config.GetPsiphonDataDirectory().
  44. PsiphonDataDirectoryName = "ca.psiphon.PsiphonTunnel.tunnel-core"
  45. // Filename constants, all relative to config.GetPsiphonDataDirectory().
  46. HomepageFilename = "homepage"
  47. NoticesFilename = "notices"
  48. OldNoticesFilename = "notices.1"
  49. UpgradeDownloadFilename = "upgrade"
  50. )
  51. // Config is the Psiphon configuration specified by the application. This
  52. // configuration controls the behavior of the core tunnel functionality.
  53. //
  54. // To distinguish omitted timeout params from explicit 0 value timeout params,
  55. // corresponding fields are int pointers. nil means no value was supplied and
  56. // to use the default; a non-nil pointer to 0 means no timeout.
  57. type Config struct {
  58. // DataRootDirectory is the directory in which to store persistent files,
  59. // which contain information such as server entries. By default, current
  60. // working directory.
  61. //
  62. // Psiphon will assume full control of files under this directory. They may
  63. // be deleted, moved or overwritten.
  64. DataRootDirectory string
  65. // UseNoticeFiles configures notice files for writing. If set, homepages
  66. // will be written to a file created at config.GetHomePageFilename()
  67. // and notices will be written to a file created at
  68. // config.GetNoticesFilename().
  69. //
  70. // The homepage file may be read after the Tunnels notice with count of 1.
  71. //
  72. // The value of UseNoticeFiles sets the size and frequency at which the
  73. // notices file, config.GetNoticesFilename(), will be rotated. See the
  74. // comment for UseNoticeFiles for more details. One rotated older file,
  75. // config.GetOldNoticesFilename(), is retained.
  76. //
  77. // The notice files may be may be read at any time; and should be opened
  78. // read-only for reading. Diagnostic notices are omitted from the notice
  79. // files.
  80. //
  81. // See comment for setNoticeFiles in notice.go for further details.
  82. UseNoticeFiles *UseNoticeFiles
  83. // PropagationChannelId is a string identifier which indicates how the
  84. // Psiphon client was distributed. This parameter is required. This value
  85. // is supplied by and depends on the Psiphon Network, and is typically
  86. // embedded in the client binary.
  87. PropagationChannelId string
  88. // SponsorId is a string identifier which indicates who is sponsoring this
  89. // Psiphon client. One purpose of this value is to determine the home
  90. // pages for display. This parameter is required. This value is supplied
  91. // by and depends on the Psiphon Network, and is typically embedded in the
  92. // client binary.
  93. SponsorId string
  94. // ClientVersion is the client version number that the client reports to
  95. // the server. The version number refers to the host client application,
  96. // not the core tunnel library. One purpose of this value is to enable
  97. // automatic updates. This value is supplied by and depends on the Psiphon
  98. // Network, and is typically embedded in the client binary.
  99. //
  100. // Note that sending a ClientPlatform string which includes "windows"
  101. // (case insensitive) and a ClientVersion of <= 44 will cause an error in
  102. // processing the response to DoConnectedRequest calls.
  103. ClientVersion string
  104. // ClientPlatform is the client platform ("Windows", "Android", etc.) that
  105. // the client reports to the server.
  106. ClientPlatform string
  107. // TunnelWholeDevice is a flag that is passed through to the handshake
  108. // request for stats purposes. Set to 1 when the host application is
  109. // tunneling the whole device, 0 otherwise.
  110. TunnelWholeDevice int
  111. // EgressRegion is a ISO 3166-1 alpha-2 country code which indicates which
  112. // country to egress from. For the default, "", the best performing server
  113. // in any country is selected.
  114. EgressRegion string
  115. // ListenInterface specifies which interface to listen on. If no
  116. // interface is provided then listen on 127.0.0.1. If 'any' is provided
  117. // then use 0.0.0.0. If there are multiple IP addresses on an interface
  118. // use the first IPv4 address.
  119. ListenInterface string
  120. // DisableLocalSocksProxy disables running the local SOCKS proxy.
  121. DisableLocalSocksProxy bool
  122. // LocalSocksProxyPort specifies a port number for the local SOCKS proxy
  123. // running at 127.0.0.1. For the default value, 0, the system selects a
  124. // free port (a notice reporting the selected port is emitted).
  125. LocalSocksProxyPort int
  126. // LocalHttpProxyPort specifies a port number for the local HTTP proxy
  127. // running at 127.0.0.1. For the default value, 0, the system selects a
  128. // free port (a notice reporting the selected port is emitted).
  129. LocalHttpProxyPort int
  130. // DisableLocalHTTPProxy disables running the local HTTP proxy.
  131. DisableLocalHTTPProxy bool
  132. // NetworkLatencyMultiplier is a multiplier that is to be applied to
  133. // default network event timeouts. Set this to tune performance for
  134. // slow networks.
  135. // When set, must be >= 1.0.
  136. NetworkLatencyMultiplier float64
  137. // LimitTunnelProtocols indicates which protocols to use. Valid values
  138. // include:
  139. // "SSH", "OSSH", "UNFRONTED-MEEK-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
  140. // "UNFRONTED-MEEK-SESSION-TICKET-OSSH", "FRONTED-MEEK-OSSH",
  141. // "FRONTED-MEEK-HTTP-OSSH", "QUIC-OSSH", "MARIONETTE-OSSH", and
  142. // "TAPDANCE-OSSH".
  143. // For the default, an empty list, all protocols are used.
  144. LimitTunnelProtocols []string
  145. // InitialLimitTunnelProtocols is an optional initial phase of limited
  146. // protocols for the first InitialLimitTunnelProtocolsCandidateCount
  147. // candidates; after these candidates, LimitTunnelProtocols applies.
  148. //
  149. // For the default, an empty list, InitialLimitTunnelProtocols is off.
  150. InitialLimitTunnelProtocols []string
  151. // InitialLimitTunnelProtocolsCandidateCount is the number of candidates
  152. // to which InitialLimitTunnelProtocols is applied instead of
  153. // LimitTunnelProtocols.
  154. //
  155. // For the default, 0, InitialLimitTunnelProtocols is off.
  156. InitialLimitTunnelProtocolsCandidateCount int
  157. // LimitTLSProfiles indicates which TLS profiles to select from. Valid
  158. // values are listed in protocols.SupportedTLSProfiles.
  159. // For the default, an empty list, all profiles are candidates for
  160. // selection.
  161. LimitTLSProfiles []string
  162. // LimitQUICVersions indicates which QUIC versions to select from. Valid
  163. // values are listed in protocols.SupportedQUICVersions.
  164. // For the default, an empty list, all versions are candidates for
  165. // selection.
  166. LimitQUICVersions []string
  167. // EstablishTunnelTimeoutSeconds specifies a time limit after which to
  168. // halt the core tunnel controller if no tunnel has been established. The
  169. // default is parameters.EstablishTunnelTimeout.
  170. EstablishTunnelTimeoutSeconds *int
  171. // EstablishTunnelPausePeriodSeconds specifies the delay between attempts
  172. // to establish tunnels. Briefly pausing allows for network conditions to
  173. // improve and for asynchronous operations such as fetch remote server
  174. // list to complete. If omitted, a default value is used. This value is
  175. // typical overridden for testing.
  176. EstablishTunnelPausePeriodSeconds *int
  177. // EstablishTunnelPausePeriodSeconds specifies the grace period, or head
  178. // start, provided to the affinity server candidate when establishing. The
  179. // affinity server is the server used for the last established tunnel.
  180. EstablishTunnelServerAffinityGracePeriodMilliseconds *int
  181. // ConnectionWorkerPoolSize specifies how many connection attempts to
  182. // attempt in parallel. If omitted of when 0, a default is used; this is
  183. // recommended.
  184. ConnectionWorkerPoolSize int
  185. // TunnelPoolSize specifies how many tunnels to run in parallel. Port
  186. // forwards are multiplexed over multiple tunnels. If omitted or when 0,
  187. // the default is TUNNEL_POOL_SIZE, which is recommended.
  188. TunnelPoolSize int
  189. // StaggerConnectionWorkersMilliseconds adds a specified delay before
  190. // making each server candidate available to connection workers. This
  191. // option is enabled when StaggerConnectionWorkersMilliseconds > 0.
  192. StaggerConnectionWorkersMilliseconds int
  193. // LimitIntensiveConnectionWorkers limits the number of concurrent
  194. // connection workers attempting connections with resource intensive
  195. // protocols. This option is enabled when LimitIntensiveConnectionWorkers
  196. // > 0.
  197. LimitIntensiveConnectionWorkers int
  198. // LimitMeekBufferSizes selects smaller buffers for meek protocols.
  199. LimitMeekBufferSizes bool
  200. // IgnoreHandshakeStatsRegexps skips compiling and using stats regexes.
  201. IgnoreHandshakeStatsRegexps bool
  202. // UpstreamProxyURL is a URL specifying an upstream proxy to use for all
  203. // outbound connections. The URL should include proxy type and
  204. // authentication information, as required. See example URLs here:
  205. // https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/psiphon/upstreamproxy
  206. UpstreamProxyURL string
  207. // CustomHeaders is a set of additional arbitrary HTTP headers that are
  208. // added to all plaintext HTTP requests and requests made through an HTTP
  209. // upstream proxy when specified by UpstreamProxyURL.
  210. CustomHeaders http.Header
  211. // NetworkConnectivityChecker is an interface that enables tunnel-core to
  212. // call into the host application to check for network connectivity. See:
  213. // NetworkConnectivityChecker doc.
  214. //
  215. // This parameter is only applicable to library deployments.
  216. NetworkConnectivityChecker NetworkConnectivityChecker
  217. // DeviceBinder is an interface that enables tunnel-core to call into the
  218. // host application to bind sockets to specific devices. See: DeviceBinder
  219. // doc.
  220. //
  221. // This parameter is only applicable to library deployments.
  222. DeviceBinder DeviceBinder
  223. // IPv6Synthesizer is an interface that allows tunnel-core to call into
  224. // the host application to synthesize IPv6 addresses. See: IPv6Synthesizer
  225. // doc.
  226. //
  227. // This parameter is only applicable to library deployments.
  228. IPv6Synthesizer IPv6Synthesizer
  229. // DnsServerGetter is an interface that enables tunnel-core to call into
  230. // the host application to discover the native network DNS server
  231. // settings. See: DnsServerGetter doc.
  232. //
  233. // This parameter is only applicable to library deployments.
  234. DnsServerGetter DnsServerGetter
  235. // NetworkIDGetter in an interface that enables tunnel-core to call into
  236. // the host application to get an identifier for the host's current active
  237. // network. See: NetworkIDGetter doc.
  238. //
  239. // This parameter is only applicable to library deployments.
  240. NetworkIDGetter NetworkIDGetter
  241. // NetworkID, when not blank, is used as the identifier for the host's
  242. // current active network.
  243. // NetworkID is ignored when NetworkIDGetter is set.
  244. NetworkID string
  245. // DisableTactics disables tactics operations including requests, payload
  246. // handling, and application of parameters.
  247. DisableTactics bool
  248. // DisableReplay causes any persisted dial parameters to be ignored when
  249. // they would otherwise be used for replay.
  250. DisableReplay bool
  251. // TargetServerEntry is an encoded server entry. When specified, this
  252. // server entry is used exclusively and all other known servers are
  253. // ignored; also, when set, ConnectionWorkerPoolSize is ignored and
  254. // the pool size is 1.
  255. TargetServerEntry string
  256. // DisableApi disables Psiphon server API calls including handshake,
  257. // connected, status, etc. This is used for special case temporary tunnels
  258. // (Windows VPN mode).
  259. DisableApi bool
  260. // TargetApiProtocol specifies whether to force use of "ssh" or "web" API
  261. // protocol. When blank, the default, the optimal API protocol is used.
  262. // Note that this capability check is not applied before the
  263. // "CandidateServers" count is emitted.
  264. //
  265. // This parameter is intended for testing and debugging only. Not all
  266. // parameters are supported in the legacy "web" API protocol, including
  267. // speed test samples.
  268. TargetApiProtocol string
  269. // RemoteServerListURLs is list of URLs which specify locations to fetch
  270. // out-of-band server entries. This facility is used when a tunnel cannot
  271. // be established to known servers. This value is supplied by and depends
  272. // on the Psiphon Network, and is typically embedded in the client binary.
  273. // All URLs must point to the same entity with the same ETag. At least one
  274. // DownloadURL must have OnlyAfterAttempts = 0.
  275. RemoteServerListURLs parameters.DownloadURLs
  276. // RemoteServerListSignaturePublicKey specifies a public key that's used
  277. // to authenticate the remote server list payload. This value is supplied
  278. // by and depends on the Psiphon Network, and is typically embedded in the
  279. // client binary.
  280. RemoteServerListSignaturePublicKey string
  281. // DisableRemoteServerListFetcher disables fetching remote server lists.
  282. // This is used for special case temporary tunnels.
  283. DisableRemoteServerListFetcher bool
  284. // FetchRemoteServerListRetryPeriodMilliseconds specifies the delay before
  285. // resuming a remote server list download after a failure. If omitted, a
  286. // default value is used. This value is typical overridden for testing.
  287. FetchRemoteServerListRetryPeriodMilliseconds *int
  288. // ObfuscatedServerListRootURLs is a list of URLs which specify root
  289. // locations from which to fetch obfuscated server list files. This value
  290. // is supplied by and depends on the Psiphon Network, and is typically
  291. // embedded in the client binary. All URLs must point to the same entity
  292. // with the same ETag. At least one DownloadURL must have
  293. // OnlyAfterAttempts = 0.
  294. ObfuscatedServerListRootURLs parameters.DownloadURLs
  295. // SplitTunnelRoutesURLFormat is a URL which specifies the location of a
  296. // routes file to use for split tunnel mode. The URL must include a
  297. // placeholder for the client region to be supplied. Split tunnel mode
  298. // uses the routes file to classify port forward destinations as foreign
  299. // or domestic and does not tunnel domestic destinations. Split tunnel
  300. // mode is on when all the SplitTunnel parameters are supplied. This value
  301. // is supplied by and depends on the Psiphon Network, and is typically
  302. // embedded in the client binary.
  303. SplitTunnelRoutesURLFormat string
  304. // SplitTunnelRoutesSignaturePublicKey specifies a public key that's used
  305. // to authenticate the split tunnel routes payload. This value is supplied
  306. // by and depends on the Psiphon Network, and is typically embedded in the
  307. // client binary.
  308. SplitTunnelRoutesSignaturePublicKey string
  309. // SplitTunnelDNSServer specifies a DNS server to use when resolving port
  310. // forward target domain names to IP addresses for classification. The DNS
  311. // server must support TCP requests.
  312. SplitTunnelDNSServer string
  313. // UpgradeDownloadURLs is list of URLs which specify locations from which
  314. // to download a host client upgrade file, when one is available. The core
  315. // tunnel controller provides a resumable download facility which
  316. // downloads this resource and emits a notice when complete. This value is
  317. // supplied by and depends on the Psiphon Network, and is typically
  318. // embedded in the client binary. All URLs must point to the same entity
  319. // with the same ETag. At least one DownloadURL must have
  320. // OnlyAfterAttempts = 0.
  321. UpgradeDownloadURLs parameters.DownloadURLs
  322. // UpgradeDownloadClientVersionHeader specifies the HTTP header name for
  323. // the entity at UpgradeDownloadURLs which specifies the client version
  324. // (an integer value). A HEAD request may be made to check the version
  325. // number available at UpgradeDownloadURLs.
  326. // UpgradeDownloadClientVersionHeader is required when UpgradeDownloadURLs
  327. // is specified.
  328. UpgradeDownloadClientVersionHeader string
  329. // FetchUpgradeRetryPeriodMilliseconds specifies the delay before resuming
  330. // a client upgrade download after a failure. If omitted, a default value
  331. // is used. This value is typical overridden for testing.
  332. FetchUpgradeRetryPeriodMilliseconds *int
  333. // EmitBytesTransferred indicates whether to emit periodic notices showing
  334. // bytes sent and received.
  335. EmitBytesTransferred bool
  336. // TrustedCACertificatesFilename specifies a file containing trusted CA
  337. // certs. When set, this toggles use of the trusted CA certs, specified in
  338. // TrustedCACertificatesFilename, for tunneled TLS connections that expect
  339. // server certificates signed with public certificate authorities
  340. // (currently, only upgrade downloads). This option is used with stock Go
  341. // TLS in cases where Go may fail to obtain a list of root CAs from the
  342. // operating system.
  343. TrustedCACertificatesFilename string
  344. // DisablePeriodicSshKeepAlive indicates whether to send an SSH keepalive
  345. // every 1-2 minutes, when the tunnel is idle. If the SSH keepalive times
  346. // out, the tunnel is considered to have failed.
  347. DisablePeriodicSshKeepAlive bool
  348. // DeviceRegion is the optional, reported region the host device is
  349. // running in. This input value should be a ISO 3166-1 alpha-2 country
  350. // code. The device region is reported to the server in the connected
  351. // request and recorded for Psiphon stats.
  352. //
  353. // When provided, this value may be used, pre-connection, to select
  354. // performance or circumvention optimization strategies for the given
  355. // region.
  356. DeviceRegion string
  357. // EmitDiagnosticNotices indicates whether to output notices containing
  358. // detailed information about the Psiphon session. As these notices may
  359. // contain sensitive information, they should not be insecurely distributed
  360. // or displayed to users. Default is off.
  361. EmitDiagnosticNotices bool
  362. // EmitDiagnosticNetworkParameters indicates whether to include network
  363. // parameters in diagnostic notices. As these parameters are sensitive
  364. // circumvention network information, they should not be insecurely
  365. // distributed or displayed to users. Default is off.
  366. EmitDiagnosticNetworkParameters bool
  367. // RateLimits specify throttling configuration for the tunnel.
  368. RateLimits common.RateLimits
  369. // EmitSLOKs indicates whether to emit notices for each seeded SLOK. As
  370. // this could reveal user browsing activity, it's intended for debugging
  371. // and testing only.
  372. EmitSLOKs bool
  373. // PacketTunnelTunDeviceFileDescriptor specifies a tun device file
  374. // descriptor to use for running a packet tunnel. When this value is > 0,
  375. // a packet tunnel is established through the server and packets are
  376. // relayed via the tun device file descriptor. The file descriptor is
  377. // duped in NewController. When PacketTunnelTunDeviceFileDescriptor is
  378. // set, TunnelPoolSize must be 1.
  379. PacketTunnelTunFileDescriptor int
  380. // SessionID specifies a client session ID to use in the Psiphon API. The
  381. // session ID should be a randomly generated value that is used only for a
  382. // single session, which is defined as the period between a user starting
  383. // a Psiphon client and stopping the client.
  384. //
  385. // A session ID must be 32 hex digits (lower case). When blank, a random
  386. // session ID is automatically generated. Supply a session ID when a
  387. // single client session will cross multiple Controller instances.
  388. SessionID string
  389. // Authorizations is a list of encoded, signed access control
  390. // authorizations that the client has obtained and will present to the
  391. // server.
  392. Authorizations []string
  393. // ServerEntrySignaturePublicKey is a base64-encoded, ed25519 public
  394. // key value used to verify individual server entry signatures. This value
  395. // is supplied by and depends on the Psiphon Network, and is typically
  396. // embedded in the client binary.
  397. ServerEntrySignaturePublicKey string
  398. // ExchangeObfuscationKey is a base64-encoded, NaCl secretbox key used to
  399. // obfuscate server info exchanges between clients.
  400. // Required for the exchange functionality.
  401. ExchangeObfuscationKey string
  402. // EmitTapdanceLogs indicates whether to emit gotapdance log messages
  403. // to stdout. Note that gotapdance log messages do not conform to the
  404. // Notice format standard. Default is off.
  405. EmitTapdanceLogs bool
  406. // TransformHostNameProbability is for testing purposes.
  407. TransformHostNameProbability *float64
  408. // FragmentorProbability and associated Fragmentor fields are for testing
  409. // purposes.
  410. FragmentorProbability *float64
  411. FragmentorLimitProtocols []string
  412. FragmentorMinTotalBytes *int
  413. FragmentorMaxTotalBytes *int
  414. FragmentorMinWriteBytes *int
  415. FragmentorMaxWriteBytes *int
  416. FragmentorMinDelayMicroseconds *int
  417. FragmentorMaxDelayMicroseconds *int
  418. // MeekTrafficShapingProbability and associated fields are for testing
  419. // purposes.
  420. MeekTrafficShapingProbability *float64
  421. MeekTrafficShapingLimitProtocols []string
  422. MeekMinTLSPadding *int
  423. MeekMaxTLSPadding *int
  424. MeekMinLimitRequestPayloadLength *int
  425. MeekMaxLimitRequestPayloadLength *int
  426. MeekRedialTLSProbability *float64
  427. // ObfuscatedSSHAlgorithms and associated ObfuscatedSSH fields are for
  428. // testing purposes. If specified, ObfuscatedSSHAlgorithms must have 4 SSH
  429. // KEX elements in order: the kex algorithm, cipher, MAC, and server host
  430. // key algorithm.
  431. ObfuscatedSSHAlgorithms []string
  432. ObfuscatedSSHMinPadding *int
  433. ObfuscatedSSHMaxPadding *int
  434. // LivenessTestMinUpstreamBytes and other LivenessTest fields are for
  435. // testing purposes.
  436. LivenessTestMinUpstreamBytes *int
  437. LivenessTestMaxUpstreamBytes *int
  438. LivenessTestMinDownstreamBytes *int
  439. LivenessTestMaxDownstreamBytes *int
  440. // ReplayCandidateCount and other Replay fields are for testing purposes.
  441. ReplayCandidateCount *int
  442. ReplayDialParametersTTLSeconds *int
  443. ReplayTargetUpstreamBytes *int
  444. ReplayTargetDownstreamBytes *int
  445. ReplayTargetTunnelDurationSeconds *int
  446. ReplayLaterRoundMoveToFrontProbability *float64
  447. ReplayRetainFailedProbability *float64
  448. // NetworkLatencyMultiplierMin and other NetworkLatencyMultiplier fields are
  449. // for testing purposes.
  450. NetworkLatencyMultiplierMin float64
  451. NetworkLatencyMultiplierMax float64
  452. NetworkLatencyMultiplierLambda float64
  453. // UseOnlyCustomTLSProfiles and other TLS configuration fields are for
  454. // testing purposes.
  455. UseOnlyCustomTLSProfiles *bool
  456. CustomTLSProfiles protocol.CustomTLSProfiles
  457. SelectRandomizedTLSProfileProbability *float64
  458. NoDefaultTLSSessionIDProbability *float64
  459. // ApplicationParameters is for testing purposes.
  460. ApplicationParameters parameters.KeyValues
  461. // MigrateHompageNoticesFilename migrates a homepage file from the path
  462. // previously configured with setNoticeFiles to the new path for homepage
  463. // files under the data root directory. The file specified by this config
  464. // value will be moved to config.GetHomePageFilename().
  465. //
  466. // Note: see comment for config.Commit() for a description of how file
  467. // migrations are performed.
  468. //
  469. // If not set, no migration operation will be performed.
  470. MigrateHompageNoticesFilename string
  471. // MigrateRotatingNoticesFilename migrates notice files from the path
  472. // previously configured with setNoticeFiles to the new path for notice
  473. // files under the data root directory.
  474. //
  475. // MigrateRotatingNoticesFilename will be moved to
  476. // config.GetNoticesFilename().
  477. //
  478. // MigrateRotatingNoticesFilename.1 will be moved to
  479. // config.GetOldNoticesFilename().
  480. //
  481. // Note: see comment for config.Commit() for a description of how file
  482. // migrations are performed.
  483. //
  484. // If not set, no migration operation will be performed.
  485. MigrateRotatingNoticesFilename string
  486. // DataStoreDirectory is the directory in which to store the persistent
  487. // database, which contains information such as server entries. By
  488. // default, current working directory.
  489. //
  490. // Deprecated:
  491. // Use MigrateDataStoreDirectory. When MigrateDataStoreDirectory
  492. // is set, this parameter is ignored.
  493. //
  494. // DataStoreDirectory has been subsumed by the new data root directory,
  495. // which is configured with DataRootDirectory. If set, datastore files
  496. // found in the specified directory will be moved under the data root
  497. // directory.
  498. DataStoreDirectory string
  499. // MigrateDataStoreDirectory indicates the location of the datastore
  500. // directory, as previously configured with the deprecated
  501. // DataStoreDirectory config field. Datastore files found in the specified
  502. // directory will be moved under the data root directory.
  503. //
  504. // Note: see comment for config.Commit() for a description of how file
  505. // migrations are performed.
  506. MigrateDataStoreDirectory string
  507. // RemoteServerListDownloadFilename specifies a target filename for
  508. // storing the remote server list download. Data is stored in co-located
  509. // files (RemoteServerListDownloadFilename.part*) to allow for resumable
  510. // downloading.
  511. //
  512. // Deprecated:
  513. // Use MigrateRemoteServerListDownloadFilename. When
  514. // MigrateRemoteServerListDownloadFilename is set, this parameter is
  515. // ignored.
  516. //
  517. // If set, remote server list download files found at the specified path
  518. // will be moved under the data root directory.
  519. RemoteServerListDownloadFilename string
  520. // MigrateRemoteServerListDownloadFilename indicates the location of
  521. // remote server list download files. The remote server list files found at
  522. // the specified path will be moved under the data root directory.
  523. //
  524. // Note: see comment for config.Commit() for a description of how file
  525. // migrations are performed.
  526. MigrateRemoteServerListDownloadFilename string
  527. // ObfuscatedServerListDownloadDirectory specifies a target directory for
  528. // storing the obfuscated remote server list downloads. Data is stored in
  529. // co-located files (<OSL filename>.part*) to allow for resumable
  530. // downloading.
  531. //
  532. // Deprecated:
  533. // Use MigrateObfuscatedServerListDownloadDirectory. When
  534. // MigrateObfuscatedServerListDownloadDirectory is set, this parameter is
  535. // ignored.
  536. //
  537. // If set, obfuscated server list download files found at the specified path
  538. // will be moved under the data root directory.
  539. ObfuscatedServerListDownloadDirectory string
  540. // MigrateObfuscatedServerListDownloadDirectory indicates the location of
  541. // the obfuscated server list downloads directory, as previously configured
  542. // with ObfuscatedServerListDownloadDirectory. Obfuscated server list
  543. // download files found in the specified directory will be moved under the
  544. // data root directory.
  545. //
  546. // Warning: if the directory is empty after obfuscated server
  547. // list files are moved, then it will be deleted.
  548. //
  549. // Note: see comment for config.Commit() for a description of how file
  550. // migrations are performed.
  551. MigrateObfuscatedServerListDownloadDirectory string
  552. // UpgradeDownloadFilename is the local target filename for an upgrade
  553. // download. This parameter is required when UpgradeDownloadURLs (or
  554. // UpgradeDownloadUrl) is specified. Data is stored in co-located files
  555. // (UpgradeDownloadFilename.part*) to allow for resumable downloading.
  556. //
  557. // Deprecated:
  558. // Use MigrateUpgradeDownloadFilename. When MigrateUpgradeDownloadFilename
  559. // is set, this parameter is ignored.
  560. //
  561. // If set, upgrade download files found at the specified path will be moved
  562. // under the data root directory.
  563. UpgradeDownloadFilename string
  564. // MigrateUpgradeDownloadFilename indicates the location of downloaded
  565. // application upgrade files. Downloaded upgrade files found at the
  566. // specified path will be moved under the data root directory.
  567. //
  568. // Note: see comment for config.Commit() for a description of how file
  569. // migrations are performed.
  570. MigrateUpgradeDownloadFilename string
  571. // TunnelProtocol indicates which protocol to use. For the default, "",
  572. // all protocols are used.
  573. //
  574. // Deprecated: Use LimitTunnelProtocols. When LimitTunnelProtocols is not
  575. // nil, this parameter is ignored.
  576. TunnelProtocol string
  577. // Deprecated: Use CustomHeaders. When CustomHeaders is not nil, this
  578. // parameter is ignored.
  579. UpstreamProxyCustomHeaders http.Header
  580. // RemoteServerListUrl is a URL which specifies a location to fetch out-
  581. // of-band server entries. This facility is used when a tunnel cannot be
  582. // established to known servers. This value is supplied by and depends on
  583. // the Psiphon Network, and is typically embedded in the client binary.
  584. //
  585. // Deprecated: Use RemoteServerListURLs. When RemoteServerListURLs is not
  586. // nil, this parameter is ignored.
  587. RemoteServerListUrl string
  588. // ObfuscatedServerListRootURL is a URL which specifies the root location
  589. // from which to fetch obfuscated server list files. This value is
  590. // supplied by and depends on the Psiphon Network, and is typically
  591. // embedded in the client binary.
  592. //
  593. // Deprecated: Use ObfuscatedServerListRootURLs. When
  594. // ObfuscatedServerListRootURLs is not nil, this parameter is ignored.
  595. ObfuscatedServerListRootURL string
  596. // UpgradeDownloadUrl specifies a URL from which to download a host client
  597. // upgrade file, when one is available. The core tunnel controller
  598. // provides a resumable download facility which downloads this resource
  599. // and emits a notice when complete. This value is supplied by and depends
  600. // on the Psiphon Network, and is typically embedded in the client binary.
  601. //
  602. // Deprecated: Use UpgradeDownloadURLs. When UpgradeDownloadURLs is not
  603. // nil, this parameter is ignored.
  604. UpgradeDownloadUrl string
  605. // clientParameters is the active ClientParameters with defaults, config
  606. // values, and, optionally, tactics applied.
  607. //
  608. // New tactics must be applied by calling Config.SetClientParameters;
  609. // calling clientParameters.Set directly will fail to add config values.
  610. clientParameters *parameters.ClientParameters
  611. dialParametersHash []byte
  612. dynamicConfigMutex sync.Mutex
  613. sponsorID string
  614. authorizations []string
  615. deviceBinder DeviceBinder
  616. networkIDGetter NetworkIDGetter
  617. committed bool
  618. loadTimestamp string
  619. }
  620. // Config field which specifies if notice files should be used and at which
  621. // frequency and size they should be rotated.
  622. //
  623. // If either RotatingFileSize or RotatingSyncFrequency are <= 0, default values
  624. // are used.
  625. //
  626. // See comment for setNoticeFiles in notice.go for further details.
  627. type UseNoticeFiles struct {
  628. RotatingFileSize int
  629. RotatingSyncFrequency int
  630. }
  631. // LoadConfig parses a JSON format Psiphon config JSON string and returns a
  632. // Config struct populated with config values.
  633. //
  634. // The Config struct may then be programmatically populated with additional
  635. // values, including callbacks such as DeviceBinder.
  636. //
  637. // Before using the Config, Commit must be called, which will perform further
  638. // validation and initialize internal data structures.
  639. func LoadConfig(configJson []byte) (*Config, error) {
  640. var config Config
  641. err := json.Unmarshal(configJson, &config)
  642. if err != nil {
  643. return nil, errors.Trace(err)
  644. }
  645. config.loadTimestamp = common.TruncateTimestampToHour(
  646. common.GetCurrentTimestamp())
  647. return &config, nil
  648. }
  649. // IsCommitted checks if Commit was called.
  650. func (config *Config) IsCommitted() bool {
  651. return config.committed
  652. }
  653. // Commit validates Config fields finalizes initialization.
  654. //
  655. // Config fields should not be set after calling Config, as any changes may
  656. // not be reflected in internal data structures.
  657. //
  658. // File migrations:
  659. // Config fields of the naming Migrate* (e.g. MigrateDataStoreDirectory) specify
  660. // a file migration operation which should be performed. These fields correspond
  661. // to deprecated fields, which previously could be used to specify where Psiphon
  662. // stored different sets of persistent files (e.g. MigrateDataStoreDirectory
  663. // corresponds to the deprecated field DataStoreDirectory).
  664. //
  665. // Psiphon now stores all persistent data under the configurable
  666. // DataRootDirectory (see Config.DataRootDirectory). The deprecated fields, and
  667. // corresponding Migrate* fields, are now used to specify the file or directory
  668. // path where, or under which, persistent files and directories created by
  669. // previous versions of Psiphon exist, so they can be moved under the
  670. // DataRootDirectory.
  671. //
  672. // For each migration operation:
  673. // - In the case of directories that could have defaulted to the current working
  674. // directory, persistent files and directories created by Psiphon are
  675. // precisely targeted to avoid moving files which were not created by Psiphon.
  676. // - If no file is found at the specified path, or an error is encountered while
  677. // migrating the file, then an error is logged and execution continues
  678. // normally.
  679. //
  680. // A sentinel file which signals that file migration has been completed, and
  681. // should not be attempted again, is created under DataRootDirectory after one
  682. // full pass through Commit(), regardless of whether file migration succeeds or
  683. // fails. It is better to not endlessly retry file migrations on each Commit()
  684. // because file system errors are expected to be rare and persistent files will
  685. // be re-populated over time.
  686. func (config *Config) Commit() error {
  687. // Do SetEmitDiagnosticNotices first, to ensure config file errors are
  688. // emitted.
  689. if config.EmitDiagnosticNotices {
  690. SetEmitDiagnosticNotices(
  691. true, config.EmitDiagnosticNetworkParameters)
  692. }
  693. // Migrate and set notice files before any operations that may emit an
  694. // error. This is to ensure config file errors are written to file when
  695. // notice files are configured with config.UseNoticeFiles.
  696. //
  697. // Note:
  698. // Errors encountered while configuring the data directory cannot be written
  699. // to notice files. This is because notices files are created within the
  700. // data directory.
  701. if config.DataRootDirectory == "" {
  702. wd, err := os.Getwd()
  703. if err != nil {
  704. return errors.Trace(err)
  705. }
  706. config.DataRootDirectory = wd
  707. }
  708. // Create root directory
  709. dataDirectoryPath := config.GetPsiphonDataDirectory()
  710. if !common.FileExists(dataDirectoryPath) {
  711. err := os.Mkdir(dataDirectoryPath, os.ModePerm)
  712. if err != nil {
  713. return errors.Tracef("failed to create datastore directory %s with error: %s", dataDirectoryPath, err.Error())
  714. }
  715. }
  716. // Check if the migration from legacy config fields has already been
  717. // completed. See the Migrate* config fields for more details.
  718. migrationCompleteFilePath := filepath.Join(config.GetPsiphonDataDirectory(), "migration_complete")
  719. needMigration := !common.FileExists(migrationCompleteFilePath)
  720. // Collect notices to emit them after notice files are set
  721. var noticeMigrationAlertMsgs []string
  722. var noticeMigrationInfoMsgs []string
  723. // Migrate notices first to ensure notice files are used for notices if
  724. // UseNoticeFiles is set.
  725. homepageFilePath := config.GetHomePageFilename()
  726. noticesFilePath := config.GetNoticesFilename()
  727. if needMigration {
  728. // Move notice files that exist at legacy file paths under the data root
  729. // directory.
  730. noticeMigrationInfoMsgs = append(noticeMigrationInfoMsgs, "Config migration: need migration")
  731. noticeMigrations := migrationsFromLegacyNoticeFilePaths(config)
  732. for _, migration := range noticeMigrations {
  733. err := common.DoFileMigration(migration)
  734. if err != nil {
  735. alertMsg := fmt.Sprintf("Config migration: %s", errors.Trace(err))
  736. noticeMigrationAlertMsgs = append(noticeMigrationAlertMsgs, alertMsg)
  737. } else {
  738. infoMsg := fmt.Sprintf("Config migration: moved %s to %s", migration.OldPath, migration.NewPath)
  739. noticeMigrationInfoMsgs = append(noticeMigrationInfoMsgs, infoMsg)
  740. }
  741. }
  742. } else {
  743. noticeMigrationInfoMsgs = append(noticeMigrationInfoMsgs, "Config migration: migration already completed")
  744. }
  745. if config.UseNoticeFiles != nil {
  746. setNoticeFiles(
  747. homepageFilePath,
  748. noticesFilePath,
  749. config.UseNoticeFiles.RotatingFileSize,
  750. config.UseNoticeFiles.RotatingSyncFrequency)
  751. }
  752. // Emit notices now that notice files are set if configured
  753. for _, msg := range noticeMigrationAlertMsgs {
  754. NoticeAlert(msg)
  755. }
  756. for _, msg := range noticeMigrationInfoMsgs {
  757. NoticeInfo(msg)
  758. }
  759. // Promote legacy fields.
  760. if config.CustomHeaders == nil {
  761. config.CustomHeaders = config.UpstreamProxyCustomHeaders
  762. config.UpstreamProxyCustomHeaders = nil
  763. }
  764. if config.RemoteServerListUrl != "" && config.RemoteServerListURLs == nil {
  765. config.RemoteServerListURLs = promoteLegacyDownloadURL(config.RemoteServerListUrl)
  766. }
  767. if config.ObfuscatedServerListRootURL != "" && config.ObfuscatedServerListRootURLs == nil {
  768. config.ObfuscatedServerListRootURLs = promoteLegacyDownloadURL(config.ObfuscatedServerListRootURL)
  769. }
  770. if config.UpgradeDownloadUrl != "" && config.UpgradeDownloadURLs == nil {
  771. config.UpgradeDownloadURLs = promoteLegacyDownloadURL(config.UpgradeDownloadUrl)
  772. }
  773. if config.TunnelProtocol != "" && len(config.LimitTunnelProtocols) == 0 {
  774. config.LimitTunnelProtocols = []string{config.TunnelProtocol}
  775. }
  776. if config.DataStoreDirectory != "" && config.MigrateDataStoreDirectory == "" {
  777. config.MigrateDataStoreDirectory = config.DataStoreDirectory
  778. }
  779. if config.RemoteServerListDownloadFilename != "" && config.MigrateRemoteServerListDownloadFilename == "" {
  780. config.MigrateRemoteServerListDownloadFilename = config.RemoteServerListDownloadFilename
  781. }
  782. if config.ObfuscatedServerListDownloadDirectory != "" && config.MigrateObfuscatedServerListDownloadDirectory == "" {
  783. config.MigrateObfuscatedServerListDownloadDirectory = config.ObfuscatedServerListDownloadDirectory
  784. }
  785. if config.UpgradeDownloadFilename != "" && config.MigrateUpgradeDownloadFilename == "" {
  786. config.MigrateUpgradeDownloadFilename = config.UpgradeDownloadFilename
  787. }
  788. // Supply default values.
  789. // Create datastore directory.
  790. dataStoreDirectoryPath := config.GetDataStoreDirectory()
  791. if !common.FileExists(dataStoreDirectoryPath) {
  792. err := os.Mkdir(dataStoreDirectoryPath, os.ModePerm)
  793. if err != nil {
  794. return errors.Tracef("failed to create datastore directory %s with error: %s", dataStoreDirectoryPath, err.Error())
  795. }
  796. }
  797. // Create OSL directory.
  798. oslDirectoryPath := config.GetObfuscatedServerListDownloadDirectory()
  799. if !common.FileExists(oslDirectoryPath) {
  800. err := os.Mkdir(oslDirectoryPath, os.ModePerm)
  801. if err != nil {
  802. return errors.Tracef("failed to create osl directory %s with error: %s", oslDirectoryPath, err.Error())
  803. }
  804. }
  805. // Create tapdance directory
  806. tapdanceDirectoryPath := config.GetTapdanceDirectory()
  807. if !common.FileExists(tapdanceDirectoryPath) {
  808. err := os.Mkdir(tapdanceDirectoryPath, os.ModePerm)
  809. if err != nil {
  810. return errors.Tracef("failed to create tapdance directory %s with error: %s", tapdanceDirectoryPath, err.Error())
  811. }
  812. }
  813. if config.ClientVersion == "" {
  814. config.ClientVersion = "0"
  815. }
  816. if config.TunnelPoolSize == 0 {
  817. config.TunnelPoolSize = TUNNEL_POOL_SIZE
  818. }
  819. // Validate config fields.
  820. if !common.FileExists(config.DataRootDirectory) {
  821. return errors.Tracef("DataRootDirectory does not exist: %s", config.DataRootDirectory)
  822. }
  823. if config.PropagationChannelId == "" {
  824. return errors.TraceNew("propagation channel ID is missing from the configuration file")
  825. }
  826. if config.SponsorId == "" {
  827. return errors.TraceNew("sponsor ID is missing from the configuration file")
  828. }
  829. _, err := strconv.Atoi(config.ClientVersion)
  830. if err != nil {
  831. return errors.Tracef("invalid client version: %s", err)
  832. }
  833. if !common.Contains(
  834. []string{"", protocol.PSIPHON_SSH_API_PROTOCOL, protocol.PSIPHON_WEB_API_PROTOCOL},
  835. config.TargetApiProtocol) {
  836. return errors.TraceNew("invalid TargetApiProtocol")
  837. }
  838. if !config.DisableRemoteServerListFetcher {
  839. if config.RemoteServerListURLs != nil {
  840. if config.RemoteServerListSignaturePublicKey == "" {
  841. return errors.TraceNew("missing RemoteServerListSignaturePublicKey")
  842. }
  843. }
  844. if config.ObfuscatedServerListRootURLs != nil {
  845. if config.RemoteServerListSignaturePublicKey == "" {
  846. return errors.TraceNew("missing RemoteServerListSignaturePublicKey")
  847. }
  848. }
  849. }
  850. if config.SplitTunnelRoutesURLFormat != "" {
  851. if config.SplitTunnelRoutesSignaturePublicKey == "" {
  852. return errors.TraceNew("missing SplitTunnelRoutesSignaturePublicKey")
  853. }
  854. if config.SplitTunnelDNSServer == "" {
  855. return errors.TraceNew("missing SplitTunnelDNSServer")
  856. }
  857. }
  858. if config.UpgradeDownloadURLs != nil {
  859. if config.UpgradeDownloadClientVersionHeader == "" {
  860. return errors.TraceNew("missing UpgradeDownloadClientVersionHeader")
  861. }
  862. }
  863. // This constraint is expected by logic in Controller.runTunnels().
  864. if config.PacketTunnelTunFileDescriptor > 0 && config.TunnelPoolSize != 1 {
  865. return errors.TraceNew("packet tunnel mode requires TunnelPoolSize to be 1")
  866. }
  867. // SessionID must be PSIPHON_API_CLIENT_SESSION_ID_LENGTH lowercase hex-encoded bytes.
  868. if config.SessionID == "" {
  869. sessionID, err := MakeSessionId()
  870. if err != nil {
  871. return errors.Trace(err)
  872. }
  873. config.SessionID = sessionID
  874. }
  875. if len(config.SessionID) != 2*protocol.PSIPHON_API_CLIENT_SESSION_ID_LENGTH ||
  876. -1 != strings.IndexFunc(config.SessionID, func(c rune) bool {
  877. return !unicode.Is(unicode.ASCII_Hex_Digit, c) || unicode.IsUpper(c)
  878. }) {
  879. return errors.TraceNew("invalid SessionID")
  880. }
  881. config.clientParameters, err = parameters.NewClientParameters(
  882. func(err error) {
  883. NoticeAlert("ClientParameters getValue failed: %s", err)
  884. })
  885. if err != nil {
  886. return errors.Trace(err)
  887. }
  888. if config.ObfuscatedSSHAlgorithms != nil &&
  889. len(config.ObfuscatedSSHAlgorithms) != 4 {
  890. // TODO: validate each algorithm?
  891. return errors.TraceNew("invalid ObfuscatedSSHAlgorithms")
  892. }
  893. // clientParameters.Set will validate the config fields applied to parameters.
  894. err = config.SetClientParameters("", false, nil)
  895. if err != nil {
  896. return errors.Trace(err)
  897. }
  898. // Calculate and set the dial parameters hash. After this point, related
  899. // config fields must not change.
  900. config.setDialParametersHash()
  901. // Set defaults for dynamic config fields.
  902. config.SetDynamicConfig(config.SponsorId, config.Authorizations)
  903. // Initialize config.deviceBinder and config.config.networkIDGetter. These
  904. // wrap config.DeviceBinder and config.NetworkIDGetter/NetworkID with
  905. // loggers.
  906. //
  907. // New variables are set to avoid mutating input config fields.
  908. // Internally, code must use config.deviceBinder and
  909. // config.networkIDGetter and not the input/exported fields.
  910. if config.DeviceBinder != nil {
  911. config.deviceBinder = newLoggingDeviceBinder(config.DeviceBinder)
  912. }
  913. networkIDGetter := config.NetworkIDGetter
  914. if networkIDGetter == nil {
  915. // Limitation: unlike NetworkIDGetter, which calls back to platform APIs
  916. // this method of network identification is not dynamic and will not reflect
  917. // network changes that occur while running.
  918. if config.NetworkID != "" {
  919. networkIDGetter = newStaticNetworkGetter(config.NetworkID)
  920. } else {
  921. networkIDGetter = newStaticNetworkGetter("UNKNOWN")
  922. }
  923. }
  924. config.networkIDGetter = newLoggingNetworkIDGetter(networkIDGetter)
  925. // Migrate from old config fields. This results in files being moved under
  926. // a config specified data root directory.
  927. // If unset, set MigrateDataStoreDirectory to the previous default value for
  928. // DataStoreDirectory to ensure that datastore files are migrated.
  929. if config.MigrateDataStoreDirectory == "" {
  930. wd, err := os.Getwd()
  931. if err != nil {
  932. return errors.Trace(err)
  933. }
  934. NoticeInfo("MigrateDataStoreDirectory unset, using working directory %s", wd)
  935. config.MigrateDataStoreDirectory = wd
  936. }
  937. if needMigration {
  938. // Move files that exist at legacy file paths under the data root
  939. // directory.
  940. migrations, err := migrationsFromLegacyFilePaths(config)
  941. if err != nil {
  942. return errors.Trace(err)
  943. }
  944. // Do migrations
  945. for _, migration := range migrations {
  946. err := common.DoFileMigration(migration)
  947. if err != nil {
  948. NoticeAlert("Config migration: %s", errors.Trace(err))
  949. } else {
  950. NoticeInfo("Config migration: moved %s to %s", migration.OldPath, migration.NewPath)
  951. }
  952. }
  953. // Remove OSL directory if empty
  954. if config.MigrateObfuscatedServerListDownloadDirectory != "" {
  955. files, err := ioutil.ReadDir(config.MigrateObfuscatedServerListDownloadDirectory)
  956. if err != nil {
  957. NoticeAlert("Error reading OSL directory %s: %s", config.MigrateObfuscatedServerListDownloadDirectory, errors.Trace(err))
  958. } else if len(files) == 0 {
  959. err := os.Remove(config.MigrateObfuscatedServerListDownloadDirectory)
  960. if err != nil {
  961. NoticeAlert("Error deleting empty OSL directory %s: %s", config.MigrateObfuscatedServerListDownloadDirectory, errors.Trace(err))
  962. }
  963. }
  964. }
  965. f, err := os.Create(migrationCompleteFilePath)
  966. if err != nil {
  967. NoticeAlert("Config migration: failed to create %s with error %s", migrationCompleteFilePath, errors.Trace(err))
  968. } else {
  969. NoticeInfo("Config migration: completed")
  970. f.Close()
  971. }
  972. }
  973. config.committed = true
  974. return nil
  975. }
  976. // GetClientParameters returns a the current client parameters.
  977. func (config *Config) GetClientParameters() *parameters.ClientParameters {
  978. return config.clientParameters
  979. }
  980. // SetClientParameters resets Config.clientParameters to the default values,
  981. // applies any config file values, and then applies the input parameters (from
  982. // tactics, etc.)
  983. //
  984. // Set skipOnError to false when initially applying only config values, as
  985. // this will validate the values and should fail. Set skipOnError to true when
  986. // applying tactics to ignore invalid or unknown parameter values from tactics.
  987. //
  988. // In the case of applying tactics, do not call Config.clientParameters.Set
  989. // directly as this will not first apply config values.
  990. //
  991. // If there is an error, the existing Config.clientParameters are left
  992. // entirely unmodified.
  993. func (config *Config) SetClientParameters(tag string, skipOnError bool, applyParameters map[string]interface{}) error {
  994. setParameters := []map[string]interface{}{config.makeConfigParameters()}
  995. if applyParameters != nil {
  996. setParameters = append(setParameters, applyParameters)
  997. }
  998. counts, err := config.clientParameters.Set(tag, skipOnError, setParameters...)
  999. if err != nil {
  1000. return errors.Trace(err)
  1001. }
  1002. NoticeInfo("applied %v parameters with tag '%s'", counts, tag)
  1003. // Emit certain individual parameter values for quick reference in diagnostics.
  1004. p := config.clientParameters.Get()
  1005. NoticeInfo(
  1006. "NetworkLatencyMultiplier Min/Max/Lambda: %f/%f/%f",
  1007. p.Float(parameters.NetworkLatencyMultiplierMin),
  1008. p.Float(parameters.NetworkLatencyMultiplierMax),
  1009. p.Float(parameters.NetworkLatencyMultiplierLambda))
  1010. // Application Parameters are feature flags/config info, delivered as Client
  1011. // Parameters via tactics/etc., to be communicated to the outer application.
  1012. // Emit these now, as notices.
  1013. if p.WeightedCoinFlip(parameters.ApplicationParametersProbability) {
  1014. NoticeApplicationParameters(p.KeyValues(parameters.ApplicationParameters))
  1015. }
  1016. return nil
  1017. }
  1018. // SetDynamicConfig sets the current client sponsor ID and authorizations.
  1019. // Invalid values for sponsor ID are ignored. The caller must not modify the
  1020. // input authorizations slice.
  1021. func (config *Config) SetDynamicConfig(sponsorID string, authorizations []string) {
  1022. config.dynamicConfigMutex.Lock()
  1023. defer config.dynamicConfigMutex.Unlock()
  1024. if sponsorID != "" {
  1025. config.sponsorID = sponsorID
  1026. }
  1027. config.authorizations = authorizations
  1028. }
  1029. // GetSponsorID returns the current client sponsor ID.
  1030. func (config *Config) GetSponsorID() string {
  1031. config.dynamicConfigMutex.Lock()
  1032. defer config.dynamicConfigMutex.Unlock()
  1033. return config.sponsorID
  1034. }
  1035. // GetAuthorizations returns the current client authorizations.
  1036. // The caller must not modify the returned slice.
  1037. func (config *Config) GetAuthorizations() []string {
  1038. config.dynamicConfigMutex.Lock()
  1039. defer config.dynamicConfigMutex.Unlock()
  1040. return config.authorizations
  1041. }
  1042. // GetPsiphonDataDirectory returns the directory under which all persistent
  1043. // files should be stored. This directory is created under
  1044. // config.DataRootDirectory. The motivation for an additional directory is that
  1045. // config.DataRootDirectory defaults to the current working directory, which may
  1046. // include non-tunnel-core files that should be excluded from directory-spanning
  1047. // operations (e.g. excluding all tunnel-core files from backup).
  1048. func (config *Config) GetPsiphonDataDirectory() string {
  1049. return filepath.Join(config.DataRootDirectory, PsiphonDataDirectoryName)
  1050. }
  1051. // GetHomePageFilename the path where the homepage notices file will be created.
  1052. func (config *Config) GetHomePageFilename() string {
  1053. return filepath.Join(config.GetPsiphonDataDirectory(), HomepageFilename)
  1054. }
  1055. // GetNoticesFilename returns the path where the notices file will be created.
  1056. // When the file is rotated it will be moved to config.GetOldNoticesFilename().
  1057. func (config *Config) GetNoticesFilename() string {
  1058. return filepath.Join(config.GetPsiphonDataDirectory(), NoticesFilename)
  1059. }
  1060. // GetOldNoticeFilename returns the path where the rotated notices file will be
  1061. // created.
  1062. func (config *Config) GetOldNoticesFilename() string {
  1063. return filepath.Join(config.GetPsiphonDataDirectory(), OldNoticesFilename)
  1064. }
  1065. // GetDataStoreDirectory returns the directory in which the persistent database
  1066. // will be stored. Created in Config.Commit(). The persistent database contains
  1067. // information such as server entries.
  1068. func (config *Config) GetDataStoreDirectory() string {
  1069. return filepath.Join(config.GetPsiphonDataDirectory(), "datastore")
  1070. }
  1071. // GetObfuscatedServerListDownloadDirectory returns the directory in which
  1072. // obfuscated remote server list downloads will be stored. Created in
  1073. // Config.Commit().
  1074. func (config *Config) GetObfuscatedServerListDownloadDirectory() string {
  1075. return filepath.Join(config.GetPsiphonDataDirectory(), "osl")
  1076. }
  1077. // GetRemoteServerListDownloadFilename returns the filename where the remote
  1078. // server list download will be stored. Data is stored in co-located files
  1079. // (RemoteServerListDownloadFilename.part*) to allow for resumable downloading.
  1080. func (config *Config) GetRemoteServerListDownloadFilename() string {
  1081. return filepath.Join(config.GetPsiphonDataDirectory(), "remote_server_list")
  1082. }
  1083. // GetUpgradeDownloadFilename specifies the filename where upgrade downloads
  1084. // will be stored. This filename is valid when UpgradeDownloadURLs
  1085. // (or UpgradeDownloadUrl) is specified. Data is stored in co-located files
  1086. // (UpgradeDownloadFilename.part*) to allow for resumable downloading.
  1087. func (config *Config) GetUpgradeDownloadFilename() string {
  1088. return filepath.Join(config.GetPsiphonDataDirectory(), UpgradeDownloadFilename)
  1089. }
  1090. // GetTapdanceDirectory returns the directory under which tapdance will create
  1091. // and manage files.
  1092. func (config *Config) GetTapdanceDirectory() string {
  1093. return filepath.Join(config.GetPsiphonDataDirectory(), "tapdance")
  1094. }
  1095. // UseUpstreamProxy indicates if an upstream proxy has been
  1096. // configured.
  1097. func (config *Config) UseUpstreamProxy() bool {
  1098. return config.UpstreamProxyURL != ""
  1099. }
  1100. // GetNetworkID returns the current network ID. When NetworkIDGetter
  1101. // is set, this calls into the host application; otherwise, a default
  1102. // value is returned.
  1103. func (config *Config) GetNetworkID() string {
  1104. return config.networkIDGetter.GetNetworkID()
  1105. }
  1106. func (config *Config) makeConfigParameters() map[string]interface{} {
  1107. // Build set of config values to apply to parameters.
  1108. //
  1109. // Note: names of some config fields such as
  1110. // StaggerConnectionWorkersMilliseconds and LimitMeekBufferSizes have
  1111. // changed in the parameters. The existing config fields are retained for
  1112. // backwards compatibility.
  1113. applyParameters := make(map[string]interface{})
  1114. // To support platform clients that configure NetworkLatencyMultiplier, set
  1115. // the NetworkLatencyMultiplierMin/NetworkLatencyMultiplierMax range to the
  1116. // specified value. Also set the older NetworkLatencyMultiplier tactic, since
  1117. // that will be used in the case of replaying with dial parameters persisted
  1118. // by an older client version.
  1119. if config.NetworkLatencyMultiplier > 0.0 {
  1120. applyParameters[parameters.NetworkLatencyMultiplier] = config.NetworkLatencyMultiplier
  1121. applyParameters[parameters.NetworkLatencyMultiplierMin] = config.NetworkLatencyMultiplier
  1122. applyParameters[parameters.NetworkLatencyMultiplierMax] = config.NetworkLatencyMultiplier
  1123. }
  1124. if config.NetworkLatencyMultiplierMin > 0.0 {
  1125. applyParameters[parameters.NetworkLatencyMultiplierMin] = config.NetworkLatencyMultiplierMin
  1126. }
  1127. if config.NetworkLatencyMultiplierMax > 0.0 {
  1128. applyParameters[parameters.NetworkLatencyMultiplierMax] = config.NetworkLatencyMultiplierMax
  1129. }
  1130. if config.NetworkLatencyMultiplierLambda > 0.0 {
  1131. applyParameters[parameters.NetworkLatencyMultiplierLambda] = config.NetworkLatencyMultiplierLambda
  1132. }
  1133. if len(config.LimitTunnelProtocols) > 0 {
  1134. applyParameters[parameters.LimitTunnelProtocols] = protocol.TunnelProtocols(config.LimitTunnelProtocols)
  1135. }
  1136. if len(config.InitialLimitTunnelProtocols) > 0 && config.InitialLimitTunnelProtocolsCandidateCount > 0 {
  1137. applyParameters[parameters.InitialLimitTunnelProtocols] = protocol.TunnelProtocols(config.InitialLimitTunnelProtocols)
  1138. applyParameters[parameters.InitialLimitTunnelProtocolsCandidateCount] = config.InitialLimitTunnelProtocolsCandidateCount
  1139. }
  1140. if len(config.LimitTLSProfiles) > 0 {
  1141. applyParameters[parameters.LimitTLSProfiles] = protocol.TunnelProtocols(config.LimitTLSProfiles)
  1142. }
  1143. if len(config.LimitQUICVersions) > 0 {
  1144. applyParameters[parameters.LimitQUICVersions] = protocol.QUICVersions(config.LimitQUICVersions)
  1145. }
  1146. if config.EstablishTunnelTimeoutSeconds != nil {
  1147. applyParameters[parameters.EstablishTunnelTimeout] = fmt.Sprintf("%ds", *config.EstablishTunnelTimeoutSeconds)
  1148. }
  1149. if config.EstablishTunnelServerAffinityGracePeriodMilliseconds != nil {
  1150. applyParameters[parameters.EstablishTunnelServerAffinityGracePeriod] = fmt.Sprintf("%dms", *config.EstablishTunnelServerAffinityGracePeriodMilliseconds)
  1151. }
  1152. if config.EstablishTunnelPausePeriodSeconds != nil {
  1153. applyParameters[parameters.EstablishTunnelPausePeriod] = fmt.Sprintf("%ds", *config.EstablishTunnelPausePeriodSeconds)
  1154. }
  1155. if config.ConnectionWorkerPoolSize != 0 {
  1156. applyParameters[parameters.ConnectionWorkerPoolSize] = config.ConnectionWorkerPoolSize
  1157. }
  1158. if config.StaggerConnectionWorkersMilliseconds > 0 {
  1159. applyParameters[parameters.StaggerConnectionWorkersPeriod] = fmt.Sprintf("%dms", config.StaggerConnectionWorkersMilliseconds)
  1160. }
  1161. if config.LimitIntensiveConnectionWorkers > 0 {
  1162. applyParameters[parameters.LimitIntensiveConnectionWorkers] = config.LimitIntensiveConnectionWorkers
  1163. }
  1164. applyParameters[parameters.MeekLimitBufferSizes] = config.LimitMeekBufferSizes
  1165. applyParameters[parameters.IgnoreHandshakeStatsRegexps] = config.IgnoreHandshakeStatsRegexps
  1166. if config.EstablishTunnelTimeoutSeconds != nil {
  1167. applyParameters[parameters.EstablishTunnelTimeout] = fmt.Sprintf("%ds", *config.EstablishTunnelTimeoutSeconds)
  1168. }
  1169. if config.FetchRemoteServerListRetryPeriodMilliseconds != nil {
  1170. applyParameters[parameters.FetchRemoteServerListRetryPeriod] = fmt.Sprintf("%dms", *config.FetchRemoteServerListRetryPeriodMilliseconds)
  1171. }
  1172. if config.FetchUpgradeRetryPeriodMilliseconds != nil {
  1173. applyParameters[parameters.FetchUpgradeRetryPeriod] = fmt.Sprintf("%dms", *config.FetchUpgradeRetryPeriodMilliseconds)
  1174. }
  1175. if !config.DisableRemoteServerListFetcher {
  1176. if config.RemoteServerListURLs != nil {
  1177. applyParameters[parameters.RemoteServerListSignaturePublicKey] = config.RemoteServerListSignaturePublicKey
  1178. applyParameters[parameters.RemoteServerListURLs] = config.RemoteServerListURLs
  1179. }
  1180. if config.ObfuscatedServerListRootURLs != nil {
  1181. applyParameters[parameters.RemoteServerListSignaturePublicKey] = config.RemoteServerListSignaturePublicKey
  1182. applyParameters[parameters.ObfuscatedServerListRootURLs] = config.ObfuscatedServerListRootURLs
  1183. }
  1184. }
  1185. applyParameters[parameters.SplitTunnelRoutesURLFormat] = config.SplitTunnelRoutesURLFormat
  1186. applyParameters[parameters.SplitTunnelRoutesSignaturePublicKey] = config.SplitTunnelRoutesSignaturePublicKey
  1187. applyParameters[parameters.SplitTunnelDNSServer] = config.SplitTunnelDNSServer
  1188. if config.UpgradeDownloadURLs != nil {
  1189. applyParameters[parameters.UpgradeDownloadClientVersionHeader] = config.UpgradeDownloadClientVersionHeader
  1190. applyParameters[parameters.UpgradeDownloadURLs] = config.UpgradeDownloadURLs
  1191. }
  1192. applyParameters[parameters.TunnelRateLimits] = config.RateLimits
  1193. if config.TransformHostNameProbability != nil {
  1194. applyParameters[parameters.TransformHostNameProbability] = *config.TransformHostNameProbability
  1195. }
  1196. if config.FragmentorProbability != nil {
  1197. applyParameters[parameters.FragmentorProbability] = *config.FragmentorProbability
  1198. }
  1199. if len(config.FragmentorLimitProtocols) > 0 {
  1200. applyParameters[parameters.FragmentorLimitProtocols] = protocol.TunnelProtocols(config.FragmentorLimitProtocols)
  1201. }
  1202. if config.FragmentorMinTotalBytes != nil {
  1203. applyParameters[parameters.FragmentorMinTotalBytes] = *config.FragmentorMinTotalBytes
  1204. }
  1205. if config.FragmentorMaxTotalBytes != nil {
  1206. applyParameters[parameters.FragmentorMaxTotalBytes] = *config.FragmentorMaxTotalBytes
  1207. }
  1208. if config.FragmentorMinWriteBytes != nil {
  1209. applyParameters[parameters.FragmentorMinWriteBytes] = *config.FragmentorMinWriteBytes
  1210. }
  1211. if config.FragmentorMaxWriteBytes != nil {
  1212. applyParameters[parameters.FragmentorMaxWriteBytes] = *config.FragmentorMaxWriteBytes
  1213. }
  1214. if config.FragmentorMinDelayMicroseconds != nil {
  1215. applyParameters[parameters.FragmentorMinDelay] = fmt.Sprintf("%dus", *config.FragmentorMinDelayMicroseconds)
  1216. }
  1217. if config.FragmentorMaxDelayMicroseconds != nil {
  1218. applyParameters[parameters.FragmentorMaxDelay] = fmt.Sprintf("%dus", *config.FragmentorMaxDelayMicroseconds)
  1219. }
  1220. if config.MeekTrafficShapingProbability != nil {
  1221. applyParameters[parameters.MeekTrafficShapingProbability] = *config.MeekTrafficShapingProbability
  1222. }
  1223. if len(config.MeekTrafficShapingLimitProtocols) > 0 {
  1224. applyParameters[parameters.MeekTrafficShapingLimitProtocols] = protocol.TunnelProtocols(config.MeekTrafficShapingLimitProtocols)
  1225. }
  1226. if config.MeekMinTLSPadding != nil {
  1227. applyParameters[parameters.MeekMinTLSPadding] = *config.MeekMinTLSPadding
  1228. }
  1229. if config.MeekMaxTLSPadding != nil {
  1230. applyParameters[parameters.MeekMaxTLSPadding] = *config.MeekMaxTLSPadding
  1231. }
  1232. if config.MeekMinLimitRequestPayloadLength != nil {
  1233. applyParameters[parameters.MeekMinLimitRequestPayloadLength] = *config.MeekMinLimitRequestPayloadLength
  1234. }
  1235. if config.MeekMaxLimitRequestPayloadLength != nil {
  1236. applyParameters[parameters.MeekMaxLimitRequestPayloadLength] = *config.MeekMaxLimitRequestPayloadLength
  1237. }
  1238. if config.MeekRedialTLSProbability != nil {
  1239. applyParameters[parameters.MeekRedialTLSProbability] = *config.MeekRedialTLSProbability
  1240. }
  1241. if config.ObfuscatedSSHMinPadding != nil {
  1242. applyParameters[parameters.ObfuscatedSSHMinPadding] = *config.ObfuscatedSSHMinPadding
  1243. }
  1244. if config.ObfuscatedSSHMaxPadding != nil {
  1245. applyParameters[parameters.ObfuscatedSSHMaxPadding] = *config.ObfuscatedSSHMaxPadding
  1246. }
  1247. if config.LivenessTestMinUpstreamBytes != nil {
  1248. applyParameters[parameters.LivenessTestMinUpstreamBytes] = *config.LivenessTestMinUpstreamBytes
  1249. }
  1250. if config.LivenessTestMaxUpstreamBytes != nil {
  1251. applyParameters[parameters.LivenessTestMaxUpstreamBytes] = *config.LivenessTestMaxUpstreamBytes
  1252. }
  1253. if config.LivenessTestMinDownstreamBytes != nil {
  1254. applyParameters[parameters.LivenessTestMinDownstreamBytes] = *config.LivenessTestMinDownstreamBytes
  1255. }
  1256. if config.LivenessTestMaxDownstreamBytes != nil {
  1257. applyParameters[parameters.LivenessTestMaxDownstreamBytes] = *config.LivenessTestMaxDownstreamBytes
  1258. }
  1259. if config.ReplayCandidateCount != nil {
  1260. applyParameters[parameters.ReplayCandidateCount] = *config.ReplayCandidateCount
  1261. }
  1262. if config.ReplayDialParametersTTLSeconds != nil {
  1263. applyParameters[parameters.ReplayDialParametersTTL] = fmt.Sprintf("%ds", *config.ReplayDialParametersTTLSeconds)
  1264. }
  1265. if config.ReplayTargetUpstreamBytes != nil {
  1266. applyParameters[parameters.ReplayTargetUpstreamBytes] = *config.ReplayTargetUpstreamBytes
  1267. }
  1268. if config.ReplayTargetDownstreamBytes != nil {
  1269. applyParameters[parameters.ReplayTargetDownstreamBytes] = *config.ReplayTargetDownstreamBytes
  1270. }
  1271. if config.ReplayTargetTunnelDurationSeconds != nil {
  1272. applyParameters[parameters.ReplayTargetTunnelDuration] = fmt.Sprintf("%ds", *config.ReplayTargetTunnelDurationSeconds)
  1273. }
  1274. if config.ReplayLaterRoundMoveToFrontProbability != nil {
  1275. applyParameters[parameters.ReplayLaterRoundMoveToFrontProbability] = *config.ReplayLaterRoundMoveToFrontProbability
  1276. }
  1277. if config.ReplayRetainFailedProbability != nil {
  1278. applyParameters[parameters.ReplayRetainFailedProbability] = *config.ReplayRetainFailedProbability
  1279. }
  1280. if config.UseOnlyCustomTLSProfiles != nil {
  1281. applyParameters[parameters.UseOnlyCustomTLSProfiles] = *config.UseOnlyCustomTLSProfiles
  1282. }
  1283. if config.CustomTLSProfiles != nil {
  1284. applyParameters[parameters.CustomTLSProfiles] = config.CustomTLSProfiles
  1285. }
  1286. if config.SelectRandomizedTLSProfileProbability != nil {
  1287. applyParameters[parameters.SelectRandomizedTLSProfileProbability] = *config.SelectRandomizedTLSProfileProbability
  1288. }
  1289. if config.NoDefaultTLSSessionIDProbability != nil {
  1290. applyParameters[parameters.NoDefaultTLSSessionIDProbability] = *config.NoDefaultTLSSessionIDProbability
  1291. }
  1292. if config.ApplicationParameters != nil {
  1293. applyParameters[parameters.ApplicationParameters] = config.ApplicationParameters
  1294. }
  1295. return applyParameters
  1296. }
  1297. func (config *Config) setDialParametersHash() {
  1298. // Calculate and store a hash of the config values that may impact
  1299. // dial parameters. This hash is used as part of the dial parameters
  1300. // replay mechanism to detect when persisted dial parameters should
  1301. // be discarded due to conflicting config changes.
  1302. //
  1303. // MD5 hash is used solely as a data checksum and not for any security
  1304. // purpose; serialization is not strictly unambiguous.
  1305. hash := md5.New()
  1306. if len(config.LimitTunnelProtocols) > 0 {
  1307. for _, protocol := range config.LimitTunnelProtocols {
  1308. hash.Write([]byte(protocol))
  1309. }
  1310. }
  1311. if len(config.InitialLimitTunnelProtocols) > 0 && config.InitialLimitTunnelProtocolsCandidateCount > 0 {
  1312. for _, protocol := range config.InitialLimitTunnelProtocols {
  1313. hash.Write([]byte(protocol))
  1314. }
  1315. binary.Write(hash, binary.LittleEndian, int64(config.InitialLimitTunnelProtocolsCandidateCount))
  1316. }
  1317. if len(config.LimitTLSProfiles) > 0 {
  1318. for _, profile := range config.LimitTLSProfiles {
  1319. hash.Write([]byte(profile))
  1320. }
  1321. }
  1322. if len(config.LimitQUICVersions) > 0 {
  1323. for _, version := range config.LimitQUICVersions {
  1324. hash.Write([]byte(version))
  1325. }
  1326. }
  1327. // Whether a custom User-Agent is specified is a binary flag: when not set,
  1328. // the replay dial parameters value applies. When set, external
  1329. // considerations apply.
  1330. if _, ok := config.CustomHeaders["User-Agent"]; ok {
  1331. hash.Write([]byte{1})
  1332. }
  1333. if config.UpstreamProxyURL != "" {
  1334. hash.Write([]byte(config.UpstreamProxyURL))
  1335. }
  1336. if config.TransformHostNameProbability != nil {
  1337. binary.Write(hash, binary.LittleEndian, *config.TransformHostNameProbability)
  1338. }
  1339. if config.FragmentorProbability != nil {
  1340. binary.Write(hash, binary.LittleEndian, *config.FragmentorProbability)
  1341. }
  1342. if len(config.FragmentorLimitProtocols) > 0 {
  1343. for _, protocol := range config.FragmentorLimitProtocols {
  1344. hash.Write([]byte(protocol))
  1345. }
  1346. }
  1347. if config.FragmentorMinTotalBytes != nil {
  1348. binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinTotalBytes))
  1349. }
  1350. if config.FragmentorMaxTotalBytes != nil {
  1351. binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxTotalBytes))
  1352. }
  1353. if config.FragmentorMinWriteBytes != nil {
  1354. binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinWriteBytes))
  1355. }
  1356. if config.FragmentorMaxWriteBytes != nil {
  1357. binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxWriteBytes))
  1358. }
  1359. if config.FragmentorMinDelayMicroseconds != nil {
  1360. binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinDelayMicroseconds))
  1361. }
  1362. if config.FragmentorMaxDelayMicroseconds != nil {
  1363. binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxDelayMicroseconds))
  1364. }
  1365. if config.MeekTrafficShapingProbability != nil {
  1366. binary.Write(hash, binary.LittleEndian, int64(*config.MeekTrafficShapingProbability))
  1367. }
  1368. if len(config.MeekTrafficShapingLimitProtocols) > 0 {
  1369. for _, protocol := range config.MeekTrafficShapingLimitProtocols {
  1370. hash.Write([]byte(protocol))
  1371. }
  1372. }
  1373. if config.MeekMinLimitRequestPayloadLength != nil {
  1374. binary.Write(hash, binary.LittleEndian, int64(*config.MeekMinLimitRequestPayloadLength))
  1375. }
  1376. if config.MeekMaxLimitRequestPayloadLength != nil {
  1377. binary.Write(hash, binary.LittleEndian, int64(*config.MeekMaxLimitRequestPayloadLength))
  1378. }
  1379. if config.MeekRedialTLSProbability != nil {
  1380. binary.Write(hash, binary.LittleEndian, *config.MeekRedialTLSProbability)
  1381. }
  1382. if config.ObfuscatedSSHMinPadding != nil {
  1383. binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMinPadding))
  1384. }
  1385. if config.ObfuscatedSSHMaxPadding != nil {
  1386. binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMaxPadding))
  1387. }
  1388. if config.LivenessTestMinUpstreamBytes != nil {
  1389. binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinUpstreamBytes))
  1390. }
  1391. if config.LivenessTestMaxUpstreamBytes != nil {
  1392. binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxUpstreamBytes))
  1393. }
  1394. if config.LivenessTestMinDownstreamBytes != nil {
  1395. binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinDownstreamBytes))
  1396. }
  1397. if config.LivenessTestMaxDownstreamBytes != nil {
  1398. binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxDownstreamBytes))
  1399. }
  1400. binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMin)
  1401. binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMax)
  1402. binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierLambda)
  1403. if config.UseOnlyCustomTLSProfiles != nil {
  1404. binary.Write(hash, binary.LittleEndian, *config.UseOnlyCustomTLSProfiles)
  1405. }
  1406. for _, customTLSProfile := range config.CustomTLSProfiles {
  1407. // Assumes consistent definition for a given profile name
  1408. hash.Write([]byte(customTLSProfile.Name))
  1409. }
  1410. if config.SelectRandomizedTLSProfileProbability != nil {
  1411. binary.Write(hash, binary.LittleEndian, *config.SelectRandomizedTLSProfileProbability)
  1412. }
  1413. if config.NoDefaultTLSSessionIDProbability != nil {
  1414. binary.Write(hash, binary.LittleEndian, *config.NoDefaultTLSSessionIDProbability)
  1415. }
  1416. config.dialParametersHash = hash.Sum(nil)
  1417. }
  1418. func promoteLegacyDownloadURL(URL string) parameters.DownloadURLs {
  1419. downloadURLs := make(parameters.DownloadURLs, 1)
  1420. downloadURLs[0] = &parameters.DownloadURL{
  1421. URL: base64.StdEncoding.EncodeToString([]byte(URL)),
  1422. SkipVerify: false,
  1423. OnlyAfterAttempts: 0,
  1424. }
  1425. return downloadURLs
  1426. }
  1427. type loggingDeviceBinder struct {
  1428. d DeviceBinder
  1429. }
  1430. func newLoggingDeviceBinder(d DeviceBinder) *loggingDeviceBinder {
  1431. return &loggingDeviceBinder{d: d}
  1432. }
  1433. func (d *loggingDeviceBinder) BindToDevice(fileDescriptor int) (string, error) {
  1434. deviceInfo, err := d.d.BindToDevice(fileDescriptor)
  1435. if err == nil && deviceInfo != "" {
  1436. NoticeBindToDevice(deviceInfo)
  1437. }
  1438. return deviceInfo, err
  1439. }
  1440. type staticNetworkGetter struct {
  1441. networkID string
  1442. }
  1443. func newStaticNetworkGetter(networkID string) *staticNetworkGetter {
  1444. return &staticNetworkGetter{networkID: networkID}
  1445. }
  1446. func (n *staticNetworkGetter) GetNetworkID() string {
  1447. return n.networkID
  1448. }
  1449. type loggingNetworkIDGetter struct {
  1450. n NetworkIDGetter
  1451. }
  1452. func newLoggingNetworkIDGetter(n NetworkIDGetter) *loggingNetworkIDGetter {
  1453. return &loggingNetworkIDGetter{n: n}
  1454. }
  1455. func (n *loggingNetworkIDGetter) GetNetworkID() string {
  1456. networkID := n.n.GetNetworkID()
  1457. // All PII must appear after the initial "-"
  1458. // See: https://godoc.org/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon#NetworkIDGetter
  1459. logNetworkID := networkID
  1460. index := strings.Index(logNetworkID, "-")
  1461. if index != -1 {
  1462. logNetworkID = logNetworkID[:index]
  1463. }
  1464. if len(logNetworkID)+1 < len(networkID) {
  1465. // Indicate when additional network info was present after the first "-".
  1466. logNetworkID += "+[redacted]"
  1467. }
  1468. NoticeNetworkID(logNetworkID)
  1469. return networkID
  1470. }
  1471. // migrationsFromLegacyNoticeFilePaths returns the file migrations which must be
  1472. // performed to move notice files from legacy file paths, which were configured
  1473. // with the legacy config fields HomepageNoticesFilename and
  1474. // RotatingNoticesFilename, to the new file paths used by Psiphon which exist
  1475. // under the data root directory.
  1476. func migrationsFromLegacyNoticeFilePaths(config *Config) []common.FileMigration {
  1477. var noticeMigrations []common.FileMigration
  1478. if config.MigrateHompageNoticesFilename != "" {
  1479. noticeMigrations = append(noticeMigrations, common.FileMigration{
  1480. OldPath: config.MigrateHompageNoticesFilename,
  1481. NewPath: config.GetHomePageFilename(),
  1482. })
  1483. }
  1484. if config.MigrateRotatingNoticesFilename != "" {
  1485. migrations := []common.FileMigration{
  1486. {
  1487. OldPath: config.MigrateRotatingNoticesFilename,
  1488. NewPath: config.GetNoticesFilename(),
  1489. IsDir: false,
  1490. },
  1491. {
  1492. OldPath: config.MigrateRotatingNoticesFilename + ".1",
  1493. NewPath: config.GetNoticesFilename() + ".1",
  1494. },
  1495. }
  1496. noticeMigrations = append(noticeMigrations, migrations...)
  1497. }
  1498. return noticeMigrations
  1499. }
  1500. // migrationsFromLegacyFilePaths returns the file migrations which must be
  1501. // performed to move files from legacy file paths, which were configured with
  1502. // legacy config fields, to the new file paths used by Psiphon which exist
  1503. // under the data root directory.
  1504. func migrationsFromLegacyFilePaths(config *Config) ([]common.FileMigration, error) {
  1505. migrations := []common.FileMigration{
  1506. {
  1507. OldPath: filepath.Join(config.MigrateDataStoreDirectory, "psiphon.boltdb"),
  1508. NewPath: filepath.Join(config.GetDataStoreDirectory(), "psiphon.boltdb"),
  1509. },
  1510. {
  1511. OldPath: filepath.Join(config.MigrateDataStoreDirectory, "psiphon.boltdb.lock"),
  1512. NewPath: filepath.Join(config.GetDataStoreDirectory(), "psiphon.boltdb.lock"),
  1513. },
  1514. {
  1515. OldPath: filepath.Join(config.MigrateDataStoreDirectory, "tapdance"),
  1516. NewPath: filepath.Join(config.GetTapdanceDirectory(), "tapdance"),
  1517. IsDir: true,
  1518. },
  1519. }
  1520. if config.MigrateRemoteServerListDownloadFilename != "" {
  1521. // Migrate remote server list files
  1522. rslMigrations := []common.FileMigration{
  1523. {
  1524. OldPath: config.MigrateRemoteServerListDownloadFilename,
  1525. NewPath: config.GetRemoteServerListDownloadFilename(),
  1526. },
  1527. {
  1528. OldPath: config.MigrateRemoteServerListDownloadFilename + ".part",
  1529. NewPath: config.GetRemoteServerListDownloadFilename() + ".part",
  1530. },
  1531. {
  1532. OldPath: config.MigrateRemoteServerListDownloadFilename + ".part.etag",
  1533. NewPath: config.GetRemoteServerListDownloadFilename() + ".part.etag",
  1534. },
  1535. }
  1536. migrations = append(migrations, rslMigrations...)
  1537. }
  1538. if config.MigrateObfuscatedServerListDownloadDirectory != "" {
  1539. // Migrate OSL registry file and downloads
  1540. oslFileRegex, err := regexp.Compile(`^osl-.+$`)
  1541. if err != nil {
  1542. return nil, errors.TraceMsg(err, "failed to compile regex for osl files")
  1543. }
  1544. files, err := ioutil.ReadDir(config.MigrateObfuscatedServerListDownloadDirectory)
  1545. if err != nil {
  1546. NoticeAlert("Migration: failed to read directory %s with error %s", config.MigrateObfuscatedServerListDownloadDirectory, err)
  1547. } else {
  1548. for _, file := range files {
  1549. if oslFileRegex.MatchString(file.Name()) {
  1550. fileMigration := common.FileMigration{
  1551. OldPath: filepath.Join(config.MigrateObfuscatedServerListDownloadDirectory, file.Name()),
  1552. NewPath: filepath.Join(config.GetObfuscatedServerListDownloadDirectory(), file.Name()),
  1553. }
  1554. migrations = append(migrations, fileMigration)
  1555. }
  1556. }
  1557. }
  1558. }
  1559. if config.MigrateUpgradeDownloadFilename != "" {
  1560. // Migrate downloaded upgrade files
  1561. oldUpgradeDownloadFilename := filepath.Base(config.MigrateUpgradeDownloadFilename)
  1562. // Create regex for:
  1563. // <old_upgrade_download_filename>
  1564. // <old_upgrade_download_filename>.<client_version_number>
  1565. // <old_upgrade_download_filename>.<client_version_number>.part
  1566. // <old_upgrade_download_filename>.<client_version_number>.part.etag
  1567. upgradeDownloadFileRegex, err := regexp.Compile(`^` + oldUpgradeDownloadFilename + `(\.\d+(\.part(\.etag)?)?)?$`)
  1568. if err != nil {
  1569. return nil, errors.TraceMsg(err, "failed to compile regex for upgrade files")
  1570. }
  1571. upgradeDownloadDir := filepath.Dir(config.MigrateUpgradeDownloadFilename)
  1572. files, err := ioutil.ReadDir(upgradeDownloadDir)
  1573. if err != nil {
  1574. NoticeAlert("Migration: failed to read directory %s with error %s", upgradeDownloadDir, err)
  1575. } else {
  1576. for _, file := range files {
  1577. if upgradeDownloadFileRegex.MatchString(file.Name()) {
  1578. oldFileSuffix := strings.TrimPrefix(file.Name(), oldUpgradeDownloadFilename)
  1579. fileMigration := common.FileMigration{
  1580. OldPath: filepath.Join(upgradeDownloadDir, file.Name()),
  1581. NewPath: config.GetUpgradeDownloadFilename() + oldFileSuffix,
  1582. }
  1583. migrations = append(migrations, fileMigration)
  1584. }
  1585. }
  1586. }
  1587. }
  1588. return migrations, nil
  1589. }