github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/dialParameters.go (about)

     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  package psiphon
    21  
    22  import (
    23  	"bytes"
    24  	"context"
    25  	"crypto/md5"
    26  	"encoding/binary"
    27  	"net"
    28  	"net/http"
    29  	"strconv"
    30  	"strings"
    31  	"sync/atomic"
    32  	"time"
    33  
    34  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
    35  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
    36  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/fragmentor"
    37  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
    38  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
    39  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
    40  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/resolver"
    41  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
    42  	utls "github.com/Psiphon-Labs/utls"
    43  	regen "github.com/zach-klippenstein/goregen"
    44  	"golang.org/x/net/bpf"
    45  )
    46  
    47  // DialParameters represents a selected protocol and all the related selected
    48  // protocol attributes, many chosen at random, for a tunnel dial attempt.
    49  //
    50  // DialParameters is used:
    51  // - to configure dialers
    52  // - as a persistent record to store successful dial parameters for replay
    53  // - to report dial stats in notices and Psiphon API calls.
    54  //
    55  // MeekResolvedIPAddress is set asynchronously, as it is not known until the
    56  // dial process has begun. The atomic.Value will contain a string, initialized
    57  // to "", and set to the resolved IP address once that part of the dial
    58  // process has completed.
    59  //
    60  // DialParameters is not safe for concurrent use.
    61  type DialParameters struct {
    62  	ServerEntry             *protocol.ServerEntry `json:"-"`
    63  	NetworkID               string                `json:"-"`
    64  	IsReplay                bool                  `json:"-"`
    65  	CandidateNumber         int                   `json:"-"`
    66  	EstablishedTunnelsCount int                   `json:"-"`
    67  
    68  	IsExchanged bool
    69  
    70  	LastUsedTimestamp       time.Time
    71  	LastUsedConfigStateHash []byte
    72  
    73  	NetworkLatencyMultiplier float64
    74  
    75  	TunnelProtocol string
    76  
    77  	DirectDialAddress              string
    78  	DialPortNumber                 string
    79  	UpstreamProxyType              string   `json:"-"`
    80  	UpstreamProxyCustomHeaderNames []string `json:"-"`
    81  
    82  	BPFProgramName         string
    83  	BPFProgramInstructions []bpf.RawInstruction
    84  
    85  	SelectedSSHClientVersion bool
    86  	SSHClientVersion         string
    87  	SSHKEXSeed               *prng.Seed
    88  
    89  	ObfuscatorPaddingSeed *prng.Seed
    90  
    91  	FragmentorSeed *prng.Seed
    92  
    93  	FrontingProviderID string
    94  
    95  	MeekFrontingDialAddress   string
    96  	MeekFrontingHost          string
    97  	MeekDialAddress           string
    98  	MeekTransformedHostName   bool
    99  	MeekSNIServerName         string
   100  	MeekVerifyServerName      string
   101  	MeekVerifyPins            []string
   102  	MeekHostHeader            string
   103  	MeekObfuscatorPaddingSeed *prng.Seed
   104  	MeekTLSPaddingSize        int
   105  	MeekResolvedIPAddress     atomic.Value `json:"-"`
   106  
   107  	SelectedUserAgent bool
   108  	UserAgent         string
   109  
   110  	SelectedTLSProfile       bool
   111  	TLSProfile               string
   112  	NoDefaultTLSSessionID    bool
   113  	TLSVersion               string
   114  	RandomizedTLSProfileSeed *prng.Seed
   115  
   116  	QUICVersion                 string
   117  	QUICDialSNIAddress          string
   118  	QUICClientHelloSeed         *prng.Seed
   119  	ObfuscatedQUICPaddingSeed   *prng.Seed
   120  	QUICDisablePathMTUDiscovery bool
   121  
   122  	ConjureCachedRegistrationTTL        time.Duration
   123  	ConjureAPIRegistration              bool
   124  	ConjureAPIRegistrarBidirectionalURL string
   125  	ConjureAPIRegistrarDelay            time.Duration
   126  	ConjureDecoyRegistration            bool
   127  	ConjureDecoyRegistrarDelay          time.Duration
   128  	ConjureDecoyRegistrarWidth          int
   129  	ConjureTransport                    string
   130  
   131  	LivenessTestSeed *prng.Seed
   132  
   133  	APIRequestPaddingSeed *prng.Seed
   134  
   135  	HoldOffTunnelDuration time.Duration
   136  
   137  	DialConnMetrics          common.MetricsSource       `json:"-"`
   138  	DialConnNoticeMetrics    common.NoticeMetricsSource `json:"-"`
   139  	ObfuscatedSSHConnMetrics common.MetricsSource       `json:"-"`
   140  
   141  	DialDuration time.Duration `json:"-"`
   142  
   143  	resolver          *resolver.Resolver `json:"-"`
   144  	ResolveParameters *resolver.ResolveParameters
   145  
   146  	dialConfig *DialConfig `json:"-"`
   147  	meekConfig *MeekConfig `json:"-"`
   148  }
   149  
   150  // MakeDialParameters creates a new DialParameters for the candidate server
   151  // entry, including selecting a protocol and all the various protocol
   152  // attributes. The input selectProtocol is used to comply with any active
   153  // protocol selection constraints.
   154  //
   155  // When stored dial parameters are available and may be used,
   156  // MakeDialParameters may replay previous dial parameters in an effort to
   157  // leverage "known working" values instead of always chosing at random from a
   158  // large space.
   159  //
   160  // MakeDialParameters will return nil/nil in cases where the candidate server
   161  // entry should be skipped.
   162  //
   163  // To support replay, the caller must call DialParameters.Succeeded when a
   164  // successful tunnel is established with the returned DialParameters; and must
   165  // call DialParameters.Failed when a tunnel dial or activation fails, except
   166  // when establishment is cancelled.
   167  func MakeDialParameters(
   168  	config *Config,
   169  	upstreamProxyErrorCallback func(error),
   170  	canReplay func(serverEntry *protocol.ServerEntry, replayProtocol string) bool,
   171  	selectProtocol func(serverEntry *protocol.ServerEntry) (string, bool),
   172  	serverEntry *protocol.ServerEntry,
   173  	isTactics bool,
   174  	candidateNumber int,
   175  	establishedTunnelsCount int) (*DialParameters, error) {
   176  
   177  	networkID := config.GetNetworkID()
   178  
   179  	p := config.GetParameters().Get()
   180  
   181  	ttl := p.Duration(parameters.ReplayDialParametersTTL)
   182  	replayBPF := p.Bool(parameters.ReplayBPF)
   183  	replaySSH := p.Bool(parameters.ReplaySSH)
   184  	replayObfuscatorPadding := p.Bool(parameters.ReplayObfuscatorPadding)
   185  	replayFragmentor := p.Bool(parameters.ReplayFragmentor)
   186  	replayTLSProfile := p.Bool(parameters.ReplayTLSProfile)
   187  	replayRandomizedTLSProfile := p.Bool(parameters.ReplayRandomizedTLSProfile)
   188  	replayFronting := p.Bool(parameters.ReplayFronting)
   189  	replayHostname := p.Bool(parameters.ReplayHostname)
   190  	replayQUICVersion := p.Bool(parameters.ReplayQUICVersion)
   191  	replayObfuscatedQUIC := p.Bool(parameters.ReplayObfuscatedQUIC)
   192  	replayConjureRegistration := p.Bool(parameters.ReplayConjureRegistration)
   193  	replayConjureTransport := p.Bool(parameters.ReplayConjureTransport)
   194  	replayLivenessTest := p.Bool(parameters.ReplayLivenessTest)
   195  	replayUserAgent := p.Bool(parameters.ReplayUserAgent)
   196  	replayAPIRequestPadding := p.Bool(parameters.ReplayAPIRequestPadding)
   197  	replayHoldOffTunnel := p.Bool(parameters.ReplayHoldOffTunnel)
   198  	replayResolveParameters := p.Bool(parameters.ReplayResolveParameters)
   199  
   200  	// Check for existing dial parameters for this server/network ID.
   201  
   202  	dialParams, err := GetDialParameters(
   203  		config, serverEntry.IpAddress, networkID)
   204  	if err != nil {
   205  		NoticeWarning("GetDialParameters failed: %s", err)
   206  		dialParams = nil
   207  		// Proceed, without existing dial parameters.
   208  	}
   209  
   210  	// Check if replay is permitted:
   211  	// - TTL must be > 0 and existing dial parameters must not have expired
   212  	//   as indicated by LastUsedTimestamp + TTL.
   213  	// - Config/tactics/server entry values must be unchanged from when
   214  	//   previous dial parameters were established.
   215  	// - The protocol selection constraints must permit replay, as indicated
   216  	//   by canReplay.
   217  	// - Must not be using an obsolete TLS profile that is no longer supported.
   218  	// - Must be using the latest Conjure API URL.
   219  	//
   220  	// When existing dial parameters don't meet these conditions, dialParams
   221  	// is reset to nil and new dial parameters will be generated.
   222  
   223  	var currentTimestamp time.Time
   224  	var configStateHash []byte
   225  
   226  	// When TTL is 0, replay is disabled; the timestamp remains 0 and the
   227  	// output DialParameters will not be stored by Success.
   228  
   229  	if ttl > 0 {
   230  		currentTimestamp = time.Now()
   231  		configStateHash = getConfigStateHash(config, p, serverEntry)
   232  	}
   233  
   234  	if dialParams != nil &&
   235  		(ttl <= 0 ||
   236  			dialParams.LastUsedTimestamp.Before(currentTimestamp.Add(-ttl)) ||
   237  			!bytes.Equal(dialParams.LastUsedConfigStateHash, configStateHash) ||
   238  			(dialParams.TLSProfile != "" &&
   239  				!common.Contains(protocol.SupportedTLSProfiles, dialParams.TLSProfile)) ||
   240  			(dialParams.QUICVersion != "" &&
   241  				!common.Contains(protocol.SupportedQUICVersions, dialParams.QUICVersion)) ||
   242  
   243  			// Legacy clients use ConjureAPIRegistrarURL with
   244  			// gotapdance.tapdance.APIRegistrar and new clients use
   245  			// ConjureAPIRegistrarBidirectionalURL with
   246  			// gotapdance.tapdance.APIRegistrarBidirectional. Updated clients
   247  			// may have replay dial parameters with the old
   248  			// ConjureAPIRegistrarURL field, which is now ignored. In this
   249  			// case, ConjureAPIRegistrarBidirectionalURL will be blank. Reset
   250  			// this replay.
   251  			(dialParams.ConjureAPIRegistration && dialParams.ConjureAPIRegistrarBidirectionalURL == "")) {
   252  
   253  		// In these cases, existing dial parameters are expired or no longer
   254  		// match the config state and so are cleared to avoid rechecking them.
   255  
   256  		err = DeleteDialParameters(serverEntry.IpAddress, networkID)
   257  		if err != nil {
   258  			NoticeWarning("DeleteDialParameters failed: %s", err)
   259  		}
   260  		dialParams = nil
   261  	}
   262  
   263  	if dialParams != nil {
   264  		if config.DisableReplay ||
   265  			!canReplay(serverEntry, dialParams.TunnelProtocol) {
   266  
   267  			// In these ephemeral cases, existing dial parameters may still be valid
   268  			// and used in future establishment phases, and so are retained.
   269  
   270  			dialParams = nil
   271  		}
   272  	}
   273  
   274  	// IsExchanged:
   275  	//
   276  	// Dial parameters received via client-to-client exchange are partially
   277  	// initialized. Only the exchange fields are retained, and all other dial
   278  	// parameters fields must be initialized. This is not considered or logged as
   279  	// a replay. The exchange case is identified by the IsExchanged flag.
   280  	//
   281  	// When previously stored, IsExchanged dial parameters will have set the same
   282  	// timestamp and state hash used for regular dial parameters and the same
   283  	// logic above should invalidate expired or invalid exchanged dial
   284  	// parameters.
   285  	//
   286  	// Limitation: metrics will indicate when an exchanged server entry is used
   287  	// (source "EXCHANGED") but will not indicate when exchanged dial parameters
   288  	// are used vs. a redial after discarding dial parameters.
   289  
   290  	isReplay := (dialParams != nil)
   291  	isExchanged := isReplay && dialParams.IsExchanged
   292  
   293  	if !isReplay {
   294  		dialParams = &DialParameters{}
   295  	}
   296  
   297  	// Point to the current resolver to be used in dials.
   298  	dialParams.resolver = config.GetResolver()
   299  	if dialParams.resolver == nil {
   300  		return nil, errors.TraceNew("missing resolver")
   301  	}
   302  
   303  	if isExchanged {
   304  		// Set isReplay to false to cause all non-exchanged values to be
   305  		// initialized; this also causes the exchange case to not log as replay.
   306  		isReplay = false
   307  	}
   308  
   309  	// Set IsExchanged such that full dial parameters are stored and replayed
   310  	// upon success.
   311  	dialParams.IsExchanged = false
   312  
   313  	dialParams.ServerEntry = serverEntry
   314  	dialParams.NetworkID = networkID
   315  	dialParams.IsReplay = isReplay
   316  	dialParams.CandidateNumber = candidateNumber
   317  	dialParams.EstablishedTunnelsCount = establishedTunnelsCount
   318  
   319  	// Even when replaying, LastUsedTimestamp is updated to extend the TTL of
   320  	// replayed dial parameters which will be updated in the datastore upon
   321  	// success.
   322  
   323  	dialParams.LastUsedTimestamp = currentTimestamp
   324  	dialParams.LastUsedConfigStateHash = configStateHash
   325  
   326  	// Initialize dial parameters.
   327  	//
   328  	// When not replaying, all required parameters are initialized. When
   329  	// replaying, existing parameters are retaing, subject to the replay-X
   330  	// tactics flags.
   331  
   332  	// Select a network latency multiplier for this dial. This allows clients to
   333  	// explore and discover timeout values appropriate for the current network.
   334  	// The selection applies per tunnel, to avoid delaying all establishment
   335  	// candidates due to excessive timeouts. The random selection is bounded by a
   336  	// min/max set in tactics and an exponential distribution is used so as to
   337  	// heavily favor values close to the min, which should be set to the
   338  	// singleton NetworkLatencyMultiplier tactics value.
   339  	//
   340  	// For NetworkLatencyMultiplierLambda close to 2.0, values near min are
   341  	// very approximately 10x more likely to be selected than values near
   342  	// max, while for NetworkLatencyMultiplierLambda close to 0.1, the
   343  	// distribution is close to uniform.
   344  	//
   345  	// Not all existing, persisted DialParameters will have a custom
   346  	// NetworkLatencyMultiplier value. Its zero value will cause the singleton
   347  	// NetworkLatencyMultiplier tactics value to be used instead, which is
   348  	// consistent with the pre-custom multiplier behavior in the older client
   349  	// version which persisted that DialParameters.
   350  
   351  	networkLatencyMultiplierMin := p.Float(parameters.NetworkLatencyMultiplierMin)
   352  	networkLatencyMultiplierMax := p.Float(parameters.NetworkLatencyMultiplierMax)
   353  
   354  	if !isReplay ||
   355  		// Was selected...
   356  		(dialParams.NetworkLatencyMultiplier != 0.0 &&
   357  			//  But is now outside tactics range...
   358  			(dialParams.NetworkLatencyMultiplier < networkLatencyMultiplierMin ||
   359  				dialParams.NetworkLatencyMultiplier > networkLatencyMultiplierMax)) {
   360  
   361  		dialParams.NetworkLatencyMultiplier = prng.ExpFloat64Range(
   362  			networkLatencyMultiplierMin,
   363  			networkLatencyMultiplierMax,
   364  			p.Float(parameters.NetworkLatencyMultiplierLambda))
   365  	}
   366  
   367  	// After this point, any tactics parameters that apply the network latency
   368  	// multiplier will use this selected value.
   369  	p = config.GetParameters().GetCustom(dialParams.NetworkLatencyMultiplier)
   370  
   371  	if !isReplay && !isExchanged {
   372  
   373  		// TODO: should there be a pre-check of selectProtocol before incurring
   374  		// overhead of unmarshaling dial parameters? In may be that a server entry
   375  		// is fully incapable of satisfying the current protocol selection
   376  		// constraints.
   377  
   378  		selectedProtocol, ok := selectProtocol(serverEntry)
   379  		if !ok {
   380  			return nil, nil
   381  		}
   382  
   383  		dialParams.TunnelProtocol = selectedProtocol
   384  	}
   385  
   386  	// Skip this candidate when the clients tactics restrict usage of the
   387  	// fronting provider ID. See the corresponding server-side enforcement
   388  	// comments in server.TacticsListener.accept.
   389  	if protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) &&
   390  		common.Contains(
   391  			p.Strings(parameters.RestrictFrontingProviderIDs),
   392  			dialParams.ServerEntry.FrontingProviderID) {
   393  		if p.WeightedCoinFlip(
   394  			parameters.RestrictFrontingProviderIDsClientProbability) {
   395  
   396  			// When skipping, return nil/nil as no error should be logged.
   397  			// NoticeSkipServerEntry emits each skip reason, regardless
   398  			// of server entry, at most once per session.
   399  
   400  			NoticeSkipServerEntry(
   401  				"restricted fronting provider ID: %s",
   402  				dialParams.ServerEntry.FrontingProviderID)
   403  
   404  			return nil, nil
   405  		}
   406  	}
   407  
   408  	if config.UseUpstreamProxy() {
   409  
   410  		// When UpstreamProxy is configured, ServerEntry.GetSupportedProtocols, when
   411  		// called via selectProtocol, will filter out protocols such that will not
   412  		// select a protocol incompatible with UpstreamProxy. This additional check
   413  		// will catch cases where selectProtocol does not apply this filter.
   414  		if !protocol.TunnelProtocolSupportsUpstreamProxy(dialParams.TunnelProtocol) {
   415  
   416  			NoticeSkipServerEntry(
   417  				"protocol does not support upstream proxy: %s",
   418  				dialParams.TunnelProtocol)
   419  
   420  			return nil, nil
   421  		}
   422  
   423  		// Skip this candidate when the server entry is not to be used with an
   424  		// upstream proxy. By not exposing servers from sources that are
   425  		// relatively hard to enumerate, this mechanism mitigates the risk of
   426  		// a malicious upstream proxy enumerating Psiphon servers. Populate
   427  		// the allowed sources with fronted servers to provide greater
   428  		// blocking resistence for clients using upstream proxy clients that
   429  		// are subject to blocking.
   430  		source := dialParams.ServerEntry.LocalSource
   431  		if !protocol.AllowServerEntrySourceWithUpstreamProxy(source) &&
   432  			!p.Bool(parameters.UpstreamProxyAllowAllServerEntrySources) {
   433  
   434  			NoticeSkipServerEntry(
   435  				"server entry source disallowed with upstream proxy: %s",
   436  				source)
   437  
   438  			return nil, nil
   439  		}
   440  	}
   441  
   442  	if (!isReplay || !replayBPF) &&
   443  		ClientBPFEnabled() &&
   444  		protocol.TunnelProtocolUsesTCP(dialParams.TunnelProtocol) {
   445  
   446  		if p.WeightedCoinFlip(parameters.BPFClientTCPProbability) {
   447  			dialParams.BPFProgramName = ""
   448  			dialParams.BPFProgramInstructions = nil
   449  			ok, name, rawInstructions := p.BPFProgram(parameters.BPFClientTCPProgram)
   450  			if ok {
   451  				dialParams.BPFProgramName = name
   452  				dialParams.BPFProgramInstructions = rawInstructions
   453  			}
   454  		}
   455  	}
   456  
   457  	if !isReplay || !replaySSH {
   458  		dialParams.SelectedSSHClientVersion = true
   459  		dialParams.SSHClientVersion = values.GetSSHClientVersion()
   460  		dialParams.SSHKEXSeed, err = prng.NewSeed()
   461  		if err != nil {
   462  			return nil, errors.Trace(err)
   463  		}
   464  	}
   465  
   466  	if !isReplay || !replayObfuscatorPadding {
   467  		dialParams.ObfuscatorPaddingSeed, err = prng.NewSeed()
   468  		if err != nil {
   469  			return nil, errors.Trace(err)
   470  		}
   471  		if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) {
   472  			dialParams.MeekObfuscatorPaddingSeed, err = prng.NewSeed()
   473  			if err != nil {
   474  				return nil, errors.Trace(err)
   475  			}
   476  		}
   477  	}
   478  
   479  	if !isReplay || !replayFragmentor {
   480  		dialParams.FragmentorSeed, err = prng.NewSeed()
   481  		if err != nil {
   482  			return nil, errors.Trace(err)
   483  		}
   484  	}
   485  
   486  	if (!isReplay || !replayConjureRegistration) &&
   487  		protocol.TunnelProtocolUsesConjure(dialParams.TunnelProtocol) {
   488  
   489  		dialParams.ConjureCachedRegistrationTTL = p.Duration(parameters.ConjureCachedRegistrationTTL)
   490  
   491  		apiURL := p.String(parameters.ConjureAPIRegistrarBidirectionalURL)
   492  		decoyWidth := p.Int(parameters.ConjureDecoyRegistrarWidth)
   493  
   494  		dialParams.ConjureAPIRegistration = apiURL != ""
   495  		dialParams.ConjureDecoyRegistration = decoyWidth != 0
   496  
   497  		// We select only one of API or decoy registration. When both are enabled,
   498  		// ConjureDecoyRegistrarProbability determines the probability of using
   499  		// decoy registration.
   500  		//
   501  		// In general, we disable retries in gotapdance and rely on Psiphon
   502  		// establishment to try/retry different registration schemes. This allows us
   503  		// to control the proportion of registration types attempted. And, in good
   504  		// network conditions, individual candidates are most likely to be cancelled
   505  		// before they exhaust their retry options.
   506  
   507  		if dialParams.ConjureAPIRegistration && dialParams.ConjureDecoyRegistration {
   508  			if p.WeightedCoinFlip(parameters.ConjureDecoyRegistrarProbability) {
   509  				dialParams.ConjureAPIRegistration = false
   510  			}
   511  		}
   512  
   513  		if dialParams.ConjureAPIRegistration {
   514  
   515  			// While Conjure API registration uses MeekConn and specifies common meek
   516  			// parameters, the meek address and SNI configuration is implemented in this
   517  			// code block and not in common code blocks below. The exception is TLS
   518  			// configuration.
   519  			//
   520  			// Accordingly, replayFronting/replayHostname have no effect on Conjure API
   521  			// registration replay.
   522  
   523  			dialParams.ConjureAPIRegistrarBidirectionalURL = apiURL
   524  
   525  			frontingSpecs := p.FrontingSpecs(parameters.ConjureAPIRegistrarFrontingSpecs)
   526  			dialParams.FrontingProviderID,
   527  				dialParams.MeekFrontingDialAddress,
   528  				dialParams.MeekSNIServerName,
   529  				dialParams.MeekVerifyServerName,
   530  				dialParams.MeekVerifyPins,
   531  				dialParams.MeekFrontingHost,
   532  				err = frontingSpecs.SelectParameters()
   533  			if err != nil {
   534  				return nil, errors.Trace(err)
   535  			}
   536  
   537  			dialParams.MeekDialAddress = net.JoinHostPort(dialParams.MeekFrontingDialAddress, "443")
   538  			dialParams.MeekHostHeader = dialParams.MeekFrontingHost
   539  
   540  			// For a FrontingSpec, an SNI value of "" indicates to disable/omit SNI, so
   541  			// never transform in that case.
   542  			if dialParams.MeekSNIServerName != "" {
   543  				if p.WeightedCoinFlip(parameters.TransformHostNameProbability) {
   544  					dialParams.MeekSNIServerName = selectHostName(dialParams.TunnelProtocol, p)
   545  					dialParams.MeekTransformedHostName = true
   546  				}
   547  			}
   548  
   549  			// The minimum delay value is determined by the Conjure station, which
   550  			// performs an asynchronous "liveness test" against the selected phantom
   551  			// IPs. The min/max range allows us to introduce some jitter so that we
   552  			// don't present a trivial inter-flow fingerprint: CDN connection, fixed
   553  			// delay, phantom dial.
   554  
   555  			minDelay := p.Duration(parameters.ConjureAPIRegistrarMinDelay)
   556  			maxDelay := p.Duration(parameters.ConjureAPIRegistrarMaxDelay)
   557  			dialParams.ConjureAPIRegistrarDelay = prng.Period(minDelay, maxDelay)
   558  
   559  		} else if dialParams.ConjureDecoyRegistration {
   560  
   561  			dialParams.ConjureDecoyRegistrarWidth = decoyWidth
   562  			minDelay := p.Duration(parameters.ConjureDecoyRegistrarMinDelay)
   563  			maxDelay := p.Duration(parameters.ConjureDecoyRegistrarMaxDelay)
   564  			dialParams.ConjureAPIRegistrarDelay = prng.Period(minDelay, maxDelay)
   565  
   566  		} else {
   567  
   568  			return nil, errors.TraceNew("no Conjure registrar configured")
   569  		}
   570  	}
   571  
   572  	if (!isReplay || !replayConjureTransport) &&
   573  		protocol.TunnelProtocolUsesConjure(dialParams.TunnelProtocol) {
   574  
   575  		dialParams.ConjureTransport = protocol.CONJURE_TRANSPORT_MIN_OSSH
   576  		if p.WeightedCoinFlip(
   577  			parameters.ConjureTransportObfs4Probability) {
   578  			dialParams.ConjureTransport = protocol.CONJURE_TRANSPORT_OBFS4_OSSH
   579  		}
   580  	}
   581  
   582  	usingTLS := protocol.TunnelProtocolUsesMeekHTTPS(dialParams.TunnelProtocol) ||
   583  		dialParams.ConjureAPIRegistration
   584  
   585  	if (!isReplay || !replayTLSProfile) && usingTLS {
   586  
   587  		dialParams.SelectedTLSProfile = true
   588  
   589  		requireTLS12SessionTickets := protocol.TunnelProtocolRequiresTLS12SessionTickets(
   590  			dialParams.TunnelProtocol)
   591  
   592  		isFronted := protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) ||
   593  			dialParams.ConjureAPIRegistration
   594  
   595  		dialParams.TLSProfile = SelectTLSProfile(
   596  			requireTLS12SessionTickets, isFronted, serverEntry.FrontingProviderID, p)
   597  
   598  		dialParams.NoDefaultTLSSessionID = p.WeightedCoinFlip(
   599  			parameters.NoDefaultTLSSessionIDProbability)
   600  	}
   601  
   602  	if (!isReplay || !replayRandomizedTLSProfile) && usingTLS &&
   603  		protocol.TLSProfileIsRandomized(dialParams.TLSProfile) {
   604  
   605  		dialParams.RandomizedTLSProfileSeed, err = prng.NewSeed()
   606  		if err != nil {
   607  			return nil, errors.Trace(err)
   608  		}
   609  	}
   610  
   611  	if (!isReplay || !replayTLSProfile) && usingTLS {
   612  
   613  		// Since "Randomized-v2"/CustomTLSProfiles may be TLS 1.2 or TLS 1.3,
   614  		// construct the ClientHello to determine if it's TLS 1.3. This test also
   615  		// covers non-randomized TLS 1.3 profiles. This check must come after
   616  		// dialParams.TLSProfile and dialParams.RandomizedTLSProfileSeed are set. No
   617  		// actual dial is made here.
   618  
   619  		utlsClientHelloID, utlsClientHelloSpec, err := getUTLSClientHelloID(
   620  			p, dialParams.TLSProfile)
   621  		if err != nil {
   622  			return nil, errors.Trace(err)
   623  		}
   624  
   625  		if protocol.TLSProfileIsRandomized(dialParams.TLSProfile) {
   626  			utlsClientHelloID.Seed = new(utls.PRNGSeed)
   627  			*utlsClientHelloID.Seed = [32]byte(*dialParams.RandomizedTLSProfileSeed)
   628  		}
   629  
   630  		dialParams.TLSVersion, err = getClientHelloVersion(
   631  			utlsClientHelloID, utlsClientHelloSpec)
   632  		if err != nil {
   633  			return nil, errors.Trace(err)
   634  		}
   635  	}
   636  
   637  	if (!isReplay || !replayFronting) &&
   638  		protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) {
   639  
   640  		dialParams.FrontingProviderID = serverEntry.FrontingProviderID
   641  
   642  		dialParams.MeekFrontingDialAddress, dialParams.MeekFrontingHost, err =
   643  			selectFrontingParameters(serverEntry)
   644  		if err != nil {
   645  			return nil, errors.Trace(err)
   646  		}
   647  	}
   648  
   649  	if !isReplay || !replayHostname {
   650  
   651  		if protocol.TunnelProtocolUsesMeekHTTPS(dialParams.TunnelProtocol) ||
   652  			protocol.TunnelProtocolUsesFrontedMeekQUIC(dialParams.TunnelProtocol) {
   653  
   654  			dialParams.MeekSNIServerName = ""
   655  			if p.WeightedCoinFlip(parameters.TransformHostNameProbability) {
   656  				dialParams.MeekSNIServerName = selectHostName(dialParams.TunnelProtocol, p)
   657  				dialParams.MeekTransformedHostName = true
   658  			}
   659  
   660  		} else if protocol.TunnelProtocolUsesMeekHTTP(dialParams.TunnelProtocol) {
   661  
   662  			dialParams.MeekHostHeader = ""
   663  			hostname := serverEntry.IpAddress
   664  			if p.WeightedCoinFlip(parameters.TransformHostNameProbability) {
   665  				hostname = selectHostName(dialParams.TunnelProtocol, p)
   666  				dialParams.MeekTransformedHostName = true
   667  			}
   668  			if serverEntry.MeekServerPort == 80 {
   669  				dialParams.MeekHostHeader = hostname
   670  			} else {
   671  				dialParams.MeekHostHeader = net.JoinHostPort(
   672  					hostname, strconv.Itoa(serverEntry.MeekServerPort))
   673  			}
   674  		} else if protocol.TunnelProtocolUsesQUIC(dialParams.TunnelProtocol) {
   675  
   676  			dialParams.QUICDialSNIAddress = net.JoinHostPort(
   677  				selectHostName(dialParams.TunnelProtocol, p),
   678  				strconv.Itoa(serverEntry.SshObfuscatedQUICPort))
   679  		}
   680  	}
   681  
   682  	if (!isReplay || !replayQUICVersion) &&
   683  		protocol.TunnelProtocolUsesQUIC(dialParams.TunnelProtocol) {
   684  
   685  		isFronted := protocol.TunnelProtocolUsesFrontedMeekQUIC(dialParams.TunnelProtocol)
   686  		dialParams.QUICVersion = selectQUICVersion(isFronted, serverEntry, p)
   687  
   688  		if protocol.QUICVersionHasRandomizedClientHello(dialParams.QUICVersion) {
   689  			dialParams.QUICClientHelloSeed, err = prng.NewSeed()
   690  			if err != nil {
   691  				return nil, errors.Trace(err)
   692  			}
   693  		}
   694  
   695  		dialParams.QUICDisablePathMTUDiscovery =
   696  			protocol.QUICVersionUsesPathMTUDiscovery(dialParams.QUICVersion) &&
   697  				p.WeightedCoinFlip(parameters.QUICDisableClientPathMTUDiscoveryProbability)
   698  	}
   699  
   700  	if (!isReplay || !replayObfuscatedQUIC) &&
   701  		protocol.QUICVersionIsObfuscated(dialParams.QUICVersion) {
   702  
   703  		dialParams.ObfuscatedQUICPaddingSeed, err = prng.NewSeed()
   704  		if err != nil {
   705  			return nil, errors.Trace(err)
   706  		}
   707  	}
   708  
   709  	if !isReplay || !replayLivenessTest {
   710  
   711  		// TODO: initialize only when LivenessTestMaxUp/DownstreamBytes > 0?
   712  		dialParams.LivenessTestSeed, err = prng.NewSeed()
   713  		if err != nil {
   714  			return nil, errors.Trace(err)
   715  		}
   716  	}
   717  
   718  	if !isReplay || !replayAPIRequestPadding {
   719  		dialParams.APIRequestPaddingSeed, err = prng.NewSeed()
   720  		if err != nil {
   721  			return nil, errors.Trace(err)
   722  		}
   723  	}
   724  
   725  	// Initialize dialParams.ResolveParameters for dials that will resolve
   726  	// domain names, which currently includes fronted meek and Conjure API
   727  	// registration, where the dial address is not an IP address.
   728  	//
   729  	// dialParams.ResolveParameters must be nil when the dial address is an IP
   730  	// address to ensure that no DNS dial parameters are reported in metrics
   731  	// or diagnostics when when no domain is resolved.
   732  
   733  	useResolver := (protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) ||
   734  		dialParams.ConjureAPIRegistration) &&
   735  		net.ParseIP(dialParams.MeekFrontingDialAddress) == nil
   736  
   737  	if (!isReplay || !replayResolveParameters) && useResolver {
   738  
   739  		dialParams.ResolveParameters, err = dialParams.resolver.MakeResolveParameters(
   740  			p, dialParams.FrontingProviderID)
   741  		if err != nil {
   742  			return nil, errors.Trace(err)
   743  		}
   744  	}
   745  
   746  	if !isReplay || !replayHoldOffTunnel {
   747  
   748  		if common.Contains(
   749  			p.TunnelProtocols(parameters.HoldOffTunnelProtocols), dialParams.TunnelProtocol) ||
   750  
   751  			(protocol.TunnelProtocolUsesFrontedMeek(dialParams.TunnelProtocol) &&
   752  				common.Contains(
   753  					p.Strings(parameters.HoldOffTunnelFrontingProviderIDs),
   754  					dialParams.FrontingProviderID)) {
   755  
   756  			if p.WeightedCoinFlip(parameters.HoldOffTunnelProbability) {
   757  
   758  				dialParams.HoldOffTunnelDuration = prng.Period(
   759  					p.Duration(parameters.HoldOffTunnelMinDuration),
   760  					p.Duration(parameters.HoldOffTunnelMaxDuration))
   761  			}
   762  		}
   763  
   764  	}
   765  
   766  	// Set dial address fields. This portion of configuration is
   767  	// deterministic, given the parameters established or replayed so far.
   768  
   769  	dialPortNumber, err := serverEntry.GetDialPortNumber(dialParams.TunnelProtocol)
   770  	if err != nil {
   771  		return nil, errors.Trace(err)
   772  	}
   773  
   774  	dialParams.DialPortNumber = strconv.Itoa(dialPortNumber)
   775  
   776  	switch dialParams.TunnelProtocol {
   777  
   778  	case protocol.TUNNEL_PROTOCOL_SSH,
   779  		protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH,
   780  		protocol.TUNNEL_PROTOCOL_TAPDANCE_OBFUSCATED_SSH,
   781  		protocol.TUNNEL_PROTOCOL_CONJURE_OBFUSCATED_SSH,
   782  		protocol.TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH:
   783  
   784  		dialParams.DirectDialAddress = net.JoinHostPort(serverEntry.IpAddress, dialParams.DialPortNumber)
   785  
   786  	case protocol.TUNNEL_PROTOCOL_FRONTED_MEEK,
   787  		protocol.TUNNEL_PROTOCOL_FRONTED_MEEK_QUIC_OBFUSCATED_SSH:
   788  
   789  		dialParams.MeekDialAddress = net.JoinHostPort(dialParams.MeekFrontingDialAddress, dialParams.DialPortNumber)
   790  		dialParams.MeekHostHeader = dialParams.MeekFrontingHost
   791  		if serverEntry.MeekFrontingDisableSNI {
   792  			dialParams.MeekSNIServerName = ""
   793  			// When SNI is omitted, the transformed host name is not used.
   794  			dialParams.MeekTransformedHostName = false
   795  		} else if !dialParams.MeekTransformedHostName {
   796  			dialParams.MeekSNIServerName = dialParams.MeekFrontingDialAddress
   797  		}
   798  
   799  	case protocol.TUNNEL_PROTOCOL_FRONTED_MEEK_HTTP:
   800  
   801  		dialParams.MeekDialAddress = net.JoinHostPort(dialParams.MeekFrontingDialAddress, dialParams.DialPortNumber)
   802  		dialParams.MeekHostHeader = dialParams.MeekFrontingHost
   803  		// For FRONTED HTTP, the Host header cannot be transformed.
   804  		dialParams.MeekTransformedHostName = false
   805  
   806  	case protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK:
   807  
   808  		dialParams.MeekDialAddress = net.JoinHostPort(serverEntry.IpAddress, dialParams.DialPortNumber)
   809  		if !dialParams.MeekTransformedHostName {
   810  			if dialPortNumber == 80 {
   811  				dialParams.MeekHostHeader = serverEntry.IpAddress
   812  			} else {
   813  				dialParams.MeekHostHeader = dialParams.MeekDialAddress
   814  			}
   815  		}
   816  
   817  	case protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_HTTPS,
   818  		protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET:
   819  
   820  		dialParams.MeekDialAddress = net.JoinHostPort(serverEntry.IpAddress, dialParams.DialPortNumber)
   821  		if !dialParams.MeekTransformedHostName {
   822  			// Note: IP address in SNI field will be omitted.
   823  			dialParams.MeekSNIServerName = serverEntry.IpAddress
   824  		}
   825  		if dialPortNumber == 443 {
   826  			dialParams.MeekHostHeader = serverEntry.IpAddress
   827  		} else {
   828  			dialParams.MeekHostHeader = dialParams.MeekDialAddress
   829  		}
   830  
   831  	default:
   832  		return nil, errors.Tracef(
   833  			"unknown tunnel protocol: %s", dialParams.TunnelProtocol)
   834  
   835  	}
   836  
   837  	if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) {
   838  
   839  		host, _, _ := net.SplitHostPort(dialParams.MeekDialAddress)
   840  
   841  		if p.Bool(parameters.MeekDialDomainsOnly) {
   842  			if net.ParseIP(host) != nil {
   843  				// No error, as this is a "not supported" case.
   844  				return nil, nil
   845  			}
   846  		}
   847  
   848  		// The underlying TLS implementation will automatically omit SNI for
   849  		// IP address server name values; we have this explicit check here so
   850  		// we record the correct value for stats.
   851  		if net.ParseIP(dialParams.MeekSNIServerName) != nil {
   852  			dialParams.MeekSNIServerName = ""
   853  		}
   854  	}
   855  
   856  	// Initialize/replay User-Agent header for HTTP upstream proxy and meek protocols.
   857  
   858  	if config.UseUpstreamProxy() {
   859  		// Note: UpstreamProxyURL will be validated in the dial
   860  		proxyURL, err := common.SafeParseURL(config.UpstreamProxyURL)
   861  		if err == nil {
   862  			dialParams.UpstreamProxyType = proxyURL.Scheme
   863  		}
   864  	}
   865  
   866  	dialCustomHeaders := makeDialCustomHeaders(config, p)
   867  
   868  	if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) ||
   869  		dialParams.UpstreamProxyType == "http" ||
   870  		dialParams.ConjureAPIRegistration {
   871  
   872  		if !isReplay || !replayUserAgent {
   873  			dialParams.SelectedUserAgent, dialParams.UserAgent = selectUserAgentIfUnset(p, dialCustomHeaders)
   874  		}
   875  
   876  		if dialParams.SelectedUserAgent {
   877  			dialCustomHeaders.Set("User-Agent", dialParams.UserAgent)
   878  		}
   879  
   880  	}
   881  
   882  	// UpstreamProxyCustomHeaderNames is a reported metric. Just the names and
   883  	// not the values are reported, in case the values are identifying.
   884  
   885  	if len(config.CustomHeaders) > 0 {
   886  		dialParams.UpstreamProxyCustomHeaderNames = make([]string, 0)
   887  		for name := range dialCustomHeaders {
   888  			if name == "User-Agent" && dialParams.SelectedUserAgent {
   889  				continue
   890  			}
   891  			dialParams.UpstreamProxyCustomHeaderNames = append(dialParams.UpstreamProxyCustomHeaderNames, name)
   892  		}
   893  	}
   894  
   895  	// Initialize Dial/MeekConfigs to be passed to the corresponding dialers.
   896  
   897  	// Custom ResolveParameters are set only when useResolver is true, but
   898  	// DialConfig.ResolveIP is required and wired up unconditionally. Any
   899  	// misconfigured or miscoded domain dial cases will use default
   900  	// ResolveParameters.
   901  	//
   902  	// ResolveIP will use the networkID obtained above, as it will be used
   903  	// almost immediately, instead of incurring the overhead of calling
   904  	// GetNetworkID again.
   905  	resolveIP := func(ctx context.Context, hostname string) ([]net.IP, error) {
   906  		IPs, err := dialParams.resolver.ResolveIP(
   907  			ctx,
   908  			networkID,
   909  			dialParams.ResolveParameters,
   910  			hostname)
   911  		if err != nil {
   912  			return nil, errors.Trace(err)
   913  		}
   914  		return IPs, nil
   915  	}
   916  
   917  	dialParams.dialConfig = &DialConfig{
   918  		DiagnosticID:                  serverEntry.GetDiagnosticID(),
   919  		UpstreamProxyURL:              config.UpstreamProxyURL,
   920  		CustomHeaders:                 dialCustomHeaders,
   921  		BPFProgramInstructions:        dialParams.BPFProgramInstructions,
   922  		DeviceBinder:                  config.deviceBinder,
   923  		IPv6Synthesizer:               config.IPv6Synthesizer,
   924  		ResolveIP:                     resolveIP,
   925  		TrustedCACertificatesFilename: config.TrustedCACertificatesFilename,
   926  		FragmentorConfig:              fragmentor.NewUpstreamConfig(p, dialParams.TunnelProtocol, dialParams.FragmentorSeed),
   927  		UpstreamProxyErrorCallback:    upstreamProxyErrorCallback,
   928  	}
   929  
   930  	// Unconditionally initialize MeekResolvedIPAddress, so a valid string can
   931  	// always be read.
   932  	dialParams.MeekResolvedIPAddress.Store("")
   933  
   934  	if protocol.TunnelProtocolUsesMeek(dialParams.TunnelProtocol) ||
   935  		dialParams.ConjureAPIRegistration {
   936  
   937  		dialParams.meekConfig = &MeekConfig{
   938  			DiagnosticID:                  serverEntry.GetDiagnosticID(),
   939  			Parameters:                    config.GetParameters(),
   940  			DialAddress:                   dialParams.MeekDialAddress,
   941  			UseQUIC:                       protocol.TunnelProtocolUsesFrontedMeekQUIC(dialParams.TunnelProtocol),
   942  			QUICVersion:                   dialParams.QUICVersion,
   943  			QUICClientHelloSeed:           dialParams.QUICClientHelloSeed,
   944  			QUICDisablePathMTUDiscovery:   dialParams.QUICDisablePathMTUDiscovery,
   945  			UseHTTPS:                      usingTLS,
   946  			TLSProfile:                    dialParams.TLSProfile,
   947  			LegacyPassthrough:             serverEntry.ProtocolUsesLegacyPassthrough(dialParams.TunnelProtocol),
   948  			NoDefaultTLSSessionID:         dialParams.NoDefaultTLSSessionID,
   949  			RandomizedTLSProfileSeed:      dialParams.RandomizedTLSProfileSeed,
   950  			UseObfuscatedSessionTickets:   dialParams.TunnelProtocol == protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET,
   951  			SNIServerName:                 dialParams.MeekSNIServerName,
   952  			VerifyServerName:              dialParams.MeekVerifyServerName,
   953  			VerifyPins:                    dialParams.MeekVerifyPins,
   954  			HostHeader:                    dialParams.MeekHostHeader,
   955  			TransformedHostName:           dialParams.MeekTransformedHostName,
   956  			ClientTunnelProtocol:          dialParams.TunnelProtocol,
   957  			MeekCookieEncryptionPublicKey: serverEntry.MeekCookieEncryptionPublicKey,
   958  			MeekObfuscatedKey:             serverEntry.MeekObfuscatedKey,
   959  			MeekObfuscatorPaddingSeed:     dialParams.MeekObfuscatorPaddingSeed,
   960  			NetworkLatencyMultiplier:      dialParams.NetworkLatencyMultiplier,
   961  		}
   962  
   963  		// Use an asynchronous callback to record the resolved IP address when
   964  		// dialing a domain name. Note that DialMeek doesn't immediately
   965  		// establish any HTTP connections, so the resolved IP address won't be
   966  		// reported in all cases until after SSH traffic is relayed or a
   967  		// endpoint request is made over the meek connection.
   968  		dialParams.dialConfig.ResolvedIPCallback = func(IPAddress string) {
   969  			dialParams.MeekResolvedIPAddress.Store(IPAddress)
   970  		}
   971  
   972  		if isTactics {
   973  			dialParams.meekConfig.Mode = MeekModeObfuscatedRoundTrip
   974  		} else if dialParams.ConjureAPIRegistration {
   975  			dialParams.meekConfig.Mode = MeekModePlaintextRoundTrip
   976  		} else {
   977  			dialParams.meekConfig.Mode = MeekModeRelay
   978  		}
   979  	}
   980  
   981  	return dialParams, nil
   982  }
   983  
   984  func (dialParams *DialParameters) GetDialConfig() *DialConfig {
   985  	return dialParams.dialConfig
   986  }
   987  
   988  func (dialParams *DialParameters) GetMeekConfig() *MeekConfig {
   989  	return dialParams.meekConfig
   990  }
   991  
   992  // GetNetworkType returns a network type name, suitable for metrics, which is
   993  // derived from the network ID.
   994  func (dialParams *DialParameters) GetNetworkType() string {
   995  
   996  	// Unlike the logic in loggingNetworkIDGetter.GetNetworkID, we don't take the
   997  	// arbitrary text before the first "-" since some platforms without network
   998  	// detection support stub in random values to enable tactics. Instead we
   999  	// check for and use the common network type prefixes currently used in
  1000  	// NetworkIDGetter implementations.
  1001  
  1002  	if strings.HasPrefix(dialParams.NetworkID, "WIFI") {
  1003  		return "WIFI"
  1004  	}
  1005  	if strings.HasPrefix(dialParams.NetworkID, "MOBILE") {
  1006  		return "MOBILE"
  1007  	}
  1008  	return "UNKNOWN"
  1009  }
  1010  
  1011  func (dialParams *DialParameters) Succeeded() {
  1012  
  1013  	// When TTL is 0, don't store dial parameters.
  1014  	if dialParams.LastUsedTimestamp.IsZero() {
  1015  		return
  1016  	}
  1017  
  1018  	NoticeInfo("Set dial parameters for %s", dialParams.ServerEntry.GetDiagnosticID())
  1019  	err := SetDialParameters(dialParams.ServerEntry.IpAddress, dialParams.NetworkID, dialParams)
  1020  	if err != nil {
  1021  		NoticeWarning("SetDialParameters failed: %s", err)
  1022  	}
  1023  }
  1024  
  1025  func (dialParams *DialParameters) Failed(config *Config) {
  1026  
  1027  	// When a tunnel fails, and the dial is a replay, clear the stored dial
  1028  	// parameters which are now presumed to be blocked, impaired or otherwise
  1029  	// no longer effective.
  1030  	//
  1031  	// It may be the case that a dial is not using stored dial parameters
  1032  	// (!IsReplay), and in this case we retain those dial parameters since they
  1033  	// were not exercised and may still be effective.
  1034  	//
  1035  	// Failed tunnel dial parameters may be retained with a configurable
  1036  	// probability; this is intended to help mitigate false positive failures due
  1037  	// to, e.g., temporary network disruptions or server load limiting.
  1038  
  1039  	if dialParams.IsReplay &&
  1040  		!config.GetParameters().Get().WeightedCoinFlip(
  1041  			parameters.ReplayRetainFailedProbability) {
  1042  
  1043  		NoticeInfo("Delete dial parameters for %s", dialParams.ServerEntry.GetDiagnosticID())
  1044  		err := DeleteDialParameters(dialParams.ServerEntry.IpAddress, dialParams.NetworkID)
  1045  		if err != nil {
  1046  			NoticeWarning("DeleteDialParameters failed: %s", err)
  1047  		}
  1048  	}
  1049  }
  1050  
  1051  func (dialParams *DialParameters) GetTLSVersionForMetrics() string {
  1052  	tlsVersion := dialParams.TLSVersion
  1053  	if dialParams.NoDefaultTLSSessionID {
  1054  		tlsVersion += "-no_def_id"
  1055  	}
  1056  	return tlsVersion
  1057  }
  1058  
  1059  // ExchangedDialParameters represents the subset of DialParameters that is
  1060  // shared in a client-to-client exchange of server connection info.
  1061  //
  1062  // The purpose of client-to-client exchange if for one user that can connect
  1063  // to help another user that cannot connect by sharing their connected
  1064  // configuration, including the server entry and dial parameters.
  1065  //
  1066  // There are two concerns regarding which dial parameter fields are safe to
  1067  // exchange:
  1068  //
  1069  // - Unlike signed server entries, there's no independent trust anchor
  1070  //   that can certify that the exchange data is valid.
  1071  //
  1072  // - While users should only perform the exchange with trusted peers,
  1073  //   the user's trust in their peer may be misplaced.
  1074  //
  1075  // This presents the possibility of attack such as the peer sending dial
  1076  // parameters that could be used to trace/monitor/flag the importer; or
  1077  // sending dial parameters, including dial address and SNI, to cause the peer
  1078  // to appear to connect to a banned service.
  1079  //
  1080  // To mitigate these risks, only a subset of dial parameters are exchanged.
  1081  // When exchanged dial parameters and imported and used, all unexchanged
  1082  // parameters are generated locally. At this time, only the tunnel protocol is
  1083  // exchanged. We consider tunnel protocol selection one of the key connection
  1084  // success factors.
  1085  //
  1086  // In addition, the exchange peers may not be on the same network with the
  1087  // same blocking and circumvention characteristics, which is another reason
  1088  // to limit exchanged dial parameter values to broadly applicable fields.
  1089  //
  1090  // Unlike the exchanged (and otherwise acquired) server entry,
  1091  // ExchangedDialParameters does not use the ServerEntry_Fields_ representation
  1092  // which allows older clients to receive and store new, unknown fields. Such a
  1093  // facility is less useful in this case, since exchanged dial parameters and
  1094  // used immediately and have a short lifespan.
  1095  //
  1096  // TODO: exchange more dial parameters, such as TLS profile, QUIC version, etc.
  1097  type ExchangedDialParameters struct {
  1098  	TunnelProtocol string
  1099  }
  1100  
  1101  // NewExchangedDialParameters creates a new ExchangedDialParameters from a
  1102  // DialParameters, including only the exchanged values.
  1103  // NewExchangedDialParameters assumes the input DialParameters has been
  1104  // initialized and populated by MakeDialParameters.
  1105  func NewExchangedDialParameters(dialParams *DialParameters) *ExchangedDialParameters {
  1106  	return &ExchangedDialParameters{
  1107  		TunnelProtocol: dialParams.TunnelProtocol,
  1108  	}
  1109  }
  1110  
  1111  // Validate checks that the ExchangedDialParameters contains only valid values
  1112  // and is compatible with the specified server entry.
  1113  func (dialParams *ExchangedDialParameters) Validate(serverEntry *protocol.ServerEntry) error {
  1114  	if !common.Contains(protocol.SupportedTunnelProtocols, dialParams.TunnelProtocol) {
  1115  		return errors.Tracef("unknown tunnel protocol: %s", dialParams.TunnelProtocol)
  1116  	}
  1117  	if !serverEntry.SupportsProtocol(dialParams.TunnelProtocol) {
  1118  		return errors.Tracef("unsupported tunnel protocol: %s", dialParams.TunnelProtocol)
  1119  	}
  1120  	return nil
  1121  }
  1122  
  1123  // MakeDialParameters creates a new, partially intitialized DialParameters
  1124  // from the values in ExchangedDialParameters. The returned DialParameters
  1125  // must not be used directly for dialing. It is intended to be stored, and
  1126  // then later fully initialized by MakeDialParameters.
  1127  func (dialParams *ExchangedDialParameters) MakeDialParameters(
  1128  	config *Config,
  1129  	p parameters.ParametersAccessor,
  1130  	serverEntry *protocol.ServerEntry) *DialParameters {
  1131  
  1132  	return &DialParameters{
  1133  		IsExchanged:             true,
  1134  		LastUsedTimestamp:       time.Now(),
  1135  		LastUsedConfigStateHash: getConfigStateHash(config, p, serverEntry),
  1136  		TunnelProtocol:          dialParams.TunnelProtocol,
  1137  	}
  1138  }
  1139  
  1140  func getConfigStateHash(
  1141  	config *Config,
  1142  	p parameters.ParametersAccessor,
  1143  	serverEntry *protocol.ServerEntry) []byte {
  1144  
  1145  	// The config state hash should reflect config, tactics, and server entry
  1146  	// settings that impact the dial parameters. The hash should change if any
  1147  	// of these input values change in a way that invalidates any stored dial
  1148  	// parameters.
  1149  
  1150  	// MD5 hash is used solely as a data checksum and not for any security
  1151  	// purpose.
  1152  	hash := md5.New()
  1153  
  1154  	// Add a hash of relevant config fields.
  1155  	// Limitation: the config hash may change even when tactics will override the
  1156  	// changed config field.
  1157  	hash.Write(config.dialParametersHash)
  1158  
  1159  	// Add the active tactics tag.
  1160  	hash.Write([]byte(p.Tag()))
  1161  
  1162  	// Add the server entry version and local timestamp, both of which should
  1163  	// change when the server entry contents change and/or a new local copy is
  1164  	// imported.
  1165  	// TODO: marshal entire server entry?
  1166  	var serverEntryConfigurationVersion [8]byte
  1167  	binary.BigEndian.PutUint64(
  1168  		serverEntryConfigurationVersion[:],
  1169  		uint64(serverEntry.ConfigurationVersion))
  1170  	hash.Write(serverEntryConfigurationVersion[:])
  1171  	hash.Write([]byte(serverEntry.LocalTimestamp))
  1172  
  1173  	return hash.Sum(nil)
  1174  }
  1175  
  1176  func selectFrontingParameters(
  1177  	serverEntry *protocol.ServerEntry) (string, string, error) {
  1178  
  1179  	frontingDialHost := ""
  1180  	frontingHost := ""
  1181  
  1182  	if len(serverEntry.MeekFrontingAddressesRegex) > 0 {
  1183  
  1184  		// Generate a front address based on the regex.
  1185  
  1186  		var err error
  1187  		frontingDialHost, err = regen.Generate(serverEntry.MeekFrontingAddressesRegex)
  1188  		if err != nil {
  1189  			return "", "", errors.Trace(err)
  1190  		}
  1191  
  1192  	} else {
  1193  
  1194  		// Randomly select, for this connection attempt, one front address for
  1195  		// fronting-capable servers.
  1196  
  1197  		if len(serverEntry.MeekFrontingAddresses) == 0 {
  1198  			return "", "", errors.TraceNew("MeekFrontingAddresses is empty")
  1199  		}
  1200  
  1201  		index := prng.Intn(len(serverEntry.MeekFrontingAddresses))
  1202  		frontingDialHost = serverEntry.MeekFrontingAddresses[index]
  1203  	}
  1204  
  1205  	if len(serverEntry.MeekFrontingHosts) > 0 {
  1206  
  1207  		index := prng.Intn(len(serverEntry.MeekFrontingHosts))
  1208  		frontingHost = serverEntry.MeekFrontingHosts[index]
  1209  
  1210  	} else {
  1211  
  1212  		// Backwards compatibility case
  1213  		frontingHost = serverEntry.MeekFrontingHost
  1214  	}
  1215  
  1216  	return frontingDialHost, frontingHost, nil
  1217  }
  1218  
  1219  func selectQUICVersion(
  1220  	isFronted bool,
  1221  	serverEntry *protocol.ServerEntry,
  1222  	p parameters.ParametersAccessor) string {
  1223  
  1224  	limitQUICVersions := p.QUICVersions(parameters.LimitQUICVersions)
  1225  
  1226  	var disableQUICVersions protocol.QUICVersions
  1227  
  1228  	if isFronted {
  1229  		if serverEntry.FrontingProviderID == "" {
  1230  			// Legacy server entry case
  1231  			disableQUICVersions = protocol.QUICVersions{
  1232  				protocol.QUIC_VERSION_V1,
  1233  				protocol.QUIC_VERSION_RANDOMIZED_V1,
  1234  				protocol.QUIC_VERSION_OBFUSCATED_V1,
  1235  				protocol.QUIC_VERSION_DECOY_V1,
  1236  			}
  1237  		} else {
  1238  			disableQUICVersions = p.LabeledQUICVersions(
  1239  				parameters.DisableFrontingProviderQUICVersions,
  1240  				serverEntry.FrontingProviderID)
  1241  		}
  1242  	}
  1243  
  1244  	quicVersions := make([]string, 0)
  1245  
  1246  	// Don't use gQUIC versions when the server entry specifies QUICv1-only.
  1247  	supportedQUICVersions := protocol.SupportedQUICVersions
  1248  	if serverEntry.SupportsOnlyQUICv1() {
  1249  		supportedQUICVersions = protocol.SupportedQUICv1Versions
  1250  	}
  1251  
  1252  	for _, quicVersion := range supportedQUICVersions {
  1253  
  1254  		if len(limitQUICVersions) > 0 &&
  1255  			!common.Contains(limitQUICVersions, quicVersion) {
  1256  			continue
  1257  		}
  1258  
  1259  		// Both tactics and the server entry can specify LimitQUICVersions. In
  1260  		// tactics, the parameter is intended to direct certain clients to
  1261  		// use a successful protocol variant. In the server entry, the
  1262  		// parameter may be used to direct all clients to send
  1263  		// consistent-looking protocol variants to a particular server; e.g.,
  1264  		// only regular QUIC, or only obfuscated QUIC.
  1265  		//
  1266  		// The isFronted/QUICVersionIsObfuscated logic predates
  1267  		// ServerEntry.LimitQUICVersions; ServerEntry.LimitQUICVersions could
  1268  		// now be used to achieve a similar outcome.
  1269  		if len(serverEntry.LimitQUICVersions) > 0 &&
  1270  			!common.Contains(serverEntry.LimitQUICVersions, quicVersion) {
  1271  			continue
  1272  		}
  1273  
  1274  		if isFronted &&
  1275  			protocol.QUICVersionIsObfuscated(quicVersion) {
  1276  			continue
  1277  		}
  1278  
  1279  		if common.Contains(disableQUICVersions, quicVersion) {
  1280  			continue
  1281  		}
  1282  
  1283  		quicVersions = append(quicVersions, quicVersion)
  1284  	}
  1285  
  1286  	if len(quicVersions) == 0 {
  1287  		return ""
  1288  	}
  1289  
  1290  	choice := prng.Intn(len(quicVersions))
  1291  
  1292  	return quicVersions[choice]
  1293  }
  1294  
  1295  // selectUserAgentIfUnset selects a User-Agent header if one is not set.
  1296  func selectUserAgentIfUnset(
  1297  	p parameters.ParametersAccessor, headers http.Header) (bool, string) {
  1298  
  1299  	if _, ok := headers["User-Agent"]; !ok {
  1300  
  1301  		userAgent := ""
  1302  		if p.WeightedCoinFlip(parameters.PickUserAgentProbability) {
  1303  			userAgent = values.GetUserAgent()
  1304  		}
  1305  
  1306  		return true, userAgent
  1307  	}
  1308  
  1309  	return false, ""
  1310  }
  1311  
  1312  func makeDialCustomHeaders(
  1313  	config *Config,
  1314  	p parameters.ParametersAccessor) http.Header {
  1315  
  1316  	dialCustomHeaders := make(http.Header)
  1317  	if config.CustomHeaders != nil {
  1318  		for k, v := range config.CustomHeaders {
  1319  			dialCustomHeaders[k] = make([]string, len(v))
  1320  			copy(dialCustomHeaders[k], v)
  1321  		}
  1322  	}
  1323  
  1324  	additionalCustomHeaders := p.HTTPHeaders(parameters.AdditionalCustomHeaders)
  1325  	for k, v := range additionalCustomHeaders {
  1326  		dialCustomHeaders[k] = make([]string, len(v))
  1327  		copy(dialCustomHeaders[k], v)
  1328  	}
  1329  	return dialCustomHeaders
  1330  }
  1331  
  1332  func selectHostName(
  1333  	tunnelProtocol string, p parameters.ParametersAccessor) string {
  1334  
  1335  	limitProtocols := p.TunnelProtocols(parameters.CustomHostNameLimitProtocols)
  1336  	if len(limitProtocols) > 0 && !common.Contains(limitProtocols, tunnelProtocol) {
  1337  		return values.GetHostName()
  1338  	}
  1339  
  1340  	if !p.WeightedCoinFlip(parameters.CustomHostNameProbability) {
  1341  		return values.GetHostName()
  1342  	}
  1343  
  1344  	regexStrings := p.RegexStrings(parameters.CustomHostNameRegexes)
  1345  	if len(regexStrings) == 0 {
  1346  		return values.GetHostName()
  1347  	}
  1348  
  1349  	choice := prng.Intn(len(regexStrings))
  1350  	hostName, err := regen.Generate(regexStrings[choice])
  1351  	if err != nil {
  1352  		NoticeWarning("selectHostName: regen.Generate failed: %v", errors.Trace(err))
  1353  		return values.GetHostName()
  1354  	}
  1355  
  1356  	return hostName
  1357  }