config.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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", "FRONTED-MEEK-OSSH". For the default,
  136. // "", the best performing protocol is used.
  137. TunnelProtocol string
  138. // EstablishTunnelTimeoutSeconds specifies a time limit after which to halt
  139. // the core tunnel controller if no tunnel has been established. By default,
  140. // the controller will keep trying indefinitely.
  141. EstablishTunnelTimeoutSeconds *int
  142. // ListenInterface specifies which interface to listen on. If no interface
  143. // is provided then listen on 127.0.0.1.
  144. // If an invalid interface is provided then listen on localhost (127.0.0.1).
  145. // If 'any' is provided then use 0.0.0.0.
  146. // If there are multiple IP addresses on an interface use the first IPv4 address.
  147. ListenInterface string
  148. // LocalSocksProxyPort specifies a port number for the local SOCKS proxy
  149. // running at 127.0.0.1. For the default value, 0, the system selects a free
  150. // port (a notice reporting the selected port is emitted).
  151. LocalSocksProxyPort int
  152. // LocalHttpProxyPort specifies a port number for the local HTTP proxy
  153. // running at 127.0.0.1. For the default value, 0, the system selects a free
  154. // port (a notice reporting the selected port is emitted).
  155. LocalHttpProxyPort int
  156. // ConnectionWorkerPoolSize specifies how many connection attempts to attempt
  157. // in parallel. The default, 0, uses CONNECTION_WORKER_POOL_SIZE which is
  158. // recommended.
  159. ConnectionWorkerPoolSize int
  160. // TunnelPoolSize specifies how many tunnels to run in parallel. Port forwards
  161. // are multiplexed over multiple tunnels. The default, 0, uses TUNNEL_POOL_SIZE
  162. // which is recommended.
  163. TunnelPoolSize int
  164. // UpstreamProxyUrl is a URL specifying an upstream proxy to use for all
  165. // outbound connections. The URL should include proxy type and authentication
  166. // information, as required. See example URLs here:
  167. // https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/psiphon/upstreamproxy
  168. UpstreamProxyUrl string
  169. // NetworkConnectivityChecker is an interface that enables the core tunnel to call
  170. // into the host application to check for network connectivity. This parameter is
  171. // only applicable to library deployments.
  172. NetworkConnectivityChecker NetworkConnectivityChecker
  173. // DeviceBinder is an interface that enables the core tunnel to call
  174. // into the host application to bind sockets to specific devices. This is used
  175. // for VPN routing exclusion. This parameter is only applicable to library
  176. // deployments.
  177. DeviceBinder DeviceBinder
  178. // DnsServerGetter is an interface that enables the core tunnel to call
  179. // into the host application to discover the native network DNS server settings.
  180. // This parameter is only applicable to library deployments.
  181. DnsServerGetter DnsServerGetter
  182. // TargetServerEntry is an encoded server entry. When specified, this server entry
  183. // is used exclusively and all other known servers are ignored.
  184. TargetServerEntry string
  185. // DisableApi disables Psiphon server API calls including handshake, connected,
  186. // status, etc. This is used for special case temporary tunnels (Windows VPN mode).
  187. DisableApi bool
  188. // DisableRemoteServerListFetcher disables fetching remote server lists. This is
  189. // used for special case temporary tunnels.
  190. DisableRemoteServerListFetcher bool
  191. // SplitTunnelRoutesUrlFormat is an URL which specifies the location of a routes
  192. // file to use for split tunnel mode. The URL must include a placeholder for the
  193. // client region to be supplied. Split tunnel mode uses the routes file to classify
  194. // port forward destinations as foreign or domestic and does not tunnel domestic
  195. // destinations. Split tunnel mode is on when all the SplitTunnel parameters are
  196. // supplied.
  197. // This value is supplied by and depends on the Psiphon Network, and is
  198. // typically embedded in the client binary.
  199. SplitTunnelRoutesUrlFormat string
  200. // SplitTunnelRoutesSignaturePublicKey specifies a public key that's
  201. // used to authenticate the split tunnel routes payload.
  202. // This value is supplied by and depends on the Psiphon Network, and is
  203. // typically embedded in the client binary.
  204. SplitTunnelRoutesSignaturePublicKey string
  205. // SplitTunnelDnsServer specifies a DNS server to use when resolving port
  206. // forward target domain names to IP addresses for classification. The DNS
  207. // server must support TCP requests.
  208. SplitTunnelDnsServer string
  209. // UpgradeDownloadUrl specifies a URL from which to download a host client upgrade
  210. // file, when one is available. The core tunnel controller provides a resumable
  211. // download facility which downloads this resource and emits a notice when complete.
  212. // This value is supplied by and depends on the Psiphon Network, and is
  213. // typically embedded in the client binary.
  214. UpgradeDownloadUrl string
  215. // UpgradeDownloadFilename is the local target filename for an upgrade download.
  216. // This parameter is required when UpgradeDownloadUrl is specified.
  217. UpgradeDownloadFilename string
  218. // EmitBytesTransferred indicates whether to emit periodic notices showing
  219. // bytes sent and received.
  220. EmitBytesTransferred bool
  221. // UseIndistinguishableTLS enables use of an alternative TLS stack with a less
  222. // distinct fingerprint (ClientHello content) than the stock Go TLS.
  223. // UseIndistinguishableTLS only applies to untunneled TLS connections. This
  224. // parameter is only supported on platforms built with OpenSSL.
  225. // Requires TrustedCACertificatesFilename to be set.
  226. UseIndistinguishableTLS bool
  227. // UseTrustedCACertificates toggles use of the trusted CA certs, specified
  228. // in TrustedCACertificatesFilename, for tunneled TLS connections that expect
  229. // server certificates signed with public certificate authorities (currently,
  230. // only upgrade downloads). This option is used with stock Go TLS in cases where
  231. // Go may fail to obtain a list of root CAs from the operating system.
  232. // Requires TrustedCACertificatesFilename to be set.
  233. UseTrustedCACertificatesForStockTLS bool
  234. // TrustedCACertificatesFilename specifies a file containing trusted CA certs.
  235. // The file contents should be compatible with OpenSSL's SSL_CTX_load_verify_locations.
  236. // When specified, this enables use of indistinguishable TLS for HTTPS requests
  237. // that require typical (system CA) server authentication.
  238. TrustedCACertificatesFilename string
  239. // DisablePeriodicSshKeepAlive indicates whether to send an SSH keepalive every
  240. // 1-2 minutes, when the tunnel is idle. If the SSH keepalive times out, the tunnel
  241. // is considered to have failed.
  242. DisablePeriodicSshKeepAlive bool
  243. }
  244. // LoadConfig parses and validates a JSON format Psiphon config JSON
  245. // string and returns a Config struct populated with config values.
  246. func LoadConfig(configJson []byte) (*Config, error) {
  247. var config Config
  248. err := json.Unmarshal(configJson, &config)
  249. if err != nil {
  250. return nil, ContextError(err)
  251. }
  252. // These fields are required; the rest are optional
  253. if config.PropagationChannelId == "" {
  254. return nil, ContextError(
  255. errors.New("propagation channel ID is missing from the configuration file"))
  256. }
  257. if config.SponsorId == "" {
  258. return nil, ContextError(
  259. errors.New("sponsor ID is missing from the configuration file"))
  260. }
  261. if config.DataStoreDirectory == "" {
  262. config.DataStoreDirectory, err = os.Getwd()
  263. if err != nil {
  264. return nil, ContextError(err)
  265. }
  266. }
  267. if config.ClientVersion == "" {
  268. config.ClientVersion = "0"
  269. }
  270. if config.TunnelProtocol != "" {
  271. if !Contains(SupportedTunnelProtocols, config.TunnelProtocol) {
  272. return nil, ContextError(
  273. errors.New("invalid tunnel protocol"))
  274. }
  275. }
  276. if config.EstablishTunnelTimeoutSeconds == nil {
  277. defaultEstablishTunnelTimeoutSeconds := ESTABLISH_TUNNEL_TIMEOUT_SECONDS
  278. config.EstablishTunnelTimeoutSeconds = &defaultEstablishTunnelTimeoutSeconds
  279. }
  280. if config.ConnectionWorkerPoolSize == 0 {
  281. config.ConnectionWorkerPoolSize = CONNECTION_WORKER_POOL_SIZE
  282. }
  283. if config.TunnelPoolSize == 0 {
  284. config.TunnelPoolSize = TUNNEL_POOL_SIZE
  285. }
  286. if config.NetworkConnectivityChecker != nil {
  287. return nil, ContextError(errors.New("NetworkConnectivityChecker interface must be set at runtime"))
  288. }
  289. if config.DeviceBinder != nil {
  290. return nil, ContextError(errors.New("DeviceBinder interface must be set at runtime"))
  291. }
  292. if config.DnsServerGetter != nil {
  293. return nil, ContextError(errors.New("DnsServerGetter interface must be set at runtime"))
  294. }
  295. return &config, nil
  296. }