config.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  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. "encoding/base64"
  22. "encoding/json"
  23. "errors"
  24. "fmt"
  25. "net/http"
  26. "os"
  27. "strconv"
  28. "strings"
  29. "unicode"
  30. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  31. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
  32. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  33. )
  34. const (
  35. TUNNEL_POOL_SIZE = 1
  36. )
  37. // Config is the Psiphon configuration specified by the application. This
  38. // configuration controls the behavior of the core tunnel functionality.
  39. //
  40. // To distinguish omitted timeout params from explicit 0 value timeout params,
  41. // corresponding fieldss are int pointers. nil means no value was supplied and
  42. // to use the default; a non-nil pointer to 0 means no timeout.
  43. type Config struct {
  44. // DataStoreDirectory is the directory in which to store the persistent
  45. // database, which contains information such as server entries. By
  46. // default, current working directory.
  47. //
  48. // Warning: If the datastore file, DataStoreDirectory/DATA_STORE_FILENAME,
  49. // exists but fails to open for any reason (checksum error, unexpected
  50. // file format, etc.) it will be deleted in order to pave a new datastore
  51. // and continue running.
  52. DataStoreDirectory string
  53. // PropagationChannelId is a string identifier which indicates how the
  54. // Psiphon client was distributed. This parameter is required. This value
  55. // is supplied by and depends on the Psiphon Network, and is typically
  56. // embedded in the client binary.
  57. PropagationChannelId string
  58. // SponsorId is a string identifier which indicates who is sponsoring this
  59. // Psiphon client. One purpose of this value is to determine the home
  60. // pages for display. This parameter is required. This value is supplied
  61. // by and depends on the Psiphon Network, and is typically embedded in the
  62. // client binary.
  63. SponsorId string
  64. // ClientVersion is the client version number that the client reports to
  65. // the server. The version number refers to the host client application,
  66. // not the core tunnel library. One purpose of this value is to enable
  67. // automatic updates. This value is supplied by and depends on the Psiphon
  68. // Network, and is typically embedded in the client binary.
  69. //
  70. // Note that sending a ClientPlatform string which includes "windows"
  71. // (case insensitive) and a ClientVersion of <= 44 will cause an error in
  72. // processing the response to DoConnectedRequest calls.
  73. ClientVersion string
  74. // ClientPlatform is the client platform ("Windows", "Android", etc.) that
  75. // the client reports to the server.
  76. ClientPlatform string
  77. // TunnelWholeDevice is a flag that is passed through to the handshake
  78. // request for stats purposes. Set to 1 when the host application is
  79. // tunneling the whole device, 0 otherwise.
  80. TunnelWholeDevice int
  81. // EgressRegion is a ISO 3166-1 alpha-2 country code which indicates which
  82. // country to egress from. For the default, "", the best performing server
  83. // in any country is selected.
  84. EgressRegion string
  85. // ListenInterface specifies which interface to listen on. If no
  86. // interface is provided then listen on 127.0.0.1. If 'any' is provided
  87. // then use 0.0.0.0. If there are multiple IP addresses on an interface
  88. // use the first IPv4 address.
  89. ListenInterface string
  90. // DisableLocalSocksProxy disables running the local SOCKS proxy.
  91. DisableLocalSocksProxy bool
  92. // LocalSocksProxyPort specifies a port number for the local SOCKS proxy
  93. // running at 127.0.0.1. For the default value, 0, the system selects a
  94. // free port (a notice reporting the selected port is emitted).
  95. LocalSocksProxyPort int
  96. // LocalHttpProxyPort specifies a port number for the local HTTP proxy
  97. // running at 127.0.0.1. For the default value, 0, the system selects a
  98. // free port (a notice reporting the selected port is emitted).
  99. LocalHttpProxyPort int
  100. // DisableLocalHTTPProxy disables running the local HTTP proxy.
  101. DisableLocalHTTPProxy bool
  102. // NetworkLatencyMultiplier is a multiplier that is to be applied to
  103. // default network event timeouts. Set this to tune performance for
  104. // slow networks.
  105. // When set, must be >= 1.0.
  106. NetworkLatencyMultiplier float64
  107. // TunnelProtocol indicates which protocol to use. For the default, "",
  108. // all protocols are used.
  109. //
  110. // Deprecated: Use TunnelProtocols. When TunnelProtocols is not nil, this
  111. // parameter is ignored.
  112. TunnelProtocol string
  113. // TunnelProtocols indicates which protocols to use. Valid values include:
  114. // "SSH", "OSSH", "UNFRONTED-MEEK-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
  115. // "UNFRONTED-MEEK-SESSION-TICKET-OSSH", "FRONTED-MEEK-OSSH", "FRONTED-
  116. // MEEK-HTTP-OSSH".
  117. //
  118. // For the default, an empty list, all protocols are used.
  119. TunnelProtocols []string
  120. // EstablishTunnelTimeoutSeconds specifies a time limit after which to
  121. // halt the core tunnel controller if no tunnel has been established. The
  122. // default is parameters.EstablishTunnelTimeoutSeconds.
  123. EstablishTunnelTimeoutSeconds *int
  124. // EstablishTunnelPausePeriodSeconds specifies the delay between attempts
  125. // to establish tunnels. Briefly pausing allows for network conditions to
  126. // improve and for asynchronous operations such as fetch remote server
  127. // list to complete. If omitted, a default value is used. This value is
  128. // typical overridden for testing.
  129. EstablishTunnelPausePeriodSeconds *int
  130. // ConnectionWorkerPoolSize specifies how many connection attempts to
  131. // attempt in parallel. If omitted of when 0, a default is used; this is
  132. // recommended.
  133. ConnectionWorkerPoolSize int
  134. // TunnelPoolSize specifies how many tunnels to run in parallel. Port
  135. // forwards are multiplexed over multiple tunnels. If omitted or when 0,
  136. // the default is TUNNEL_POOL_SIZE, which is recommended.
  137. TunnelPoolSize int
  138. // StaggerConnectionWorkersMilliseconds adds a specified delay before
  139. // making each server candidate available to connection workers. This
  140. // option is enabled when StaggerConnectionWorkersMilliseconds > 0.
  141. StaggerConnectionWorkersMilliseconds int
  142. // LimitMeekConnectionWorkers limits the number of concurrent connection
  143. // workers attempting connections with meek protocols. This option is
  144. // enabled when LimitMeekConnectionWorkers > 0.
  145. LimitMeekConnectionWorkers int
  146. // LimitMeekBufferSizes selects smaller buffers for meek protocols.
  147. LimitMeekBufferSizes bool
  148. // IgnoreHandshakeStatsRegexps skips compiling and using stats regexes.
  149. IgnoreHandshakeStatsRegexps bool
  150. // UpstreamProxyURL is a URL specifying an upstream proxy to use for all
  151. // outbound connections. The URL should include proxy type and
  152. // authentication information, as required. See example URLs here:
  153. // https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/psiphon/upstreamproxy
  154. UpstreamProxyURL string
  155. // CustomHeaders is a set of additional arbitrary HTTP headers that are
  156. // added to all plaintext HTTP requests and requests made through an HTTP
  157. // upstream proxy when specified by UpstreamProxyURL.
  158. CustomHeaders http.Header
  159. // Deprecated: Use CustomHeaders. When CustomHeaders is not nil, this
  160. // parameter is ignored.
  161. UpstreamProxyCustomHeaders http.Header
  162. // NetworkConnectivityChecker is an interface that enables tunnel-core to
  163. // call into the host application to check for network connectivity. See:
  164. // NetworkConnectivityChecker doc.
  165. //
  166. // This parameter is only applicable to library deployments.
  167. NetworkConnectivityChecker NetworkConnectivityChecker
  168. // DeviceBinder is an interface that enables tunnel-core to call into the
  169. // host application to bind sockets to specific devices. See: DeviceBinder
  170. // doc.
  171. //
  172. // This parameter is only applicable to library deployments.
  173. DeviceBinder DeviceBinder
  174. // IPv6Synthesizer is an interface that allows tunnel-core to call into
  175. // the host application to synthesize IPv6 addresses. See: IPv6Synthesizer
  176. // doc.
  177. //
  178. // This parameter is only applicable to library deployments.
  179. IPv6Synthesizer IPv6Synthesizer
  180. // DnsServerGetter is an interface that enables tunnel-core to call into
  181. // the host application to discover the native network DNS server
  182. // settings. See: DnsServerGetter doc.
  183. //
  184. // This parameter is only applicable to library deployments.
  185. DnsServerGetter DnsServerGetter
  186. // NetworkIDGetter in an interface that enables tunnel-core to call into
  187. // the host application to get an identifier for the host's current active
  188. // network. See: NetworkIDGetter doc.
  189. //
  190. // This parameter is only applicable to library deployments.
  191. NetworkIDGetter NetworkIDGetter
  192. // DisableTactics disables tactics operations including requests, payload
  193. // handling, and application of parameters.
  194. DisableTactics bool
  195. // TransformHostNames specifies whether to use hostname transformation
  196. // circumvention strategies. Set to "always" to always transform, "never"
  197. // to never transform, and "", the default, for the default transformation
  198. // strategy.
  199. TransformHostNames string
  200. // TargetServerEntry is an encoded server entry. When specified, this
  201. // server entry is used exclusively and all other known servers are
  202. // ignored.
  203. TargetServerEntry string
  204. // DisableApi disables Psiphon server API calls including handshake,
  205. // connected, status, etc. This is used for special case temporary tunnels
  206. // (Windows VPN mode).
  207. DisableApi bool
  208. // TargetApiProtocol specifies whether to force use of "ssh" or "web" API
  209. // protocol. When blank, the default, the optimal API protocol is used.
  210. // Note that this capability check is not applied before the
  211. // "CandidateServers" count is emitted. This parameter is intended for
  212. // testing and debugging only.
  213. TargetApiProtocol string
  214. // RemoteServerListUrl is a URL which specifies a location to fetch out-
  215. // of-band server entries. This facility is used when a tunnel cannot be
  216. // established to known servers. This value is supplied by and depends on
  217. // the Psiphon Network, and is typically embedded in the client binary.
  218. //
  219. // Deprecated: Use RemoteServerListURLs. When RemoteServerListURLs is not
  220. // nil, this parameter is ignored.
  221. RemoteServerListUrl string
  222. // RemoteServerListURLs is list of URLs which specify locations to fetch
  223. // out-of-band server entries. This facility is used when a tunnel cannot
  224. // be established to known servers. This value is supplied by and depends
  225. // on the Psiphon Network, and is typically embedded in the client binary.
  226. // All URLs must point to the same entity with the same ETag. At least one
  227. // DownloadURL must have OnlyAfterAttempts = 0.
  228. RemoteServerListURLs parameters.DownloadURLs
  229. // RemoteServerListDownloadFilename specifies a target filename for
  230. // storing the remote server list download. Data is stored in co-located
  231. // files (RemoteServerListDownloadFilename.part*) to allow for resumable
  232. // downloading.
  233. RemoteServerListDownloadFilename string
  234. // RemoteServerListSignaturePublicKey specifies a public key that's used
  235. // to authenticate the remote server list payload. This value is supplied
  236. // by and depends on the Psiphon Network, and is typically embedded in the
  237. // client binary.
  238. RemoteServerListSignaturePublicKey string
  239. // DisableRemoteServerListFetcher disables fetching remote server lists.
  240. // This is used for special case temporary tunnels.
  241. DisableRemoteServerListFetcher bool
  242. // FetchRemoteServerListRetryPeriodMilliseconds specifies the delay before
  243. // resuming a remote server list download after a failure. If omitted, a
  244. // default value is used. This value is typical overridden for testing.
  245. FetchRemoteServerListRetryPeriodMilliseconds *int
  246. // ObfuscatedServerListRootURL is a URL which specifies the root location
  247. // from which to fetch obfuscated server list files. This value is
  248. // supplied by and depends on the Psiphon Network, and is typically
  249. // embedded in the client binary.
  250. //
  251. // Deprecated: Use ObfuscatedServerListRootURLs. When
  252. // ObfuscatedServerListRootURLs is not nil, this parameter is ignored.
  253. ObfuscatedServerListRootURL string
  254. // ObfuscatedServerListRootURLs is a list of URLs which specify root
  255. // locations from which to fetch obfuscated server list files. This value
  256. // is supplied by and depends on the Psiphon Network, and is typically
  257. // embedded in the client binary. All URLs must point to the same entity
  258. // with the same ETag. At least one DownloadURL must have
  259. // OnlyAfterAttempts = 0.
  260. ObfuscatedServerListRootURLs parameters.DownloadURLs
  261. // ObfuscatedServerListDownloadDirectory specifies a target directory for
  262. // storing the obfuscated remote server list downloads. Data is stored in
  263. // co-located files (<OSL filename>.part*) to allow for resumable
  264. // downloading.
  265. ObfuscatedServerListDownloadDirectory string
  266. // SplitTunnelRoutesURLFormat is a URL which specifies the location of a
  267. // routes file to use for split tunnel mode. The URL must include a
  268. // placeholder for the client region to be supplied. Split tunnel mode
  269. // uses the routes file to classify port forward destinations as foreign
  270. // or domestic and does not tunnel domestic destinations. Split tunnel
  271. // mode is on when all the SplitTunnel parameters are supplied. This value
  272. // is supplied by and depends on the Psiphon Network, and is typically
  273. // embedded in the client binary.
  274. SplitTunnelRoutesURLFormat string
  275. // SplitTunnelRoutesSignaturePublicKey specifies a public key that's used
  276. // to authenticate the split tunnel routes payload. This value is supplied
  277. // by and depends on the Psiphon Network, and is typically embedded in the
  278. // client binary.
  279. SplitTunnelRoutesSignaturePublicKey string
  280. // SplitTunnelDNSServer specifies a DNS server to use when resolving port
  281. // forward target domain names to IP addresses for classification. The DNS
  282. // server must support TCP requests.
  283. SplitTunnelDNSServer string
  284. // UpgradeDownloadUrl specifies a URL from which to download a host client
  285. // upgrade file, when one is available. The core tunnel controller
  286. // provides a resumable download facility which downloads this resource
  287. // and emits a notice when complete. This value is supplied by and depends
  288. // on the Psiphon Network, and is typically embedded in the client binary.
  289. //
  290. // Deprecated: Use UpgradeDownloadURLs. When UpgradeDownloadURLs is not
  291. // nil, this parameter is ignored.
  292. UpgradeDownloadUrl string
  293. // UpgradeDownloadURLs is list of URLs which specify locations from which
  294. // to download a host client upgrade file, when one is available. The core
  295. // tunnel controller provides a resumable download facility which
  296. // downloads this resource and emits a notice when complete. This value is
  297. // supplied by and depends on the Psiphon Network, and is typically
  298. // embedded in the client binary. All URLs must point to the same entity
  299. // with the same ETag. At least one DownloadURL must have
  300. // OnlyAfterAttempts = 0.
  301. UpgradeDownloadURLs parameters.DownloadURLs
  302. // UpgradeDownloadClientVersionHeader specifies the HTTP header name for
  303. // the entity at UpgradeDownloadURLs which specifies the client version
  304. // (an integer value). A HEAD request may be made to check the version
  305. // number available at UpgradeDownloadURLs.
  306. // UpgradeDownloadClientVersionHeader is required when UpgradeDownloadURLs
  307. // is specified.
  308. UpgradeDownloadClientVersionHeader string
  309. // UpgradeDownloadFilename is the local target filename for an upgrade
  310. // download. This parameter is required when UpgradeDownloadURLs (or
  311. // UpgradeDownloadUrl) is specified. Data is stored in co-located files
  312. // (UpgradeDownloadFilename.part*) to allow for resumable downloading.
  313. UpgradeDownloadFilename string
  314. // FetchUpgradeRetryPeriodMilliseconds specifies the delay before resuming
  315. // a client upgrade download after a failure. If omitted, a default value
  316. // is used. This value is typical overridden for testing.
  317. FetchUpgradeRetryPeriodMilliseconds *int
  318. // EmitBytesTransferred indicates whether to emit periodic notices showing
  319. // bytes sent and received.
  320. EmitBytesTransferred bool
  321. // UseIndistinguishableTLS enables use of alternative TLS profiles with a
  322. // less distinct fingerprint (ClientHello content) than the stock Go TLS.
  323. UseIndistinguishableTLS bool
  324. // UseTrustedCACertificatesForStockTLS toggles use of the trusted CA
  325. // certs, specified in TrustedCACertificatesFilename, for tunneled TLS
  326. // connections that expect server certificates signed with public
  327. // certificate authorities (currently, only upgrade downloads). This
  328. // option is used with stock Go TLS in cases where Go may fail to obtain a
  329. // list of root CAs from the operating system. Requires
  330. // TrustedCACertificatesFilename to be set.
  331. UseTrustedCACertificatesForStockTLS bool
  332. // TrustedCACertificatesFilename specifies a file containing trusted CA
  333. // certs.
  334. TrustedCACertificatesFilename string
  335. // DisablePeriodicSshKeepAlive indicates whether to send an SSH keepalive
  336. // every 1-2 minutes, when the tunnel is idle. If the SSH keepalive times
  337. // out, the tunnel is considered to have failed.
  338. DisablePeriodicSshKeepAlive bool
  339. // DeviceRegion is the optional, reported region the host device is
  340. // running in. This input value should be a ISO 3166-1 alpha-2 country
  341. // code. The device region is reported to the server in the connected
  342. // request and recorded for Psiphon stats.
  343. //
  344. // When provided, this value may be used, pre-connection, to select
  345. // performance or circumvention optimization strategies for the given
  346. // region.
  347. DeviceRegion string
  348. // EmitDiagnosticNotices indicates whether to output notices containing
  349. // detailed information about the Psiphon session. As these notices may
  350. // contain sensitive network information, they should not be insecurely
  351. // distributed or displayed to users. Default is off.
  352. EmitDiagnosticNotices bool
  353. // RateLimits specify throttling configuration for the tunnel.
  354. RateLimits common.RateLimits
  355. // EmitSLOKs indicates whether to emit notices for each seeded SLOK. As
  356. // this could reveal user browsing activity, it's intended for debugging
  357. // and testing only.
  358. EmitSLOKs bool
  359. // PacketTunnelTunDeviceFileDescriptor specifies a tun device file
  360. // descriptor to use for running a packet tunnel. When this value is > 0,
  361. // a packet tunnel is established through the server and packets are
  362. // relayed via the tun device file descriptor. The file descriptor is
  363. // duped in NewController. When PacketTunnelTunDeviceFileDescriptor is
  364. // set, TunnelPoolSize must be 1.
  365. PacketTunnelTunFileDescriptor int
  366. // SessionID specifies a client session ID to use in the Psiphon API. The
  367. // session ID should be a randomly generated value that is used only for a
  368. // single session, which is defined as the period between a user starting
  369. // a Psiphon client and stopping the client.
  370. //
  371. // A session ID must be 32 hex digits (lower case). When blank, a random
  372. // session ID is automatically generated. Supply a session ID when a
  373. // single client session will cross multiple Controller instances.
  374. SessionID string
  375. // Authorizations is a list of encoded, signed access control
  376. // authorizations that the client has obtained and will present to the
  377. // server.
  378. Authorizations []string
  379. // clientParameters is the active ClientParameters with defaults, config
  380. // values, and, optionally, tactics applied.
  381. //
  382. // New tactics must be applied by calling Config.SetClientParameters;
  383. // calling clientParameters.Set directly will fail to add config values.
  384. clientParameters *parameters.ClientParameters
  385. }
  386. // LoadConfig parses and validates a JSON format Psiphon config JSON
  387. // string and returns a Config struct populated with config values.
  388. func LoadConfig(configJson []byte) (*Config, error) {
  389. var config Config
  390. err := json.Unmarshal(configJson, &config)
  391. if err != nil {
  392. return nil, common.ContextError(err)
  393. }
  394. // Do SetEmitDiagnosticNotices first, to ensure config file errors are emitted.
  395. if config.EmitDiagnosticNotices {
  396. SetEmitDiagnosticNotices(true)
  397. }
  398. // Promote legacy fields.
  399. if config.CustomHeaders == nil {
  400. config.CustomHeaders = config.UpstreamProxyCustomHeaders
  401. config.UpstreamProxyCustomHeaders = nil
  402. }
  403. if config.RemoteServerListUrl != "" && config.RemoteServerListURLs == nil {
  404. config.RemoteServerListURLs = promoteLegacyDownloadURL(config.RemoteServerListUrl)
  405. }
  406. if config.ObfuscatedServerListRootURL != "" && config.ObfuscatedServerListRootURLs == nil {
  407. config.ObfuscatedServerListRootURLs = promoteLegacyDownloadURL(config.ObfuscatedServerListRootURL)
  408. }
  409. if config.UpgradeDownloadUrl != "" && config.UpgradeDownloadURLs == nil {
  410. config.UpgradeDownloadURLs = promoteLegacyDownloadURL(config.UpgradeDownloadUrl)
  411. }
  412. // Supply default values.
  413. if config.DataStoreDirectory == "" {
  414. config.DataStoreDirectory, err = os.Getwd()
  415. if err != nil {
  416. return nil, common.ContextError(err)
  417. }
  418. }
  419. if config.ClientVersion == "" {
  420. config.ClientVersion = "0"
  421. }
  422. if config.TunnelPoolSize == 0 {
  423. config.TunnelPoolSize = TUNNEL_POOL_SIZE
  424. }
  425. // Validate config fields.
  426. if config.PropagationChannelId == "" {
  427. return nil, common.ContextError(
  428. errors.New("propagation channel ID is missing from the configuration file"))
  429. }
  430. if config.SponsorId == "" {
  431. return nil, common.ContextError(
  432. errors.New("sponsor ID is missing from the configuration file"))
  433. }
  434. _, err = strconv.Atoi(config.ClientVersion)
  435. if err != nil {
  436. return nil, common.ContextError(
  437. fmt.Errorf("invalid client version: %s", err))
  438. }
  439. if config.NetworkConnectivityChecker != nil {
  440. return nil, common.ContextError(
  441. errors.New("NetworkConnectivityChecker interface must be set at runtime"))
  442. }
  443. if config.DeviceBinder != nil {
  444. return nil, common.ContextError(
  445. errors.New("DeviceBinder interface must be set at runtime"))
  446. }
  447. if config.DnsServerGetter != nil {
  448. return nil, common.ContextError(
  449. errors.New("DnsServerGetter interface must be set at runtime"))
  450. }
  451. if !common.Contains(
  452. []string{"", protocol.PSIPHON_SSH_API_PROTOCOL, protocol.PSIPHON_WEB_API_PROTOCOL},
  453. config.TargetApiProtocol) {
  454. return nil, common.ContextError(
  455. errors.New("invalid TargetApiProtocol"))
  456. }
  457. if !config.DisableRemoteServerListFetcher {
  458. if config.RemoteServerListURLs != nil {
  459. if config.RemoteServerListSignaturePublicKey == "" {
  460. return nil, common.ContextError(errors.New("missing RemoteServerListSignaturePublicKey"))
  461. }
  462. if config.RemoteServerListDownloadFilename == "" {
  463. return nil, common.ContextError(errors.New("missing RemoteServerListDownloadFilename"))
  464. }
  465. }
  466. if config.ObfuscatedServerListRootURLs != nil {
  467. if config.RemoteServerListSignaturePublicKey == "" {
  468. return nil, common.ContextError(errors.New("missing RemoteServerListSignaturePublicKey"))
  469. }
  470. if config.ObfuscatedServerListDownloadDirectory == "" {
  471. return nil, common.ContextError(errors.New("missing ObfuscatedServerListDownloadDirectory"))
  472. }
  473. }
  474. }
  475. if config.SplitTunnelRoutesURLFormat != "" {
  476. if config.SplitTunnelRoutesSignaturePublicKey == "" {
  477. return nil, common.ContextError(errors.New("missing SplitTunnelRoutesSignaturePublicKey"))
  478. }
  479. if config.SplitTunnelDNSServer == "" {
  480. return nil, common.ContextError(errors.New("missing SplitTunnelDNSServer"))
  481. }
  482. }
  483. if config.UpgradeDownloadURLs != nil {
  484. if config.UpgradeDownloadClientVersionHeader == "" {
  485. return nil, common.ContextError(errors.New("missing UpgradeDownloadClientVersionHeader"))
  486. }
  487. if config.UpgradeDownloadFilename == "" {
  488. return nil, common.ContextError(errors.New("missing UpgradeDownloadFilename"))
  489. }
  490. }
  491. // This constraint is expected by logic in Controller.runTunnels().
  492. if config.PacketTunnelTunFileDescriptor > 0 && config.TunnelPoolSize != 1 {
  493. return nil, common.ContextError(errors.New("packet tunnel mode requires TunnelPoolSize to be 1"))
  494. }
  495. // SessionID must be PSIPHON_API_CLIENT_SESSION_ID_LENGTH lowercase hex-encoded bytes.
  496. if config.SessionID == "" {
  497. sessionID, err := MakeSessionId()
  498. if err != nil {
  499. return nil, common.ContextError(err)
  500. }
  501. config.SessionID = sessionID
  502. }
  503. if len(config.SessionID) != 2*protocol.PSIPHON_API_CLIENT_SESSION_ID_LENGTH ||
  504. -1 != strings.IndexFunc(config.SessionID, func(c rune) bool {
  505. return !unicode.Is(unicode.ASCII_Hex_Digit, c) || unicode.IsUpper(c)
  506. }) {
  507. return nil, common.ContextError(errors.New("invalid SessionID"))
  508. }
  509. config.clientParameters, err = parameters.NewClientParameters(
  510. func(err error) {
  511. NoticeAlert("ClientParameters getValue failed: %s", err)
  512. })
  513. if err != nil {
  514. return nil, common.ContextError(err)
  515. }
  516. // clientParameters.Set will validate the config fields applied to parameters.
  517. err = config.SetClientParameters("", false, nil)
  518. if err != nil {
  519. return nil, common.ContextError(err)
  520. }
  521. return &config, nil
  522. }
  523. // GetClientParameters returns a snapshot of the current client parameters.
  524. func (config *Config) GetClientParameters() *parameters.ClientParametersSnapshot {
  525. return config.clientParameters.Get()
  526. }
  527. // SetClientParameters resets Config.clientParameters to the default values,
  528. // applies any config file values, and then applies the input parameters (from
  529. // tactics, etc.)
  530. //
  531. // Set skipOnError to false when initially applying only config values, as
  532. // this will validate the values and should fail. Set skipOnError to true when
  533. // applying tactics to ignore invalid or unknown parameter values from tactics.
  534. //
  535. // In the case of applying tactics, do not call Config.clientParameters.Set
  536. // directly as this will not first apply config values.
  537. //
  538. // If there is an error, the existing Config.clientParameters are left
  539. // entirely unmodified.
  540. func (config *Config) SetClientParameters(tag string, skipOnError bool, applyParameters map[string]interface{}) error {
  541. setParameters := []map[string]interface{}{config.makeConfigParameters()}
  542. if applyParameters != nil {
  543. setParameters = append(setParameters, applyParameters)
  544. }
  545. counts, err := config.clientParameters.Set(tag, skipOnError, setParameters...)
  546. if err != nil {
  547. return common.ContextError(err)
  548. }
  549. NoticeInfo("applied %v parameters with tag '%s'", counts, tag)
  550. // Emit certain individual parameter values for quick reference in diagnostics.
  551. NoticeInfo(
  552. "NetworkLatencyMultiplier: %f",
  553. config.clientParameters.Get().Float(parameters.NetworkLatencyMultiplier))
  554. return nil
  555. }
  556. func (config *Config) makeConfigParameters() map[string]interface{} {
  557. // Build set of config values to apply to parameters.
  558. //
  559. // Note: names of some config fields such as
  560. // StaggerConnectionWorkersMilliseconds and LimitMeekBufferSizes have
  561. // changed in the parameters. The existing config fields are retained for
  562. // backwards compatibility.
  563. applyParameters := make(map[string]interface{})
  564. if config.NetworkLatencyMultiplier > 0.0 {
  565. applyParameters[parameters.NetworkLatencyMultiplier] = config.NetworkLatencyMultiplier
  566. }
  567. if len(config.TunnelProtocols) > 0 {
  568. applyParameters[parameters.LimitTunnelProtocols] = protocol.TunnelProtocols(config.TunnelProtocols)
  569. } else if config.TunnelProtocol != "" {
  570. applyParameters[parameters.LimitTunnelProtocols] = protocol.TunnelProtocols{config.TunnelProtocol}
  571. }
  572. if config.EstablishTunnelTimeoutSeconds != nil {
  573. applyParameters[parameters.EstablishTunnelTimeout] = fmt.Sprintf("%ds", *config.EstablishTunnelTimeoutSeconds)
  574. }
  575. if config.EstablishTunnelPausePeriodSeconds != nil {
  576. applyParameters[parameters.EstablishTunnelPausePeriod] = fmt.Sprintf("%ds", *config.EstablishTunnelPausePeriodSeconds)
  577. }
  578. if config.ConnectionWorkerPoolSize != 0 {
  579. applyParameters[parameters.ConnectionWorkerPoolSize] = config.ConnectionWorkerPoolSize
  580. }
  581. if config.StaggerConnectionWorkersMilliseconds > 0 {
  582. applyParameters[parameters.StaggerConnectionWorkersPeriod] = fmt.Sprintf("%dms", config.StaggerConnectionWorkersMilliseconds)
  583. }
  584. if config.LimitMeekConnectionWorkers > 0 {
  585. applyParameters[parameters.LimitMeekConnectionWorkers] = config.LimitMeekConnectionWorkers
  586. }
  587. applyParameters[parameters.MeekLimitBufferSizes] = config.LimitMeekBufferSizes
  588. applyParameters[parameters.IgnoreHandshakeStatsRegexps] = config.IgnoreHandshakeStatsRegexps
  589. if config.EstablishTunnelTimeoutSeconds != nil {
  590. applyParameters[parameters.EstablishTunnelTimeout] = fmt.Sprintf("%ds", *config.EstablishTunnelTimeoutSeconds)
  591. }
  592. if config.FetchRemoteServerListRetryPeriodMilliseconds != nil {
  593. applyParameters[parameters.FetchRemoteServerListRetryPeriod] = fmt.Sprintf("%dms", *config.FetchRemoteServerListRetryPeriodMilliseconds)
  594. }
  595. if config.FetchUpgradeRetryPeriodMilliseconds != nil {
  596. applyParameters[parameters.FetchUpgradeRetryPeriod] = fmt.Sprintf("%dms", *config.FetchUpgradeRetryPeriodMilliseconds)
  597. }
  598. if !config.DisableRemoteServerListFetcher {
  599. if config.RemoteServerListURLs != nil {
  600. applyParameters[parameters.RemoteServerListSignaturePublicKey] = config.RemoteServerListSignaturePublicKey
  601. applyParameters[parameters.RemoteServerListURLs] = config.RemoteServerListURLs
  602. }
  603. if config.ObfuscatedServerListRootURLs != nil {
  604. applyParameters[parameters.RemoteServerListSignaturePublicKey] = config.RemoteServerListSignaturePublicKey
  605. applyParameters[parameters.ObfuscatedServerListRootURLs] = config.ObfuscatedServerListRootURLs
  606. }
  607. }
  608. applyParameters[parameters.SplitTunnelRoutesURLFormat] = config.SplitTunnelRoutesURLFormat
  609. applyParameters[parameters.SplitTunnelRoutesSignaturePublicKey] = config.SplitTunnelRoutesSignaturePublicKey
  610. applyParameters[parameters.SplitTunnelDNSServer] = config.SplitTunnelDNSServer
  611. if config.UpgradeDownloadURLs != nil {
  612. applyParameters[parameters.UpgradeDownloadClientVersionHeader] = config.UpgradeDownloadClientVersionHeader
  613. applyParameters[parameters.UpgradeDownloadURLs] = config.UpgradeDownloadURLs
  614. }
  615. applyParameters[parameters.TunnelRateLimits] = config.RateLimits
  616. return applyParameters
  617. }
  618. func promoteLegacyDownloadURL(URL string) parameters.DownloadURLs {
  619. downloadURLs := make(parameters.DownloadURLs, 1)
  620. downloadURLs[0] = &parameters.DownloadURL{
  621. URL: base64.StdEncoding.EncodeToString([]byte(URL)),
  622. SkipVerify: false,
  623. OnlyAfterAttempts: 0,
  624. }
  625. return downloadURLs
  626. }