1/*
2 * Copyright (c) 2018, 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/*
21Package parameters implements dynamic, concurrency-safe parameters that
22determine Psiphon client and server behaviors.
23
24Parameters include network timeouts, probabilities for actions, lists of
25protocols, etc. Parameters are initialized with reasonable defaults. New
26values may be applied, allowing the client or server to customize its
27parameters from both a config file and tactics data. Sane minimum values are
28enforced.
29
30Parameters may be read and updated concurrently. The read mechanism offers a
31snapshot so that related parameters, such as two Ints representing a range; or
32a more complex series of related parameters; may be read in an atomic and
33consistent way. For example:
34
35    p := params.Get()
36    min := p.Int("Min")
37    max := p.Int("Max")
38    p = nil
39
40For long-running operations, it is recommended to set any pointer to the
41snapshot to nil to allow garbage collection of old snaphots in cases where the
42parameters change.
43
44In general, parameters should be read as close to the point of use as possible
45to ensure that dynamic changes to the parameter values take effect.
46
47For duration parameters, time.ParseDuration-compatible string values are
48supported when applying new values. This allows specifying durations as, for
49example, "100ms" or "24h".
50
51Values read from the parameters are not deep copies and must be treated as
52read-only.
53*/
54package parameters
55
56import (
57	"encoding/json"
58	"net/http"
59	"reflect"
60	"sync/atomic"
61	"time"
62
63	"github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
64	"github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
65	"github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/obfuscator"
66	"github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
67	"github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
68	"github.com/ooni/psiphon/oopsi/golang.org/x/net/bpf"
69)
70
71const (
72	NetworkLatencyMultiplier                         = "NetworkLatencyMultiplier"
73	NetworkLatencyMultiplierMin                      = "NetworkLatencyMultiplierMin"
74	NetworkLatencyMultiplierMax                      = "NetworkLatencyMultiplierMax"
75	NetworkLatencyMultiplierLambda                   = "NetworkLatencyMultiplierLambda"
76	TacticsWaitPeriod                                = "TacticsWaitPeriod"
77	TacticsRetryPeriod                               = "TacticsRetryPeriod"
78	TacticsRetryPeriodJitter                         = "TacticsRetryPeriodJitter"
79	TacticsTimeout                                   = "TacticsTimeout"
80	ConnectionWorkerPoolSize                         = "ConnectionWorkerPoolSize"
81	TunnelPoolSize                                   = "TunnelPoolSize"
82	TunnelConnectTimeout                             = "TunnelConnectTimeout"
83	EstablishTunnelTimeout                           = "EstablishTunnelTimeout"
84	EstablishTunnelWorkTime                          = "EstablishTunnelWorkTime"
85	EstablishTunnelPausePeriod                       = "EstablishTunnelPausePeriod"
86	EstablishTunnelPausePeriodJitter                 = "EstablishTunnelPausePeriodJitter"
87	EstablishTunnelServerAffinityGracePeriod         = "EstablishTunnelServerAffinityGracePeriod"
88	StaggerConnectionWorkersPeriod                   = "StaggerConnectionWorkersPeriod"
89	StaggerConnectionWorkersJitter                   = "StaggerConnectionWorkersJitter"
90	LimitIntensiveConnectionWorkers                  = "LimitIntensiveConnectionWorkers"
91	UpstreamProxyErrorMinWaitDuration                = "UpstreamProxyErrorMinWaitDuration"
92	UpstreamProxyErrorMaxWaitDuration                = "UpstreamProxyErrorMaxWaitDuration"
93	IgnoreHandshakeStatsRegexps                      = "IgnoreHandshakeStatsRegexps"
94	PrioritizeTunnelProtocolsProbability             = "PrioritizeTunnelProtocolsProbability"
95	PrioritizeTunnelProtocols                        = "PrioritizeTunnelProtocols"
96	PrioritizeTunnelProtocolsCandidateCount          = "PrioritizeTunnelProtocolsCandidateCount"
97	InitialLimitTunnelProtocolsProbability           = "InitialLimitTunnelProtocolsProbability"
98	InitialLimitTunnelProtocols                      = "InitialLimitTunnelProtocols"
99	InitialLimitTunnelProtocolsCandidateCount        = "InitialLimitTunnelProtocolsCandidateCount"
100	LimitTunnelProtocolsProbability                  = "LimitTunnelProtocolsProbability"
101	LimitTunnelProtocols                             = "LimitTunnelProtocols"
102	LimitTLSProfilesProbability                      = "LimitTLSProfilesProbability"
103	LimitTLSProfiles                                 = "LimitTLSProfiles"
104	UseOnlyCustomTLSProfiles                         = "UseOnlyCustomTLSProfiles"
105	CustomTLSProfiles                                = "CustomTLSProfiles"
106	SelectRandomizedTLSProfileProbability            = "SelectRandomizedTLSProfileProbability"
107	NoDefaultTLSSessionIDProbability                 = "NoDefaultTLSSessionIDProbability"
108	DisableFrontingProviderTLSProfiles               = "DisableFrontingProviderTLSProfiles"
109	LimitQUICVersionsProbability                     = "LimitQUICVersionsProbability"
110	LimitQUICVersions                                = "LimitQUICVersions"
111	DisableFrontingProviderQUICVersions              = "DisableFrontingProviderQUICVersions"
112	FragmentorProbability                            = "FragmentorProbability"
113	FragmentorLimitProtocols                         = "FragmentorLimitProtocols"
114	FragmentorMinTotalBytes                          = "FragmentorMinTotalBytes"
115	FragmentorMaxTotalBytes                          = "FragmentorMaxTotalBytes"
116	FragmentorMinWriteBytes                          = "FragmentorMinWriteBytes"
117	FragmentorMaxWriteBytes                          = "FragmentorMaxWriteBytes"
118	FragmentorMinDelay                               = "FragmentorMinDelay"
119	FragmentorMaxDelay                               = "FragmentorMaxDelay"
120	FragmentorDownstreamProbability                  = "FragmentorDownstreamProbability"
121	FragmentorDownstreamLimitProtocols               = "FragmentorDownstreamLimitProtocols"
122	FragmentorDownstreamMinTotalBytes                = "FragmentorDownstreamMinTotalBytes"
123	FragmentorDownstreamMaxTotalBytes                = "FragmentorDownstreamMaxTotalBytes"
124	FragmentorDownstreamMinWriteBytes                = "FragmentorDownstreamMinWriteBytes"
125	FragmentorDownstreamMaxWriteBytes                = "FragmentorDownstreamMaxWriteBytes"
126	FragmentorDownstreamMinDelay                     = "FragmentorDownstreamMinDelay"
127	FragmentorDownstreamMaxDelay                     = "FragmentorDownstreamMaxDelay"
128	ObfuscatedSSHMinPadding                          = "ObfuscatedSSHMinPadding"
129	ObfuscatedSSHMaxPadding                          = "ObfuscatedSSHMaxPadding"
130	TunnelOperateShutdownTimeout                     = "TunnelOperateShutdownTimeout"
131	TunnelPortForwardDialTimeout                     = "TunnelPortForwardDialTimeout"
132	PacketTunnelReadTimeout                          = "PacketTunnelReadTimeout"
133	TunnelRateLimits                                 = "TunnelRateLimits"
134	AdditionalCustomHeaders                          = "AdditionalCustomHeaders"
135	SpeedTestPaddingMinBytes                         = "SpeedTestPaddingMinBytes"
136	SpeedTestPaddingMaxBytes                         = "SpeedTestPaddingMaxBytes"
137	SpeedTestMaxSampleCount                          = "SpeedTestMaxSampleCount"
138	SSHKeepAliveSpeedTestSampleProbability           = "SSHKeepAliveSpeedTestSampleProbability"
139	SSHKeepAlivePaddingMinBytes                      = "SSHKeepAlivePaddingMinBytes"
140	SSHKeepAlivePaddingMaxBytes                      = "SSHKeepAlivePaddingMaxBytes"
141	SSHKeepAlivePeriodMin                            = "SSHKeepAlivePeriodMin"
142	SSHKeepAlivePeriodMax                            = "SSHKeepAlivePeriodMax"
143	SSHKeepAlivePeriodicTimeout                      = "SSHKeepAlivePeriodicTimeout"
144	SSHKeepAlivePeriodicInactivePeriod               = "SSHKeepAlivePeriodicInactivePeriod"
145	SSHKeepAliveProbeTimeout                         = "SSHKeepAliveProbeTimeout"
146	SSHKeepAliveProbeInactivePeriod                  = "SSHKeepAliveProbeInactivePeriod"
147	SSHKeepAliveNetworkConnectivityPollingPeriod     = "SSHKeepAliveNetworkConnectivityPollingPeriod"
148	SSHKeepAliveResetOnFailureProbability            = "SSHKeepAliveResetOnFailureProbability"
149	HTTPProxyOriginServerTimeout                     = "HTTPProxyOriginServerTimeout"
150	HTTPProxyMaxIdleConnectionsPerHost               = "HTTPProxyMaxIdleConnectionsPerHost"
151	FetchRemoteServerListTimeout                     = "FetchRemoteServerListTimeout"
152	FetchRemoteServerListRetryPeriod                 = "FetchRemoteServerListRetryPeriod"
153	FetchRemoteServerListStalePeriod                 = "FetchRemoteServerListStalePeriod"
154	RemoteServerListSignaturePublicKey               = "RemoteServerListSignaturePublicKey"
155	RemoteServerListURLs                             = "RemoteServerListURLs"
156	ObfuscatedServerListRootURLs                     = "ObfuscatedServerListRootURLs"
157	PsiphonAPIRequestTimeout                         = "PsiphonAPIRequestTimeout"
158	PsiphonAPIStatusRequestPeriodMin                 = "PsiphonAPIStatusRequestPeriodMin"
159	PsiphonAPIStatusRequestPeriodMax                 = "PsiphonAPIStatusRequestPeriodMax"
160	PsiphonAPIStatusRequestShortPeriodMin            = "PsiphonAPIStatusRequestShortPeriodMin"
161	PsiphonAPIStatusRequestShortPeriodMax            = "PsiphonAPIStatusRequestShortPeriodMax"
162	PsiphonAPIStatusRequestPaddingMinBytes           = "PsiphonAPIStatusRequestPaddingMinBytes"
163	PsiphonAPIStatusRequestPaddingMaxBytes           = "PsiphonAPIStatusRequestPaddingMaxBytes"
164	PsiphonAPIPersistentStatsMaxCount                = "PsiphonAPIPersistentStatsMaxCount"
165	PsiphonAPIConnectedRequestPeriod                 = "PsiphonAPIConnectedRequestPeriod"
166	PsiphonAPIConnectedRequestRetryPeriod            = "PsiphonAPIConnectedRequestRetryPeriod"
167	FetchSplitTunnelRoutesTimeout                    = "FetchSplitTunnelRoutesTimeout"
168	SplitTunnelRoutesURLFormat                       = "SplitTunnelRoutesURLFormat"
169	SplitTunnelRoutesSignaturePublicKey              = "SplitTunnelRoutesSignaturePublicKey"
170	SplitTunnelDNSServer                             = "SplitTunnelDNSServer"
171	SplitTunnelClassificationTTL                     = "SplitTunnelClassificationTTL"
172	SplitTunnelClassificationMaxEntries              = "SplitTunnelClassificationMaxEntries"
173	FetchUpgradeTimeout                              = "FetchUpgradeTimeout"
174	FetchUpgradeRetryPeriod                          = "FetchUpgradeRetryPeriod"
175	FetchUpgradeStalePeriod                          = "FetchUpgradeStalePeriod"
176	UpgradeDownloadURLs                              = "UpgradeDownloadURLs"
177	UpgradeDownloadClientVersionHeader               = "UpgradeDownloadClientVersionHeader"
178	TotalBytesTransferredNoticePeriod                = "TotalBytesTransferredNoticePeriod"
179	TotalBytesTransferredEmitMemoryMetrics           = "TotalBytesTransferredEmitMemoryMetrics"
180	MeekDialDomainsOnly                              = "MeekDialDomainsOnly"
181	MeekLimitBufferSizes                             = "MeekLimitBufferSizes"
182	MeekCookieMaxPadding                             = "MeekCookieMaxPadding"
183	MeekFullReceiveBufferLength                      = "MeekFullReceiveBufferLength"
184	MeekReadPayloadChunkLength                       = "MeekReadPayloadChunkLength"
185	MeekLimitedFullReceiveBufferLength               = "MeekLimitedFullReceiveBufferLength"
186	MeekLimitedReadPayloadChunkLength                = "MeekLimitedReadPayloadChunkLength"
187	MeekMinPollInterval                              = "MeekMinPollInterval"
188	MeekMinPollIntervalJitter                        = "MeekMinPollIntervalJitter"
189	MeekMaxPollInterval                              = "MeekMaxPollInterval"
190	MeekMaxPollIntervalJitter                        = "MeekMaxPollIntervalJitter"
191	MeekPollIntervalMultiplier                       = "MeekPollIntervalMultiplier"
192	MeekPollIntervalJitter                           = "MeekPollIntervalJitter"
193	MeekApplyPollIntervalMultiplierProbability       = "MeekApplyPollIntervalMultiplierProbability"
194	MeekRoundTripRetryDeadline                       = "MeekRoundTripRetryDeadline"
195	MeekRoundTripRetryMinDelay                       = "MeekRoundTripRetryMinDelay"
196	MeekRoundTripRetryMaxDelay                       = "MeekRoundTripRetryMaxDelay"
197	MeekRoundTripRetryMultiplier                     = "MeekRoundTripRetryMultiplier"
198	MeekRoundTripTimeout                             = "MeekRoundTripTimeout"
199	MeekTrafficShapingProbability                    = "MeekTrafficShapingProbability"
200	MeekTrafficShapingLimitProtocols                 = "MeekTrafficShapingLimitProtocols"
201	MeekMinTLSPadding                                = "MeekMinTLSPadding"
202	MeekMaxTLSPadding                                = "MeekMaxTLSPadding"
203	MeekMinLimitRequestPayloadLength                 = "MeekMinLimitRequestPayloadLength"
204	MeekMaxLimitRequestPayloadLength                 = "MeekMaxLimitRequestPayloadLength"
205	MeekRedialTLSProbability                         = "MeekRedialTLSProbability"
206	TransformHostNameProbability                     = "TransformHostNameProbability"
207	PickUserAgentProbability                         = "PickUserAgentProbability"
208	LivenessTestMinUpstreamBytes                     = "LivenessTestMinUpstreamBytes"
209	LivenessTestMaxUpstreamBytes                     = "LivenessTestMaxUpstreamBytes"
210	LivenessTestMinDownstreamBytes                   = "LivenessTestMinDownstreamBytes"
211	LivenessTestMaxDownstreamBytes                   = "LivenessTestMaxDownstreamBytes"
212	ReplayCandidateCount                             = "ReplayCandidateCount"
213	ReplayDialParametersTTL                          = "ReplayDialParametersTTL"
214	ReplayTargetUpstreamBytes                        = "ReplayTargetUpstreamBytes"
215	ReplayTargetDownstreamBytes                      = "ReplayTargetDownstreamBytes"
216	ReplayTargetTunnelDuration                       = "ReplayTargetTunnelDuration"
217	ReplayBPF                                        = "ReplayBPF"
218	ReplaySSH                                        = "ReplaySSH"
219	ReplayObfuscatorPadding                          = "ReplayObfuscatorPadding"
220	ReplayFragmentor                                 = "ReplayFragmentor"
221	ReplayTLSProfile                                 = "ReplayTLSProfile"
222	ReplayRandomizedTLSProfile                       = "ReplayRandomizedTLSProfile"
223	ReplayFronting                                   = "ReplayFronting"
224	ReplayHostname                                   = "ReplayHostname"
225	ReplayQUICVersion                                = "ReplayQUICVersion"
226	ReplayObfuscatedQUIC                             = "ReplayObfuscatedQUIC"
227	ReplayConjureRegistration                        = "ReplayConjureRegistration"
228	ReplayConjureTransport                           = "ReplayConjureTransport"
229	ReplayLivenessTest                               = "ReplayLivenessTest"
230	ReplayUserAgent                                  = "ReplayUserAgent"
231	ReplayAPIRequestPadding                          = "ReplayAPIRequestPadding"
232	ReplayLaterRoundMoveToFrontProbability           = "ReplayLaterRoundMoveToFrontProbability"
233	ReplayRetainFailedProbability                    = "ReplayRetainFailedProbability"
234	APIRequestUpstreamPaddingMinBytes                = "APIRequestUpstreamPaddingMinBytes"
235	APIRequestUpstreamPaddingMaxBytes                = "APIRequestUpstreamPaddingMaxBytes"
236	APIRequestDownstreamPaddingMinBytes              = "APIRequestDownstreamPaddingMinBytes"
237	APIRequestDownstreamPaddingMaxBytes              = "APIRequestDownstreamPaddingMaxBytes"
238	PersistentStatsMaxStoreRecords                   = "PersistentStatsMaxStoreRecords"
239	PersistentStatsMaxSendBytes                      = "PersistentStatsMaxSendBytes"
240	RecordRemoteServerListPersistentStatsProbability = "RecordRemoteServerListPersistentStatsProbability"
241	RecordFailedTunnelPersistentStatsProbability     = "RecordFailedTunnelPersistentStatsProbability"
242	ServerEntryMinimumAgeForPruning                  = "ServerEntryMinimumAgeForPruning"
243	ApplicationParametersProbability                 = "ApplicationParametersProbability"
244	ApplicationParameters                            = "ApplicationParameters"
245	BPFServerTCPProgram                              = "BPFServerTCPProgram"
246	BPFServerTCPProbability                          = "BPFServerTCPProbability"
247	BPFClientTCPProgram                              = "BPFClientTCPProgram"
248	BPFClientTCPProbability                          = "BPFClientTCPProbability"
249	ServerPacketManipulationSpecs                    = "ServerPacketManipulationSpecs"
250	ServerProtocolPacketManipulations                = "ServerProtocolPacketManipulations"
251	ServerPacketManipulationProbability              = "ServerPacketManipulationProbability"
252	FeedbackUploadURLs                               = "FeedbackUploadURLs"
253	FeedbackEncryptionPublicKey                      = "FeedbackEncryptionPublicKey"
254	FeedbackTacticsWaitPeriod                        = "FeedbackTacticsWaitPeriod"
255	FeedbackUploadMaxAttempts                        = "FeedbackUploadMaxAttempts"
256	FeedbackUploadRetryMinDelaySeconds               = "FeedbackUploadRetryMinDelaySeconds"
257	FeedbackUploadRetryMaxDelaySeconds               = "FeedbackUploadRetryMaxDelaySeconds"
258	FeedbackUploadTimeoutSeconds                     = "FeedbackUploadTimeoutSeconds"
259	ServerReplayPacketManipulation                   = "ServerReplayPacketManipulation"
260	ServerReplayFragmentor                           = "ServerReplayFragmentor"
261	ServerReplayUnknownGeoIP                         = "ServerReplayUnknownGeoIP"
262	ServerReplayTTL                                  = "ServerReplayTTL"
263	ServerReplayTargetWaitDuration                   = "ServerReplayTargetWaitDuration"
264	ServerReplayTargetTunnelDuration                 = "ServerReplayTargetTunnelDuration"
265	ServerReplayTargetUpstreamBytes                  = "ServerReplayTargetUpstreamBytes"
266	ServerReplayTargetDownstreamBytes                = "ServerReplayTargetDownstreamBytes"
267	ServerReplayFailedCountThreshold                 = "ServerReplayFailedCountThreshold"
268	ServerBurstUpstreamDeadline                      = "ServerBurstUpstreamDeadline"
269	ServerBurstUpstreamTargetBytes                   = "ServerBurstUpstreamTargetBytes"
270	ServerBurstDownstreamDeadline                    = "ServerBurstDownstreamDeadline"
271	ServerBurstDownstreamTargetBytes                 = "ServerBurstDownstreamTargetBytes"
272	ClientBurstUpstreamDeadline                      = "ClientBurstUpstreamDeadline"
273	ClientBurstUpstreamTargetBytes                   = "ClientBurstUpstreamTargetBytes"
274	ClientBurstDownstreamDeadline                    = "ClientBurstDownstreamDeadline"
275	ClientBurstDownstreamTargetBytes                 = "ClientBurstDownstreamTargetBytes"
276	ConjureCachedRegistrationTTL                     = "ConjureCachedRegistrationTTL"
277	ConjureAPIRegistrarURL                           = "ConjureAPIRegistrarURL"
278	ConjureAPIRegistrarFrontingSpecs                 = "ConjureAPIRegistrarFrontingSpecs"
279	ConjureAPIRegistrarMinDelay                      = "ConjureAPIRegistrarMinDelay"
280	ConjureAPIRegistrarMaxDelay                      = "ConjureAPIRegistrarMaxDelay"
281	ConjureDecoyRegistrarProbability                 = "ConjureDecoyRegistrarProbability"
282	ConjureDecoyRegistrarWidth                       = "ConjureDecoyRegistrarWidth"
283	ConjureDecoyRegistrarMinDelay                    = "ConjureDecoyRegistrarMinDelay"
284	ConjureDecoyRegistrarMaxDelay                    = "ConjureDecoyRegistrarMaxDelay"
285	ConjureTransportObfs4Probability                 = "ConjureTransportObfs4Probability"
286	CustomHostNameRegexes                            = "CustomHostNameRegexes"
287	CustomHostNameProbability                        = "CustomHostNameProbability"
288	CustomHostNameLimitProtocols                     = "CustomHostNameLimitProtocols"
289)
290
291const (
292	useNetworkLatencyMultiplier = 1
293	serverSideOnly              = 2
294)
295
296// defaultParameters specifies the type, default value, and minimum value for
297// all dynamically configurable client and server parameters.
298//
299// Do not change the names or types of existing values, as that can break
300// client logic or cause parameters to not be applied.
301//
302// Minimum values are a fail-safe for cases where lower values would break the
303// client logic. For example, setting a ConnectionWorkerPoolSize of 0 would
304// make the client never connect.
305var defaultParameters = map[string]struct {
306	value   interface{}
307	minimum interface{}
308	flags   int32
309}{
310	// NetworkLatencyMultiplier defaults to 0, meaning off. But when set, it
311	// must be a multiplier >= 1.
312
313	NetworkLatencyMultiplier:       {value: 0.0, minimum: 1.0},
314	NetworkLatencyMultiplierMin:    {value: 1.0, minimum: 1.0},
315	NetworkLatencyMultiplierMax:    {value: 3.0, minimum: 1.0},
316	NetworkLatencyMultiplierLambda: {value: 2.0, minimum: 0.001},
317
318	TacticsWaitPeriod:        {value: 10 * time.Second, minimum: 0 * time.Second, flags: useNetworkLatencyMultiplier},
319	TacticsRetryPeriod:       {value: 5 * time.Second, minimum: 1 * time.Millisecond},
320	TacticsRetryPeriodJitter: {value: 0.3, minimum: 0.0},
321	TacticsTimeout:           {value: 2 * time.Minute, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
322
323	ConnectionWorkerPoolSize:                 {value: 10, minimum: 1},
324	TunnelPoolSize:                           {value: 1, minimum: 1},
325	TunnelConnectTimeout:                     {value: 20 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
326	EstablishTunnelTimeout:                   {value: 300 * time.Second, minimum: time.Duration(0)},
327	EstablishTunnelWorkTime:                  {value: 60 * time.Second, minimum: 1 * time.Second},
328	EstablishTunnelPausePeriod:               {value: 5 * time.Second, minimum: 1 * time.Millisecond},
329	EstablishTunnelPausePeriodJitter:         {value: 0.1, minimum: 0.0},
330	EstablishTunnelServerAffinityGracePeriod: {value: 1 * time.Second, minimum: time.Duration(0), flags: useNetworkLatencyMultiplier},
331	StaggerConnectionWorkersPeriod:           {value: time.Duration(0), minimum: time.Duration(0)},
332	StaggerConnectionWorkersJitter:           {value: 0.1, minimum: 0.0},
333	LimitIntensiveConnectionWorkers:          {value: 0, minimum: 0},
334	UpstreamProxyErrorMinWaitDuration:        {value: 10 * time.Second, minimum: time.Duration(0)},
335	UpstreamProxyErrorMaxWaitDuration:        {value: 30 * time.Second, minimum: time.Duration(0)},
336	IgnoreHandshakeStatsRegexps:              {value: false},
337	TunnelOperateShutdownTimeout:             {value: 1 * time.Second, minimum: 1 * time.Millisecond, flags: useNetworkLatencyMultiplier},
338	TunnelPortForwardDialTimeout:             {value: 10 * time.Second, minimum: 1 * time.Millisecond, flags: useNetworkLatencyMultiplier},
339	PacketTunnelReadTimeout:                  {value: 10 * time.Second, minimum: 1 * time.Millisecond, flags: useNetworkLatencyMultiplier},
340	TunnelRateLimits:                         {value: common.RateLimits{}},
341
342	// PrioritizeTunnelProtocols parameters are obsoleted by InitialLimitTunnelProtocols.
343	// TODO: remove once no longer required for older clients.
344	PrioritizeTunnelProtocolsProbability:    {value: 1.0, minimum: 0.0},
345	PrioritizeTunnelProtocols:               {value: protocol.TunnelProtocols{}},
346	PrioritizeTunnelProtocolsCandidateCount: {value: 10, minimum: 0},
347
348	InitialLimitTunnelProtocolsProbability:    {value: 1.0, minimum: 0.0},
349	InitialLimitTunnelProtocols:               {value: protocol.TunnelProtocols{}},
350	InitialLimitTunnelProtocolsCandidateCount: {value: 0, minimum: 0},
351
352	LimitTunnelProtocolsProbability: {value: 1.0, minimum: 0.0},
353	LimitTunnelProtocols:            {value: protocol.TunnelProtocols{}},
354
355	LimitTLSProfilesProbability:           {value: 1.0, minimum: 0.0},
356	LimitTLSProfiles:                      {value: protocol.TLSProfiles{}},
357	UseOnlyCustomTLSProfiles:              {value: false},
358	CustomTLSProfiles:                     {value: protocol.CustomTLSProfiles{}},
359	SelectRandomizedTLSProfileProbability: {value: 0.25, minimum: 0.0},
360	NoDefaultTLSSessionIDProbability:      {value: 0.5, minimum: 0.0},
361	DisableFrontingProviderTLSProfiles:    {value: protocol.LabeledTLSProfiles{}},
362
363	LimitQUICVersionsProbability:        {value: 1.0, minimum: 0.0},
364	LimitQUICVersions:                   {value: protocol.QUICVersions{}},
365	DisableFrontingProviderQUICVersions: {value: protocol.LabeledQUICVersions{}},
366
367	FragmentorProbability:              {value: 0.5, minimum: 0.0},
368	FragmentorLimitProtocols:           {value: protocol.TunnelProtocols{}},
369	FragmentorMinTotalBytes:            {value: 0, minimum: 0},
370	FragmentorMaxTotalBytes:            {value: 0, minimum: 0},
371	FragmentorMinWriteBytes:            {value: 1, minimum: 1},
372	FragmentorMaxWriteBytes:            {value: 1500, minimum: 1},
373	FragmentorMinDelay:                 {value: time.Duration(0), minimum: time.Duration(0)},
374	FragmentorMaxDelay:                 {value: 10 * time.Millisecond, minimum: time.Duration(0)},
375	FragmentorDownstreamProbability:    {value: 0.5, minimum: 0.0, flags: serverSideOnly},
376	FragmentorDownstreamLimitProtocols: {value: protocol.TunnelProtocols{}, flags: serverSideOnly},
377	FragmentorDownstreamMinTotalBytes:  {value: 0, minimum: 0, flags: serverSideOnly},
378	FragmentorDownstreamMaxTotalBytes:  {value: 0, minimum: 0, flags: serverSideOnly},
379	FragmentorDownstreamMinWriteBytes:  {value: 1, minimum: 1, flags: serverSideOnly},
380	FragmentorDownstreamMaxWriteBytes:  {value: 1500, minimum: 1, flags: serverSideOnly},
381	FragmentorDownstreamMinDelay:       {value: time.Duration(0), minimum: time.Duration(0), flags: serverSideOnly},
382	FragmentorDownstreamMaxDelay:       {value: 10 * time.Millisecond, minimum: time.Duration(0), flags: serverSideOnly},
383
384	// The Psiphon server will reject obfuscated SSH seed messages with
385	// padding greater than OBFUSCATE_MAX_PADDING.
386	// obfuscator.NewClientObfuscator will ignore invalid min/max padding
387	// configurations.
388
389	ObfuscatedSSHMinPadding: {value: 0, minimum: 0},
390	ObfuscatedSSHMaxPadding: {value: obfuscator.OBFUSCATE_MAX_PADDING, minimum: 0},
391
392	AdditionalCustomHeaders: {value: make(http.Header)},
393
394	// Speed test and SSH keep alive padding is intended to frustrate
395	// fingerprinting and should not exceed ~1 IP packet size.
396	//
397	// Currently, each serialized speed test sample, populated with real
398	// values, is approximately 100 bytes. All SpeedTestMaxSampleCount samples
399	// are loaded into memory are sent as API inputs.
400
401	SpeedTestPaddingMinBytes: {value: 0, minimum: 0},
402	SpeedTestPaddingMaxBytes: {value: 256, minimum: 0},
403	SpeedTestMaxSampleCount:  {value: 25, minimum: 1},
404
405	// The Psiphon server times out inactive tunnels after 5 minutes, so this
406	// is a soft max for SSHKeepAlivePeriodMax.
407
408	SSHKeepAliveSpeedTestSampleProbability:       {value: 0.5, minimum: 0.0},
409	SSHKeepAlivePaddingMinBytes:                  {value: 0, minimum: 0},
410	SSHKeepAlivePaddingMaxBytes:                  {value: 256, minimum: 0},
411	SSHKeepAlivePeriodMin:                        {value: 1 * time.Minute, minimum: 1 * time.Second},
412	SSHKeepAlivePeriodMax:                        {value: 2 * time.Minute, minimum: 1 * time.Second},
413	SSHKeepAlivePeriodicTimeout:                  {value: 30 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
414	SSHKeepAlivePeriodicInactivePeriod:           {value: 10 * time.Second, minimum: 1 * time.Second},
415	SSHKeepAliveProbeTimeout:                     {value: 5 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
416	SSHKeepAliveProbeInactivePeriod:              {value: 10 * time.Second, minimum: 1 * time.Second},
417	SSHKeepAliveNetworkConnectivityPollingPeriod: {value: 500 * time.Millisecond, minimum: 1 * time.Millisecond},
418	SSHKeepAliveResetOnFailureProbability:        {value: 0.0, minimum: 0.0},
419
420	HTTPProxyOriginServerTimeout:       {value: 15 * time.Second, minimum: time.Duration(0), flags: useNetworkLatencyMultiplier},
421	HTTPProxyMaxIdleConnectionsPerHost: {value: 50, minimum: 0},
422
423	FetchRemoteServerListTimeout:       {value: 30 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
424	FetchRemoteServerListRetryPeriod:   {value: 30 * time.Second, minimum: 1 * time.Millisecond},
425	FetchRemoteServerListStalePeriod:   {value: 6 * time.Hour, minimum: 1 * time.Hour},
426	RemoteServerListSignaturePublicKey: {value: ""},
427	RemoteServerListURLs:               {value: TransferURLs{}},
428	ObfuscatedServerListRootURLs:       {value: TransferURLs{}},
429
430	PsiphonAPIRequestTimeout: {value: 20 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
431
432	PsiphonAPIStatusRequestPeriodMin:      {value: 5 * time.Minute, minimum: 1 * time.Second},
433	PsiphonAPIStatusRequestPeriodMax:      {value: 10 * time.Minute, minimum: 1 * time.Second},
434	PsiphonAPIStatusRequestShortPeriodMin: {value: 5 * time.Second, minimum: 1 * time.Second},
435	PsiphonAPIStatusRequestShortPeriodMax: {value: 10 * time.Second, minimum: 1 * time.Second},
436	// PsiphonAPIPersistentStatsMaxCount parameter is obsoleted by PersistentStatsMaxSendBytes.
437	// TODO: remove once no longer required for older clients.
438	PsiphonAPIPersistentStatsMaxCount: {value: 100, minimum: 1},
439	// PsiphonAPIStatusRequestPadding parameters are obsoleted by APIRequestUp/DownstreamPadding.
440	// TODO: remove once no longer required for older clients.
441	PsiphonAPIStatusRequestPaddingMinBytes: {value: 0, minimum: 0},
442	PsiphonAPIStatusRequestPaddingMaxBytes: {value: 256, minimum: 0},
443
444	PsiphonAPIConnectedRequestRetryPeriod: {value: 5 * time.Second, minimum: 1 * time.Millisecond},
445
446	// FetchSplitTunnelRoutesTimeout, SplitTunnelRoutesURLFormat,
447	// SplitTunnelRoutesSignaturePublicKey and SplitTunnelDNSServer are obsoleted
448	// by the server-assisted split tunnel implementation.
449	// TODO: remove once no longer required for older clients.
450	FetchSplitTunnelRoutesTimeout:       {value: 60 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
451	SplitTunnelRoutesURLFormat:          {value: ""},
452	SplitTunnelRoutesSignaturePublicKey: {value: ""},
453	SplitTunnelDNSServer:                {value: ""},
454
455	SplitTunnelClassificationTTL:        {value: 24 * time.Hour, minimum: 0 * time.Second},
456	SplitTunnelClassificationMaxEntries: {value: 65536, minimum: 0},
457
458	FetchUpgradeTimeout:                {value: 60 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
459	FetchUpgradeRetryPeriod:            {value: 30 * time.Second, minimum: 1 * time.Millisecond},
460	FetchUpgradeStalePeriod:            {value: 6 * time.Hour, minimum: 1 * time.Hour},
461	UpgradeDownloadURLs:                {value: TransferURLs{}},
462	UpgradeDownloadClientVersionHeader: {value: ""},
463
464	TotalBytesTransferredNoticePeriod:      {value: 5 * time.Minute, minimum: 1 * time.Second},
465	TotalBytesTransferredEmitMemoryMetrics: {value: true},
466
467	// The meek server times out inactive sessions after 45 seconds, so this
468	// is a soft max for MeekMaxPollInterval,  MeekRoundTripTimeout, and
469	// MeekRoundTripRetryDeadline.
470	//
471	// MeekCookieMaxPadding cannot exceed common.OBFUSCATE_SEED_LENGTH.
472	//
473	// MeekMinTLSPadding/MeekMinTLSPadding are subject to TLS server limitations.
474	//
475	// MeekMinLimitRequestPayloadLength/MeekMaxLimitRequestPayloadLength
476	// cannot exceed server.MEEK_MAX_REQUEST_PAYLOAD_LENGTH.
477
478	MeekDialDomainsOnly:                        {value: false},
479	MeekLimitBufferSizes:                       {value: false},
480	MeekCookieMaxPadding:                       {value: 256, minimum: 0},
481	MeekFullReceiveBufferLength:                {value: 4194304, minimum: 1024},
482	MeekReadPayloadChunkLength:                 {value: 65536, minimum: 1024},
483	MeekLimitedFullReceiveBufferLength:         {value: 131072, minimum: 1024},
484	MeekLimitedReadPayloadChunkLength:          {value: 4096, minimum: 1024},
485	MeekMinPollInterval:                        {value: 100 * time.Millisecond, minimum: 1 * time.Millisecond},
486	MeekMinPollIntervalJitter:                  {value: 0.3, minimum: 0.0},
487	MeekMaxPollInterval:                        {value: 5 * time.Second, minimum: 1 * time.Millisecond},
488	MeekMaxPollIntervalJitter:                  {value: 0.1, minimum: 0.0},
489	MeekPollIntervalMultiplier:                 {value: 1.5, minimum: 0.0},
490	MeekPollIntervalJitter:                     {value: 0.1, minimum: 0.0},
491	MeekApplyPollIntervalMultiplierProbability: {value: 0.5},
492	MeekRoundTripRetryDeadline:                 {value: 5 * time.Second, minimum: 1 * time.Millisecond, flags: useNetworkLatencyMultiplier},
493	MeekRoundTripRetryMinDelay:                 {value: 50 * time.Millisecond, minimum: time.Duration(0)},
494	MeekRoundTripRetryMaxDelay:                 {value: 1 * time.Second, minimum: time.Duration(0)},
495	MeekRoundTripRetryMultiplier:               {value: 2.0, minimum: 0.0},
496	MeekRoundTripTimeout:                       {value: 20 * time.Second, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
497
498	MeekTrafficShapingProbability:    {value: 1.0, minimum: 0.0},
499	MeekTrafficShapingLimitProtocols: {value: protocol.TunnelProtocols{}},
500	MeekMinTLSPadding:                {value: 0, minimum: 0},
501	MeekMaxTLSPadding:                {value: 0, minimum: 0},
502	MeekMinLimitRequestPayloadLength: {value: 65536, minimum: 1},
503	MeekMaxLimitRequestPayloadLength: {value: 65536, minimum: 1},
504	MeekRedialTLSProbability:         {value: 0.0, minimum: 0.0},
505
506	TransformHostNameProbability: {value: 0.5, minimum: 0.0},
507	PickUserAgentProbability:     {value: 0.5, minimum: 0.0},
508
509	LivenessTestMinUpstreamBytes:   {value: 0, minimum: 0},
510	LivenessTestMaxUpstreamBytes:   {value: 0, minimum: 0},
511	LivenessTestMinDownstreamBytes: {value: 0, minimum: 0},
512	LivenessTestMaxDownstreamBytes: {value: 0, minimum: 0},
513
514	ReplayCandidateCount:                   {value: 10, minimum: -1},
515	ReplayDialParametersTTL:                {value: 24 * time.Hour, minimum: time.Duration(0)},
516	ReplayTargetUpstreamBytes:              {value: 0, minimum: 0},
517	ReplayTargetDownstreamBytes:            {value: 0, minimum: 0},
518	ReplayTargetTunnelDuration:             {value: 1 * time.Second, minimum: time.Duration(0)},
519	ReplayBPF:                              {value: true},
520	ReplaySSH:                              {value: true},
521	ReplayObfuscatorPadding:                {value: true},
522	ReplayFragmentor:                       {value: true},
523	ReplayTLSProfile:                       {value: true},
524	ReplayRandomizedTLSProfile:             {value: true},
525	ReplayFronting:                         {value: true},
526	ReplayHostname:                         {value: true},
527	ReplayQUICVersion:                      {value: true},
528	ReplayObfuscatedQUIC:                   {value: true},
529	ReplayConjureRegistration:              {value: true},
530	ReplayConjureTransport:                 {value: true},
531	ReplayLivenessTest:                     {value: true},
532	ReplayUserAgent:                        {value: true},
533	ReplayAPIRequestPadding:                {value: true},
534	ReplayLaterRoundMoveToFrontProbability: {value: 0.0, minimum: 0.0},
535	ReplayRetainFailedProbability:          {value: 0.5, minimum: 0.0},
536
537	APIRequestUpstreamPaddingMinBytes:   {value: 0, minimum: 0},
538	APIRequestUpstreamPaddingMaxBytes:   {value: 1024, minimum: 0},
539	APIRequestDownstreamPaddingMinBytes: {value: 0, minimum: 0},
540	APIRequestDownstreamPaddingMaxBytes: {value: 1024, minimum: 0},
541
542	PersistentStatsMaxStoreRecords:                   {value: 200, minimum: 1},
543	PersistentStatsMaxSendBytes:                      {value: 65536, minimum: 1},
544	RecordRemoteServerListPersistentStatsProbability: {value: 1.0, minimum: 0.0},
545	RecordFailedTunnelPersistentStatsProbability:     {value: 0.0, minimum: 0.0},
546
547	ServerEntryMinimumAgeForPruning: {value: 7 * 24 * time.Hour, minimum: 24 * time.Hour},
548
549	ApplicationParametersProbability: {value: 1.0, minimum: 0.0},
550	ApplicationParameters:            {value: KeyValues{}},
551
552	BPFServerTCPProgram:     {value: (*BPFProgramSpec)(nil), flags: serverSideOnly},
553	BPFServerTCPProbability: {value: 0.5, minimum: 0.0, flags: serverSideOnly},
554	BPFClientTCPProgram:     {value: (*BPFProgramSpec)(nil)},
555	BPFClientTCPProbability: {value: 0.5, minimum: 0.0},
556
557	ServerPacketManipulationSpecs:       {value: PacketManipulationSpecs{}, flags: serverSideOnly},
558	ServerProtocolPacketManipulations:   {value: make(ProtocolPacketManipulations), flags: serverSideOnly},
559	ServerPacketManipulationProbability: {value: 0.5, minimum: 0.0, flags: serverSideOnly},
560
561	FeedbackUploadURLs:                 {value: TransferURLs{}},
562	FeedbackEncryptionPublicKey:        {value: ""},
563	FeedbackTacticsWaitPeriod:          {value: 5 * time.Second, minimum: 0 * time.Second, flags: useNetworkLatencyMultiplier},
564	FeedbackUploadMaxAttempts:          {value: 5, minimum: 0},
565	FeedbackUploadRetryMinDelaySeconds: {value: 1 * time.Minute, minimum: time.Duration(0), flags: useNetworkLatencyMultiplier},
566	FeedbackUploadRetryMaxDelaySeconds: {value: 5 * time.Minute, minimum: 1 * time.Second, flags: useNetworkLatencyMultiplier},
567	FeedbackUploadTimeoutSeconds:       {value: 30 * time.Second, minimum: 0 * time.Second, flags: useNetworkLatencyMultiplier},
568
569	ServerReplayPacketManipulation:    {value: true, flags: serverSideOnly},
570	ServerReplayFragmentor:            {value: true, flags: serverSideOnly},
571	ServerReplayUnknownGeoIP:          {value: false, flags: serverSideOnly},
572	ServerReplayTTL:                   {value: time.Duration(0), minimum: time.Duration(0), flags: serverSideOnly},
573	ServerReplayTargetWaitDuration:    {value: time.Duration(0), minimum: time.Duration(0), flags: serverSideOnly},
574	ServerReplayTargetTunnelDuration:  {value: time.Duration(0), minimum: time.Duration(0), flags: serverSideOnly},
575	ServerReplayTargetUpstreamBytes:   {value: 0, minimum: 0, flags: serverSideOnly},
576	ServerReplayTargetDownstreamBytes: {value: 0, minimum: 0, flags: serverSideOnly},
577	ServerReplayFailedCountThreshold:  {value: 0, minimum: 0, flags: serverSideOnly},
578
579	ServerBurstUpstreamTargetBytes:   {value: 0, minimum: 0, flags: serverSideOnly},
580	ServerBurstUpstreamDeadline:      {value: time.Duration(0), minimum: time.Duration(0), flags: serverSideOnly},
581	ServerBurstDownstreamTargetBytes: {value: 0, minimum: 0, flags: serverSideOnly},
582	ServerBurstDownstreamDeadline:    {value: time.Duration(0), minimum: time.Duration(0), flags: serverSideOnly},
583	ClientBurstUpstreamTargetBytes:   {value: 0, minimum: 0},
584	ClientBurstUpstreamDeadline:      {value: time.Duration(0), minimum: time.Duration(0)},
585	ClientBurstDownstreamTargetBytes: {value: 0, minimum: 0},
586	ClientBurstDownstreamDeadline:    {value: time.Duration(0), minimum: time.Duration(0)},
587
588	ConjureCachedRegistrationTTL:     {value: time.Duration(0), minimum: time.Duration(0)},
589	ConjureAPIRegistrarURL:           {value: ""},
590	ConjureAPIRegistrarFrontingSpecs: {value: FrontingSpecs{}},
591	ConjureAPIRegistrarMinDelay:      {value: time.Duration(0), minimum: time.Duration(0)},
592	ConjureAPIRegistrarMaxDelay:      {value: time.Duration(0), minimum: time.Duration(0)},
593	ConjureDecoyRegistrarProbability: {value: 0.0, minimum: 0.0},
594	ConjureDecoyRegistrarWidth:       {value: 5, minimum: 0},
595	ConjureDecoyRegistrarMinDelay:    {value: time.Duration(0), minimum: time.Duration(0)},
596	ConjureDecoyRegistrarMaxDelay:    {value: time.Duration(0), minimum: time.Duration(0)},
597
598	ConjureTransportObfs4Probability: {value: 0.0, minimum: 0.0},
599
600	CustomHostNameRegexes:        {value: RegexStrings{}},
601	CustomHostNameProbability:    {value: 0.0, minimum: 0.0},
602	CustomHostNameLimitProtocols: {value: protocol.TunnelProtocols{}},
603}
604
605// IsServerSideOnly indicates if the parameter specified by name is used
606// server-side only.
607func IsServerSideOnly(name string) bool {
608	defaultParameter, ok := defaultParameters[name]
609	return ok && (defaultParameter.flags&serverSideOnly) != 0
610}
611
612// Parameters is a set of parameters. To use the parameters, call Get. To
613// apply new values to the parameters, call Set.
614type Parameters struct {
615	getValueLogger func(error)
616	snapshot       atomic.Value
617}
618
619// NewParameters initializes a new Parameters with the default parameter
620// values.
621//
622// getValueLogger is optional, and is used to report runtime errors with
623// getValue; see comment in getValue.
624func NewParameters(
625	getValueLogger func(error)) (*Parameters, error) {
626
627	parameters := &Parameters{
628		getValueLogger: getValueLogger,
629	}
630
631	_, err := parameters.Set("", false)
632	if err != nil {
633		return nil, errors.Trace(err)
634	}
635
636	return parameters, nil
637}
638
639func makeDefaultParameters() (map[string]interface{}, error) {
640
641	parameters := make(map[string]interface{})
642
643	for name, defaults := range defaultParameters {
644
645		if defaults.value == nil {
646			return nil, errors.Tracef("default parameter missing value: %s", name)
647		}
648
649		if defaults.minimum != nil &&
650			reflect.TypeOf(defaults.value) != reflect.TypeOf(defaults.minimum) {
651
652			return nil, errors.Tracef("default parameter value and minimum type mismatch: %s", name)
653		}
654
655		_, isDuration := defaults.value.(time.Duration)
656		if defaults.flags&useNetworkLatencyMultiplier != 0 && !isDuration {
657			return nil, errors.Tracef("default non-duration parameter uses multipler: %s", name)
658		}
659
660		parameters[name] = defaults.value
661	}
662
663	return parameters, nil
664}
665
666// Set replaces the current parameters. First, a set of parameters are
667// initialized using the default values. Then, each applyParameters is applied
668// in turn, with the later instances having precedence.
669//
670// When skipOnError is true, unknown or invalid parameters in any
671// applyParameters are skipped instead of aborting with an error.
672//
673// For protocol.TunnelProtocols and protocol.TLSProfiles type values, when
674// skipOnError is true the values are filtered instead of validated, so
675// only known tunnel protocols and TLS profiles are retained.
676//
677// When an error is returned, the previous parameters remain completely
678// unmodified.
679//
680// For use in logging, Set returns a count of the number of parameters applied
681// from each applyParameters.
682func (p *Parameters) Set(
683	tag string, skipOnError bool, applyParameters ...map[string]interface{}) ([]int, error) {
684
685	makeTypedValue := func(templateValue, value interface{}) (interface{}, error) {
686
687		// Accept strings such as "1h" for duration parameters.
688
689		switch templateValue.(type) {
690		case time.Duration:
691			if s, ok := value.(string); ok {
692				if d, err := time.ParseDuration(s); err == nil {
693					value = d
694				}
695			}
696		}
697
698		// A JSON remarshal resolves cases where applyParameters is a
699		// result of unmarshal-into-interface, in which case non-scalar
700		// values will not have the expected types; see:
701		// https://github.com/ooni/psiphon/oopsi/golang.org/pkg/encoding/json/#Unmarshal. This remarshal
702		// also results in a deep copy.
703
704		marshaledValue, err := json.Marshal(value)
705		if err != nil {
706			return nil, errors.Trace(err)
707		}
708
709		newValuePtr := reflect.New(reflect.TypeOf(templateValue))
710
711		err = json.Unmarshal(marshaledValue, newValuePtr.Interface())
712		if err != nil {
713			return nil, errors.Trace(err)
714		}
715
716		return newValuePtr.Elem().Interface(), nil
717	}
718
719	getAppliedValue := func(
720		name string,
721		parameters map[string]interface{},
722		applyParameters []map[string]interface{}) (interface{}, error) {
723
724		templateValue := parameters[name]
725		if templateValue == nil {
726			return nil, errors.Tracef("unknown parameter: %s", name)
727		}
728
729		value := templateValue
730		for i := len(applyParameters) - 1; i >= 0; i-- {
731			if v := applyParameters[i][name]; v != nil {
732				value = v
733				break
734			}
735		}
736
737		return makeTypedValue(templateValue, value)
738	}
739
740	var counts []int
741
742	parameters, err := makeDefaultParameters()
743	if err != nil {
744		return nil, errors.Trace(err)
745	}
746
747	// Special case: TLSProfiles/LabeledTLSProfiles may reference
748	// CustomTLSProfiles names. Inspect the CustomTLSProfiles parameter and
749	// extract its names. Do not call Get().CustomTLSProfilesNames() as
750	// CustomTLSProfiles may not yet be validated.
751
752	customTLSProfilesValue, err := getAppliedValue(
753		CustomTLSProfiles, parameters, applyParameters)
754	if err != nil {
755		return nil, errors.Trace(err)
756	}
757	customTLSProfiles, _ := customTLSProfilesValue.(protocol.CustomTLSProfiles)
758	customTLSProfileNames := make([]string, len(customTLSProfiles))
759	for i, profile := range customTLSProfiles {
760		customTLSProfileNames[i] = profile.Name
761	}
762
763	// Special case: PacketManipulations will reference PacketManipulationSpecs.
764
765	serverPacketManipulationSpecsValue, err := getAppliedValue(
766		ServerPacketManipulationSpecs, parameters, applyParameters)
767	if err != nil {
768		return nil, errors.Trace(err)
769	}
770	serverPacketManipulationSpecs, _ :=
771		serverPacketManipulationSpecsValue.(PacketManipulationSpecs)
772
773	for i := 0; i < len(applyParameters); i++ {
774
775		count := 0
776
777		for name, value := range applyParameters[i] {
778
779			templateValue, ok := parameters[name]
780			if !ok {
781				if skipOnError {
782					continue
783				}
784				return nil, errors.Tracef("unknown parameter: %s", name)
785			}
786
787			newValue, err := makeTypedValue(templateValue, value)
788			if err != nil {
789				if skipOnError {
790					continue
791				}
792				return nil, errors.Tracef(
793					"unmarshal parameter %s failed: %v", name, err)
794			}
795
796			// Perform type-specific validation for some cases.
797
798			// TODO: require RemoteServerListSignaturePublicKey when
799			// RemoteServerListURLs is set?
800
801			switch v := newValue.(type) {
802			case TransferURLs:
803				err := v.DecodeAndValidate()
804				if err != nil {
805					if skipOnError {
806						continue
807					}
808					return nil, errors.Trace(err)
809				}
810			case protocol.TunnelProtocols:
811				if skipOnError {
812					newValue = v.PruneInvalid()
813				} else {
814					err := v.Validate()
815					if err != nil {
816						return nil, errors.Trace(err)
817					}
818				}
819			case protocol.TLSProfiles:
820				if skipOnError {
821					newValue = v.PruneInvalid(customTLSProfileNames)
822				} else {
823					err := v.Validate(customTLSProfileNames)
824					if err != nil {
825						return nil, errors.Trace(err)
826					}
827				}
828			case protocol.LabeledTLSProfiles:
829
830				if skipOnError {
831					newValue = v.PruneInvalid(customTLSProfileNames)
832				} else {
833					err := v.Validate(customTLSProfileNames)
834					if err != nil {
835						return nil, errors.Trace(err)
836					}
837				}
838			case protocol.QUICVersions:
839				if skipOnError {
840					newValue = v.PruneInvalid()
841				} else {
842					err := v.Validate()
843					if err != nil {
844						return nil, errors.Trace(err)
845					}
846				}
847			case protocol.LabeledQUICVersions:
848				if skipOnError {
849					newValue = v.PruneInvalid()
850				} else {
851					err := v.Validate()
852					if err != nil {
853						return nil, errors.Trace(err)
854					}
855				}
856			case protocol.CustomTLSProfiles:
857				err := v.Validate()
858				if err != nil {
859					if skipOnError {
860						continue
861					}
862					return nil, errors.Trace(err)
863				}
864			case KeyValues:
865				err := v.Validate()
866				if err != nil {
867					if skipOnError {
868						continue
869					}
870					return nil, errors.Trace(err)
871				}
872			case *BPFProgramSpec:
873				if v != nil {
874					err := v.Validate()
875					if err != nil {
876						if skipOnError {
877							continue
878						}
879						return nil, errors.Trace(err)
880					}
881				}
882			case PacketManipulationSpecs:
883				err := v.Validate()
884				if err != nil {
885					if skipOnError {
886						continue
887					}
888					return nil, errors.Trace(err)
889				}
890			case ProtocolPacketManipulations:
891
892				var packetManipulationSpecs PacketManipulationSpecs
893				if name == ServerProtocolPacketManipulations {
894					packetManipulationSpecs = serverPacketManipulationSpecs
895				}
896
897				err := v.Validate(packetManipulationSpecs)
898				if err != nil {
899					if skipOnError {
900						continue
901					}
902					return nil, errors.Trace(err)
903				}
904			case RegexStrings:
905				err := v.Validate()
906				if err != nil {
907					if skipOnError {
908						continue
909					}
910					return nil, errors.Trace(err)
911				}
912			}
913
914			// Enforce any minimums. Assumes defaultParameters[name]
915			// exists.
916			if defaultParameters[name].minimum != nil {
917				valid := true
918				switch v := newValue.(type) {
919				case int:
920					m, ok := defaultParameters[name].minimum.(int)
921					if !ok || v < m {
922						valid = false
923					}
924				case float64:
925					m, ok := defaultParameters[name].minimum.(float64)
926					if !ok || v < m {
927						valid = false
928					}
929				case time.Duration:
930					m, ok := defaultParameters[name].minimum.(time.Duration)
931					if !ok || v < m {
932						valid = false
933					}
934				default:
935					if skipOnError {
936						continue
937					}
938					return nil, errors.Tracef("unexpected parameter with minimum: %s", name)
939				}
940				if !valid {
941					if skipOnError {
942						continue
943					}
944					return nil, errors.Tracef("parameter below minimum: %s", name)
945				}
946			}
947
948			parameters[name] = newValue
949
950			count++
951		}
952
953		counts = append(counts, count)
954	}
955
956	snapshot := &parametersSnapshot{
957		getValueLogger: p.getValueLogger,
958		tag:            tag,
959		parameters:     parameters,
960	}
961
962	p.snapshot.Store(snapshot)
963
964	return counts, nil
965}
966
967// Get returns the current parameters.
968//
969// Values read from the current parameters are not deep copies and must be
970// treated read-only.
971//
972// The returned ParametersAccessor may be used to read multiple related values
973// atomically and consistently while the current set of values in Parameters
974// may change concurrently.
975//
976// Get does not perform any heap allocations and is intended for repeated,
977// direct, low-overhead invocations.
978func (p *Parameters) Get() ParametersAccessor {
979	return ParametersAccessor{
980		snapshot: p.snapshot.Load().(*parametersSnapshot)}
981}
982
983// GetCustom returns the current parameters while also setting customizations
984// for this instance.
985//
986// The properties of Get also apply to GetCustom: must be read-only; atomic
987// and consisent view; no heap allocations.
988//
989// Customizations include:
990//
991// - customNetworkLatencyMultiplier, which overrides NetworkLatencyMultiplier
992//   for this instance only.
993//
994func (p *Parameters) GetCustom(
995	customNetworkLatencyMultiplier float64) ParametersAccessor {
996
997	return ParametersAccessor{
998		snapshot:                       p.snapshot.Load().(*parametersSnapshot),
999		customNetworkLatencyMultiplier: customNetworkLatencyMultiplier,
1000	}
1001}
1002
1003// parametersSnapshot is an atomic snapshot of the parameter values.
1004// Parameters.Get will return a snapshot which may be used to read multiple
1005// related values atomically and consistently while the current snapshot in
1006// Parameters may change concurrently.
1007type parametersSnapshot struct {
1008	getValueLogger func(error)
1009	tag            string
1010	parameters     map[string]interface{}
1011}
1012
1013// getValue sets target to the value of the named parameter.
1014//
1015// It is an error if the name is not found, target is not a pointer, or the
1016// type of target points to does not match the value.
1017//
1018// Any of these conditions would be a bug in the caller. getValue does not
1019// panic in these cases as clients are deployed as a library in various apps
1020// and the failure of Psiphon may not be a failure for the app process.
1021//
1022// Instead, errors are logged to the getValueLogger and getValue leaves the
1023// target unset, which will result in the caller getting and using a zero
1024// value of the requested type.
1025func (p *parametersSnapshot) getValue(name string, target interface{}) {
1026
1027	value, ok := p.parameters[name]
1028	if !ok {
1029		if p.getValueLogger != nil {
1030			p.getValueLogger(errors.Tracef(
1031				"value %s not found", name))
1032		}
1033		return
1034	}
1035
1036	valueType := reflect.TypeOf(value)
1037
1038	if reflect.PtrTo(valueType) != reflect.TypeOf(target) {
1039		if p.getValueLogger != nil {
1040			p.getValueLogger(errors.Tracef(
1041				"value %s has unexpected type %s", name, valueType.Name()))
1042		}
1043		return
1044	}
1045
1046	// Note: there is no deep copy of parameter values; the returned value may
1047	// share memory with the original and should not be modified.
1048
1049	targetValue := reflect.ValueOf(target)
1050
1051	if targetValue.Kind() != reflect.Ptr {
1052		p.getValueLogger(errors.Tracef(
1053			"target for value %s is not pointer", name))
1054		return
1055	}
1056
1057	targetValue.Elem().Set(reflect.ValueOf(value))
1058}
1059
1060// ParametersAccessor provides consistent, atomic access to  parameter values.
1061// Any customizations are applied transparently.
1062type ParametersAccessor struct {
1063	snapshot                       *parametersSnapshot
1064	customNetworkLatencyMultiplier float64
1065}
1066
1067// MakeNilParametersAccessor produces a stub ParametersAccessor which returns
1068// true for IsNil. This may be used where a ParametersAccessor value is
1069// required, but Parameters.Get may not succeed. In contexts where
1070// MakeNilParametersAccessor may be used, calls to ParametersAccessor must
1071// first check IsNil before calling accessor functions.
1072func MakeNilParametersAccessor() ParametersAccessor {
1073	return ParametersAccessor{}
1074}
1075
1076// IsNil indicates that this ParametersAccessor is a stub and its accessor
1077// functions may not be called. A ParametersAccessor produced by
1078// Parameters.Get will never return true for IsNil and IsNil guards are not
1079// required for ParametersAccessors known to be produced by Parameters.Get.
1080func (p ParametersAccessor) IsNil() bool {
1081	return p.snapshot == nil
1082}
1083
1084// Close clears internal references to large memory objects, allowing them to
1085// be garbage collected. Call Close when done using a ParametersAccessor,
1086// where memory footprint is a concern, and where the ParametersAccessor is
1087// not immediately going out of scope. After Close is called, all other
1088// ParametersAccessor functions will panic if called.
1089func (p ParametersAccessor) Close() {
1090	p.snapshot = nil
1091}
1092
1093// Tag returns the tag associated with these parameters.
1094func (p ParametersAccessor) Tag() string {
1095	return p.snapshot.tag
1096}
1097
1098// String returns a string parameter value.
1099func (p ParametersAccessor) String(name string) string {
1100	value := ""
1101	p.snapshot.getValue(name, &value)
1102	return value
1103}
1104
1105func (p ParametersAccessor) Strings(name string) []string {
1106	value := []string{}
1107	p.snapshot.getValue(name, &value)
1108	return value
1109}
1110
1111// Int returns an int parameter value.
1112func (p ParametersAccessor) Int(name string) int {
1113	value := int(0)
1114	p.snapshot.getValue(name, &value)
1115	return value
1116}
1117
1118// Bool returns a bool parameter value.
1119func (p ParametersAccessor) Bool(name string) bool {
1120	value := false
1121	p.snapshot.getValue(name, &value)
1122	return value
1123}
1124
1125// Float returns a float64 parameter value.
1126func (p ParametersAccessor) Float(name string) float64 {
1127	value := float64(0.0)
1128	p.snapshot.getValue(name, &value)
1129	return value
1130}
1131
1132// WeightedCoinFlip returns the result of prng.FlipWeightedCoin using the
1133// specified float parameter as the probability input.
1134func (p ParametersAccessor) WeightedCoinFlip(name string) bool {
1135	var value float64
1136	p.snapshot.getValue(name, &value)
1137	return prng.FlipWeightedCoin(value)
1138}
1139
1140// Duration returns a time.Duration parameter value. When the duration
1141// parameter has the useNetworkLatencyMultiplier flag, the
1142// NetworkLatencyMultiplier is applied to the returned value.
1143func (p ParametersAccessor) Duration(name string) time.Duration {
1144	value := time.Duration(0)
1145	p.snapshot.getValue(name, &value)
1146
1147	defaultParameter, ok := defaultParameters[name]
1148	if value > 0 && ok && defaultParameter.flags&useNetworkLatencyMultiplier != 0 {
1149
1150		multiplier := float64(0.0)
1151
1152		if p.customNetworkLatencyMultiplier != 0.0 {
1153			multiplier = p.customNetworkLatencyMultiplier
1154		} else {
1155			p.snapshot.getValue(NetworkLatencyMultiplier, &multiplier)
1156		}
1157
1158		if multiplier > 0.0 {
1159			value = time.Duration(float64(value) * multiplier)
1160		}
1161
1162	}
1163
1164	return value
1165}
1166
1167// TunnelProtocols returns a protocol.TunnelProtocols parameter value.
1168// If there is a corresponding Probability value, a weighted coin flip
1169// will be performed and, depending on the result, the value or the
1170// parameter default will be returned.
1171func (p ParametersAccessor) TunnelProtocols(name string) protocol.TunnelProtocols {
1172
1173	probabilityName := name + "Probability"
1174	_, ok := p.snapshot.parameters[probabilityName]
1175	if ok {
1176		probabilityValue := float64(1.0)
1177		p.snapshot.getValue(probabilityName, &probabilityValue)
1178		if !prng.FlipWeightedCoin(probabilityValue) {
1179			defaultParameter, ok := defaultParameters[name]
1180			if ok {
1181				defaultValue, ok := defaultParameter.value.(protocol.TunnelProtocols)
1182				if ok {
1183					value := make(protocol.TunnelProtocols, len(defaultValue))
1184					copy(value, defaultValue)
1185					return value
1186				}
1187			}
1188		}
1189	}
1190
1191	value := protocol.TunnelProtocols{}
1192	p.snapshot.getValue(name, &value)
1193	return value
1194}
1195
1196// TLSProfiles returns a protocol.TLSProfiles parameter value.
1197// If there is a corresponding Probability value, a weighted coin flip
1198// will be performed and, depending on the result, the value or the
1199// parameter default will be returned.
1200func (p ParametersAccessor) TLSProfiles(name string) protocol.TLSProfiles {
1201
1202	probabilityName := name + "Probability"
1203	_, ok := p.snapshot.parameters[probabilityName]
1204	if ok {
1205		probabilityValue := float64(1.0)
1206		p.snapshot.getValue(probabilityName, &probabilityValue)
1207		if !prng.FlipWeightedCoin(probabilityValue) {
1208			defaultParameter, ok := defaultParameters[name]
1209			if ok {
1210				defaultValue, ok := defaultParameter.value.(protocol.TLSProfiles)
1211				if ok {
1212					value := make(protocol.TLSProfiles, len(defaultValue))
1213					copy(value, defaultValue)
1214					return value
1215				}
1216			}
1217		}
1218	}
1219
1220	value := protocol.TLSProfiles{}
1221	p.snapshot.getValue(name, &value)
1222	return value
1223}
1224
1225// LabeledTLSProfiles returns a protocol.TLSProfiles parameter value
1226// corresponding to the specified labeled set and label value. The return
1227// value is nil when no set is found.
1228func (p ParametersAccessor) LabeledTLSProfiles(name, label string) protocol.TLSProfiles {
1229	var value protocol.LabeledTLSProfiles
1230	p.snapshot.getValue(name, &value)
1231	return value[label]
1232}
1233
1234// QUICVersions returns a protocol.QUICVersions parameter value.
1235// If there is a corresponding Probability value, a weighted coin flip
1236// will be performed and, depending on the result, the value or the
1237// parameter default will be returned.
1238func (p ParametersAccessor) QUICVersions(name string) protocol.QUICVersions {
1239
1240	probabilityName := name + "Probability"
1241	_, ok := p.snapshot.parameters[probabilityName]
1242	if ok {
1243		probabilityValue := float64(1.0)
1244		p.snapshot.getValue(probabilityName, &probabilityValue)
1245		if !prng.FlipWeightedCoin(probabilityValue) {
1246			defaultParameter, ok := defaultParameters[name]
1247			if ok {
1248				defaultValue, ok := defaultParameter.value.(protocol.QUICVersions)
1249				if ok {
1250					value := make(protocol.QUICVersions, len(defaultValue))
1251					copy(value, defaultValue)
1252					return value
1253				}
1254			}
1255		}
1256	}
1257
1258	value := protocol.QUICVersions{}
1259	p.snapshot.getValue(name, &value)
1260	return value
1261}
1262
1263// LabeledQUICVersions returns a protocol.QUICVersions parameter value
1264// corresponding to the specified labeled set and label value. The return
1265// value is nil when no set is found.
1266func (p ParametersAccessor) LabeledQUICVersions(name, label string) protocol.QUICVersions {
1267	value := protocol.LabeledQUICVersions{}
1268	p.snapshot.getValue(name, &value)
1269	return value[label]
1270}
1271
1272// TransferURLs returns a TransferURLs parameter value.
1273func (p ParametersAccessor) TransferURLs(name string) TransferURLs {
1274	value := TransferURLs{}
1275	p.snapshot.getValue(name, &value)
1276	return value
1277}
1278
1279// RateLimits returns a common.RateLimits parameter value.
1280func (p ParametersAccessor) RateLimits(name string) common.RateLimits {
1281	value := common.RateLimits{}
1282	p.snapshot.getValue(name, &value)
1283	return value
1284}
1285
1286// HTTPHeaders returns an http.Header parameter value.
1287func (p ParametersAccessor) HTTPHeaders(name string) http.Header {
1288	value := make(http.Header)
1289	p.snapshot.getValue(name, &value)
1290	return value
1291}
1292
1293// CustomTLSProfileNames returns the CustomTLSProfile.Name fields for
1294// each profile in the CustomTLSProfiles parameter value.
1295func (p ParametersAccessor) CustomTLSProfileNames() []string {
1296	value := protocol.CustomTLSProfiles{}
1297	p.snapshot.getValue(CustomTLSProfiles, &value)
1298	names := make([]string, len(value))
1299	for i := 0; i < len(value); i++ {
1300		names[i] = value[i].Name
1301	}
1302	return names
1303}
1304
1305// CustomTLSProfile returns the CustomTLSProfile fields with the specified
1306// Name field if it exists in the CustomTLSProfiles parameter value.
1307// Returns nil if not found.
1308func (p ParametersAccessor) CustomTLSProfile(name string) *protocol.CustomTLSProfile {
1309	value := protocol.CustomTLSProfiles{}
1310	p.snapshot.getValue(CustomTLSProfiles, &value)
1311
1312	// Note: linear lookup -- assumes a short list
1313
1314	for i := 0; i < len(value); i++ {
1315		if value[i].Name == name {
1316			return value[i]
1317		}
1318	}
1319	return nil
1320}
1321
1322// KeyValues returns a KeyValues parameter value.
1323func (p ParametersAccessor) KeyValues(name string) KeyValues {
1324	value := KeyValues{}
1325	p.snapshot.getValue(name, &value)
1326	return value
1327}
1328
1329// BPFProgram returns an assembled BPF program corresponding to a
1330// BPFProgramSpec parameter value. Returns nil in the case of any empty
1331// program.
1332func (p ParametersAccessor) BPFProgram(name string) (bool, string, []bpf.RawInstruction) {
1333	var value *BPFProgramSpec
1334	p.snapshot.getValue(name, &value)
1335	if value == nil {
1336		return false, "", nil
1337	}
1338	// Validation checks that Assemble is successful.
1339	rawInstructions, _ := value.Assemble()
1340	return true, value.Name, rawInstructions
1341}
1342
1343// PacketManipulationSpecs returns a PacketManipulationSpecs parameter value.
1344func (p ParametersAccessor) PacketManipulationSpecs(name string) PacketManipulationSpecs {
1345	value := PacketManipulationSpecs{}
1346	p.snapshot.getValue(name, &value)
1347	return value
1348}
1349
1350// ProtocolPacketManipulations returns a ProtocolPacketManipulations parameter value.
1351func (p ParametersAccessor) ProtocolPacketManipulations(name string) ProtocolPacketManipulations {
1352	value := make(ProtocolPacketManipulations)
1353	p.snapshot.getValue(name, &value)
1354	return value
1355}
1356
1357// RegexStrings returns a RegexStrings parameter value.
1358func (p ParametersAccessor) RegexStrings(name string) RegexStrings {
1359	value := RegexStrings{}
1360	p.snapshot.getValue(name, &value)
1361	return value
1362}
1363
1364// FrontingSpecs returns a FrontingSpecs parameter value.
1365func (p ParametersAccessor) FrontingSpecs(name string) FrontingSpecs {
1366	value := FrontingSpecs{}
1367	p.snapshot.getValue(name, &value)
1368	return value
1369}
1370