Explorar o código

Add tactics parameters for in-proxy incompatible network types

- Default to no incompatible network types

- Ignore incompatible network types in personal pairing modes

- Fix proxy personal pairing mode checks, which incorrectly checked the client
  mode
Rod Hynes hai 1 ano
pai
achega
f1ae9bb228

+ 4 - 0
psiphon/common/parameters/parameters.go

@@ -458,6 +458,8 @@ const (
 	InproxyFrontingProviderClientMaxRequestTimeouts    = "InproxyFrontingProviderClientMaxRequestTimeouts"
 	InproxyFrontingProviderServerMaxRequestTimeouts    = "InproxyFrontingProviderServerMaxRequestTimeouts"
 	InproxyProxyOnBrokerClientFailedRetryPeriod        = "InproxyProxyOnBrokerClientFailedRetryPeriod"
+	InproxyProxyIncompatibleNetworkTypes               = "InproxyProxyIncompatibleNetworkTypes"
+	InproxyClientIncompatibleNetworkTypes              = "InproxyClientIncompatibleNetworkTypes"
 
 	// Retired parameters
 
@@ -975,6 +977,8 @@ var defaultParameters = map[string]struct {
 	InproxyFrontingProviderClientMaxRequestTimeouts:    {value: KeyDurations{}},
 	InproxyFrontingProviderServerMaxRequestTimeouts:    {value: KeyDurations{}, flags: serverSideOnly},
 	InproxyProxyOnBrokerClientFailedRetryPeriod:        {value: 30 * time.Second, minimum: time.Duration(0)},
+	InproxyProxyIncompatibleNetworkTypes:               {value: []string{}},
+	InproxyClientIncompatibleNetworkTypes:              {value: []string{}},
 }
 
 // IsServerSideOnly indicates if the parameter specified by name is used

+ 20 - 3
psiphon/config.go

@@ -1039,6 +1039,8 @@ type Config struct {
 	InproxyClientNoMatchFailoverPersonalProbability         *float64
 	InproxyFrontingProviderClientMaxRequestTimeouts         map[string]string
 	InproxyProxyOnBrokerClientFailedRetryPeriodMilliseconds *int
+	InproxyProxyIncompatibleNetworkTypes                    []string
+	InproxyClientIncompatibleNetworkTypes                   []string
 
 	InproxySkipAwaitFullyConnected  bool
 	InproxyEnableWebRTCDebugLogging bool
@@ -1805,13 +1807,20 @@ func (config *Config) SetSignalComponentFailure(signalComponentFailure func()) {
 	config.signalComponentFailure.Store(signalComponentFailure)
 }
 
-// IsInproxyPersonalPairingMode indicates that the client is in in-proxy
+// IsInproxyClientPersonalPairingMode indicates that the client is in in-proxy
 // personal pairing mode, where connections are made only through in-proxy
 // proxies with the corresponding personal compartment ID.
-func (config *Config) IsInproxyPersonalPairingMode() bool {
+func (config *Config) IsInproxyClientPersonalPairingMode() bool {
 	return len(config.InproxyClientPersonalCompartmentID) > 0
 }
 
+// IsInproxyProxyPersonalPairingMode indicates that the proxy is in in-proxy
+// personal pairing mode, where connections are made only with in-proxy
+// clients with the corresponding personal compartment ID.
+func (config *Config) IsInproxyProxyPersonalPairingMode() bool {
+	return len(config.InproxyProxyPersonalCompartmentID) > 0
+}
+
 // OnInproxyMustUpgrade is invoked when the in-proxy broker returns the
 // MustUpgrade response. When either running a proxy, or when running a
 // client in personal-pairing mode -- two states that require in-proxy
@@ -1823,7 +1832,7 @@ func (config *Config) OnInproxyMustUpgrade() {
 	// protocols; this is another case where in-proxy functionality is
 	// required.
 
-	if config.InproxyEnableProxy || config.IsInproxyPersonalPairingMode() {
+	if config.InproxyEnableProxy || config.IsInproxyClientPersonalPairingMode() {
 		if atomic.CompareAndSwapInt32(&config.inproxyMustUpgradePosted, 0, 1) {
 			NoticeInproxyMustUpgrade()
 		}
@@ -2692,6 +2701,14 @@ func (config *Config) makeConfigParameters() map[string]interface{} {
 		applyParameters[parameters.InproxyProxyOnBrokerClientFailedRetryPeriod] = fmt.Sprintf("%dms", *config.InproxyProxyOnBrokerClientFailedRetryPeriodMilliseconds)
 	}
 
+	if len(config.InproxyProxyIncompatibleNetworkTypes) > 0 {
+		applyParameters[parameters.InproxyProxyIncompatibleNetworkTypes] = config.InproxyProxyIncompatibleNetworkTypes
+	}
+
+	if len(config.InproxyClientIncompatibleNetworkTypes) > 0 {
+		applyParameters[parameters.InproxyClientIncompatibleNetworkTypes] = config.InproxyClientIncompatibleNetworkTypes
+	}
+
 	// When adding new config dial parameters that may override tactics, also
 	// update setDialParametersHash.
 

+ 27 - 15
psiphon/controller.go

@@ -1612,7 +1612,7 @@ func (p *protocolSelectionConstraints) selectProtocol(
 	//
 	// TODO: replace token on fast failure that doesn't reach the broker?
 
-	if p.config.IsInproxyPersonalPairingMode() ||
+	if p.config.IsInproxyClientPersonalPairingMode() ||
 		p.getLimitTunnelProtocols(connectTunnelCount).IsOnlyInproxyTunnelProtocols() {
 
 		// Check for missing in-proxy broker request requirements before
@@ -1625,7 +1625,7 @@ func (p *protocolSelectionConstraints) selectProtocol(
 			NoticeInfo("in-proxy protocol selection failed: no broker specs")
 			return "", 0, false
 		}
-		if !p.config.IsInproxyPersonalPairingMode() &&
+		if !p.config.IsInproxyClientPersonalPairingMode() &&
 			!haveInproxyCommonCompartmentIDs(p.config) {
 			NoticeInfo("in-proxy protocol selection failed: no common compartment IDs")
 			return "", 0, false
@@ -1897,7 +1897,7 @@ func (controller *Controller) launchEstablishing() {
 	// corresponding personal compartment ID, so non-in-proxy tunnel
 	// protocols are disabled.
 
-	if controller.config.IsInproxyPersonalPairingMode() {
+	if controller.config.IsInproxyClientPersonalPairingMode() {
 
 		if len(controller.protocolSelectionConstraints.initialLimitTunnelProtocols) > 0 {
 			controller.protocolSelectionConstraints.initialLimitTunnelProtocols =
@@ -1928,7 +1928,7 @@ func (controller *Controller) launchEstablishing() {
 	// announcement consumption for personal proxies.
 
 	var workerPoolSize int
-	if controller.config.IsInproxyPersonalPairingMode() {
+	if controller.config.IsInproxyClientPersonalPairingMode() {
 		workerPoolSize = p.Int(parameters.InproxyPersonalPairingConnectionWorkerPoolSize)
 	} else {
 		workerPoolSize = p.Int(parameters.ConnectionWorkerPoolSize)
@@ -2360,7 +2360,7 @@ loop:
 				controller.establishConnectTunnelCount).IsOnlyInproxyTunnelProtocols()
 			controller.concurrentEstablishTunnelsMutex.Unlock()
 
-			if limitInproxyOnly || controller.config.IsInproxyPersonalPairingMode() {
+			if limitInproxyOnly || controller.config.IsInproxyClientPersonalPairingMode() {
 
 				// Simply sleep and poll for any imported server entries;
 				// perform one sleep after HasServerEntries, in order to give
@@ -2562,7 +2562,7 @@ loop:
 			// tuning/limiting in-proxy usage independent of
 			// LimitTunnelProtocol targeting.
 
-			onlyInproxy := controller.config.IsInproxyPersonalPairingMode()
+			onlyInproxy := controller.config.IsInproxyClientPersonalPairingMode()
 			includeInproxy := onlyInproxy || prng.FlipWeightedCoin(inproxySelectionProbability)
 
 			selectedProtocol, rateLimitDelay, ok := controller.protocolSelectionConstraints.selectProtocol(
@@ -3079,16 +3079,28 @@ func (controller *Controller) inproxyAwaitProxyBrokerSpecs() bool {
 
 func (controller *Controller) inproxyWaitForNetworkConnectivity() bool {
 
-	// Pause announcing proxies when currently running on an incompatible
-	// network, such as a non-Psiphon VPN.
-	emitted := false
-	isCompatibleNetwork := func() bool {
-		compatibleNetwork := IsInproxyCompatibleNetworkType(controller.config.GetNetworkID())
-		if !compatibleNetwork && !emitted {
-			NoticeInfo("inproxy proxy: waiting due to incompatible network")
-			emitted = true
+	var isCompatibleNetwork func() bool
+	emittedIncompatibleNetworkNotice := false
+
+	if !controller.config.IsInproxyProxyPersonalPairingMode() {
+
+		// Pause announcing proxies when currently running on an incompatible
+		// network, such as a non-Psiphon VPN.
+
+		p := controller.config.GetParameters().Get()
+		incompatibleNetworkTypes := p.Strings(parameters.InproxyProxyIncompatibleNetworkTypes)
+		p.Close()
+
+		isCompatibleNetwork = func() bool {
+			compatibleNetwork := !common.Contains(
+				incompatibleNetworkTypes,
+				GetNetworkType(controller.config.GetNetworkID()))
+			if !compatibleNetwork && !emittedIncompatibleNetworkNotice {
+				NoticeInfo("inproxy proxy: waiting due to incompatible network")
+				emittedIncompatibleNetworkNotice = true
+			}
+			return compatibleNetwork
 		}
-		return compatibleNetwork
 	}
 
 	return WaitForNetworkConnectivity(

+ 13 - 3
psiphon/dialParameters.go

@@ -1099,7 +1099,7 @@ func MakeDialParameters(
 			isFronted := protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol)
 
 			params, err := makeHTTPTransformerParameters(
-				config.GetParameters().Get(), serverEntry.FrontingProviderID, isFronted)
+				p, serverEntry.FrontingProviderID, isFronted)
 			if err != nil {
 				return nil, errors.Trace(err)
 			}
@@ -1124,8 +1124,18 @@ func MakeDialParameters(
 		// MakeDialParameters, such as in selectProtocol during iteration,
 		// checking here uses the network ID obtained in MakeDialParameters,
 		// and the logged warning is useful for diagnostics.
-		if !IsInproxyCompatibleNetworkType(dialParams.NetworkID) {
-			return nil, errors.TraceNew("inproxy protocols skipped on incompatible network")
+		//
+		// This check is skipped when in-proxy protocols must be used.
+		if !config.IsInproxyClientPersonalPairingMode() &&
+			!p.TunnelProtocols(parameters.LimitTunnelProtocols).IsOnlyInproxyTunnelProtocols() {
+
+			incompatibleNetworkTypes := p.Strings(parameters.InproxyClientIncompatibleNetworkTypes)
+			compatibleNetwork := !common.Contains(
+				incompatibleNetworkTypes,
+				GetNetworkType(dialParams.NetworkID))
+			if !compatibleNetwork {
+				return nil, errors.TraceNew("inproxy protocols skipped on incompatible network")
+			}
 		}
 
 		// inproxyDialInitialized indicates that the inproxy dial was wired

+ 5 - 5
psiphon/inproxy.go

@@ -180,7 +180,7 @@ func (b *InproxyBrokerClientManager) resetBrokerClientOnNoMatch(
 	defer p.Close()
 
 	probability := parameters.InproxyClientNoMatchFailoverProbability
-	if b.config.IsInproxyPersonalPairingMode() {
+	if b.config.IsInproxyClientPersonalPairingMode() {
 		probability = parameters.InproxyClientNoMatchFailoverPersonalProbability
 	}
 	if !p.WeightedCoinFlip(probability) {
@@ -531,7 +531,7 @@ func NewInproxyBrokerClientInstance(
 		replayUpdateFrequency:         p.Duration(parameters.InproxyReplayBrokerUpdateFrequency),
 	}
 
-	if isProxy && !config.IsInproxyPersonalPairingMode() {
+	if isProxy && !config.IsInproxyProxyPersonalPairingMode() {
 		// This retry is applied only for proxies and only in common pairing
 		// mode. See comment in BrokerClientRoundTripperFailed.
 		b.retryOnFailedPeriod = p.Duration(parameters.InproxyProxyOnBrokerClientFailedRetryPeriod)
@@ -596,7 +596,7 @@ func getInproxyBrokerSpecs(
 	isProxy bool) parameters.InproxyBrokerSpecsValue {
 
 	if isProxy {
-		if config.IsInproxyPersonalPairingMode() {
+		if config.IsInproxyProxyPersonalPairingMode() {
 			return p.InproxyBrokerSpecs(
 				parameters.InproxyProxyPersonalPairingBrokerSpecs,
 				parameters.InproxyPersonalPairingBrokerSpecs,
@@ -608,7 +608,7 @@ func getInproxyBrokerSpecs(
 				parameters.InproxyBrokerSpecs)
 		}
 	} else {
-		if config.IsInproxyPersonalPairingMode() {
+		if config.IsInproxyClientPersonalPairingMode() {
 			return p.InproxyBrokerSpecs(
 				parameters.InproxyClientPersonalPairingBrokerSpecs,
 				parameters.InproxyPersonalPairingBrokerSpecs,
@@ -915,7 +915,7 @@ func (b *InproxyBrokerClientInstance) BrokerClientRoundTripperFailed(roundTrippe
 	// briefly unavailable.
 
 	if b.brokerClientManager.isProxy &&
-		!b.config.IsInproxyPersonalPairingMode() &&
+		!b.config.IsInproxyProxyPersonalPairingMode() &&
 		b.retryOnFailedPeriod > 0 &&
 		!b.lastSuccess.IsZero() &&
 		time.Since(b.lastSuccess) <= b.retryOnFailedPeriod {

+ 0 - 10
psiphon/utils.go

@@ -299,13 +299,3 @@ func GetNetworkType(networkID string) string {
 	}
 	return "UNKNOWN"
 }
-
-// IsInproxyCompatibleNetworkType indicates if the network type for the given
-// network ID is compatible with in-proxy operation.
-func IsInproxyCompatibleNetworkType(networkID string) bool {
-
-	// When the network type is "VPN", the outer client (or MobileLibrary) has
-	// detected that some other, non-Psiphon VPN is active. In this case,
-	// most in-proxy operations are expected to fail.
-	return GetNetworkType(networkID) != "VPN"
-}