config.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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/json"
  22. "errors"
  23. "os"
  24. "time"
  25. )
  26. // TODO: allow all params to be configured
  27. const (
  28. LEGACY_DATA_STORE_FILENAME = "psiphon.db"
  29. DATA_STORE_FILENAME = "psiphon.boltdb"
  30. CONNECTION_WORKER_POOL_SIZE = 10
  31. TUNNEL_POOL_SIZE = 1
  32. TUNNEL_CONNECT_TIMEOUT = 20 * time.Second
  33. TUNNEL_OPERATE_SHUTDOWN_TIMEOUT = 1 * time.Second
  34. TUNNEL_PORT_FORWARD_DIAL_TIMEOUT = 10 * time.Second
  35. TUNNEL_SSH_KEEP_ALIVE_PAYLOAD_MAX_BYTES = 256
  36. TUNNEL_SSH_KEEP_ALIVE_PERIOD_MIN = 60 * time.Second
  37. TUNNEL_SSH_KEEP_ALIVE_PERIOD_MAX = 120 * time.Second
  38. TUNNEL_SSH_KEEP_ALIVE_PERIODIC_TIMEOUT = 30 * time.Second
  39. TUNNEL_SSH_KEEP_ALIVE_PERIODIC_INACTIVE_PERIOD = 10 * time.Second
  40. TUNNEL_SSH_KEEP_ALIVE_PROBE_TIMEOUT = 5 * time.Second
  41. TUNNEL_SSH_KEEP_ALIVE_PROBE_INACTIVE_PERIOD = 10 * time.Second
  42. ESTABLISH_TUNNEL_TIMEOUT_SECONDS = 300
  43. ESTABLISH_TUNNEL_WORK_TIME = 60 * time.Second
  44. ESTABLISH_TUNNEL_PAUSE_PERIOD = 5 * time.Second
  45. ESTABLISH_TUNNEL_SERVER_AFFINITY_GRACE_PERIOD = 1 * time.Second
  46. HTTP_PROXY_ORIGIN_SERVER_TIMEOUT = 15 * time.Second
  47. HTTP_PROXY_MAX_IDLE_CONNECTIONS_PER_HOST = 50
  48. FETCH_REMOTE_SERVER_LIST_TIMEOUT = 30 * time.Second
  49. FETCH_REMOTE_SERVER_LIST_RETRY_PERIOD = 5 * time.Second
  50. FETCH_REMOTE_SERVER_LIST_STALE_PERIOD = 6 * time.Hour
  51. PSIPHON_API_CLIENT_SESSION_ID_LENGTH = 16
  52. PSIPHON_API_SERVER_TIMEOUT = 20 * time.Second
  53. PSIPHON_API_SHUTDOWN_SERVER_TIMEOUT = 1 * time.Second
  54. PSIPHON_API_STATUS_REQUEST_PERIOD_MIN = 5 * time.Minute
  55. PSIPHON_API_STATUS_REQUEST_PERIOD_MAX = 10 * time.Minute
  56. PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MIN = 5 * time.Second
  57. PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MAX = 10 * time.Second
  58. PSIPHON_API_STATUS_REQUEST_PADDING_MAX_BYTES = 256
  59. PSIPHON_API_CONNECTED_REQUEST_PERIOD = 24 * time.Hour
  60. PSIPHON_API_CONNECTED_REQUEST_RETRY_PERIOD = 5 * time.Second
  61. PSIPHON_API_TUNNEL_STATS_MAX_COUNT = 1000
  62. FETCH_ROUTES_TIMEOUT = 1 * time.Minute
  63. DOWNLOAD_UPGRADE_TIMEOUT = 15 * time.Minute
  64. DOWNLOAD_UPGRADE_RETRY_PAUSE_PERIOD = 5 * time.Second
  65. IMPAIRED_PROTOCOL_CLASSIFICATION_DURATION = 2 * time.Minute
  66. IMPAIRED_PROTOCOL_CLASSIFICATION_THRESHOLD = 3
  67. TOTAL_BYTES_TRANSFERRED_NOTICE_PERIOD = 5 * time.Minute
  68. )
  69. // To distinguish omitted timeout params from explicit 0 value timeout
  70. // params, these params are int pointers. nil means no param was supplied
  71. // so use the default; a non-nil pointer to 0 means no timeout.
  72. // Config is the Psiphon configuration specified by the application. This
  73. // configuration controls the behavior of the core tunnel functionality.
  74. type Config struct {
  75. // LogFilename specifies a file to receive event notices (JSON format)
  76. // By default, notices are emitted to stdout.
  77. LogFilename string
  78. // DataStoreDirectory is the directory in which to store the persistent
  79. // database, which contains information such as server entries.
  80. // By default, current working directory.
  81. //
  82. // Warning: If the datastore file, DataStoreDirectory/DATA_STORE_FILENAME,
  83. // exists but fails to open for any reason (checksum error, unexpected file
  84. // format, etc.) it will be deleted in order to pave a new datastore and
  85. // continue running.
  86. DataStoreDirectory string
  87. // DataStoreTempDirectory is the directory in which to store temporary
  88. // work files associated with the persistent database.
  89. // This parameter is deprecated and may be removed.
  90. DataStoreTempDirectory string
  91. // PropagationChannelId is a string identifier which indicates how the
  92. // Psiphon client was distributed. This parameter is required.
  93. // This value is supplied by and depends on the Psiphon Network, and is
  94. // typically embedded in the client binary.
  95. PropagationChannelId string
  96. // PropagationChannelId is a string identifier which indicates who
  97. // is sponsoring this Psiphon client. One purpose of this value is to
  98. // determine the home pages for display. This parameter is required.
  99. // This value is supplied by and depends on the Psiphon Network, and is
  100. // typically embedded in the client binary.
  101. SponsorId string
  102. // RemoteServerListUrl is a URL which specifies a location to fetch
  103. // out-of-band server entries. This facility is used when a tunnel cannot
  104. // be established to known servers.
  105. // This value is supplied by and depends on the Psiphon Network, and is
  106. // typically embedded in the client binary.
  107. RemoteServerListUrl string
  108. // RemoteServerListSignaturePublicKey specifies a public key that's
  109. // used to authenticate the remote server list payload.
  110. // This value is supplied by and depends on the Psiphon Network, and is
  111. // typically embedded in the client binary.
  112. RemoteServerListSignaturePublicKey string
  113. // ClientVersion is the client version number that the client reports
  114. // to the server. The version number refers to the host client application,
  115. // not the core tunnel library. One purpose of this value is to enable
  116. // automatic updates.
  117. // This value is supplied by and depends on the Psiphon Network, and is
  118. // typically embedded in the client binary.
  119. // Note that sending a ClientPlatform string which includes "windows"
  120. // (case insensitive) and a ClientVersion of <= 44 will cause an
  121. // error in processing the response to DoConnectedRequest calls.
  122. ClientVersion string
  123. // ClientPlatform is the client platform ("Windows", "Android", etc.) that
  124. // the client reports to the server.
  125. ClientPlatform string
  126. // TunnelWholeDevice is a flag that is passed through to the handshake
  127. // request for stats purposes. Set to 1 when the host application is tunneling
  128. // the whole device, 0 otherwise.
  129. TunnelWholeDevice int
  130. // EgressRegion is a ISO 3166-1 alpha-2 country code which indicates which
  131. // country to egress from. For the default, "", the best performing server
  132. // in any country is selected.
  133. EgressRegion string
  134. // TunnelProtocol indicates which protocol to use. Valid values include:
  135. // "SSH", "OSSH", "UNFRONTED-MEEK-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
  136. // "FRONTED-MEEK-OSSH". For the default, "", the best performing protocol
  137. // is used.
  138. TunnelProtocol string
  139. // EstablishTunnelTimeoutSeconds specifies a time limit after which to halt
  140. // the core tunnel controller if no tunnel has been established. By default,
  141. // the controller will keep trying indefinitely.
  142. EstablishTunnelTimeoutSeconds *int
  143. // ListenInterface specifies which interface to listen on. If no interface
  144. // is provided then listen on 127.0.0.1.
  145. // If an invalid interface is provided then listen on localhost (127.0.0.1).
  146. // If 'any' is provided then use 0.0.0.0.
  147. // If there are multiple IP addresses on an interface use the first IPv4 address.
  148. ListenInterface string
  149. // LocalSocksProxyPort specifies a port number for the local SOCKS proxy
  150. // running at 127.0.0.1. For the default value, 0, the system selects a free
  151. // port (a notice reporting the selected port is emitted).
  152. LocalSocksProxyPort int
  153. // LocalHttpProxyPort specifies a port number for the local HTTP proxy
  154. // running at 127.0.0.1. For the default value, 0, the system selects a free
  155. // port (a notice reporting the selected port is emitted).
  156. LocalHttpProxyPort int
  157. // ConnectionWorkerPoolSize specifies how many connection attempts to attempt
  158. // in parallel. The default, 0, uses CONNECTION_WORKER_POOL_SIZE which is
  159. // recommended.
  160. ConnectionWorkerPoolSize int
  161. // TunnelPoolSize specifies how many tunnels to run in parallel. Port forwards
  162. // are multiplexed over multiple tunnels. The default, 0, uses TUNNEL_POOL_SIZE
  163. // which is recommended.
  164. TunnelPoolSize int
  165. // UpstreamProxyUrl is a URL specifying an upstream proxy to use for all
  166. // outbound connections. The URL should include proxy type and authentication
  167. // information, as required. See example URLs here:
  168. // https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/psiphon/upstreamproxy
  169. UpstreamProxyUrl string
  170. // NetworkConnectivityChecker is an interface that enables the core tunnel to call
  171. // into the host application to check for network connectivity. This parameter is
  172. // only applicable to library deployments.
  173. NetworkConnectivityChecker NetworkConnectivityChecker
  174. // DeviceBinder is an interface that enables the core tunnel to call
  175. // into the host application to bind sockets to specific devices. This is used
  176. // for VPN routing exclusion. This parameter is only applicable to library
  177. // deployments.
  178. DeviceBinder DeviceBinder
  179. // DnsServerGetter is an interface that enables the core tunnel to call
  180. // into the host application to discover the native network DNS server settings.
  181. // This parameter is only applicable to library deployments.
  182. DnsServerGetter DnsServerGetter
  183. // TargetServerEntry is an encoded server entry. When specified, this server entry
  184. // is used exclusively and all other known servers are ignored.
  185. TargetServerEntry string
  186. // DisableApi disables Psiphon server API calls including handshake, connected,
  187. // status, etc. This is used for special case temporary tunnels (Windows VPN mode).
  188. DisableApi bool
  189. // DisableRemoteServerListFetcher disables fetching remote server lists. This is
  190. // used for special case temporary tunnels.
  191. DisableRemoteServerListFetcher bool
  192. // SplitTunnelRoutesUrlFormat is an URL which specifies the location of a routes
  193. // file to use for split tunnel mode. The URL must include a placeholder for the
  194. // client region to be supplied. Split tunnel mode uses the routes file to classify
  195. // port forward destinations as foreign or domestic and does not tunnel domestic
  196. // destinations. Split tunnel mode is on when all the SplitTunnel parameters are
  197. // supplied.
  198. // This value is supplied by and depends on the Psiphon Network, and is
  199. // typically embedded in the client binary.
  200. SplitTunnelRoutesUrlFormat string
  201. // SplitTunnelRoutesSignaturePublicKey specifies a public key that's
  202. // used to authenticate the split tunnel routes payload.
  203. // This value is supplied by and depends on the Psiphon Network, and is
  204. // typically embedded in the client binary.
  205. SplitTunnelRoutesSignaturePublicKey string
  206. // SplitTunnelDnsServer specifies a DNS server to use when resolving port
  207. // forward target domain names to IP addresses for classification. The DNS
  208. // server must support TCP requests.
  209. SplitTunnelDnsServer string
  210. // UpgradeDownloadUrl specifies a URL from which to download a host client upgrade
  211. // file, when one is available. The core tunnel controller provides a resumable
  212. // download facility which downloads this resource and emits a notice when complete.
  213. // This value is supplied by and depends on the Psiphon Network, and is
  214. // typically embedded in the client binary.
  215. UpgradeDownloadUrl string
  216. // UpgradeDownloadFilename is the local target filename for an upgrade download.
  217. // This parameter is required when UpgradeDownloadUrl is specified.
  218. UpgradeDownloadFilename string
  219. // EmitBytesTransferred indicates whether to emit periodic notices showing
  220. // bytes sent and received.
  221. EmitBytesTransferred bool
  222. // UseIndistinguishableTLS enables use of an alternative TLS stack with a less
  223. // distinct fingerprint (ClientHello content) than the stock Go TLS.
  224. // UseIndistinguishableTLS only applies to untunneled TLS connections. This
  225. // parameter is only supported on platforms built with OpenSSL.
  226. // Requires TrustedCACertificatesFilename to be set.
  227. UseIndistinguishableTLS bool
  228. // UseTrustedCACertificates toggles use of the trusted CA certs, specified
  229. // in TrustedCACertificatesFilename, for tunneled TLS connections that expect
  230. // server certificates signed with public certificate authorities (currently,
  231. // only upgrade downloads). This option is used with stock Go TLS in cases where
  232. // Go may fail to obtain a list of root CAs from the operating system.
  233. // Requires TrustedCACertificatesFilename to be set.
  234. UseTrustedCACertificatesForStockTLS bool
  235. // TrustedCACertificatesFilename specifies a file containing trusted CA certs.
  236. // The file contents should be compatible with OpenSSL's SSL_CTX_load_verify_locations.
  237. // When specified, this enables use of indistinguishable TLS for HTTPS requests
  238. // that require typical (system CA) server authentication.
  239. TrustedCACertificatesFilename string
  240. // DisablePeriodicSshKeepAlive indicates whether to send an SSH keepalive every
  241. // 1-2 minutes, when the tunnel is idle. If the SSH keepalive times out, the tunnel
  242. // is considered to have failed.
  243. DisablePeriodicSshKeepAlive bool
  244. }
  245. // LoadConfig parses and validates a JSON format Psiphon config JSON
  246. // string and returns a Config struct populated with config values.
  247. func LoadConfig(configJson []byte) (*Config, error) {
  248. var config Config
  249. err := json.Unmarshal(configJson, &config)
  250. if err != nil {
  251. return nil, ContextError(err)
  252. }
  253. // These fields are required; the rest are optional
  254. if config.PropagationChannelId == "" {
  255. return nil, ContextError(
  256. errors.New("propagation channel ID is missing from the configuration file"))
  257. }
  258. if config.SponsorId == "" {
  259. return nil, ContextError(
  260. errors.New("sponsor ID is missing from the configuration file"))
  261. }
  262. if config.DataStoreDirectory == "" {
  263. config.DataStoreDirectory, err = os.Getwd()
  264. if err != nil {
  265. return nil, ContextError(err)
  266. }
  267. }
  268. if config.ClientVersion == "" {
  269. config.ClientVersion = "0"
  270. }
  271. if config.TunnelProtocol != "" {
  272. if !Contains(SupportedTunnelProtocols, config.TunnelProtocol) {
  273. return nil, ContextError(
  274. errors.New("invalid tunnel protocol"))
  275. }
  276. }
  277. if config.EstablishTunnelTimeoutSeconds == nil {
  278. defaultEstablishTunnelTimeoutSeconds := ESTABLISH_TUNNEL_TIMEOUT_SECONDS
  279. config.EstablishTunnelTimeoutSeconds = &defaultEstablishTunnelTimeoutSeconds
  280. }
  281. if config.ConnectionWorkerPoolSize == 0 {
  282. config.ConnectionWorkerPoolSize = CONNECTION_WORKER_POOL_SIZE
  283. }
  284. if config.TunnelPoolSize == 0 {
  285. config.TunnelPoolSize = TUNNEL_POOL_SIZE
  286. }
  287. if config.NetworkConnectivityChecker != nil {
  288. return nil, ContextError(errors.New("NetworkConnectivityChecker interface must be set at runtime"))
  289. }
  290. if config.DeviceBinder != nil {
  291. return nil, ContextError(errors.New("DeviceBinder interface must be set at runtime"))
  292. }
  293. if config.DnsServerGetter != nil {
  294. return nil, ContextError(errors.New("DnsServerGetter interface must be set at runtime"))
  295. }
  296. return &config, nil
  297. }