Bläddra i källkod

Add HoldOffTunnelFronting

Miro 1 år sedan
förälder
incheckning
e627219bfb

+ 12 - 5
psiphon/common/parameters/parameters.go

@@ -313,8 +313,11 @@ const (
 	HoldOffTunnelMinDuration                           = "HoldOffTunnelMinDuration"
 	HoldOffTunnelMaxDuration                           = "HoldOffTunnelMaxDuration"
 	HoldOffTunnelProtocols                             = "HoldOffTunnelProtocols"
-	HoldOffTunnelFrontingProviderIDs                   = "HoldOffTunnelFrontingProviderIDs"
 	HoldOffTunnelProbability                           = "HoldOffTunnelProbability"
+	HoldOffTunnelFrontingMinDuration                   = "HoldOffTunnelFrontingMinDuration"
+	HoldOffTunnelFrontingMaxDuration                   = "HoldOffTunnelFrontingMaxDuration"
+	HoldOffTunnelFrontingProviderIDs                   = "HoldOffTunnelFrontingProviderIDs"
+	HoldOffTunnelFrontingProbability                   = "HoldOffTunnelFrontingProbability"
 	RestrictFrontingProviderIDs                        = "RestrictFrontingProviderIDs"
 	RestrictFrontingProviderIDsServerProbability       = "RestrictFrontingProviderIDsServerProbability"
 	RestrictFrontingProviderIDsClientProbability       = "RestrictFrontingProviderIDsClientProbability"
@@ -806,11 +809,15 @@ var defaultParameters = map[string]struct {
 	CustomHostNameProbability:    {value: 0.0, minimum: 0.0},
 	CustomHostNameLimitProtocols: {value: protocol.TunnelProtocols{}},
 
-	HoldOffTunnelMinDuration:         {value: time.Duration(0), minimum: time.Duration(0)},
-	HoldOffTunnelMaxDuration:         {value: time.Duration(0), minimum: time.Duration(0)},
-	HoldOffTunnelProtocols:           {value: protocol.TunnelProtocols{}},
+	HoldOffTunnelMinDuration: {value: time.Duration(0), minimum: time.Duration(0)},
+	HoldOffTunnelMaxDuration: {value: time.Duration(0), minimum: time.Duration(0)},
+	HoldOffTunnelProtocols:   {value: protocol.TunnelProtocols{}},
+	HoldOffTunnelProbability: {value: 0.0, minimum: 0.0},
+
+	HoldOffTunnelFrontingMinDuration: {value: time.Duration(0), minimum: time.Duration(0)},
+	HoldOffTunnelFrontingMaxDuration: {value: time.Duration(0), minimum: time.Duration(0)},
 	HoldOffTunnelFrontingProviderIDs: {value: []string{}},
-	HoldOffTunnelProbability:         {value: 0.0, minimum: 0.0},
+	HoldOffTunnelFrontingProbability: {value: 0.0, minimum: 0.0},
 
 	RestrictFrontingProviderIDs:                  {value: []string{}},
 	RestrictFrontingProviderIDsServerProbability: {value: 0.0, minimum: 0.0, flags: serverSideOnly},

+ 16 - 0
psiphon/common/utils.go

@@ -276,3 +276,19 @@ func MergeContextCancel(ctx, cancelCtx context.Context) (context.Context, contex
 		cancel(context.Canceled)
 	}
 }
+
+// MaxDuration returns the maximum duration in durations or 0 if durations is
+// empty.
+func MaxDuration(durations ...time.Duration) time.Duration {
+	if len(durations) == 0 {
+		return 0
+	}
+
+	max := durations[0]
+	for _, d := range durations[1:] {
+		if d > max {
+			max = d
+		}
+	}
+	return max
+}

+ 41 - 8
psiphon/config.go

@@ -877,9 +877,15 @@ type Config struct {
 	HoldOffTunnelMinDurationMilliseconds *int
 	HoldOffTunnelMaxDurationMilliseconds *int
 	HoldOffTunnelProtocols               []string
-	HoldOffTunnelFrontingProviderIDs     []string
 	HoldOffTunnelProbability             *float64
 
+	// HoldOffTunnelFrontingMinDurationMilliseconds and other
+	// HoldOffTunnelFronting fields are for testing purposes.
+	HoldOffTunnelFrontingMinDurationMilliseconds *int
+	HoldOffTunnelFrontingMaxDurationMilliseconds *int
+	HoldOffTunnelFrontingProviderIDs             []string
+	HoldOffTunnelFrontingProbability             *float64
+
 	// RestrictFrontingProviderIDs and other RestrictFrontingProviderIDs fields
 	// are for testing purposes.
 	RestrictFrontingProviderIDs                  []string
@@ -2214,12 +2220,24 @@ func (config *Config) makeConfigParameters() map[string]interface{} {
 		applyParameters[parameters.HoldOffTunnelProtocols] = protocol.TunnelProtocols(config.HoldOffTunnelProtocols)
 	}
 
+	if config.HoldOffTunnelProbability != nil {
+		applyParameters[parameters.HoldOffTunnelProbability] = *config.HoldOffTunnelProbability
+	}
+
+	if config.HoldOffTunnelFrontingMinDurationMilliseconds != nil {
+		applyParameters[parameters.HoldOffTunnelFrontingMinDuration] = fmt.Sprintf("%dms", *config.HoldOffTunnelFrontingMinDurationMilliseconds)
+	}
+
+	if config.HoldOffTunnelFrontingMaxDurationMilliseconds != nil {
+		applyParameters[parameters.HoldOffTunnelFrontingMaxDuration] = fmt.Sprintf("%dms", *config.HoldOffTunnelFrontingMaxDurationMilliseconds)
+	}
+
 	if len(config.HoldOffTunnelFrontingProviderIDs) > 0 {
 		applyParameters[parameters.HoldOffTunnelFrontingProviderIDs] = config.HoldOffTunnelFrontingProviderIDs
 	}
 
-	if config.HoldOffTunnelProbability != nil {
-		applyParameters[parameters.HoldOffTunnelProbability] = *config.HoldOffTunnelProbability
+	if config.HoldOffTunnelFrontingProbability != nil {
+		applyParameters[parameters.HoldOffTunnelFrontingProbability] = *config.HoldOffTunnelFrontingProbability
 	}
 
 	if config.HoldOffDirectTunnelMinDurationMilliseconds != nil {
@@ -3022,6 +3040,21 @@ func (config *Config) setDialParametersHash() {
 		}
 	}
 
+	if config.HoldOffTunnelProbability != nil {
+		hash.Write([]byte("HoldOffTunnelProbability"))
+		binary.Write(hash, binary.LittleEndian, *config.HoldOffTunnelProbability)
+	}
+
+	if config.HoldOffTunnelFrontingMinDurationMilliseconds != nil {
+		hash.Write([]byte("HoldOffTunnelFrontingMinDurationMilliseconds"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.HoldOffTunnelFrontingMinDurationMilliseconds))
+	}
+
+	if config.HoldOffTunnelFrontingMaxDurationMilliseconds != nil {
+		hash.Write([]byte("HoldOffTunnelFrontingMaxDurationMilliseconds"))
+		binary.Write(hash, binary.LittleEndian, int64(*config.HoldOffTunnelFrontingMaxDurationMilliseconds))
+	}
+
 	if len(config.HoldOffTunnelFrontingProviderIDs) > 0 {
 		hash.Write([]byte("HoldOffTunnelFrontingProviderIDs"))
 		for _, providerID := range config.HoldOffTunnelFrontingProviderIDs {
@@ -3029,6 +3062,11 @@ func (config *Config) setDialParametersHash() {
 		}
 	}
 
+	if config.HoldOffTunnelFrontingProbability != nil {
+		hash.Write([]byte("HoldOffTunnelFrontingProbability"))
+		binary.Write(hash, binary.LittleEndian, *config.HoldOffTunnelFrontingProbability)
+	}
+
 	if config.HoldOffDirectTunnelProbability != nil {
 		hash.Write([]byte("HoldOffDirectTunnelProbability"))
 		binary.Write(hash, binary.LittleEndian, *config.HoldOffDirectTunnelProbability)
@@ -3054,11 +3092,6 @@ func (config *Config) setDialParametersHash() {
 		}
 	}
 
-	if config.HoldOffTunnelProbability != nil {
-		hash.Write([]byte("HoldOffTunnelProbability"))
-		binary.Write(hash, binary.LittleEndian, *config.HoldOffTunnelProbability)
-	}
-
 	if len(config.RestrictDirectProviderRegions) > 0 {
 		hash.Write([]byte("RestrictDirectProviderRegions"))
 		for providerID, regions := range config.RestrictDirectProviderRegions {

+ 19 - 11
psiphon/dialParameters.go

@@ -981,15 +981,11 @@ func MakeDialParameters(
 	if !isReplay || !replayHoldOffTunnel {
 
 		var holdOffTunnelDuration time.Duration
+		var holdOffTunnelFrontingDuration time.Duration
 		var holdOffDirectTunnelDuration time.Duration
 
 		if common.Contains(
-			p.TunnelProtocols(parameters.HoldOffTunnelProtocols), dialParams.TunnelProtocol) ||
-
-			(protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) &&
-				common.Contains(
-					p.Strings(parameters.HoldOffTunnelFrontingProviderIDs),
-					dialParams.FrontingProviderID)) {
+			p.TunnelProtocols(parameters.HoldOffTunnelProtocols), dialParams.TunnelProtocol) {
 
 			if p.WeightedCoinFlip(parameters.HoldOffTunnelProbability) {
 
@@ -999,6 +995,19 @@ func MakeDialParameters(
 			}
 		}
 
+		if protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) &&
+			common.Contains(
+				p.Strings(parameters.HoldOffTunnelFrontingProviderIDs),
+				dialParams.FrontingProviderID) {
+
+			if p.WeightedCoinFlip(parameters.HoldOffTunnelFrontingProbability) {
+
+				holdOffTunnelFrontingDuration = prng.Period(
+					p.Duration(parameters.HoldOffTunnelFrontingMinDuration),
+					p.Duration(parameters.HoldOffTunnelFrontingMaxDuration))
+			}
+		}
+
 		if protocol.TunnelProtocolIsDirect(dialParams.TunnelProtocol) &&
 			common.ContainsAny(
 				p.KeyStrings(parameters.HoldOffDirectTunnelProviderRegions, dialParams.ServerEntry.ProviderID), []string{"", serverEntry.Region}) {
@@ -1012,11 +1021,10 @@ func MakeDialParameters(
 		}
 
 		// Use the longest hold off duration
-		if holdOffTunnelDuration >= holdOffDirectTunnelDuration {
-			dialParams.HoldOffTunnelDuration = holdOffTunnelDuration
-		} else {
-			dialParams.HoldOffTunnelDuration = holdOffDirectTunnelDuration
-		}
+		dialParams.HoldOffTunnelDuration = common.MaxDuration(
+			holdOffTunnelDuration,
+			holdOffTunnelFrontingDuration,
+			holdOffDirectTunnelDuration)
 	}
 
 	// OSSH prefix and seed transform are applied only to the OSSH tunnel protocol,

+ 4 - 1
psiphon/dialParameters_test.go

@@ -96,8 +96,11 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	applyParameters[parameters.HoldOffTunnelMinDuration] = "1ms"
 	applyParameters[parameters.HoldOffTunnelMaxDuration] = "10ms"
 	applyParameters[parameters.HoldOffTunnelProtocols] = holdOffTunnelProtocols
-	applyParameters[parameters.HoldOffTunnelFrontingProviderIDs] = []string{frontingProviderID}
 	applyParameters[parameters.HoldOffTunnelProbability] = 1.0
+	applyParameters[parameters.HoldOffTunnelFrontingMinDuration] = "1ms"
+	applyParameters[parameters.HoldOffTunnelFrontingMaxDuration] = "10ms"
+	applyParameters[parameters.HoldOffTunnelFrontingProviderIDs] = []string{frontingProviderID}
+	applyParameters[parameters.HoldOffTunnelFrontingProbability] = 1.0
 	applyParameters[parameters.HoldOffDirectTunnelMinDuration] = "1ms"
 	applyParameters[parameters.HoldOffDirectTunnelMaxDuration] = "10ms"
 	applyParameters[parameters.HoldOffDirectTunnelProviderRegions] = holdOffDirectTunnelProviderRegions