Sfoglia il codice sorgente

Add parameters missing from setDialParametersHash

Rod Hynes 4 anni fa
parent
commit
5a14da9026
1 ha cambiato i file con 119 aggiunte e 4 eliminazioni
  1. 119 4
      psiphon/config.go

+ 119 - 4
psiphon/config.go

@@ -1663,6 +1663,9 @@ func (config *Config) makeConfigParameters() map[string]interface{} {
 		applyParameters[parameters.ConjureDecoyRegistrarMaxDelay] = fmt.Sprintf("%dms", *config.ConjureDecoyRegistrarMaxDelayMilliseconds)
 		applyParameters[parameters.ConjureDecoyRegistrarMaxDelay] = fmt.Sprintf("%dms", *config.ConjureDecoyRegistrarMaxDelayMilliseconds)
 	}
 	}
 
 
+	// When adding new config dial parameters that may override tactics, also
+	// update setDialParametersHash.
+
 	return applyParameters
 	return applyParameters
 }
 }
 
 
@@ -1673,18 +1676,34 @@ func (config *Config) setDialParametersHash() {
 	// replay mechanism to detect when persisted dial parameters should
 	// replay mechanism to detect when persisted dial parameters should
 	// be discarded due to conflicting config changes.
 	// be discarded due to conflicting config changes.
 	//
 	//
+	// With a couple of minor exceptions, configuring dial parameters via the
+	// config is intended for testing only, and so these parameters are expected
+	// to be present in test runs only. It remains an important case to discard
+	// replay dial parameters when test config parameters are varied.
+	//
+	//
+	// Hashing the parameter names detects some ambiguous hash cases, such as two
+	// consecutive int64 parameters, one omitted and one not, that are flipped.
+	// The serialization is not completely unambiguous, and the format is
+	// currently limited by legacy cases (not invalidating replay dial parameters
+	// for production clients is more important than invalidating for test runs).
+	// We cannot hash the entire config JSON as it contains non-dial parameter
+	// fields which may frequently change across runs.
+	//
 	// MD5 hash is used solely as a data checksum and not for any security
 	// MD5 hash is used solely as a data checksum and not for any security
-	// purpose; serialization is not strictly unambiguous.
+	// purpose.
 
 
 	hash := md5.New()
 	hash := md5.New()
 
 
 	if len(config.LimitTunnelProtocols) > 0 {
 	if len(config.LimitTunnelProtocols) > 0 {
+		hash.Write([]byte("LimitTunnelProtocols"))
 		for _, protocol := range config.LimitTunnelProtocols {
 		for _, protocol := range config.LimitTunnelProtocols {
 			hash.Write([]byte(protocol))
 			hash.Write([]byte(protocol))
 		}
 		}
 	}
 	}
 
 
 	if len(config.InitialLimitTunnelProtocols) > 0 && config.InitialLimitTunnelProtocolsCandidateCount > 0 {
 	if len(config.InitialLimitTunnelProtocols) > 0 && config.InitialLimitTunnelProtocolsCandidateCount > 0 {
+		hash.Write([]byte("InitialLimitTunnelProtocols"))
 		for _, protocol := range config.InitialLimitTunnelProtocols {
 		for _, protocol := range config.InitialLimitTunnelProtocols {
 			hash.Write([]byte(protocol))
 			hash.Write([]byte(protocol))
 		}
 		}
@@ -1692,12 +1711,14 @@ func (config *Config) setDialParametersHash() {
 	}
 	}
 
 
 	if len(config.LimitTLSProfiles) > 0 {
 	if len(config.LimitTLSProfiles) > 0 {
+		hash.Write([]byte("LimitTLSProfiles"))
 		for _, profile := range config.LimitTLSProfiles {
 		for _, profile := range config.LimitTLSProfiles {
 			hash.Write([]byte(profile))
 			hash.Write([]byte(profile))
 		}
 		}
 	}
 	}
 
 
 	if len(config.LimitQUICVersions) > 0 {
 	if len(config.LimitQUICVersions) > 0 {
+		hash.Write([]byte("LimitQUICVersions"))
 		for _, version := range config.LimitQUICVersions {
 		for _, version := range config.LimitQUICVersions {
 			hash.Write([]byte(version))
 			hash.Write([]byte(version))
 		}
 		}
@@ -1707,118 +1728,212 @@ func (config *Config) setDialParametersHash() {
 	// the replay dial parameters value applies. When set, external
 	// the replay dial parameters value applies. When set, external
 	// considerations apply.
 	// considerations apply.
 	if _, ok := config.CustomHeaders["User-Agent"]; ok {
 	if _, ok := config.CustomHeaders["User-Agent"]; ok {
+		hash.Write([]byte("CustomHeaders User-Agent"))
 		hash.Write([]byte{1})
 		hash.Write([]byte{1})
 	}
 	}
 
 
 	if config.UpstreamProxyURL != "" {
 	if config.UpstreamProxyURL != "" {
+		hash.Write([]byte("UpstreamProxyURL"))
 		hash.Write([]byte(config.UpstreamProxyURL))
 		hash.Write([]byte(config.UpstreamProxyURL))
 	}
 	}
 
 
 	if config.TransformHostNameProbability != nil {
 	if config.TransformHostNameProbability != nil {
+		hash.Write([]byte("TransformHostNameProbability"))
 		binary.Write(hash, binary.LittleEndian, *config.TransformHostNameProbability)
 		binary.Write(hash, binary.LittleEndian, *config.TransformHostNameProbability)
 	}
 	}
 
 
 	if config.FragmentorProbability != nil {
 	if config.FragmentorProbability != nil {
+		hash.Write([]byte("FragmentorProbability"))
 		binary.Write(hash, binary.LittleEndian, *config.FragmentorProbability)
 		binary.Write(hash, binary.LittleEndian, *config.FragmentorProbability)
 	}
 	}
 
 
 	if len(config.FragmentorLimitProtocols) > 0 {
 	if len(config.FragmentorLimitProtocols) > 0 {
+		hash.Write([]byte("FragmentorLimitProtocols"))
 		for _, protocol := range config.FragmentorLimitProtocols {
 		for _, protocol := range config.FragmentorLimitProtocols {
 			hash.Write([]byte(protocol))
 			hash.Write([]byte(protocol))
 		}
 		}
 	}
 	}
 
 
 	if config.FragmentorMinTotalBytes != nil {
 	if config.FragmentorMinTotalBytes != nil {
+		hash.Write([]byte("FragmentorMinTotalBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinTotalBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinTotalBytes))
 	}
 	}
 
 
 	if config.FragmentorMaxTotalBytes != nil {
 	if config.FragmentorMaxTotalBytes != nil {
+		hash.Write([]byte("FragmentorMaxTotalBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxTotalBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxTotalBytes))
 	}
 	}
 
 
 	if config.FragmentorMinWriteBytes != nil {
 	if config.FragmentorMinWriteBytes != nil {
+		hash.Write([]byte("FragmentorMinWriteBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinWriteBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinWriteBytes))
 	}
 	}
 
 
 	if config.FragmentorMaxWriteBytes != nil {
 	if config.FragmentorMaxWriteBytes != nil {
+		hash.Write([]byte("FragmentorMaxWriteBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxWriteBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxWriteBytes))
 	}
 	}
 
 
 	if config.FragmentorMinDelayMicroseconds != nil {
 	if config.FragmentorMinDelayMicroseconds != nil {
+		hash.Write([]byte("FragmentorMinDelayMicroseconds"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinDelayMicroseconds))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMinDelayMicroseconds))
 	}
 	}
 
 
 	if config.FragmentorMaxDelayMicroseconds != nil {
 	if config.FragmentorMaxDelayMicroseconds != nil {
+		hash.Write([]byte("FragmentorMaxDelayMicroseconds"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxDelayMicroseconds))
 		binary.Write(hash, binary.LittleEndian, int64(*config.FragmentorMaxDelayMicroseconds))
 	}
 	}
 
 
 	if config.MeekTrafficShapingProbability != nil {
 	if config.MeekTrafficShapingProbability != nil {
+		hash.Write([]byte("MeekTrafficShapingProbability"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.MeekTrafficShapingProbability))
 		binary.Write(hash, binary.LittleEndian, int64(*config.MeekTrafficShapingProbability))
 	}
 	}
 
 
 	if len(config.MeekTrafficShapingLimitProtocols) > 0 {
 	if len(config.MeekTrafficShapingLimitProtocols) > 0 {
+		hash.Write([]byte("MeekTrafficShapingLimitProtocols"))
 		for _, protocol := range config.MeekTrafficShapingLimitProtocols {
 		for _, protocol := range config.MeekTrafficShapingLimitProtocols {
 			hash.Write([]byte(protocol))
 			hash.Write([]byte(protocol))
 		}
 		}
 	}
 	}
 
 
 	if config.MeekMinLimitRequestPayloadLength != nil {
 	if config.MeekMinLimitRequestPayloadLength != nil {
+		hash.Write([]byte("MeekMinLimitRequestPayloadLength"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.MeekMinLimitRequestPayloadLength))
 		binary.Write(hash, binary.LittleEndian, int64(*config.MeekMinLimitRequestPayloadLength))
 	}
 	}
 
 
 	if config.MeekMaxLimitRequestPayloadLength != nil {
 	if config.MeekMaxLimitRequestPayloadLength != nil {
+		hash.Write([]byte("MeekMaxLimitRequestPayloadLength"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.MeekMaxLimitRequestPayloadLength))
 		binary.Write(hash, binary.LittleEndian, int64(*config.MeekMaxLimitRequestPayloadLength))
 	}
 	}
 
 
 	if config.MeekRedialTLSProbability != nil {
 	if config.MeekRedialTLSProbability != nil {
+		hash.Write([]byte("MeekRedialTLSProbability"))
 		binary.Write(hash, binary.LittleEndian, *config.MeekRedialTLSProbability)
 		binary.Write(hash, binary.LittleEndian, *config.MeekRedialTLSProbability)
 	}
 	}
 
 
 	if config.ObfuscatedSSHMinPadding != nil {
 	if config.ObfuscatedSSHMinPadding != nil {
+		hash.Write([]byte("ObfuscatedSSHMinPadding"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMinPadding))
 		binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMinPadding))
 	}
 	}
 
 
 	if config.ObfuscatedSSHMaxPadding != nil {
 	if config.ObfuscatedSSHMaxPadding != nil {
+		hash.Write([]byte("ObfuscatedSSHMaxPadding"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMaxPadding))
 		binary.Write(hash, binary.LittleEndian, int64(*config.ObfuscatedSSHMaxPadding))
 	}
 	}
 
 
 	if config.LivenessTestMinUpstreamBytes != nil {
 	if config.LivenessTestMinUpstreamBytes != nil {
+		hash.Write([]byte("LivenessTestMinUpstreamBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinUpstreamBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinUpstreamBytes))
 	}
 	}
 
 
 	if config.LivenessTestMaxUpstreamBytes != nil {
 	if config.LivenessTestMaxUpstreamBytes != nil {
+		hash.Write([]byte("LivenessTestMaxUpstreamBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxUpstreamBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxUpstreamBytes))
 	}
 	}
 
 
 	if config.LivenessTestMinDownstreamBytes != nil {
 	if config.LivenessTestMinDownstreamBytes != nil {
+		hash.Write([]byte("LivenessTestMinDownstreamBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinDownstreamBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMinDownstreamBytes))
 	}
 	}
 
 
 	if config.LivenessTestMaxDownstreamBytes != nil {
 	if config.LivenessTestMaxDownstreamBytes != nil {
+		hash.Write([]byte("LivenessTestMaxDownstreamBytes"))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxDownstreamBytes))
 		binary.Write(hash, binary.LittleEndian, int64(*config.LivenessTestMaxDownstreamBytes))
 	}
 	}
 
 
+	// Legacy case: these parameters are included in the hash unconditionally,
+	// and so will impact almost all production clients. These parameter names
+	// are not hashed since that would invalidate all replay dial parameters for
+	// existing clients whose hashes predate the inclusion of parameter names.
 	binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMin)
 	binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMin)
 	binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMax)
 	binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierMax)
 	binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierLambda)
 	binary.Write(hash, binary.LittleEndian, config.NetworkLatencyMultiplierLambda)
 
 
 	if config.UseOnlyCustomTLSProfiles != nil {
 	if config.UseOnlyCustomTLSProfiles != nil {
+		hash.Write([]byte("UseOnlyCustomTLSProfiles"))
 		binary.Write(hash, binary.LittleEndian, *config.UseOnlyCustomTLSProfiles)
 		binary.Write(hash, binary.LittleEndian, *config.UseOnlyCustomTLSProfiles)
 	}
 	}
 
 
-	for _, customTLSProfile := range config.CustomTLSProfiles {
-		// Assumes consistent definition for a given profile name
-		hash.Write([]byte(customTLSProfile.Name))
+	if len(config.CustomTLSProfiles) > 0 {
+		hash.Write([]byte("CustomTLSProfiles"))
+		for _, customTLSProfile := range config.CustomTLSProfiles {
+			encodedCustomTLSProofile, _ := json.Marshal(customTLSProfile)
+			hash.Write(encodedCustomTLSProofile)
+		}
 	}
 	}
 
 
 	if config.SelectRandomizedTLSProfileProbability != nil {
 	if config.SelectRandomizedTLSProfileProbability != nil {
+		hash.Write([]byte("SelectRandomizedTLSProfileProbability"))
 		binary.Write(hash, binary.LittleEndian, *config.SelectRandomizedTLSProfileProbability)
 		binary.Write(hash, binary.LittleEndian, *config.SelectRandomizedTLSProfileProbability)
 	}
 	}
 
 
 	if config.NoDefaultTLSSessionIDProbability != nil {
 	if config.NoDefaultTLSSessionIDProbability != nil {
+		hash.Write([]byte("NoDefaultTLSSessionIDProbability"))
 		binary.Write(hash, binary.LittleEndian, *config.NoDefaultTLSSessionIDProbability)
 		binary.Write(hash, binary.LittleEndian, *config.NoDefaultTLSSessionIDProbability)
 	}
 	}
 
 
+	if len(config.CustomHostNameRegexes) > 0 {
+		hash.Write([]byte("CustomHostNameRegexes"))
+		for _, customHostNameRegex := range config.CustomHostNameRegexes {
+			hash.Write([]byte(customHostNameRegex))
+		}
+	}
+
+	if config.CustomHostNameProbability != nil {
+		hash.Write([]byte("CustomHostNameProbability"))
+		binary.Write(hash, binary.LittleEndian, *config.CustomHostNameProbability)
+	}
+
+	if len(config.CustomHostNameLimitProtocols) > 0 {
+		hash.Write([]byte("CustomHostNameLimitProtocols"))
+		for _, protocol := range config.CustomHostNameLimitProtocols {
+			hash.Write([]byte(protocol))
+		}
+	}
+
+	if config.ConjureCachedRegistrationTTLSeconds != nil {
+		hash.Write([]byte("ConjureCachedRegistrationTTLSeconds"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.ConjureCachedRegistrationTTLSeconds))
+	}
+
+	if config.ConjureAPIRegistrarURL != "" {
+		hash.Write([]byte("ConjureAPIRegistrarURL"))
+		hash.Write([]byte(config.ConjureAPIRegistrarURL))
+	}
+
+	if len(config.ConjureAPIRegistrarFrontingSpecs) > 0 {
+		hash.Write([]byte("ConjureAPIRegistrarFrontingSpecs"))
+		for _, frontingSpec := range config.ConjureAPIRegistrarFrontingSpecs {
+			encodedFrontSpec, _ := json.Marshal(frontingSpec)
+			hash.Write(encodedFrontSpec)
+		}
+	}
+
+	if config.ConjureAPIRegistrarMinDelayMilliseconds != nil {
+		hash.Write([]byte("ConjureAPIRegistrarMinDelayMilliseconds"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.ConjureAPIRegistrarMinDelayMilliseconds))
+	}
+
+	if config.ConjureAPIRegistrarMaxDelayMilliseconds != nil {
+		hash.Write([]byte("ConjureAPIRegistrarMaxDelayMilliseconds"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.ConjureAPIRegistrarMaxDelayMilliseconds))
+	}
+
+	if config.ConjureDecoyRegistrarWidth != nil {
+		hash.Write([]byte("ConjureDecoyRegistrarWidth"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.ConjureDecoyRegistrarWidth))
+	}
+
+	if config.ConjureDecoyRegistrarMinDelayMilliseconds != nil {
+		hash.Write([]byte("ConjureDecoyRegistrarMinDelayMilliseconds"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.ConjureDecoyRegistrarMinDelayMilliseconds))
+	}
+
+	if config.ConjureDecoyRegistrarMaxDelayMilliseconds != nil {
+		hash.Write([]byte("ConjureDecoyRegistrarMaxDelayMilliseconds"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.ConjureDecoyRegistrarMaxDelayMilliseconds))
+	}
+
 	config.dialParametersHash = hash.Sum(nil)
 	config.dialParametersHash = hash.Sum(nil)
 }
 }