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