github.com/Psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/config.go (about) 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 20 package psiphon 21 22 import ( 23 "crypto/md5" 24 "encoding/base64" 25 "encoding/binary" 26 "encoding/json" 27 "fmt" 28 "io/ioutil" 29 "net/http" 30 "os" 31 "path/filepath" 32 "regexp" 33 "strconv" 34 "strings" 35 "sync" 36 "unicode" 37 38 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 39 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 40 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters" 41 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol" 42 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/resolver" 43 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/transforms" 44 ) 45 46 const ( 47 TUNNEL_POOL_SIZE = 1 48 MAX_TUNNEL_POOL_SIZE = 32 49 50 // Psiphon data directory name, relative to config.DataRootDirectory. 51 // See config.GetPsiphonDataDirectory(). 52 PsiphonDataDirectoryName = "ca.psiphon.PsiphonTunnel.tunnel-core" 53 54 // Filename constants, all relative to config.GetPsiphonDataDirectory(). 55 HomepageFilename = "homepage" 56 NoticesFilename = "notices" 57 OldNoticesFilename = "notices.1" 58 UpgradeDownloadFilename = "upgrade" 59 ) 60 61 // Config is the Psiphon configuration specified by the application. This 62 // configuration controls the behavior of the core tunnel functionality. 63 // 64 // To distinguish omitted timeout params from explicit 0 value timeout params, 65 // corresponding fields are int pointers. nil means no value was supplied and 66 // to use the default; a non-nil pointer to 0 means no timeout. 67 type Config struct { 68 69 // DataRootDirectory is the directory in which to store persistent files, 70 // which contain information such as server entries. By default, current 71 // working directory. 72 // 73 // Psiphon will assume full control of files under this directory. They may 74 // be deleted, moved or overwritten. 75 DataRootDirectory string 76 77 // UseNoticeFiles configures notice files for writing. If set, homepages 78 // will be written to a file created at config.GetHomePageFilename() 79 // and notices will be written to a file created at 80 // config.GetNoticesFilename(). 81 // 82 // The homepage file may be read after the Tunnels notice with count of 1. 83 // 84 // The value of UseNoticeFiles sets the size and frequency at which the 85 // notices file, config.GetNoticesFilename(), will be rotated. See the 86 // comment for UseNoticeFiles for more details. One rotated older file, 87 // config.GetOldNoticesFilename(), is retained. 88 // 89 // The notice files may be may be read at any time; and should be opened 90 // read-only for reading. Diagnostic notices are omitted from the notice 91 // files. 92 // 93 // See comment for setNoticeFiles in notice.go for further details. 94 UseNoticeFiles *UseNoticeFiles 95 96 // PropagationChannelId is a string identifier which indicates how the 97 // Psiphon client was distributed. This parameter is required. This value 98 // is supplied by and depends on the Psiphon Network, and is typically 99 // embedded in the client binary. 100 PropagationChannelId string 101 102 // SponsorId is a string identifier which indicates who is sponsoring this 103 // Psiphon client. One purpose of this value is to determine the home 104 // pages for display. This parameter is required. This value is supplied 105 // by and depends on the Psiphon Network, and is typically embedded in the 106 // client binary. 107 SponsorId string 108 109 // ClientVersion is the client version number that the client reports to 110 // the server. The version number refers to the host client application, 111 // not the core tunnel library. One purpose of this value is to enable 112 // automatic updates. This value is supplied by and depends on the Psiphon 113 // Network, and is typically embedded in the client binary. 114 // 115 // Note that sending a ClientPlatform string which includes "windows" 116 // (case insensitive) and a ClientVersion of <= 44 will cause an error in 117 // processing the response to DoConnectedRequest calls. 118 ClientVersion string 119 120 // ClientPlatform is the client platform ("Windows", "Android", etc.) that 121 // the client reports to the server. 122 ClientPlatform string 123 124 // ClientFeatures is a list of feature names denoting enabled application 125 // features. Clients report enabled features to the server for stats 126 // purposes. 127 ClientFeatures []string 128 129 // EgressRegion is a ISO 3166-1 alpha-2 country code which indicates which 130 // country to egress from. For the default, "", the best performing server 131 // in any country is selected. 132 EgressRegion string 133 134 // SplitTunnelOwnRegion enables split tunnel mode for the client's own 135 // country. When enabled, TCP port forward destinations that resolve to 136 // the same GeoIP country as the client are connected to directly, 137 // untunneled. 138 SplitTunnelOwnRegion bool 139 140 // SplitTunnelRegions enables selected split tunnel mode in which the 141 // client specifies a list of ISO 3166-1 alpha-2 country codes for which 142 // traffic should be untunneled. TCP port forwards destined to any 143 // country specified in SplitTunnelRegions will be untunneled, regardless 144 // of whether SplitTunnelOwnRegion is on or off. 145 SplitTunnelRegions []string 146 147 // ListenInterface specifies which interface to listen on. If no 148 // interface is provided then listen on 127.0.0.1. If 'any' is provided 149 // then use 0.0.0.0. If there are multiple IP addresses on an interface 150 // use the first IPv4 address. 151 ListenInterface string 152 153 // DisableLocalSocksProxy disables running the local SOCKS proxy. 154 DisableLocalSocksProxy bool 155 156 // LocalSocksProxyPort specifies a port number for the local SOCKS proxy 157 // running at 127.0.0.1. For the default value, 0, the system selects a 158 // free port (a notice reporting the selected port is emitted). 159 LocalSocksProxyPort int 160 161 // LocalHttpProxyPort specifies a port number for the local HTTP proxy 162 // running at 127.0.0.1. For the default value, 0, the system selects a 163 // free port (a notice reporting the selected port is emitted). 164 LocalHttpProxyPort int 165 166 // DisableLocalHTTPProxy disables running the local HTTP proxy. 167 DisableLocalHTTPProxy bool 168 169 // NetworkLatencyMultiplier is a multiplier that is to be applied to 170 // default network event timeouts. Set this to tune performance for 171 // slow networks. 172 // When set, must be >= 1.0. 173 NetworkLatencyMultiplier float64 174 175 // LimitTunnelProtocols indicates which protocols to use. Valid values 176 // include: "SSH", "OSSH", "UNFRONTED-MEEK-OSSH", 177 // "UNFRONTED-MEEK-HTTPS-OSSH", "UNFRONTED-MEEK-SESSION-TICKET-OSSH", 178 // "FRONTED-MEEK-OSSH", "FRONTED-MEEK-HTTP-OSSH", "QUIC-OSSH", 179 // "FRONTED-MEEK-QUIC-OSSH", "TAPDANCE-OSSH", and "CONJURE-OSSH". 180 181 // For the default, an empty list, all protocols are used. 182 LimitTunnelProtocols []string 183 184 // InitialLimitTunnelProtocols is an optional initial phase of limited 185 // protocols for the first InitialLimitTunnelProtocolsCandidateCount 186 // candidates; after these candidates, LimitTunnelProtocols applies. 187 // 188 // For the default, an empty list, InitialLimitTunnelProtocols is off. 189 InitialLimitTunnelProtocols []string 190 191 // InitialLimitTunnelProtocolsCandidateCount is the number of candidates 192 // to which InitialLimitTunnelProtocols is applied instead of 193 // LimitTunnelProtocols. 194 // 195 // For the default, 0, InitialLimitTunnelProtocols is off. 196 InitialLimitTunnelProtocolsCandidateCount int 197 198 // LimitTLSProfiles indicates which TLS profiles to select from. Valid 199 // values are listed in protocols.SupportedTLSProfiles. 200 // For the default, an empty list, all profiles are candidates for 201 // selection. 202 LimitTLSProfiles []string 203 204 // LimitQUICVersions indicates which QUIC versions to select from. Valid 205 // values are listed in protocols.SupportedQUICVersions. 206 // For the default, an empty list, all versions are candidates for 207 // selection. 208 LimitQUICVersions []string 209 210 // EstablishTunnelTimeoutSeconds specifies a time limit after which to 211 // halt the core tunnel controller if no tunnel has been established. The 212 // default is parameters.EstablishTunnelTimeout. 213 EstablishTunnelTimeoutSeconds *int 214 215 // EstablishTunnelPausePeriodSeconds specifies the delay between attempts 216 // to establish tunnels. Briefly pausing allows for network conditions to 217 // improve and for asynchronous operations such as fetch remote server 218 // list to complete. If omitted, a default value is used. This value is 219 // typical overridden for testing. 220 EstablishTunnelPausePeriodSeconds *int 221 222 // EstablishTunnelPausePeriodSeconds specifies the grace period, or head 223 // start, provided to the affinity server candidate when establishing. The 224 // affinity server is the server used for the last established tunnel. 225 EstablishTunnelServerAffinityGracePeriodMilliseconds *int 226 227 // ConnectionWorkerPoolSize specifies how many connection attempts to 228 // attempt in parallel. If omitted of when 0, a default is used; this is 229 // recommended. 230 ConnectionWorkerPoolSize int 231 232 // TunnelPoolSize specifies how many tunnels to run in parallel. Port 233 // forwards are multiplexed over multiple tunnels. If omitted or when 0, 234 // the default is TUNNEL_POOL_SIZE, which is recommended. Any value over 235 // MAX_TUNNEL_POOL_SIZE is treated as MAX_TUNNEL_POOL_SIZE. 236 TunnelPoolSize int 237 238 // StaggerConnectionWorkersMilliseconds adds a specified delay before 239 // making each server candidate available to connection workers. This 240 // option is enabled when StaggerConnectionWorkersMilliseconds > 0. 241 StaggerConnectionWorkersMilliseconds int 242 243 // LimitIntensiveConnectionWorkers limits the number of concurrent 244 // connection workers attempting connections with resource intensive 245 // protocols. This option is enabled when LimitIntensiveConnectionWorkers 246 // > 0. 247 LimitIntensiveConnectionWorkers int 248 249 // LimitMeekBufferSizes selects smaller buffers for meek protocols. 250 LimitMeekBufferSizes bool 251 252 // LimitCPUThreads minimizes the number of CPU threads -- and associated 253 // overhead -- the are used. 254 LimitCPUThreads bool 255 256 // LimitRelayBufferSizes selects smaller buffers for port forward relaying. 257 LimitRelayBufferSizes bool 258 259 // IgnoreHandshakeStatsRegexps skips compiling and using stats regexes. 260 IgnoreHandshakeStatsRegexps bool 261 262 // UpstreamProxyURL is a URL specifying an upstream proxy to use for all 263 // outbound connections. The URL should include proxy type and 264 // authentication information, as required. See example URLs here: 265 // https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/psiphon/upstreamproxy 266 UpstreamProxyURL string 267 268 // CustomHeaders is a set of additional arbitrary HTTP headers that are 269 // added to all plaintext HTTP requests and requests made through an HTTP 270 // upstream proxy when specified by UpstreamProxyURL. 271 CustomHeaders http.Header 272 273 // NetworkConnectivityChecker is an interface that enables tunnel-core to 274 // call into the host application to check for network connectivity. See: 275 // NetworkConnectivityChecker doc. 276 NetworkConnectivityChecker NetworkConnectivityChecker 277 278 // DeviceBinder is an interface that enables tunnel-core to call into the 279 // host application to bind sockets to specific devices. See: DeviceBinder 280 // doc. 281 // 282 // When DeviceBinder is set, the "VPN" feature name is automatically added 283 // when reporting ClientFeatures. 284 DeviceBinder DeviceBinder 285 286 // AllowDefaultDNSResolverWithBindToDevice indicates that it's safe to use 287 // the default resolver when DeviceBinder is configured, as the host OS 288 // will automatically exclude DNS requests from the VPN. 289 AllowDefaultDNSResolverWithBindToDevice bool 290 291 // IPv6Synthesizer is an interface that allows tunnel-core to call into 292 // the host application to synthesize IPv6 addresses. See: IPv6Synthesizer 293 // doc. 294 IPv6Synthesizer IPv6Synthesizer 295 296 // HasIPv6RouteGetter is an interface that allows tunnel-core to call into 297 // the host application to determine if the host has an IPv6 route. See: 298 // HasIPv6RouteGetter doc. 299 HasIPv6RouteGetter HasIPv6RouteGetter 300 301 // DNSServerGetter is an interface that enables tunnel-core to call into 302 // the host application to discover the native network DNS server 303 // settings. See: DNSServerGetter doc. 304 DNSServerGetter DNSServerGetter 305 306 // NetworkIDGetter in an interface that enables tunnel-core to call into 307 // the host application to get an identifier for the host's current active 308 // network. See: NetworkIDGetter doc. 309 NetworkIDGetter NetworkIDGetter 310 311 // NetworkID, when not blank, is used as the identifier for the host's 312 // current active network. 313 // NetworkID is ignored when NetworkIDGetter is set. 314 NetworkID string 315 316 // DisableTactics disables tactics operations including requests, payload 317 // handling, and application of parameters. 318 DisableTactics bool 319 320 // DisableReplay causes any persisted dial parameters to be ignored when 321 // they would otherwise be used for replay. 322 DisableReplay bool 323 324 // TargetServerEntry is an encoded server entry. When specified, this 325 // server entry is used exclusively and all other known servers are 326 // ignored; also, when set, ConnectionWorkerPoolSize is ignored and 327 // the pool size is 1. 328 TargetServerEntry string 329 330 // DisableApi disables Psiphon server API calls including handshake, 331 // connected, status, etc. This is used for special case temporary tunnels 332 // (Windows VPN mode). 333 DisableApi bool 334 335 // TargetApiProtocol specifies whether to force use of "ssh" or "web" API 336 // protocol. When blank, the default, the optimal API protocol is used. 337 // Note that this capability check is not applied before the 338 // "CandidateServers" count is emitted. 339 // 340 // This parameter is intended for testing and debugging only. Not all 341 // parameters are supported in the legacy "web" API protocol, including 342 // speed test samples. 343 TargetApiProtocol string 344 345 // RemoteServerListURLs is list of URLs which specify locations to fetch 346 // out-of-band server entries. This facility is used when a tunnel cannot 347 // be established to known servers. This value is supplied by and depends 348 // on the Psiphon Network, and is typically embedded in the client binary. 349 // All URLs must point to the same entity with the same ETag. At least one 350 // TransferURL must have OnlyAfterAttempts = 0. 351 RemoteServerListURLs parameters.TransferURLs 352 353 // RemoteServerListSignaturePublicKey specifies a public key that's used 354 // to authenticate the remote server list payload. This value is supplied 355 // by and depends on the Psiphon Network, and is typically embedded in the 356 // client binary. 357 RemoteServerListSignaturePublicKey string 358 359 // DisableRemoteServerListFetcher disables fetching remote server lists. 360 // This is used for special case temporary tunnels. 361 DisableRemoteServerListFetcher bool 362 363 // FetchRemoteServerListRetryPeriodMilliseconds specifies the delay before 364 // resuming a remote server list download after a failure. If omitted, a 365 // default value is used. This value is typical overridden for testing. 366 FetchRemoteServerListRetryPeriodMilliseconds *int 367 368 // ObfuscatedServerListRootURLs is a list of URLs which specify root 369 // locations from which to fetch obfuscated server list files. This value 370 // is supplied by and depends on the Psiphon Network, and is typically 371 // embedded in the client binary. All URLs must point to the same entity 372 // with the same ETag. At least one DownloadURL must have 373 // OnlyAfterAttempts = 0. 374 ObfuscatedServerListRootURLs parameters.TransferURLs 375 376 // UpgradeDownloadURLs is list of URLs which specify locations from which 377 // to download a host client upgrade file, when one is available. The core 378 // tunnel controller provides a resumable download facility which 379 // downloads this resource and emits a notice when complete. This value is 380 // supplied by and depends on the Psiphon Network, and is typically 381 // embedded in the client binary. All URLs must point to the same entity 382 // with the same ETag. At least one DownloadURL must have 383 // OnlyAfterAttempts = 0. 384 UpgradeDownloadURLs parameters.TransferURLs 385 386 // UpgradeDownloadClientVersionHeader specifies the HTTP header name for 387 // the entity at UpgradeDownloadURLs which specifies the client version 388 // (an integer value). A HEAD request may be made to check the version 389 // number available at UpgradeDownloadURLs. 390 // UpgradeDownloadClientVersionHeader is required when UpgradeDownloadURLs 391 // is specified. 392 UpgradeDownloadClientVersionHeader string 393 394 // FetchUpgradeRetryPeriodMilliseconds specifies the delay before resuming 395 // a client upgrade download after a failure. If omitted, a default value 396 // is used. This value is typical overridden for testing. 397 FetchUpgradeRetryPeriodMilliseconds *int 398 399 // FeedbackUploadURLs is a list of SecureTransferURLs which specify 400 // locations where feedback data can be uploaded, pairing with each 401 // location a public key with which to encrypt the feedback data. This 402 // value is supplied by and depends on the Psiphon Network, and is 403 // typically embedded in the client binary. At least one TransferURL must 404 // have OnlyAfterAttempts = 0. 405 FeedbackUploadURLs parameters.TransferURLs 406 407 // FeedbackEncryptionPublicKey is a default base64-encoded, RSA public key 408 // value used to encrypt feedback data. Used when uploading feedback with a 409 // TransferURL which has no public key value configured, i.e. 410 // B64EncodedPublicKey = "". 411 FeedbackEncryptionPublicKey string 412 413 // TrustedCACertificatesFilename specifies a file containing trusted CA 414 // certs. When set, this toggles use of the trusted CA certs, specified in 415 // TrustedCACertificatesFilename, for tunneled TLS connections that expect 416 // server certificates signed with public certificate authorities 417 // (currently, only upgrade downloads). This option is used with stock Go 418 // TLS in cases where Go may fail to obtain a list of root CAs from the 419 // operating system. 420 TrustedCACertificatesFilename string 421 422 // DisablePeriodicSshKeepAlive indicates whether to send an SSH keepalive 423 // every 1-2 minutes, when the tunnel is idle. If the SSH keepalive times 424 // out, the tunnel is considered to have failed. 425 DisablePeriodicSshKeepAlive bool 426 427 // DeviceRegion is the optional, reported region the host device is 428 // running in. This input value should be a ISO 3166-1 alpha-2 country 429 // code. The device region is reported to the server in the connected 430 // request and recorded for Psiphon stats. 431 // 432 // When provided, this value may be used, pre-connection, to select 433 // performance or circumvention optimization strategies for the given 434 // region. 435 DeviceRegion string 436 437 // EmitDiagnosticNotices indicates whether to output notices containing 438 // detailed information about the Psiphon session. As these notices may 439 // contain sensitive information, they should not be insecurely distributed 440 // or displayed to users. Default is off. 441 EmitDiagnosticNotices bool 442 443 // EmitDiagnosticNetworkParameters indicates whether to include network 444 // parameters in diagnostic notices. As these parameters are sensitive 445 // circumvention network information, they should not be insecurely 446 // distributed or displayed to users. Default is off. 447 EmitDiagnosticNetworkParameters bool 448 449 // EmitBytesTransferred indicates whether to emit periodic notices showing 450 // bytes sent and received. 451 EmitBytesTransferred bool 452 453 // EmitSLOKs indicates whether to emit notices for each seeded SLOK. As 454 // this could reveal user browsing activity, it's intended for debugging 455 // and testing only. 456 EmitSLOKs bool 457 458 // EmitRefractionNetworkingLogs indicates whether to emit gotapdance log 459 // messages to stdout. Note that gotapdance log messages do not conform to 460 // the Notice format standard. Default is off. 461 EmitRefractionNetworkingLogs bool 462 463 // EmitServerAlerts indicates whether to emit notices for server alerts. 464 EmitServerAlerts bool 465 466 // EmitClientAddress indicates whether to emit the client's public network 467 // address, IP and port, as seen by the server. 468 EmitClientAddress bool 469 470 // RateLimits specify throttling configuration for the tunnel. 471 RateLimits common.RateLimits 472 473 // PacketTunnelTunDeviceFileDescriptor specifies a tun device file 474 // descriptor to use for running a packet tunnel. When this value is > 0, 475 // a packet tunnel is established through the server and packets are 476 // relayed via the tun device file descriptor. The file descriptor is 477 // duped in NewController. When PacketTunnelTunDeviceFileDescriptor is 478 // set, TunnelPoolSize must be 1. 479 PacketTunnelTunFileDescriptor int 480 481 // SessionID specifies a client session ID to use in the Psiphon API. The 482 // session ID should be a randomly generated value that is used only for a 483 // single session, which is defined as the period between a user starting 484 // a Psiphon client and stopping the client. 485 // 486 // A session ID must be 32 hex digits (lower case). When blank, a random 487 // session ID is automatically generated. Supply a session ID when a 488 // single client session will cross multiple Controller instances. 489 SessionID string 490 491 // Authorizations is a list of encoded, signed access control 492 // authorizations that the client has obtained and will present to the 493 // server. 494 Authorizations []string 495 496 // ServerEntrySignaturePublicKey is a base64-encoded, ed25519 public 497 // key value used to verify individual server entry signatures. This value 498 // is supplied by and depends on the Psiphon Network, and is typically 499 // embedded in the client binary. 500 ServerEntrySignaturePublicKey string 501 502 // ExchangeObfuscationKey is a base64-encoded, NaCl secretbox key used to 503 // obfuscate server info exchanges between clients. 504 // Required for the exchange functionality. 505 ExchangeObfuscationKey string 506 507 // MigrateHomepageNoticesFilename migrates a homepage file from the path 508 // previously configured with setNoticeFiles to the new path for homepage 509 // files under the data root directory. The file specified by this config 510 // value will be moved to config.GetHomePageFilename(). 511 // 512 // Note: see comment for config.Commit() for a description of how file 513 // migrations are performed. 514 // 515 // If not set, no migration operation will be performed. 516 MigrateHomepageNoticesFilename string 517 518 // MigrateRotatingNoticesFilename migrates notice files from the path 519 // previously configured with setNoticeFiles to the new path for notice 520 // files under the data root directory. 521 // 522 // MigrateRotatingNoticesFilename will be moved to 523 // config.GetNoticesFilename(). 524 // 525 // MigrateRotatingNoticesFilename.1 will be moved to 526 // config.GetOldNoticesFilename(). 527 // 528 // Note: see comment for config.Commit() for a description of how file 529 // migrations are performed. 530 // 531 // If not set, no migration operation will be performed. 532 MigrateRotatingNoticesFilename string 533 534 // MigrateDataStoreDirectory indicates the location of the datastore 535 // directory, as previously configured with the deprecated 536 // DataStoreDirectory config field. Datastore files found in the specified 537 // directory will be moved under the data root directory. 538 // 539 // Note: see comment for config.Commit() for a description of how file 540 // migrations are performed. 541 MigrateDataStoreDirectory string 542 543 // MigrateRemoteServerListDownloadFilename indicates the location of 544 // remote server list download files. The remote server list files found at 545 // the specified path will be moved under the data root directory. 546 // 547 // Note: see comment for config.Commit() for a description of how file 548 // migrations are performed. 549 MigrateRemoteServerListDownloadFilename string 550 551 // MigrateObfuscatedServerListDownloadDirectory indicates the location of 552 // the obfuscated server list downloads directory, as previously configured 553 // with ObfuscatedServerListDownloadDirectory. Obfuscated server list 554 // download files found in the specified directory will be moved under the 555 // data root directory. 556 // 557 // Warning: if the directory is empty after obfuscated server 558 // list files are moved, then it will be deleted. 559 // 560 // Note: see comment for config.Commit() for a description of how file 561 // migrations are performed. 562 MigrateObfuscatedServerListDownloadDirectory string 563 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 572 // 573 // The following parameters are deprecated. 574 // 575 576 // DataStoreDirectory is the directory in which to store the persistent 577 // database, which contains information such as server entries. By 578 // default, current working directory. 579 // 580 // Deprecated: 581 // Use MigrateDataStoreDirectory. When MigrateDataStoreDirectory 582 // is set, this parameter is ignored. 583 // 584 // DataStoreDirectory has been subsumed by the new data root directory, 585 // which is configured with DataRootDirectory. If set, datastore files 586 // found in the specified directory will be moved under the data root 587 // directory. 588 DataStoreDirectory string 589 590 // RemoteServerListDownloadFilename specifies a target filename for 591 // storing the remote server list download. Data is stored in co-located 592 // files (RemoteServerListDownloadFilename.part*) to allow for resumable 593 // downloading. 594 // 595 // Deprecated: 596 // Use MigrateRemoteServerListDownloadFilename. When 597 // MigrateRemoteServerListDownloadFilename is set, this parameter is 598 // ignored. 599 // 600 // If set, remote server list download files found at the specified path 601 // will be moved under the data root directory. 602 RemoteServerListDownloadFilename string 603 604 // ObfuscatedServerListDownloadDirectory specifies a target directory for 605 // storing the obfuscated remote server list downloads. Data is stored in 606 // co-located files (<OSL filename>.part*) to allow for resumable 607 // downloading. 608 // 609 // Deprecated: 610 // Use MigrateObfuscatedServerListDownloadDirectory. When 611 // MigrateObfuscatedServerListDownloadDirectory is set, this parameter is 612 // ignored. 613 // 614 // If set, obfuscated server list download files found at the specified path 615 // will be moved under the data root directory. 616 ObfuscatedServerListDownloadDirectory string 617 618 // UpgradeDownloadFilename is the local target filename for an upgrade 619 // download. This parameter is required when UpgradeDownloadURLs (or 620 // UpgradeDownloadUrl) is specified. Data is stored in co-located files 621 // (UpgradeDownloadFilename.part*) to allow for resumable downloading. 622 // 623 // Deprecated: 624 // Use MigrateUpgradeDownloadFilename. When MigrateUpgradeDownloadFilename 625 // is set, this parameter is ignored. 626 // 627 // If set, upgrade download files found at the specified path will be moved 628 // under the data root directory. 629 UpgradeDownloadFilename string 630 631 // TunnelProtocol indicates which protocol to use. For the default, "", 632 // all protocols are used. 633 // 634 // Deprecated: Use LimitTunnelProtocols. When LimitTunnelProtocols is not 635 // nil, this parameter is ignored. 636 TunnelProtocol string 637 638 // Deprecated: Use CustomHeaders. When CustomHeaders is not nil, this 639 // parameter is ignored. 640 UpstreamProxyCustomHeaders http.Header 641 642 // RemoteServerListUrl is a URL which specifies a location to fetch out- 643 // of-band server entries. This facility is used when a tunnel cannot be 644 // established to known servers. This value is supplied by and depends on 645 // the Psiphon Network, and is typically embedded in the client binary. 646 // 647 // Deprecated: Use RemoteServerListURLs. When RemoteServerListURLs is not 648 // nil, this parameter is ignored. 649 RemoteServerListUrl string 650 651 // ObfuscatedServerListRootURL is a URL which specifies the root location 652 // from which to fetch obfuscated server list files. This value is 653 // supplied by and depends on the Psiphon Network, and is typically 654 // embedded in the client binary. 655 // 656 // Deprecated: Use ObfuscatedServerListRootURLs. When 657 // ObfuscatedServerListRootURLs is not nil, this parameter is ignored. 658 ObfuscatedServerListRootURL string 659 660 // UpgradeDownloadUrl specifies a URL from which to download a host client 661 // upgrade file, when one is available. The core tunnel controller 662 // provides a resumable download facility which downloads this resource 663 // and emits a notice when complete. This value is supplied by and depends 664 // on the Psiphon Network, and is typically embedded in the client binary. 665 // 666 // Deprecated: Use UpgradeDownloadURLs. When UpgradeDownloadURLs is not 667 // nil, this parameter is ignored. 668 UpgradeDownloadUrl string 669 670 // 671 // The following parameters are for testing purposes. 672 // 673 674 // TransformHostNameProbability is for testing purposes. 675 TransformHostNameProbability *float64 676 677 // FragmentorProbability and associated Fragmentor fields are for testing 678 // purposes. 679 FragmentorProbability *float64 680 FragmentorLimitProtocols []string 681 FragmentorMinTotalBytes *int 682 FragmentorMaxTotalBytes *int 683 FragmentorMinWriteBytes *int 684 FragmentorMaxWriteBytes *int 685 FragmentorMinDelayMicroseconds *int 686 FragmentorMaxDelayMicroseconds *int 687 688 // MeekTrafficShapingProbability and associated fields are for testing 689 // purposes. 690 MeekTrafficShapingProbability *float64 691 MeekTrafficShapingLimitProtocols []string 692 MeekMinTLSPadding *int 693 MeekMaxTLSPadding *int 694 MeekMinLimitRequestPayloadLength *int 695 MeekMaxLimitRequestPayloadLength *int 696 MeekRedialTLSProbability *float64 697 MeekAlternateCookieNameProbability *float64 698 MeekAlternateContentTypeProbability *float64 699 700 // ObfuscatedSSHAlgorithms and associated ObfuscatedSSH fields are for 701 // testing purposes. If specified, ObfuscatedSSHAlgorithms must have 4 SSH 702 // KEX elements in order: the kex algorithm, cipher, MAC, and server host 703 // key algorithm. 704 ObfuscatedSSHAlgorithms []string 705 ObfuscatedSSHMinPadding *int 706 ObfuscatedSSHMaxPadding *int 707 708 // LivenessTestMinUpstreamBytes and other LivenessTest fields are for 709 // testing purposes. 710 LivenessTestMinUpstreamBytes *int 711 LivenessTestMaxUpstreamBytes *int 712 LivenessTestMinDownstreamBytes *int 713 LivenessTestMaxDownstreamBytes *int 714 715 // ReplayCandidateCount and other Replay fields are for testing purposes. 716 ReplayCandidateCount *int 717 ReplayDialParametersTTLSeconds *int 718 ReplayTargetUpstreamBytes *int 719 ReplayTargetDownstreamBytes *int 720 ReplayTargetTunnelDurationSeconds *int 721 ReplayLaterRoundMoveToFrontProbability *float64 722 ReplayRetainFailedProbability *float64 723 724 // NetworkLatencyMultiplierMin and other NetworkLatencyMultiplier fields are 725 // for testing purposes. 726 NetworkLatencyMultiplierMin float64 727 NetworkLatencyMultiplierMax float64 728 NetworkLatencyMultiplierLambda float64 729 730 // UseOnlyCustomTLSProfiles and other TLS configuration fields are for 731 // testing purposes. 732 UseOnlyCustomTLSProfiles *bool 733 CustomTLSProfiles protocol.CustomTLSProfiles 734 SelectRandomizedTLSProfileProbability *float64 735 NoDefaultTLSSessionIDProbability *float64 736 DisableFrontingProviderTLSProfiles protocol.LabeledTLSProfiles 737 738 // ClientBurstUpstreamTargetBytes and other burst metric fields are for 739 // testing purposes. 740 ClientBurstUpstreamTargetBytes *int 741 ClientBurstUpstreamDeadlineMilliseconds *int 742 ClientBurstDownstreamTargetBytes *int 743 ClientBurstDownstreamDeadlineMilliseconds *int 744 745 // ApplicationParameters is for testing purposes. 746 ApplicationParameters parameters.KeyValues 747 748 // CustomHostNameRegexes and other custom host name fields are for testing 749 // purposes. 750 CustomHostNameRegexes []string 751 CustomHostNameProbability *float64 752 CustomHostNameLimitProtocols []string 753 754 // ConjureCachedRegistrationTTLSeconds and other Conjure fields are for 755 // testing purposes. 756 ConjureCachedRegistrationTTLSeconds *int 757 ConjureAPIRegistrarBidirectionalURL string 758 ConjureAPIRegistrarFrontingSpecs parameters.FrontingSpecs 759 ConjureAPIRegistrarMinDelayMilliseconds *int 760 ConjureAPIRegistrarMaxDelayMilliseconds *int 761 ConjureDecoyRegistrarProbability *float64 762 ConjureDecoyRegistrarWidth *int 763 ConjureDecoyRegistrarMinDelayMilliseconds *int 764 ConjureDecoyRegistrarMaxDelayMilliseconds *int 765 766 // HoldOffTunnelMinDurationMilliseconds and other HoldOffTunnel fields are 767 // for testing purposes. 768 HoldOffTunnelMinDurationMilliseconds *int 769 HoldOffTunnelMaxDurationMilliseconds *int 770 HoldOffTunnelProtocols []string 771 HoldOffTunnelFrontingProviderIDs []string 772 HoldOffTunnelProbability *float64 773 774 // RestrictFrontingProviderIDs and other RestrictFrontingProviderIDs fields 775 // are for testing purposes. 776 RestrictFrontingProviderIDs []string 777 RestrictFrontingProviderIDsClientProbability *float64 778 779 // UpstreamProxyAllowAllServerEntrySources is for testing purposes. 780 UpstreamProxyAllowAllServerEntrySources *bool 781 782 // LimitTunnelDialPortNumbers is for testing purposes. 783 LimitTunnelDialPortNumbers parameters.TunnelProtocolPortLists 784 785 // QUICDisablePathMTUDiscoveryProbability is for testing purposes. 786 QUICDisablePathMTUDiscoveryProbability *float64 787 788 // DNSResolverAttemptsPerServer and other DNSResolver fields are for 789 // testing purposes. 790 DNSResolverAttemptsPerServer *int 791 DNSResolverAttemptsPerPreferredServer *int 792 DNSResolverRequestTimeoutMilliseconds *int 793 DNSResolverAwaitTimeoutMilliseconds *int 794 DNSResolverPreresolvedIPAddressCIDRs parameters.LabeledCIDRs 795 DNSResolverPreresolvedIPAddressProbability *float64 796 DNSResolverAlternateServers []string 797 DNSResolverPreferredAlternateServers []string 798 DNSResolverPreferAlternateServerProbability *float64 799 DNSResolverProtocolTransformSpecs transforms.Specs 800 DNSResolverProtocolTransformScopedSpecNames transforms.ScopedSpecNames 801 DNSResolverProtocolTransformProbability *float64 802 DNSResolverIncludeEDNS0Probability *float64 803 DNSResolverCacheExtensionInitialTTLMilliseconds *int 804 DNSResolverCacheExtensionVerifiedTTLMilliseconds *int 805 806 // params is the active parameters.Parameters with defaults, config values, 807 // and, optionally, tactics applied. 808 // 809 // New tactics must be applied by calling Config.SetParameters; calling 810 // params.Set directly will fail to add config values. 811 params *parameters.Parameters 812 813 dialParametersHash []byte 814 815 dynamicConfigMutex sync.Mutex 816 sponsorID string 817 authorizations []string 818 819 deviceBinder DeviceBinder 820 networkIDGetter NetworkIDGetter 821 822 clientFeatures []string 823 824 resolverMutex sync.Mutex 825 resolver *resolver.Resolver 826 827 committed bool 828 829 loadTimestamp string 830 } 831 832 // Config field which specifies if notice files should be used and at which 833 // frequency and size they should be rotated. 834 // 835 // If either RotatingFileSize or RotatingSyncFrequency are <= 0, default values 836 // are used. 837 // 838 // See comment for setNoticeFiles in notice.go for further details. 839 type UseNoticeFiles struct { 840 RotatingFileSize int 841 RotatingSyncFrequency int 842 } 843 844 // LoadConfig parses a JSON format Psiphon config JSON string and returns a 845 // Config struct populated with config values. 846 // 847 // The Config struct may then be programmatically populated with additional 848 // values, including callbacks such as DeviceBinder. 849 // 850 // Before using the Config, Commit must be called, which will perform further 851 // validation and initialize internal data structures. 852 func LoadConfig(configJson []byte) (*Config, error) { 853 854 var config Config 855 err := json.Unmarshal(configJson, &config) 856 if err != nil { 857 return nil, errors.Trace(err) 858 } 859 860 config.loadTimestamp = common.TruncateTimestampToHour( 861 common.GetCurrentTimestamp()) 862 863 return &config, nil 864 } 865 866 // IsCommitted checks if Commit was called. 867 func (config *Config) IsCommitted() bool { 868 return config.committed 869 } 870 871 // Commit validates Config fields finalizes initialization. 872 // 873 // Config fields should not be set after calling Config, as any changes may 874 // not be reflected in internal data structures. 875 // 876 // If migrateFromLegacyFields is set to true, then an attempt to migrate from 877 // legacy fields is made. 878 // 879 // Migration from legacy fields: 880 // Config fields of the naming Migrate* (e.g. MigrateDataStoreDirectory) specify 881 // a file migration operation which should be performed. These fields correspond 882 // to deprecated fields, which previously could be used to specify where Psiphon 883 // stored different sets of persistent files (e.g. MigrateDataStoreDirectory 884 // corresponds to the deprecated field DataStoreDirectory). 885 // 886 // Psiphon now stores all persistent data under the configurable 887 // DataRootDirectory (see Config.DataRootDirectory). The deprecated fields, and 888 // corresponding Migrate* fields, are now used to specify the file or directory 889 // path where, or under which, persistent files and directories created by 890 // previous versions of Psiphon exist, so they can be moved under the 891 // DataRootDirectory. 892 // 893 // For each migration operation: 894 // - In the case of directories that could have defaulted to the current working 895 // directory, persistent files and directories created by Psiphon are 896 // precisely targeted to avoid moving files which were not created by Psiphon. 897 // - If no file is found at the specified path, or an error is encountered while 898 // migrating the file, then an error is logged and execution continues 899 // normally. 900 // 901 // A sentinel file which signals that file migration has been completed, and 902 // should not be attempted again, is created under DataRootDirectory after one 903 // full pass through Commit(), regardless of whether file migration succeeds or 904 // fails. It is better to not endlessly retry file migrations on each Commit() 905 // because file system errors are expected to be rare and persistent files will 906 // be re-populated over time. 907 func (config *Config) Commit(migrateFromLegacyFields bool) error { 908 909 // Do SetEmitDiagnosticNotices first, to ensure config file errors are 910 // emitted. 911 if config.EmitDiagnosticNotices { 912 SetEmitDiagnosticNotices( 913 true, config.EmitDiagnosticNetworkParameters) 914 } 915 916 // Migrate and set notice files before any operations that may emit an 917 // error. This is to ensure config file errors are written to file when 918 // notice files are configured with config.UseNoticeFiles. 919 // 920 // Note: 921 // Errors encountered while configuring the data directory cannot be written 922 // to notice files. This is because notices files are created within the 923 // data directory. 924 925 if config.DataRootDirectory == "" { 926 wd, err := os.Getwd() 927 if err != nil { 928 return errors.Trace(common.RedactFilePathsError(err)) 929 } 930 config.DataRootDirectory = wd 931 } 932 933 // Create root directory 934 dataDirectoryPath := config.GetPsiphonDataDirectory() 935 if !common.FileExists(dataDirectoryPath) { 936 err := os.Mkdir(dataDirectoryPath, os.ModePerm) 937 if err != nil { 938 return errors.Tracef( 939 "failed to create datastore directory with error: %s", 940 common.RedactFilePathsError(err, dataDirectoryPath)) 941 } 942 } 943 944 // Check if the migration from legacy config fields has already been 945 // completed. See the Migrate* config fields for more details. 946 migrationCompleteFilePath := filepath.Join(config.GetPsiphonDataDirectory(), "migration_complete") 947 needMigration := !common.FileExists(migrationCompleteFilePath) 948 949 // Collect notices to emit them after notice files are set 950 var noticeMigrationAlertMsgs []string 951 var noticeMigrationInfoMsgs []string 952 953 // Migrate notices first to ensure notice files are used for notices if 954 // UseNoticeFiles is set. 955 homepageFilePath := config.GetHomePageFilename() 956 noticesFilePath := config.GetNoticesFilename() 957 958 if migrateFromLegacyFields { 959 if needMigration { 960 961 // Move notice files that exist at legacy file paths under the data root 962 // directory. 963 964 noticeMigrationInfoMsgs = append(noticeMigrationInfoMsgs, "Config migration: need migration") 965 noticeMigrations := migrationsFromLegacyNoticeFilePaths(config) 966 967 successfulMigrations := 0 968 969 for _, migration := range noticeMigrations { 970 err := DoFileMigration(migration) 971 if err != nil { 972 alertMsg := fmt.Sprintf("Config migration: %s", errors.Trace(err)) 973 noticeMigrationAlertMsgs = append(noticeMigrationAlertMsgs, alertMsg) 974 } else { 975 successfulMigrations += 1 976 } 977 } 978 infoMsg := fmt.Sprintf("Config migration: %d/%d notice files successfully migrated", successfulMigrations, len(noticeMigrations)) 979 noticeMigrationInfoMsgs = append(noticeMigrationInfoMsgs, infoMsg) 980 } else { 981 noticeMigrationInfoMsgs = append(noticeMigrationInfoMsgs, "Config migration: migration already completed") 982 } 983 } 984 985 if config.UseNoticeFiles != nil { 986 setNoticeFiles( 987 homepageFilePath, 988 noticesFilePath, 989 config.UseNoticeFiles.RotatingFileSize, 990 config.UseNoticeFiles.RotatingSyncFrequency) 991 } 992 993 // Emit notices now that notice files are set if configured 994 for _, msg := range noticeMigrationAlertMsgs { 995 NoticeWarning(msg) 996 } 997 for _, msg := range noticeMigrationInfoMsgs { 998 NoticeInfo(msg) 999 } 1000 1001 // Promote legacy fields. 1002 1003 if config.CustomHeaders == nil { 1004 config.CustomHeaders = config.UpstreamProxyCustomHeaders 1005 config.UpstreamProxyCustomHeaders = nil 1006 } 1007 1008 if config.RemoteServerListUrl != "" && config.RemoteServerListURLs == nil { 1009 config.RemoteServerListURLs = promoteLegacyTransferURL(config.RemoteServerListUrl) 1010 } 1011 1012 if config.ObfuscatedServerListRootURL != "" && config.ObfuscatedServerListRootURLs == nil { 1013 config.ObfuscatedServerListRootURLs = promoteLegacyTransferURL(config.ObfuscatedServerListRootURL) 1014 } 1015 1016 if config.UpgradeDownloadUrl != "" && config.UpgradeDownloadURLs == nil { 1017 config.UpgradeDownloadURLs = promoteLegacyTransferURL(config.UpgradeDownloadUrl) 1018 } 1019 1020 if config.TunnelProtocol != "" && len(config.LimitTunnelProtocols) == 0 { 1021 config.LimitTunnelProtocols = []string{config.TunnelProtocol} 1022 } 1023 1024 if config.DataStoreDirectory != "" && config.MigrateDataStoreDirectory == "" { 1025 config.MigrateDataStoreDirectory = config.DataStoreDirectory 1026 } 1027 1028 if config.RemoteServerListDownloadFilename != "" && config.MigrateRemoteServerListDownloadFilename == "" { 1029 config.MigrateRemoteServerListDownloadFilename = config.RemoteServerListDownloadFilename 1030 } 1031 1032 if config.ObfuscatedServerListDownloadDirectory != "" && config.MigrateObfuscatedServerListDownloadDirectory == "" { 1033 config.MigrateObfuscatedServerListDownloadDirectory = config.ObfuscatedServerListDownloadDirectory 1034 } 1035 1036 if config.UpgradeDownloadFilename != "" && config.MigrateUpgradeDownloadFilename == "" { 1037 config.MigrateUpgradeDownloadFilename = config.UpgradeDownloadFilename 1038 } 1039 1040 // Supply default values. 1041 1042 // Create datastore directory. 1043 dataStoreDirectoryPath := config.GetDataStoreDirectory() 1044 if !common.FileExists(dataStoreDirectoryPath) { 1045 err := os.Mkdir(dataStoreDirectoryPath, os.ModePerm) 1046 if err != nil { 1047 return errors.Tracef( 1048 "failed to create datastore directory with error: %s", 1049 common.RedactFilePathsError(err, dataStoreDirectoryPath)) 1050 } 1051 } 1052 1053 // Create OSL directory. 1054 oslDirectoryPath := config.GetObfuscatedServerListDownloadDirectory() 1055 if !common.FileExists(oslDirectoryPath) { 1056 err := os.Mkdir(oslDirectoryPath, os.ModePerm) 1057 if err != nil { 1058 return errors.Tracef( 1059 "failed to create osl directory with error: %s", 1060 common.RedactFilePathsError(err, oslDirectoryPath)) 1061 } 1062 } 1063 1064 if config.ClientVersion == "" { 1065 config.ClientVersion = "0" 1066 } 1067 1068 if config.TunnelPoolSize == 0 { 1069 config.TunnelPoolSize = TUNNEL_POOL_SIZE 1070 } 1071 1072 // Validate config fields. 1073 1074 if !common.FileExists(config.DataRootDirectory) { 1075 return errors.TraceNew("DataRootDirectory does not exist") 1076 } 1077 1078 if config.PropagationChannelId == "" { 1079 return errors.TraceNew("propagation channel ID is missing from the configuration file") 1080 } 1081 if config.SponsorId == "" { 1082 return errors.TraceNew("sponsor ID is missing from the configuration file") 1083 } 1084 1085 _, err := strconv.Atoi(config.ClientVersion) 1086 if err != nil { 1087 return errors.Tracef("invalid client version: %s", err) 1088 } 1089 1090 if !common.Contains( 1091 []string{"", protocol.PSIPHON_SSH_API_PROTOCOL, protocol.PSIPHON_WEB_API_PROTOCOL}, 1092 config.TargetApiProtocol) { 1093 1094 return errors.TraceNew("invalid TargetApiProtocol") 1095 } 1096 1097 if !config.DisableRemoteServerListFetcher { 1098 1099 if config.RemoteServerListURLs != nil { 1100 if config.RemoteServerListSignaturePublicKey == "" { 1101 return errors.TraceNew("missing RemoteServerListSignaturePublicKey") 1102 } 1103 } 1104 1105 if config.ObfuscatedServerListRootURLs != nil { 1106 if config.RemoteServerListSignaturePublicKey == "" { 1107 return errors.TraceNew("missing RemoteServerListSignaturePublicKey") 1108 } 1109 } 1110 } 1111 1112 if config.UpgradeDownloadURLs != nil { 1113 if config.UpgradeDownloadClientVersionHeader == "" { 1114 return errors.TraceNew("missing UpgradeDownloadClientVersionHeader") 1115 } 1116 } 1117 1118 if config.FeedbackUploadURLs != nil { 1119 if config.FeedbackEncryptionPublicKey == "" { 1120 return errors.TraceNew("missing FeedbackEncryptionPublicKey") 1121 } 1122 } 1123 1124 // This constraint is expected by logic in Controller.runTunnels(). 1125 1126 if config.PacketTunnelTunFileDescriptor > 0 && config.TunnelPoolSize != 1 { 1127 return errors.TraceNew("packet tunnel mode requires TunnelPoolSize to be 1") 1128 } 1129 1130 // SessionID must be PSIPHON_API_CLIENT_SESSION_ID_LENGTH lowercase hex-encoded bytes. 1131 1132 if config.SessionID == "" { 1133 sessionID, err := MakeSessionId() 1134 if err != nil { 1135 return errors.Trace(err) 1136 } 1137 config.SessionID = sessionID 1138 } 1139 1140 if len(config.SessionID) != 2*protocol.PSIPHON_API_CLIENT_SESSION_ID_LENGTH || 1141 -1 != strings.IndexFunc(config.SessionID, func(c rune) bool { 1142 return !unicode.Is(unicode.ASCII_Hex_Digit, c) || unicode.IsUpper(c) 1143 }) { 1144 return errors.TraceNew("invalid SessionID") 1145 } 1146 1147 config.params, err = parameters.NewParameters( 1148 func(err error) { 1149 NoticeWarning("Parameters getValue failed: %s", err) 1150 }) 1151 if err != nil { 1152 return errors.Trace(err) 1153 } 1154 1155 if config.ObfuscatedSSHAlgorithms != nil && 1156 len(config.ObfuscatedSSHAlgorithms) != 4 { 1157 // TODO: validate each algorithm? 1158 return errors.TraceNew("invalid ObfuscatedSSHAlgorithms") 1159 } 1160 1161 // parametersParameters.Set will validate the config fields applied to 1162 // parametersParameters. 1163 1164 err = config.SetParameters("", false, nil) 1165 if err != nil { 1166 return errors.Trace(err) 1167 } 1168 1169 // Calculate and set the dial parameters hash. After this point, related 1170 // config fields must not change. 1171 1172 config.setDialParametersHash() 1173 1174 // Set defaults for dynamic config fields. 1175 1176 config.SetDynamicConfig(config.SponsorId, config.Authorizations) 1177 1178 // Initialize config.deviceBinder and config.config.networkIDGetter. These 1179 // wrap config.DeviceBinder and config.NetworkIDGetter/NetworkID with 1180 // loggers. 1181 // 1182 // New variables are set to avoid mutating input config fields. 1183 // Internally, code must use config.deviceBinder and 1184 // config.networkIDGetter and not the input/exported fields. 1185 1186 if config.DeviceBinder != nil { 1187 config.deviceBinder = newLoggingDeviceBinder(config.DeviceBinder) 1188 } 1189 1190 networkIDGetter := config.NetworkIDGetter 1191 1192 if networkIDGetter == nil { 1193 // Limitation: unlike NetworkIDGetter, which calls back to platform APIs 1194 // this method of network identification is not dynamic and will not reflect 1195 // network changes that occur while running. 1196 if config.NetworkID != "" { 1197 networkIDGetter = newStaticNetworkGetter(config.NetworkID) 1198 } else { 1199 networkIDGetter = newStaticNetworkGetter("UNKNOWN") 1200 } 1201 } 1202 1203 config.networkIDGetter = newLoggingNetworkIDGetter(networkIDGetter) 1204 1205 // Initialize config.clientFeatures, which adds feature names on top of 1206 // those specified by the host application in config.ClientFeatures. 1207 1208 config.clientFeatures = config.ClientFeatures 1209 1210 feature := "VPN" 1211 if config.DeviceBinder != nil && !common.Contains(config.clientFeatures, feature) { 1212 config.clientFeatures = append(config.clientFeatures, feature) 1213 } 1214 1215 // Migrate from old config fields. This results in files being moved under 1216 // a config specified data root directory. 1217 if migrateFromLegacyFields && needMigration { 1218 1219 // If unset, set MigrateDataStoreDirectory to the previous default value for 1220 // DataStoreDirectory to ensure that datastore files are migrated. 1221 if config.MigrateDataStoreDirectory == "" { 1222 wd, err := os.Getwd() 1223 if err != nil { 1224 return errors.Trace(err) 1225 } 1226 NoticeInfo("MigrateDataStoreDirectory unset, using working directory") 1227 config.MigrateDataStoreDirectory = wd 1228 } 1229 1230 // Move files that exist at legacy file paths under the data root 1231 // directory. 1232 1233 migrations, err := migrationsFromLegacyFilePaths(config) 1234 if err != nil { 1235 return errors.Trace(err) 1236 } 1237 1238 // Do migrations 1239 1240 successfulMigrations := 0 1241 for _, migration := range migrations { 1242 err := DoFileMigration(migration) 1243 if err != nil { 1244 NoticeWarning("Config migration: %s", errors.Trace(err)) 1245 } else { 1246 successfulMigrations += 1 1247 } 1248 } 1249 NoticeInfo(fmt.Sprintf( 1250 "Config migration: %d/%d legacy files successfully migrated", 1251 successfulMigrations, len(migrations))) 1252 1253 // Remove OSL directory if empty 1254 if config.MigrateObfuscatedServerListDownloadDirectory != "" { 1255 files, err := ioutil.ReadDir(config.MigrateObfuscatedServerListDownloadDirectory) 1256 if err != nil { 1257 NoticeWarning( 1258 "Error reading OSL directory: %s", 1259 errors.Trace(common.RedactFilePathsError(err, config.MigrateObfuscatedServerListDownloadDirectory))) 1260 } else if len(files) == 0 { 1261 err := os.Remove(config.MigrateObfuscatedServerListDownloadDirectory) 1262 if err != nil { 1263 NoticeWarning( 1264 "Error deleting empty OSL directory: %s", 1265 errors.Trace(common.RedactFilePathsError(err, config.MigrateObfuscatedServerListDownloadDirectory))) 1266 } 1267 } 1268 } 1269 1270 f, err := os.Create(migrationCompleteFilePath) 1271 if err != nil { 1272 NoticeWarning( 1273 "Config migration: failed to create migration completed file with error %s", 1274 errors.Trace(common.RedactFilePathsError(err, migrationCompleteFilePath))) 1275 } else { 1276 NoticeInfo("Config migration: completed") 1277 f.Close() 1278 } 1279 } 1280 1281 config.committed = true 1282 1283 return nil 1284 } 1285 1286 // GetParameters returns the current parameters.Parameters. 1287 func (config *Config) GetParameters() *parameters.Parameters { 1288 return config.params 1289 } 1290 1291 // SetParameters resets the parameters.Parameters to the default values, 1292 // applies any config file values, and then applies the input parameters (from 1293 // tactics, etc.) 1294 // 1295 // Set skipOnError to false when initially applying only config values, as 1296 // this will validate the values and should fail. Set skipOnError to true when 1297 // applying tactics to ignore invalid or unknown parameter values from tactics. 1298 // 1299 // In the case of applying tactics, do not call Config.parameters.Set 1300 // directly as this will not first apply config values. 1301 // 1302 // If there is an error, the existing Config.parameters are left 1303 // entirely unmodified. 1304 func (config *Config) SetParameters(tag string, skipOnError bool, applyParameters map[string]interface{}) error { 1305 1306 setParameters := []map[string]interface{}{config.makeConfigParameters()} 1307 if applyParameters != nil { 1308 setParameters = append(setParameters, applyParameters) 1309 } 1310 1311 counts, err := config.params.Set(tag, skipOnError, setParameters...) 1312 if err != nil { 1313 return errors.Trace(err) 1314 } 1315 1316 NoticeInfo("applied %v parameters with tag '%s'", counts, tag) 1317 1318 // Emit certain individual parameter values for quick reference in diagnostics. 1319 p := config.params.Get() 1320 NoticeInfo( 1321 "NetworkLatencyMultiplier Min/Max/Lambda: %f/%f/%f", 1322 p.Float(parameters.NetworkLatencyMultiplierMin), 1323 p.Float(parameters.NetworkLatencyMultiplierMax), 1324 p.Float(parameters.NetworkLatencyMultiplierLambda)) 1325 1326 // Application Parameters are feature flags/config info, delivered as Client 1327 // Parameters via tactics/etc., to be communicated to the outer application. 1328 // Emit these now, as notices. 1329 if p.WeightedCoinFlip(parameters.ApplicationParametersProbability) { 1330 NoticeApplicationParameters(p.KeyValues(parameters.ApplicationParameters)) 1331 } 1332 1333 return nil 1334 } 1335 1336 // SetResolver sets the current resolver. 1337 func (config *Config) SetResolver(resolver *resolver.Resolver) { 1338 config.resolverMutex.Lock() 1339 defer config.resolverMutex.Unlock() 1340 config.resolver = resolver 1341 } 1342 1343 // GetResolver returns the current resolver. May return nil. 1344 func (config *Config) GetResolver() *resolver.Resolver { 1345 config.resolverMutex.Lock() 1346 defer config.resolverMutex.Unlock() 1347 return config.resolver 1348 } 1349 1350 // SetDynamicConfig sets the current client sponsor ID and authorizations. 1351 // Invalid values for sponsor ID are ignored. The caller must not modify the 1352 // input authorizations slice. 1353 func (config *Config) SetDynamicConfig(sponsorID string, authorizations []string) { 1354 config.dynamicConfigMutex.Lock() 1355 defer config.dynamicConfigMutex.Unlock() 1356 if sponsorID != "" { 1357 config.sponsorID = sponsorID 1358 } 1359 config.authorizations = authorizations 1360 } 1361 1362 // GetSponsorID returns the current client sponsor ID. 1363 func (config *Config) GetSponsorID() string { 1364 config.dynamicConfigMutex.Lock() 1365 defer config.dynamicConfigMutex.Unlock() 1366 return config.sponsorID 1367 } 1368 1369 // IsSplitTunnelEnabled indicates if split tunnel mode is enabled, either for 1370 // the client's own country, a specified list of countries, or both. 1371 func (config *Config) IsSplitTunnelEnabled() bool { 1372 return config.SplitTunnelOwnRegion || len(config.SplitTunnelRegions) > 0 1373 } 1374 1375 // GetAuthorizations returns the current client authorizations. 1376 // The caller must not modify the returned slice. 1377 func (config *Config) GetAuthorizations() []string { 1378 config.dynamicConfigMutex.Lock() 1379 defer config.dynamicConfigMutex.Unlock() 1380 return config.authorizations 1381 } 1382 1383 // GetPsiphonDataDirectory returns the directory under which all persistent 1384 // files should be stored. This directory is created under 1385 // config.DataRootDirectory. The motivation for an additional directory is that 1386 // config.DataRootDirectory defaults to the current working directory, which may 1387 // include non-tunnel-core files that should be excluded from directory-spanning 1388 // operations (e.g. excluding all tunnel-core files from backup). 1389 func (config *Config) GetPsiphonDataDirectory() string { 1390 return filepath.Join(config.DataRootDirectory, PsiphonDataDirectoryName) 1391 } 1392 1393 // GetHomePageFilename the path where the homepage notices file will be created. 1394 func (config *Config) GetHomePageFilename() string { 1395 return filepath.Join(config.GetPsiphonDataDirectory(), HomepageFilename) 1396 } 1397 1398 // GetNoticesFilename returns the path where the notices file will be created. 1399 // When the file is rotated it will be moved to config.GetOldNoticesFilename(). 1400 func (config *Config) GetNoticesFilename() string { 1401 return filepath.Join(config.GetPsiphonDataDirectory(), NoticesFilename) 1402 } 1403 1404 // GetOldNoticeFilename returns the path where the rotated notices file will be 1405 // created. 1406 func (config *Config) GetOldNoticesFilename() string { 1407 return filepath.Join(config.GetPsiphonDataDirectory(), OldNoticesFilename) 1408 } 1409 1410 // GetDataStoreDirectory returns the directory in which the persistent database 1411 // will be stored. Created in Config.Commit(). The persistent database contains 1412 // information such as server entries. 1413 func (config *Config) GetDataStoreDirectory() string { 1414 return filepath.Join(config.GetPsiphonDataDirectory(), "datastore") 1415 } 1416 1417 // GetObfuscatedServerListDownloadDirectory returns the directory in which 1418 // obfuscated remote server list downloads will be stored. Created in 1419 // Config.Commit(). 1420 func (config *Config) GetObfuscatedServerListDownloadDirectory() string { 1421 return filepath.Join(config.GetPsiphonDataDirectory(), "osl") 1422 } 1423 1424 // GetRemoteServerListDownloadFilename returns the filename where the remote 1425 // server list download will be stored. Data is stored in co-located files 1426 // (RemoteServerListDownloadFilename.part*) to allow for resumable downloading. 1427 func (config *Config) GetRemoteServerListDownloadFilename() string { 1428 return filepath.Join(config.GetPsiphonDataDirectory(), "remote_server_list") 1429 } 1430 1431 // GetUpgradeDownloadFilename specifies the filename where upgrade downloads 1432 // will be stored. This filename is valid when UpgradeDownloadURLs 1433 // (or UpgradeDownloadUrl) is specified. Data is stored in co-located files 1434 // (UpgradeDownloadFilename.part*) to allow for resumable downloading. 1435 func (config *Config) GetUpgradeDownloadFilename() string { 1436 return filepath.Join(config.GetPsiphonDataDirectory(), UpgradeDownloadFilename) 1437 } 1438 1439 // UseUpstreamProxy indicates if an upstream proxy has been 1440 // configured. 1441 func (config *Config) UseUpstreamProxy() bool { 1442 return config.UpstreamProxyURL != "" 1443 } 1444 1445 // GetNetworkID returns the current network ID. When NetworkIDGetter 1446 // is set, this calls into the host application; otherwise, a default 1447 // value is returned. 1448 func (config *Config) GetNetworkID() string { 1449 return config.networkIDGetter.GetNetworkID() 1450 } 1451 1452 func (config *Config) makeConfigParameters() map[string]interface{} { 1453 1454 // Build set of config values to apply to parameters. 1455 // 1456 // Note: names of some config fields such as 1457 // StaggerConnectionWorkersMilliseconds and LimitMeekBufferSizes have 1458 // changed in the parameters. The existing config fields are retained for 1459 // backwards compatibility. 1460 1461 applyParameters := make(map[string]interface{}) 1462 1463 // To support platform clients that configure NetworkLatencyMultiplier, set 1464 // the NetworkLatencyMultiplierMin/NetworkLatencyMultiplierMax range to the 1465 // specified value. Also set the older NetworkLatencyMultiplier tactic, since 1466 // that will be used in the case of replaying with dial parameters persisted 1467 // by an older client version. 1468 if config.NetworkLatencyMultiplier > 0.0 { 1469 applyParameters[parameters.NetworkLatencyMultiplier] = config.NetworkLatencyMultiplier 1470 applyParameters[parameters.NetworkLatencyMultiplierMin] = config.NetworkLatencyMultiplier 1471 applyParameters[parameters.NetworkLatencyMultiplierMax] = config.NetworkLatencyMultiplier 1472 } 1473 1474 if config.NetworkLatencyMultiplierMin > 0.0 { 1475 applyParameters[parameters.NetworkLatencyMultiplierMin] = config.NetworkLatencyMultiplierMin 1476 } 1477 1478 if config.NetworkLatencyMultiplierMax > 0.0 { 1479 applyParameters[parameters.NetworkLatencyMultiplierMax] = config.NetworkLatencyMultiplierMax 1480 } 1481 1482 if config.NetworkLatencyMultiplierLambda > 0.0 { 1483 applyParameters[parameters.NetworkLatencyMultiplierLambda] = config.NetworkLatencyMultiplierLambda 1484 } 1485 1486 if len(config.LimitTunnelProtocols) > 0 { 1487 applyParameters[parameters.LimitTunnelProtocols] = protocol.TunnelProtocols(config.LimitTunnelProtocols) 1488 } 1489 1490 if len(config.InitialLimitTunnelProtocols) > 0 && config.InitialLimitTunnelProtocolsCandidateCount > 0 { 1491 applyParameters[parameters.InitialLimitTunnelProtocols] = protocol.TunnelProtocols(config.InitialLimitTunnelProtocols) 1492 applyParameters[parameters.InitialLimitTunnelProtocolsCandidateCount] = config.InitialLimitTunnelProtocolsCandidateCount 1493 } 1494 1495 if len(config.LimitTLSProfiles) > 0 { 1496 applyParameters[parameters.LimitTLSProfiles] = protocol.TunnelProtocols(config.LimitTLSProfiles) 1497 } 1498 1499 if len(config.LimitQUICVersions) > 0 { 1500 applyParameters[parameters.LimitQUICVersions] = protocol.QUICVersions(config.LimitQUICVersions) 1501 } 1502 1503 if config.EstablishTunnelTimeoutSeconds != nil { 1504 applyParameters[parameters.EstablishTunnelTimeout] = fmt.Sprintf("%ds", *config.EstablishTunnelTimeoutSeconds) 1505 } 1506 1507 if config.EstablishTunnelServerAffinityGracePeriodMilliseconds != nil { 1508 applyParameters[parameters.EstablishTunnelServerAffinityGracePeriod] = fmt.Sprintf("%dms", *config.EstablishTunnelServerAffinityGracePeriodMilliseconds) 1509 } 1510 1511 if config.EstablishTunnelPausePeriodSeconds != nil { 1512 applyParameters[parameters.EstablishTunnelPausePeriod] = fmt.Sprintf("%ds", *config.EstablishTunnelPausePeriodSeconds) 1513 } 1514 1515 if config.ConnectionWorkerPoolSize != 0 { 1516 applyParameters[parameters.ConnectionWorkerPoolSize] = config.ConnectionWorkerPoolSize 1517 } 1518 1519 if config.TunnelPoolSize != 0 { 1520 applyParameters[parameters.TunnelPoolSize] = config.TunnelPoolSize 1521 } 1522 1523 if config.StaggerConnectionWorkersMilliseconds > 0 { 1524 applyParameters[parameters.StaggerConnectionWorkersPeriod] = fmt.Sprintf("%dms", config.StaggerConnectionWorkersMilliseconds) 1525 } 1526 1527 if config.LimitIntensiveConnectionWorkers > 0 { 1528 applyParameters[parameters.LimitIntensiveConnectionWorkers] = config.LimitIntensiveConnectionWorkers 1529 } 1530 1531 applyParameters[parameters.MeekLimitBufferSizes] = config.LimitMeekBufferSizes 1532 1533 applyParameters[parameters.IgnoreHandshakeStatsRegexps] = config.IgnoreHandshakeStatsRegexps 1534 1535 if config.EstablishTunnelTimeoutSeconds != nil { 1536 applyParameters[parameters.EstablishTunnelTimeout] = fmt.Sprintf("%ds", *config.EstablishTunnelTimeoutSeconds) 1537 } 1538 1539 if config.FetchRemoteServerListRetryPeriodMilliseconds != nil { 1540 applyParameters[parameters.FetchRemoteServerListRetryPeriod] = fmt.Sprintf("%dms", *config.FetchRemoteServerListRetryPeriodMilliseconds) 1541 } 1542 1543 if config.FetchUpgradeRetryPeriodMilliseconds != nil { 1544 applyParameters[parameters.FetchUpgradeRetryPeriod] = fmt.Sprintf("%dms", *config.FetchUpgradeRetryPeriodMilliseconds) 1545 } 1546 1547 if !config.DisableRemoteServerListFetcher { 1548 1549 if config.RemoteServerListURLs != nil { 1550 applyParameters[parameters.RemoteServerListSignaturePublicKey] = config.RemoteServerListSignaturePublicKey 1551 applyParameters[parameters.RemoteServerListURLs] = config.RemoteServerListURLs 1552 } 1553 1554 if config.ObfuscatedServerListRootURLs != nil { 1555 applyParameters[parameters.RemoteServerListSignaturePublicKey] = config.RemoteServerListSignaturePublicKey 1556 applyParameters[parameters.ObfuscatedServerListRootURLs] = config.ObfuscatedServerListRootURLs 1557 } 1558 1559 } 1560 1561 if config.UpgradeDownloadURLs != nil { 1562 applyParameters[parameters.UpgradeDownloadClientVersionHeader] = config.UpgradeDownloadClientVersionHeader 1563 applyParameters[parameters.UpgradeDownloadURLs] = config.UpgradeDownloadURLs 1564 } 1565 1566 if len(config.FeedbackUploadURLs) > 0 { 1567 applyParameters[parameters.FeedbackUploadURLs] = config.FeedbackUploadURLs 1568 } 1569 1570 if config.FeedbackEncryptionPublicKey != "" { 1571 applyParameters[parameters.FeedbackEncryptionPublicKey] = config.FeedbackEncryptionPublicKey 1572 } 1573 1574 applyParameters[parameters.TunnelRateLimits] = config.RateLimits 1575 1576 if config.TransformHostNameProbability != nil { 1577 applyParameters[parameters.TransformHostNameProbability] = *config.TransformHostNameProbability 1578 } 1579 1580 if config.FragmentorProbability != nil { 1581 applyParameters[parameters.FragmentorProbability] = *config.FragmentorProbability 1582 } 1583 1584 if len(config.FragmentorLimitProtocols) > 0 { 1585 applyParameters[parameters.FragmentorLimitProtocols] = protocol.TunnelProtocols(config.FragmentorLimitProtocols) 1586 } 1587 1588 if config.FragmentorMinTotalBytes != nil { 1589 applyParameters[parameters.FragmentorMinTotalBytes] = *config.FragmentorMinTotalBytes 1590 } 1591 1592 if config.FragmentorMaxTotalBytes != nil { 1593 applyParameters[parameters.FragmentorMaxTotalBytes] = *config.FragmentorMaxTotalBytes 1594 } 1595 1596 if config.FragmentorMinWriteBytes != nil { 1597 applyParameters[parameters.FragmentorMinWriteBytes] = *config.FragmentorMinWriteBytes 1598 } 1599 1600 if config.FragmentorMaxWriteBytes != nil { 1601 applyParameters[parameters.FragmentorMaxWriteBytes] = *config.FragmentorMaxWriteBytes 1602 } 1603 1604 if config.FragmentorMinDelayMicroseconds != nil { 1605 applyParameters[parameters.FragmentorMinDelay] = fmt.Sprintf("%dus", *config.FragmentorMinDelayMicroseconds) 1606 } 1607 1608 if config.FragmentorMaxDelayMicroseconds != nil { 1609 applyParameters[parameters.FragmentorMaxDelay] = fmt.Sprintf("%dus", *config.FragmentorMaxDelayMicroseconds) 1610 } 1611 1612 if config.MeekTrafficShapingProbability != nil { 1613 applyParameters[parameters.MeekTrafficShapingProbability] = *config.MeekTrafficShapingProbability 1614 } 1615 1616 if len(config.MeekTrafficShapingLimitProtocols) > 0 { 1617 applyParameters[parameters.MeekTrafficShapingLimitProtocols] = protocol.TunnelProtocols(config.MeekTrafficShapingLimitProtocols) 1618 } 1619 1620 if config.MeekMinTLSPadding != nil { 1621 applyParameters[parameters.MeekMinTLSPadding] = *config.MeekMinTLSPadding 1622 } 1623 1624 if config.MeekMaxTLSPadding != nil { 1625 applyParameters[parameters.MeekMaxTLSPadding] = *config.MeekMaxTLSPadding 1626 } 1627 1628 if config.MeekMinLimitRequestPayloadLength != nil { 1629 applyParameters[parameters.MeekMinLimitRequestPayloadLength] = *config.MeekMinLimitRequestPayloadLength 1630 } 1631 1632 if config.MeekMaxLimitRequestPayloadLength != nil { 1633 applyParameters[parameters.MeekMaxLimitRequestPayloadLength] = *config.MeekMaxLimitRequestPayloadLength 1634 } 1635 1636 if config.MeekRedialTLSProbability != nil { 1637 applyParameters[parameters.MeekRedialTLSProbability] = *config.MeekRedialTLSProbability 1638 } 1639 1640 if config.MeekAlternateCookieNameProbability != nil { 1641 applyParameters[parameters.MeekAlternateCookieNameProbability] = *config.MeekAlternateCookieNameProbability 1642 } 1643 1644 if config.MeekAlternateContentTypeProbability != nil { 1645 applyParameters[parameters.MeekAlternateContentTypeProbability] = *config.MeekAlternateContentTypeProbability 1646 } 1647 1648 if config.ObfuscatedSSHMinPadding != nil { 1649 applyParameters[parameters.ObfuscatedSSHMinPadding] = *config.ObfuscatedSSHMinPadding 1650 } 1651 1652 if config.ObfuscatedSSHMaxPadding != nil { 1653 applyParameters[parameters.ObfuscatedSSHMaxPadding] = *config.ObfuscatedSSHMaxPadding 1654 } 1655 1656 if config.LivenessTestMinUpstreamBytes != nil { 1657 applyParameters[parameters.LivenessTestMinUpstreamBytes] = *config.LivenessTestMinUpstreamBytes 1658 } 1659 1660 if config.LivenessTestMaxUpstreamBytes != nil { 1661 applyParameters[parameters.LivenessTestMaxUpstreamBytes] = *config.LivenessTestMaxUpstreamBytes 1662 } 1663 1664 if config.LivenessTestMinDownstreamBytes != nil { 1665 applyParameters[parameters.LivenessTestMinDownstreamBytes] = *config.LivenessTestMinDownstreamBytes 1666 } 1667 1668 if config.LivenessTestMaxDownstreamBytes != nil { 1669 applyParameters[parameters.LivenessTestMaxDownstreamBytes] = *config.LivenessTestMaxDownstreamBytes 1670 } 1671 1672 if config.ReplayCandidateCount != nil { 1673 applyParameters[parameters.ReplayCandidateCount] = *config.ReplayCandidateCount 1674 } 1675 1676 if config.ReplayDialParametersTTLSeconds != nil { 1677 applyParameters[parameters.ReplayDialParametersTTL] = fmt.Sprintf("%ds", *config.ReplayDialParametersTTLSeconds) 1678 } 1679 1680 if config.ReplayTargetUpstreamBytes != nil { 1681 applyParameters[parameters.ReplayTargetUpstreamBytes] = *config.ReplayTargetUpstreamBytes 1682 } 1683 1684 if config.ReplayTargetDownstreamBytes != nil { 1685 applyParameters[parameters.ReplayTargetDownstreamBytes] = *config.ReplayTargetDownstreamBytes 1686 } 1687 1688 if config.ReplayTargetTunnelDurationSeconds != nil { 1689 applyParameters[parameters.ReplayTargetTunnelDuration] = fmt.Sprintf("%ds", *config.ReplayTargetTunnelDurationSeconds) 1690 } 1691 1692 if config.ReplayLaterRoundMoveToFrontProbability != nil { 1693 applyParameters[parameters.ReplayLaterRoundMoveToFrontProbability] = *config.ReplayLaterRoundMoveToFrontProbability 1694 } 1695 1696 if config.ReplayRetainFailedProbability != nil { 1697 applyParameters[parameters.ReplayRetainFailedProbability] = *config.ReplayRetainFailedProbability 1698 } 1699 1700 if config.UseOnlyCustomTLSProfiles != nil { 1701 applyParameters[parameters.UseOnlyCustomTLSProfiles] = *config.UseOnlyCustomTLSProfiles 1702 } 1703 1704 if len(config.CustomTLSProfiles) > 0 { 1705 applyParameters[parameters.CustomTLSProfiles] = config.CustomTLSProfiles 1706 } 1707 1708 if config.SelectRandomizedTLSProfileProbability != nil { 1709 applyParameters[parameters.SelectRandomizedTLSProfileProbability] = *config.SelectRandomizedTLSProfileProbability 1710 } 1711 1712 if config.NoDefaultTLSSessionIDProbability != nil { 1713 applyParameters[parameters.NoDefaultTLSSessionIDProbability] = *config.NoDefaultTLSSessionIDProbability 1714 } 1715 1716 if len(config.DisableFrontingProviderTLSProfiles) > 0 { 1717 applyParameters[parameters.DisableFrontingProviderTLSProfiles] = config.DisableFrontingProviderTLSProfiles 1718 } 1719 1720 if config.ClientBurstUpstreamTargetBytes != nil { 1721 applyParameters[parameters.ClientBurstUpstreamTargetBytes] = *config.ClientBurstUpstreamTargetBytes 1722 } 1723 1724 if config.ClientBurstUpstreamDeadlineMilliseconds != nil { 1725 applyParameters[parameters.ClientBurstUpstreamDeadline] = fmt.Sprintf("%dms", *config.ClientBurstUpstreamDeadlineMilliseconds) 1726 } 1727 1728 if config.ClientBurstDownstreamTargetBytes != nil { 1729 applyParameters[parameters.ClientBurstDownstreamTargetBytes] = *config.ClientBurstDownstreamTargetBytes 1730 } 1731 1732 if config.ClientBurstDownstreamDeadlineMilliseconds != nil { 1733 applyParameters[parameters.ClientBurstDownstreamDeadline] = fmt.Sprintf("%dms", *config.ClientBurstDownstreamDeadlineMilliseconds) 1734 } 1735 1736 if config.ApplicationParameters != nil { 1737 applyParameters[parameters.ApplicationParameters] = config.ApplicationParameters 1738 } 1739 1740 if config.CustomHostNameRegexes != nil { 1741 applyParameters[parameters.CustomHostNameRegexes] = parameters.RegexStrings(config.CustomHostNameRegexes) 1742 } 1743 1744 if config.CustomHostNameProbability != nil { 1745 applyParameters[parameters.CustomHostNameProbability] = *config.CustomHostNameProbability 1746 } 1747 1748 if config.CustomHostNameLimitProtocols != nil { 1749 applyParameters[parameters.CustomHostNameLimitProtocols] = protocol.TunnelProtocols(config.CustomHostNameLimitProtocols) 1750 } 1751 1752 if config.ConjureCachedRegistrationTTLSeconds != nil { 1753 applyParameters[parameters.ConjureCachedRegistrationTTL] = fmt.Sprintf("%ds", *config.ConjureCachedRegistrationTTLSeconds) 1754 } 1755 1756 if config.ConjureAPIRegistrarBidirectionalURL != "" { 1757 applyParameters[parameters.ConjureAPIRegistrarBidirectionalURL] = config.ConjureAPIRegistrarBidirectionalURL 1758 } 1759 1760 if len(config.ConjureAPIRegistrarFrontingSpecs) > 0 { 1761 applyParameters[parameters.ConjureAPIRegistrarFrontingSpecs] = config.ConjureAPIRegistrarFrontingSpecs 1762 } 1763 1764 if config.ConjureAPIRegistrarMinDelayMilliseconds != nil { 1765 applyParameters[parameters.ConjureAPIRegistrarMinDelay] = fmt.Sprintf("%dms", *config.ConjureAPIRegistrarMinDelayMilliseconds) 1766 } 1767 1768 if config.ConjureAPIRegistrarMaxDelayMilliseconds != nil { 1769 applyParameters[parameters.ConjureAPIRegistrarMaxDelay] = fmt.Sprintf("%dms", *config.ConjureAPIRegistrarMaxDelayMilliseconds) 1770 } 1771 1772 if config.ConjureDecoyRegistrarProbability != nil { 1773 applyParameters[parameters.ConjureDecoyRegistrarProbability] = *config.ConjureDecoyRegistrarProbability 1774 } 1775 1776 if config.ConjureDecoyRegistrarWidth != nil { 1777 applyParameters[parameters.ConjureDecoyRegistrarWidth] = *config.ConjureDecoyRegistrarWidth 1778 } 1779 1780 if config.ConjureDecoyRegistrarMinDelayMilliseconds != nil { 1781 applyParameters[parameters.ConjureDecoyRegistrarMinDelay] = fmt.Sprintf("%dms", *config.ConjureDecoyRegistrarMinDelayMilliseconds) 1782 } 1783 1784 if config.ConjureDecoyRegistrarMaxDelayMilliseconds != nil { 1785 applyParameters[parameters.ConjureDecoyRegistrarMaxDelay] = fmt.Sprintf("%dms", *config.ConjureDecoyRegistrarMaxDelayMilliseconds) 1786 } 1787 1788 if config.HoldOffTunnelMinDurationMilliseconds != nil { 1789 applyParameters[parameters.HoldOffTunnelMinDuration] = fmt.Sprintf("%dms", *config.HoldOffTunnelMinDurationMilliseconds) 1790 } 1791 1792 if config.HoldOffTunnelMaxDurationMilliseconds != nil { 1793 applyParameters[parameters.HoldOffTunnelMaxDuration] = fmt.Sprintf("%dms", *config.HoldOffTunnelMaxDurationMilliseconds) 1794 } 1795 1796 if len(config.HoldOffTunnelProtocols) > 0 { 1797 applyParameters[parameters.HoldOffTunnelProtocols] = protocol.TunnelProtocols(config.HoldOffTunnelProtocols) 1798 } 1799 1800 if len(config.HoldOffTunnelFrontingProviderIDs) > 0 { 1801 applyParameters[parameters.HoldOffTunnelFrontingProviderIDs] = config.HoldOffTunnelFrontingProviderIDs 1802 } 1803 1804 if config.HoldOffTunnelProbability != nil { 1805 applyParameters[parameters.HoldOffTunnelProbability] = *config.HoldOffTunnelProbability 1806 } 1807 1808 if len(config.RestrictFrontingProviderIDs) > 0 { 1809 applyParameters[parameters.RestrictFrontingProviderIDs] = config.RestrictFrontingProviderIDs 1810 } 1811 1812 if config.RestrictFrontingProviderIDsClientProbability != nil { 1813 applyParameters[parameters.RestrictFrontingProviderIDsClientProbability] = *config.RestrictFrontingProviderIDsClientProbability 1814 } 1815 1816 if config.UpstreamProxyAllowAllServerEntrySources != nil { 1817 applyParameters[parameters.UpstreamProxyAllowAllServerEntrySources] = *config.UpstreamProxyAllowAllServerEntrySources 1818 } 1819 1820 if len(config.LimitTunnelDialPortNumbers) > 0 { 1821 applyParameters[parameters.LimitTunnelDialPortNumbers] = config.LimitTunnelDialPortNumbers 1822 } 1823 1824 if config.QUICDisablePathMTUDiscoveryProbability != nil { 1825 applyParameters[parameters.QUICDisableClientPathMTUDiscoveryProbability] = *config.QUICDisablePathMTUDiscoveryProbability 1826 } 1827 1828 if config.DNSResolverAttemptsPerServer != nil { 1829 applyParameters[parameters.DNSResolverAttemptsPerServer] = *config.DNSResolverAttemptsPerServer 1830 } 1831 1832 if config.DNSResolverAttemptsPerPreferredServer != nil { 1833 applyParameters[parameters.DNSResolverAttemptsPerPreferredServer] = *config.DNSResolverAttemptsPerPreferredServer 1834 } 1835 1836 if config.DNSResolverRequestTimeoutMilliseconds != nil { 1837 applyParameters[parameters.DNSResolverRequestTimeout] = fmt.Sprintf("%dms", *config.DNSResolverRequestTimeoutMilliseconds) 1838 } 1839 1840 if config.DNSResolverAwaitTimeoutMilliseconds != nil { 1841 applyParameters[parameters.DNSResolverAwaitTimeout] = fmt.Sprintf("%dms", *config.DNSResolverAwaitTimeoutMilliseconds) 1842 } 1843 1844 if config.DNSResolverPreresolvedIPAddressProbability != nil { 1845 applyParameters[parameters.DNSResolverPreresolvedIPAddressProbability] = *config.DNSResolverPreresolvedIPAddressProbability 1846 } 1847 1848 if config.DNSResolverPreresolvedIPAddressCIDRs != nil { 1849 applyParameters[parameters.DNSResolverPreresolvedIPAddressCIDRs] = config.DNSResolverPreresolvedIPAddressCIDRs 1850 } 1851 1852 if config.DNSResolverAlternateServers != nil { 1853 applyParameters[parameters.DNSResolverAlternateServers] = config.DNSResolverAlternateServers 1854 } 1855 1856 if config.DNSResolverPreferredAlternateServers != nil { 1857 applyParameters[parameters.DNSResolverPreferredAlternateServers] = config.DNSResolverPreferredAlternateServers 1858 } 1859 1860 if config.DNSResolverPreferAlternateServerProbability != nil { 1861 applyParameters[parameters.DNSResolverPreferAlternateServerProbability] = *config.DNSResolverPreferAlternateServerProbability 1862 } 1863 1864 if config.DNSResolverProtocolTransformSpecs != nil { 1865 applyParameters[parameters.DNSResolverProtocolTransformSpecs] = config.DNSResolverProtocolTransformSpecs 1866 } 1867 1868 if config.DNSResolverProtocolTransformScopedSpecNames != nil { 1869 applyParameters[parameters.DNSResolverProtocolTransformScopedSpecNames] = config.DNSResolverProtocolTransformScopedSpecNames 1870 } 1871 1872 if config.DNSResolverProtocolTransformProbability != nil { 1873 applyParameters[parameters.DNSResolverProtocolTransformProbability] = *config.DNSResolverProtocolTransformProbability 1874 } 1875 1876 if config.DNSResolverIncludeEDNS0Probability != nil { 1877 applyParameters[parameters.DNSResolverIncludeEDNS0Probability] = *config.DNSResolverIncludeEDNS0Probability 1878 } 1879 1880 if config.DNSResolverCacheExtensionInitialTTLMilliseconds != nil { 1881 applyParameters[parameters.DNSResolverCacheExtensionInitialTTL] = fmt.Sprintf("%dms", *config.DNSResolverCacheExtensionInitialTTLMilliseconds) 1882 } 1883 1884 if config.DNSResolverCacheExtensionVerifiedTTLMilliseconds != nil { 1885 applyParameters[parameters.DNSResolverCacheExtensionVerifiedTTL] = fmt.Sprintf("%dms", *config.DNSResolverCacheExtensionVerifiedTTLMilliseconds) 1886 } 1887 1888 // When adding new config dial parameters that may override tactics, also 1889 // update setDialParametersHash. 1890 1891 return applyParameters 1892 } 1893 1894 func (config *Config) setDialParametersHash() { 1895 1896 // Calculate and store a hash of the config values that may impact 1897 // dial parameters. This hash is used as part of the dial parameters 1898 // replay mechanism to detect when persisted dial parameters should 1899 // be discarded due to conflicting config changes. 1900 // 1901 // With a couple of minor exceptions, configuring dial parameters via the 1902 // config is intended for testing only, and so these parameters are expected 1903 // to be present in test runs only. It remains an important case to discard 1904 // replay dial parameters when test config parameters are varied. 1905 // 1906 // Hashing the parameter names detects some ambiguous hash cases, such as two 1907 // consecutive int64 parameters, one omitted and one not, that are flipped. 1908 // The serialization is not completely unambiguous, and the format is 1909 // currently limited by legacy cases (not invalidating replay dial parameters 1910 // for production clients is more important than invalidating for test runs). 1911 // We cannot hash the entire config JSON as it contains non-dial parameter 1912 // fields which may frequently change across runs. 1913 // 1914 // MD5 hash is used solely as a data checksum and not for any security 1915 // purpose. 1916 1917 hash := md5.New() 1918 1919 if len(config.LimitTunnelProtocols) > 0 { 1920 hash.Write([]byte("LimitTunnelProtocols")) 1921 for _, protocol := range config.LimitTunnelProtocols { 1922 hash.Write([]byte(protocol)) 1923 } 1924 } 1925 1926 if len(config.InitialLimitTunnelProtocols) > 0 && config.InitialLimitTunnelProtocolsCandidateCount > 0 { 1927 hash.Write([]byte("InitialLimitTunnelProtocols")) 1928 for _, protocol := range config.InitialLimitTunnelProtocols { 1929 hash.Write([]byte(protocol)) 1930 } 1931 binary.Write(hash, binary.LittleEndian, int64(config.InitialLimitTunnelProtocolsCandidateCount)) 1932 } 1933 1934 if len(config.LimitTLSProfiles) > 0 { 1935 hash.Write([]byte("LimitTLSProfiles")) 1936 for _, profile := range config.LimitTLSProfiles { 1937 hash.Write([]byte(profile)) 1938 } 1939 } 1940 1941 if len(config.LimitQUICVersions) > 0 { 1942 hash.Write([]byte("LimitQUICVersions")) 1943 for _, version := range config.LimitQUICVersions { 1944 hash.Write([]byte(version)) 1945 } 1946 } 1947 1948 // Whether a custom User-Agent is specified is a binary flag: when not set, 1949 // the replay dial parameters value applies. When set, external 1950 // considerations apply. 1951 if _, ok := config.CustomHeaders["User-Agent"]; ok { 1952 hash.Write([]byte("CustomHeaders User-Agent")) 1953 hash.Write([]byte{1}) 1954 } 1955 1956 if config.UpstreamProxyURL != "" { 1957 hash.Write([]byte("UpstreamProxyURL")) 1958 hash.Write([]byte(config.UpstreamProxyURL)) 1959 } 1960 1961 if config.TransformHostNameProbability != nil { 1962 hash.Write([]byte("TransformHostNameProbability")) 1963 binary.Write(hash, binary.LittleEndian, *config.TransformHostNameProbability) 1964 } 1965 1966 if config.FragmentorProbability != nil { 1967 hash.Write([]byte("FragmentorProbability")) 1968 binary.Write(hash, binary.LittleEndian, *config.FragmentorProbability) 1969 } 1970 1971 if len(config.FragmentorLimitProtocols) > 0 { 1972 hash.Write([]byte("FragmentorLimitProtocols")) 1973 for _, protocol := range config.FragmentorLimitProtocols { 1974 hash.Write([]byte(protocol)) 1975 } 1976 } 1977 1978 if config.FragmentorMinTotalBytes != nil { 1979 hash.Write([]byte("FragmentorMinTotalBytes")) 1980 binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinTotalBytes)) 1981 } 1982 1983 if config.FragmentorMaxTotalBytes != nil { 1984 hash.Write([]byte("FragmentorMaxTotalBytes")) 1985 binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxTotalBytes)) 1986 } 1987 1988 if config.FragmentorMinWriteBytes != nil { 1989 hash.Write([]byte("FragmentorMinWriteBytes")) 1990 binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinWriteBytes)) 1991 } 1992 1993 if config.FragmentorMaxWriteBytes != nil { 1994 hash.Write([]byte("FragmentorMaxWriteBytes")) 1995 binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxWriteBytes)) 1996 } 1997 1998 if config.FragmentorMinDelayMicroseconds != nil { 1999 hash.Write([]byte("FragmentorMinDelayMicroseconds")) 2000 binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinDelayMicroseconds)) 2001 } 2002 2003 if config.FragmentorMaxDelayMicroseconds != nil { 2004 hash.Write([]byte("FragmentorMaxDelayMicroseconds")) 2005 binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxDelayMicroseconds)) 2006 } 2007 2008 if config.MeekTrafficShapingProbability != nil { 2009 hash.Write([]byte("MeekTrafficShapingProbability")) 2010 binary.Write(hash, binary.LittleEndian, int64(*config.MeekTrafficShapingProbability)) 2011 } 2012 2013 if len(config.MeekTrafficShapingLimitProtocols) > 0 { 2014 hash.Write([]byte("MeekTrafficShapingLimitProtocols")) 2015 for _, protocol := range config.MeekTrafficShapingLimitProtocols { 2016 hash.Write([]byte(protocol)) 2017 } 2018 } 2019 2020 if config.MeekMinLimitRequestPayloadLength != nil { 2021 hash.Write([]byte("MeekMinLimitRequestPayloadLength")) 2022 binary.Write(hash, binary.LittleEndian, int64(*config.MeekMinLimitRequestPayloadLength)) 2023 } 2024 2025 if config.MeekMaxLimitRequestPayloadLength != nil { 2026 hash.Write([]byte("MeekMaxLimitRequestPayloadLength")) 2027 binary.Write(hash, binary.LittleEndian, int64(*config.MeekMaxLimitRequestPayloadLength)) 2028 } 2029 2030 if config.MeekRedialTLSProbability != nil { 2031 hash.Write([]byte("MeekRedialTLSProbability")) 2032 binary.Write(hash, binary.LittleEndian, *config.MeekRedialTLSProbability) 2033 } 2034 2035 if config.ObfuscatedSSHMinPadding != nil { 2036 hash.Write([]byte("ObfuscatedSSHMinPadding")) 2037 binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMinPadding)) 2038 } 2039 2040 if config.ObfuscatedSSHMaxPadding != nil { 2041 hash.Write([]byte("ObfuscatedSSHMaxPadding")) 2042 binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMaxPadding)) 2043 } 2044 2045 if config.LivenessTestMinUpstreamBytes != nil { 2046 hash.Write([]byte("LivenessTestMinUpstreamBytes")) 2047 binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinUpstreamBytes)) 2048 } 2049 2050 if config.LivenessTestMaxUpstreamBytes != nil { 2051 hash.Write([]byte("LivenessTestMaxUpstreamBytes")) 2052 binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxUpstreamBytes)) 2053 } 2054 2055 if config.LivenessTestMinDownstreamBytes != nil { 2056 hash.Write([]byte("LivenessTestMinDownstreamBytes")) 2057 binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinDownstreamBytes)) 2058 } 2059 2060 if config.LivenessTestMaxDownstreamBytes != nil { 2061 hash.Write([]byte("LivenessTestMaxDownstreamBytes")) 2062 binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxDownstreamBytes)) 2063 } 2064 2065 // Legacy case: these parameters are included in the hash unconditionally, 2066 // and so will impact almost all production clients. These parameter names 2067 // are not hashed since that would invalidate all replay dial parameters for 2068 // existing clients whose hashes predate the inclusion of parameter names. 2069 binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMin) 2070 binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMax) 2071 binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierLambda) 2072 2073 if config.UseOnlyCustomTLSProfiles != nil { 2074 hash.Write([]byte("UseOnlyCustomTLSProfiles")) 2075 binary.Write(hash, binary.LittleEndian, *config.UseOnlyCustomTLSProfiles) 2076 } 2077 2078 if len(config.CustomTLSProfiles) > 0 { 2079 hash.Write([]byte("CustomTLSProfiles")) 2080 for _, customTLSProfile := range config.CustomTLSProfiles { 2081 encodedCustomTLSProofile, _ := json.Marshal(customTLSProfile) 2082 hash.Write(encodedCustomTLSProofile) 2083 } 2084 } 2085 2086 if config.SelectRandomizedTLSProfileProbability != nil { 2087 hash.Write([]byte("SelectRandomizedTLSProfileProbability")) 2088 binary.Write(hash, binary.LittleEndian, *config.SelectRandomizedTLSProfileProbability) 2089 } 2090 2091 if config.NoDefaultTLSSessionIDProbability != nil { 2092 hash.Write([]byte("NoDefaultTLSSessionIDProbability")) 2093 binary.Write(hash, binary.LittleEndian, *config.NoDefaultTLSSessionIDProbability) 2094 } 2095 2096 if len(config.DisableFrontingProviderTLSProfiles) > 0 { 2097 hash.Write([]byte("DisableFrontingProviderTLSProfiles")) 2098 encodedDisableFrontingProviderTLSProfiles, _ := 2099 json.Marshal(config.DisableFrontingProviderTLSProfiles) 2100 hash.Write(encodedDisableFrontingProviderTLSProfiles) 2101 } 2102 2103 if len(config.CustomHostNameRegexes) > 0 { 2104 hash.Write([]byte("CustomHostNameRegexes")) 2105 for _, customHostNameRegex := range config.CustomHostNameRegexes { 2106 hash.Write([]byte(customHostNameRegex)) 2107 } 2108 } 2109 2110 if config.CustomHostNameProbability != nil { 2111 hash.Write([]byte("CustomHostNameProbability")) 2112 binary.Write(hash, binary.LittleEndian, *config.CustomHostNameProbability) 2113 } 2114 2115 if len(config.CustomHostNameLimitProtocols) > 0 { 2116 hash.Write([]byte("CustomHostNameLimitProtocols")) 2117 for _, protocol := range config.CustomHostNameLimitProtocols { 2118 hash.Write([]byte(protocol)) 2119 } 2120 } 2121 2122 if config.ConjureCachedRegistrationTTLSeconds != nil { 2123 hash.Write([]byte("ConjureCachedRegistrationTTLSeconds")) 2124 binary.Write(hash, binary.LittleEndian, int64(*config.ConjureCachedRegistrationTTLSeconds)) 2125 } 2126 2127 if config.ConjureAPIRegistrarBidirectionalURL != "" { 2128 hash.Write([]byte("ConjureAPIRegistrarBidirectionalURL")) 2129 hash.Write([]byte(config.ConjureAPIRegistrarBidirectionalURL)) 2130 } 2131 2132 if len(config.ConjureAPIRegistrarFrontingSpecs) > 0 { 2133 hash.Write([]byte("ConjureAPIRegistrarFrontingSpecs")) 2134 for _, frontingSpec := range config.ConjureAPIRegistrarFrontingSpecs { 2135 encodedFrontSpec, _ := json.Marshal(frontingSpec) 2136 hash.Write(encodedFrontSpec) 2137 } 2138 } 2139 2140 if config.ConjureAPIRegistrarMinDelayMilliseconds != nil { 2141 hash.Write([]byte("ConjureAPIRegistrarMinDelayMilliseconds")) 2142 binary.Write(hash, binary.LittleEndian, int64(*config.ConjureAPIRegistrarMinDelayMilliseconds)) 2143 } 2144 2145 if config.ConjureAPIRegistrarMaxDelayMilliseconds != nil { 2146 hash.Write([]byte("ConjureAPIRegistrarMaxDelayMilliseconds")) 2147 binary.Write(hash, binary.LittleEndian, int64(*config.ConjureAPIRegistrarMaxDelayMilliseconds)) 2148 } 2149 2150 if config.ConjureDecoyRegistrarWidth != nil { 2151 hash.Write([]byte("ConjureDecoyRegistrarWidth")) 2152 binary.Write(hash, binary.LittleEndian, int64(*config.ConjureDecoyRegistrarWidth)) 2153 } 2154 2155 if config.ConjureDecoyRegistrarMinDelayMilliseconds != nil { 2156 hash.Write([]byte("ConjureDecoyRegistrarMinDelayMilliseconds")) 2157 binary.Write(hash, binary.LittleEndian, int64(*config.ConjureDecoyRegistrarMinDelayMilliseconds)) 2158 } 2159 2160 if config.ConjureDecoyRegistrarMaxDelayMilliseconds != nil { 2161 hash.Write([]byte("ConjureDecoyRegistrarMaxDelayMilliseconds")) 2162 binary.Write(hash, binary.LittleEndian, int64(*config.ConjureDecoyRegistrarMaxDelayMilliseconds)) 2163 } 2164 2165 if config.HoldOffTunnelMinDurationMilliseconds != nil { 2166 hash.Write([]byte("HoldOffTunnelMinDurationMilliseconds")) 2167 binary.Write(hash, binary.LittleEndian, int64(*config.HoldOffTunnelMinDurationMilliseconds)) 2168 } 2169 2170 if config.HoldOffTunnelMaxDurationMilliseconds != nil { 2171 hash.Write([]byte("HoldOffTunnelMaxDurationMilliseconds")) 2172 binary.Write(hash, binary.LittleEndian, int64(*config.HoldOffTunnelMaxDurationMilliseconds)) 2173 } 2174 2175 if len(config.HoldOffTunnelProtocols) > 0 { 2176 hash.Write([]byte("HoldOffTunnelProtocols")) 2177 for _, protocol := range config.HoldOffTunnelProtocols { 2178 hash.Write([]byte(protocol)) 2179 } 2180 } 2181 2182 if len(config.HoldOffTunnelFrontingProviderIDs) > 0 { 2183 hash.Write([]byte("HoldOffTunnelFrontingProviderIDs")) 2184 for _, providerID := range config.HoldOffTunnelFrontingProviderIDs { 2185 hash.Write([]byte(providerID)) 2186 } 2187 } 2188 2189 if config.HoldOffTunnelProbability != nil { 2190 hash.Write([]byte("HoldOffTunnelProbability")) 2191 binary.Write(hash, binary.LittleEndian, *config.HoldOffTunnelProbability) 2192 } 2193 2194 if len(config.RestrictFrontingProviderIDs) > 0 { 2195 hash.Write([]byte("RestrictFrontingProviderIDs")) 2196 for _, providerID := range config.RestrictFrontingProviderIDs { 2197 hash.Write([]byte(providerID)) 2198 } 2199 } 2200 2201 if config.RestrictFrontingProviderIDsClientProbability != nil { 2202 hash.Write([]byte("RestrictFrontingProviderIDsClientProbability")) 2203 binary.Write(hash, binary.LittleEndian, *config.RestrictFrontingProviderIDsClientProbability) 2204 } 2205 2206 if config.UpstreamProxyAllowAllServerEntrySources != nil { 2207 hash.Write([]byte("UpstreamProxyAllowAllServerEntrySources")) 2208 binary.Write(hash, binary.LittleEndian, *config.UpstreamProxyAllowAllServerEntrySources) 2209 } 2210 2211 if len(config.LimitTunnelDialPortNumbers) > 0 { 2212 hash.Write([]byte("LimitTunnelDialPortNumbers")) 2213 encodedLimitTunnelDialPortNumbers, _ := 2214 json.Marshal(config.LimitTunnelDialPortNumbers) 2215 hash.Write(encodedLimitTunnelDialPortNumbers) 2216 } 2217 2218 if config.QUICDisablePathMTUDiscoveryProbability != nil { 2219 hash.Write([]byte("QUICDisablePathMTUDiscoveryProbability")) 2220 binary.Write(hash, binary.LittleEndian, *config.QUICDisablePathMTUDiscoveryProbability) 2221 } 2222 2223 if config.DNSResolverAttemptsPerServer != nil { 2224 hash.Write([]byte("DNSResolverAttemptsPerServer")) 2225 binary.Write(hash, binary.LittleEndian, int64(*config.DNSResolverAttemptsPerServer)) 2226 } 2227 2228 if config.DNSResolverRequestTimeoutMilliseconds != nil { 2229 hash.Write([]byte("DNSResolverRequestTimeoutMilliseconds")) 2230 binary.Write(hash, binary.LittleEndian, int64(*config.DNSResolverRequestTimeoutMilliseconds)) 2231 } 2232 2233 if config.DNSResolverAwaitTimeoutMilliseconds != nil { 2234 hash.Write([]byte("DNSResolverAwaitTimeoutMilliseconds")) 2235 binary.Write(hash, binary.LittleEndian, int64(*config.DNSResolverAwaitTimeoutMilliseconds)) 2236 } 2237 2238 if config.DNSResolverPreresolvedIPAddressCIDRs != nil { 2239 hash.Write([]byte("DNSResolverPreresolvedIPAddressCIDRs")) 2240 encodedDNSResolverPreresolvedIPAddressCIDRs, _ := 2241 json.Marshal(config.DNSResolverPreresolvedIPAddressCIDRs) 2242 hash.Write(encodedDNSResolverPreresolvedIPAddressCIDRs) 2243 } 2244 2245 if config.DNSResolverPreresolvedIPAddressProbability != nil { 2246 hash.Write([]byte("DNSResolverPreresolvedIPAddressProbability")) 2247 binary.Write(hash, binary.LittleEndian, *config.DNSResolverPreresolvedIPAddressProbability) 2248 } 2249 2250 if config.DNSResolverAlternateServers != nil { 2251 hash.Write([]byte("DNSResolverAlternateServers")) 2252 for _, server := range config.DNSResolverAlternateServers { 2253 hash.Write([]byte(server)) 2254 } 2255 } 2256 2257 if config.DNSResolverPreferAlternateServerProbability != nil { 2258 hash.Write([]byte("DNSResolverPreferAlternateServerProbability")) 2259 binary.Write(hash, binary.LittleEndian, *config.DNSResolverPreferAlternateServerProbability) 2260 } 2261 2262 if config.DNSResolverProtocolTransformSpecs != nil { 2263 hash.Write([]byte("DNSResolverProtocolTransformSpecs")) 2264 encodedDNSResolverProtocolTransformSpecs, _ := 2265 json.Marshal(config.DNSResolverProtocolTransformSpecs) 2266 hash.Write(encodedDNSResolverProtocolTransformSpecs) 2267 } 2268 2269 if config.DNSResolverProtocolTransformScopedSpecNames != nil { 2270 hash.Write([]byte("")) 2271 encodedDNSResolverProtocolTransformScopedSpecNames, _ := 2272 json.Marshal(config.DNSResolverProtocolTransformScopedSpecNames) 2273 hash.Write(encodedDNSResolverProtocolTransformScopedSpecNames) 2274 } 2275 2276 if config.DNSResolverProtocolTransformProbability != nil { 2277 hash.Write([]byte("DNSResolverProtocolTransformProbability")) 2278 binary.Write(hash, binary.LittleEndian, *config.DNSResolverProtocolTransformProbability) 2279 } 2280 2281 if config.DNSResolverIncludeEDNS0Probability != nil { 2282 hash.Write([]byte("DNSResolverIncludeEDNS0Probability")) 2283 binary.Write(hash, binary.LittleEndian, *config.DNSResolverIncludeEDNS0Probability) 2284 } 2285 2286 if config.DNSResolverCacheExtensionInitialTTLMilliseconds != nil { 2287 hash.Write([]byte("DNSResolverCacheExtensionInitialTTLMilliseconds")) 2288 binary.Write(hash, binary.LittleEndian, int64(*config.DNSResolverCacheExtensionInitialTTLMilliseconds)) 2289 } 2290 2291 if config.DNSResolverCacheExtensionVerifiedTTLMilliseconds != nil { 2292 hash.Write([]byte("DNSResolverCacheExtensionVerifiedTTLMilliseconds")) 2293 binary.Write(hash, binary.LittleEndian, int64(*config.DNSResolverCacheExtensionVerifiedTTLMilliseconds)) 2294 } 2295 2296 config.dialParametersHash = hash.Sum(nil) 2297 } 2298 2299 func promoteLegacyTransferURL(URL string) parameters.TransferURLs { 2300 transferURLs := make(parameters.TransferURLs, 1) 2301 transferURLs[0] = ¶meters.TransferURL{ 2302 URL: base64.StdEncoding.EncodeToString([]byte(URL)), 2303 SkipVerify: false, 2304 OnlyAfterAttempts: 0, 2305 } 2306 return transferURLs 2307 } 2308 2309 type loggingDeviceBinder struct { 2310 d DeviceBinder 2311 } 2312 2313 func newLoggingDeviceBinder(d DeviceBinder) *loggingDeviceBinder { 2314 return &loggingDeviceBinder{d: d} 2315 } 2316 2317 func (d *loggingDeviceBinder) BindToDevice(fileDescriptor int) (string, error) { 2318 deviceInfo, err := d.d.BindToDevice(fileDescriptor) 2319 if err == nil && deviceInfo != "" { 2320 NoticeBindToDevice(deviceInfo) 2321 } 2322 return deviceInfo, err 2323 } 2324 2325 type staticNetworkGetter struct { 2326 networkID string 2327 } 2328 2329 func newStaticNetworkGetter(networkID string) *staticNetworkGetter { 2330 return &staticNetworkGetter{networkID: networkID} 2331 } 2332 2333 func (n *staticNetworkGetter) GetNetworkID() string { 2334 return n.networkID 2335 } 2336 2337 type loggingNetworkIDGetter struct { 2338 n NetworkIDGetter 2339 } 2340 2341 func newLoggingNetworkIDGetter(n NetworkIDGetter) *loggingNetworkIDGetter { 2342 return &loggingNetworkIDGetter{n: n} 2343 } 2344 2345 func (n *loggingNetworkIDGetter) GetNetworkID() string { 2346 networkID := n.n.GetNetworkID() 2347 2348 // All PII must appear after the initial "-" 2349 // See: https://godoc.org/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon#NetworkIDGetter 2350 logNetworkID := networkID 2351 index := strings.Index(logNetworkID, "-") 2352 if index != -1 { 2353 logNetworkID = logNetworkID[:index] 2354 } 2355 if len(logNetworkID)+1 < len(networkID) { 2356 // Indicate when additional network info was present after the first "-". 2357 logNetworkID += "+[redacted]" 2358 } 2359 NoticeNetworkID(logNetworkID) 2360 2361 return networkID 2362 } 2363 2364 // migrationsFromLegacyNoticeFilePaths returns the file migrations which must be 2365 // performed to move notice files from legacy file paths, which were configured 2366 // with the legacy config fields HomepageNoticesFilename and 2367 // RotatingNoticesFilename, to the new file paths used by Psiphon which exist 2368 // under the data root directory. 2369 func migrationsFromLegacyNoticeFilePaths(config *Config) []FileMigration { 2370 var noticeMigrations []FileMigration 2371 2372 if config.MigrateHomepageNoticesFilename != "" { 2373 noticeMigrations = append(noticeMigrations, FileMigration{ 2374 Name: "hompage", 2375 OldPath: config.MigrateHomepageNoticesFilename, 2376 NewPath: config.GetHomePageFilename(), 2377 }) 2378 } 2379 2380 if config.MigrateRotatingNoticesFilename != "" { 2381 migrations := []FileMigration{ 2382 { 2383 Name: "notices", 2384 OldPath: config.MigrateRotatingNoticesFilename, 2385 NewPath: config.GetNoticesFilename(), 2386 IsDir: false, 2387 }, 2388 { 2389 Name: "notices.1", 2390 OldPath: config.MigrateRotatingNoticesFilename + ".1", 2391 NewPath: config.GetNoticesFilename() + ".1", 2392 }, 2393 } 2394 noticeMigrations = append(noticeMigrations, migrations...) 2395 } 2396 2397 return noticeMigrations 2398 } 2399 2400 // migrationsFromLegacyFilePaths returns the file migrations which must be 2401 // performed to move files from legacy file paths, which were configured with 2402 // legacy config fields, to the new file paths used by Psiphon which exist 2403 // under the data root directory. 2404 // Note: an attempt is made to redact any file paths from the returned error. 2405 func migrationsFromLegacyFilePaths(config *Config) ([]FileMigration, error) { 2406 2407 migrations := []FileMigration{ 2408 { 2409 Name: "psiphon.boltdb", 2410 OldPath: filepath.Join(config.MigrateDataStoreDirectory, "psiphon.boltdb"), 2411 NewPath: filepath.Join(config.GetDataStoreDirectory(), "psiphon.boltdb"), 2412 }, 2413 { 2414 Name: "psiphon.boltdb.lock", 2415 OldPath: filepath.Join(config.MigrateDataStoreDirectory, "psiphon.boltdb.lock"), 2416 NewPath: filepath.Join(config.GetDataStoreDirectory(), "psiphon.boltdb.lock"), 2417 }, 2418 } 2419 2420 if config.MigrateRemoteServerListDownloadFilename != "" { 2421 2422 // Migrate remote server list files 2423 2424 rslMigrations := []FileMigration{ 2425 { 2426 Name: "remote_server_list", 2427 OldPath: config.MigrateRemoteServerListDownloadFilename, 2428 NewPath: config.GetRemoteServerListDownloadFilename(), 2429 }, 2430 { 2431 Name: "remote_server_list.part", 2432 OldPath: config.MigrateRemoteServerListDownloadFilename + ".part", 2433 NewPath: config.GetRemoteServerListDownloadFilename() + ".part", 2434 }, 2435 { 2436 Name: "remote_server_list.part.etag", 2437 OldPath: config.MigrateRemoteServerListDownloadFilename + ".part.etag", 2438 NewPath: config.GetRemoteServerListDownloadFilename() + ".part.etag", 2439 }, 2440 } 2441 2442 migrations = append(migrations, rslMigrations...) 2443 } 2444 2445 if config.MigrateObfuscatedServerListDownloadDirectory != "" { 2446 2447 // Migrate OSL registry file and downloads 2448 2449 oslFileRegex, err := regexp.Compile(`^osl-.+$`) 2450 if err != nil { 2451 return nil, errors.TraceMsg(err, "failed to compile regex for osl files") 2452 } 2453 2454 files, err := ioutil.ReadDir(config.MigrateObfuscatedServerListDownloadDirectory) 2455 if err != nil { 2456 NoticeWarning( 2457 "Migration: failed to read OSL download directory with error %s", 2458 common.RedactFilePathsError(err, config.MigrateObfuscatedServerListDownloadDirectory)) 2459 } else { 2460 for _, file := range files { 2461 if oslFileRegex.MatchString(file.Name()) { 2462 fileMigration := FileMigration{ 2463 Name: "osl", 2464 OldPath: filepath.Join(config.MigrateObfuscatedServerListDownloadDirectory, file.Name()), 2465 NewPath: filepath.Join(config.GetObfuscatedServerListDownloadDirectory(), file.Name()), 2466 } 2467 migrations = append(migrations, fileMigration) 2468 } 2469 } 2470 } 2471 } 2472 2473 if config.MigrateUpgradeDownloadFilename != "" { 2474 2475 // Migrate downloaded upgrade files 2476 2477 oldUpgradeDownloadFilename := filepath.Base(config.MigrateUpgradeDownloadFilename) 2478 2479 // Create regex for: 2480 // <old_upgrade_download_filename> 2481 // <old_upgrade_download_filename>.<client_version_number> 2482 // <old_upgrade_download_filename>.<client_version_number>.part 2483 // <old_upgrade_download_filename>.<client_version_number>.part.etag 2484 upgradeDownloadFileRegex, err := regexp.Compile(`^` + oldUpgradeDownloadFilename + `(\.\d+(\.part(\.etag)?)?)?$`) 2485 if err != nil { 2486 return nil, errors.TraceMsg(err, "failed to compile regex for upgrade files") 2487 } 2488 2489 upgradeDownloadDir := filepath.Dir(config.MigrateUpgradeDownloadFilename) 2490 2491 files, err := ioutil.ReadDir(upgradeDownloadDir) 2492 if err != nil { 2493 NoticeWarning( 2494 "Migration: failed to read upgrade download directory with error %s", 2495 common.RedactFilePathsError(err, upgradeDownloadDir)) 2496 } else { 2497 2498 for _, file := range files { 2499 2500 if upgradeDownloadFileRegex.MatchString(file.Name()) { 2501 2502 oldFileSuffix := strings.TrimPrefix(file.Name(), oldUpgradeDownloadFilename) 2503 2504 fileMigration := FileMigration{ 2505 Name: "upgrade", 2506 OldPath: filepath.Join(upgradeDownloadDir, file.Name()), 2507 NewPath: config.GetUpgradeDownloadFilename() + oldFileSuffix, 2508 } 2509 migrations = append(migrations, fileMigration) 2510 } 2511 } 2512 } 2513 } 2514 2515 return migrations, nil 2516 }