Skip to content

Commit

Permalink
Merge pull request #700 from rod-hynes/incompatible-networks-tactics
Browse files Browse the repository at this point in the history
Add tactics parameters for in-proxy incompatible network types
  • Loading branch information
rod-hynes authored Nov 4, 2024
2 parents 149259b + f1ae9bb commit 0247401
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 36 deletions.
4 changes: 4 additions & 0 deletions psiphon/common/parameters/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ const (
InproxyFrontingProviderClientMaxRequestTimeouts = "InproxyFrontingProviderClientMaxRequestTimeouts"
InproxyFrontingProviderServerMaxRequestTimeouts = "InproxyFrontingProviderServerMaxRequestTimeouts"
InproxyProxyOnBrokerClientFailedRetryPeriod = "InproxyProxyOnBrokerClientFailedRetryPeriod"
InproxyProxyIncompatibleNetworkTypes = "InproxyProxyIncompatibleNetworkTypes"
InproxyClientIncompatibleNetworkTypes = "InproxyClientIncompatibleNetworkTypes"

// Retired parameters

Expand Down Expand Up @@ -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
Expand Down
23 changes: 20 additions & 3 deletions psiphon/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,8 @@ type Config struct {
InproxyClientNoMatchFailoverPersonalProbability *float64
InproxyFrontingProviderClientMaxRequestTimeouts map[string]string
InproxyProxyOnBrokerClientFailedRetryPeriodMilliseconds *int
InproxyProxyIncompatibleNetworkTypes []string
InproxyClientIncompatibleNetworkTypes []string

InproxySkipAwaitFullyConnected bool
InproxyEnableWebRTCDebugLogging bool
Expand Down Expand Up @@ -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
Expand All @@ -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()
}
Expand Down Expand Up @@ -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.

Expand Down
42 changes: 27 additions & 15 deletions psiphon/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down
16 changes: 13 additions & 3 deletions psiphon/dialParameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
Expand Down
10 changes: 5 additions & 5 deletions psiphon/inproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -608,7 +608,7 @@ func getInproxyBrokerSpecs(
parameters.InproxyBrokerSpecs)
}
} else {
if config.IsInproxyPersonalPairingMode() {
if config.IsInproxyClientPersonalPairingMode() {
return p.InproxyBrokerSpecs(
parameters.InproxyClientPersonalPairingBrokerSpecs,
parameters.InproxyPersonalPairingBrokerSpecs,
Expand Down Expand Up @@ -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 {
Expand Down
10 changes: 0 additions & 10 deletions psiphon/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

0 comments on commit 0247401

Please sign in to comment.