Skip to content

Commit

Permalink
Change to only modify global config details via update call
Browse files Browse the repository at this point in the history
  • Loading branch information
myleshorton committed Dec 3, 2024
1 parent 6b6fc13 commit 9b577b9
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 28 deletions.
44 changes: 25 additions & 19 deletions fronted.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ type fronted struct {
frontsMu sync.RWMutex
frontedMu sync.RWMutex
stopCh chan interface{}
crawlOnce sync.Once
}

// Interface for sending HTTP traffic over domain fronting.
type Fronted interface {
http.RoundTripper

// UpdateConfig updates the set of domain fronts to try.
UpdateConfig(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string)
UpdateConfig(pool *x509.CertPool, providers map[string]*Provider)

// Close closes any resources, such as goroutines that are testing fronts.
Close()
Expand All @@ -70,40 +71,31 @@ type Fronted interface {
//
// defaultProviderID is used when a front without a provider is
// encountered (eg in a cache file)
func NewFronted(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string, cacheFile string,
clientHello tls.ClientHelloID) (Fronted, error) {
func NewFronted(cacheFile string, clientHello tls.ClientHelloID, defaultProviderID string) (Fronted, error) {
log.Debug("Creating new fronted")
// Log method elapsed time
defer func(start time.Time) {
log.Debugf("Creating a new fronted took %v", time.Since(start))
}(time.Now())

if len(providers) == 0 {
return nil, log.Errorf("No providers configured")
}

providersCopy := copyProviders(providers)
fronts := loadFronts(providersCopy)

f := &fronted{
certPool: pool,
fronts: fronts,
certPool: nil,
fronts: make(sortedFronts, 0),
maxAllowedCachedAge: defaultMaxAllowedCachedAge,
maxCacheSize: defaultMaxCacheSize,
cacheSaveInterval: defaultCacheSaveInterval,
cacheDirty: make(chan interface{}, 1),
cacheClosed: make(chan interface{}),
defaultProviderID: defaultProviderID,
providers: providersCopy,
providers: make(map[string]*Provider),
clientHelloID: clientHello,
workingFronts: newConnectingFronts(len(fronts)),
workingFronts: newConnectingFronts(4000),
stopCh: make(chan interface{}),
defaultProviderID: defaultProviderID,
}

if cacheFile != "" {
f.initCaching(cacheFile)
}
go f.findWorkingFronts()

return f, nil
}
Expand Down Expand Up @@ -151,17 +143,25 @@ func loadFronts(providers map[string]*Provider) sortedFronts {
return fronts
}

func (f *fronted) UpdateConfig(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string) {
func (f *fronted) UpdateConfig(pool *x509.CertPool, providers map[string]*Provider) {
// Make copies just to avoid any concurrency issues with access that may be happening on the
// caller side.
log.Debug("Updating fronted configuration")
if len(providers) == 0 {
log.Errorf("No providers configured")
return
}
providersCopy := copyProviders(providers)
f.frontedMu.Lock()
defer f.frontedMu.Unlock()
f.addProviders(providersCopy)
f.addFronts(loadFronts(providersCopy))
f.defaultProviderID = defaultProviderID

f.certPool = pool

f.crawlOnce.Do(func() {
go f.findWorkingFronts()
})
}

func (f *fronted) addProviders(providers map[string]*Provider) {
Expand Down Expand Up @@ -457,7 +457,7 @@ func (f *fronted) doDial(m Front) (net.Conn, bool, error) {
var conn net.Conn
var err error
retriable := false
conn, err = m.dial(f.certPool, f.clientHelloID)
conn, err = m.dial(f.getCertPool(), f.clientHelloID)
if err != nil {
if !isNetworkUnreachable(err) {
op.FailIf(err)
Expand All @@ -477,6 +477,12 @@ func (f *fronted) doDial(m Front) (net.Conn, bool, error) {
return conn, retriable, err
}

func (f *fronted) getCertPool() *x509.CertPool {
f.frontedMu.RLock()
defer f.frontedMu.RUnlock()
return f.certPool
}

func isNetworkUnreachable(err error) bool {
var opErr *net.OpError
if errors.As(err, &opErr) {
Expand Down
28 changes: 21 additions & 7 deletions fronted_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ func TestDirectDomainFrontingWithSNIConfig(t *testing.T) {
UseArbitrarySNIs: true,
ArbitrarySNIs: []string{"mercadopago.com", "amazon.com.br", "facebook.com", "google.com", "twitter.com", "youtube.com", "instagram.com", "linkedin.com", "whatsapp.com", "netflix.com", "microsoft.com", "yahoo.com", "bing.com", "wikipedia.org", "github.com"},
})
transport, err := NewFronted(certs, p, "akamai", cacheFile, tls.HelloChrome_100)
transport, err := NewFronted(cacheFile, tls.HelloChrome_100, "akamai")
require.NoError(t, err)
transport.UpdateConfig(certs, p)

client := &http.Client{
Transport: transport,
Expand All @@ -80,17 +82,19 @@ func doTestDomainFronting(t *testing.T, cacheFile string, expectedMasqueradesAtE
}
certs := trustedCACerts(t)
p := testProvidersWithHosts(hosts)
transport, err := NewFronted(certs, p, testProviderID, cacheFile, tls.HelloChrome_100)
transport, err := NewFronted(cacheFile, tls.HelloChrome_100, testProviderID)
require.NoError(t, err)
transport.UpdateConfig(certs, p)

client := &http.Client{
Transport: transport,
Timeout: 5 * time.Second,
}
require.True(t, doCheck(client, http.MethodPost, http.StatusAccepted, pingURL))

transport, err = NewFronted(certs, p, testProviderID, cacheFile, tls.HelloChrome_100)
transport, err = NewFronted(cacheFile, tls.HelloChrome_100, testProviderID)
require.NoError(t, err)
transport.UpdateConfig(certs, p)
client = &http.Client{
Transport: transport,
}
Expand Down Expand Up @@ -203,7 +207,9 @@ func TestHostAliasesBasic(t *testing.T) {
certs := x509.NewCertPool()
certs.AddCert(cloudSack.Certificate())

rt, err := NewFronted(certs, map[string]*Provider{"cloudsack": p}, "cloudsack", "", tls.HelloChrome_100)
rt, err := NewFronted("", tls.HelloChrome_100, "cloudsack")
require.NoError(t, err)
rt.UpdateConfig(certs, map[string]*Provider{"cloudsack": p})

client := &http.Client{Transport: rt}
for _, test := range tests {
Expand Down Expand Up @@ -311,7 +317,9 @@ func TestHostAliasesMulti(t *testing.T) {
"sadcloud": p2,
}

rt, err := NewFronted(certs, providers, "cloudsack", "", tls.HelloChrome_100)
rt, err := NewFronted("", tls.HelloChrome_100, "cloudsack")
require.NoError(t, err)
rt.UpdateConfig(certs, providers)

client := &http.Client{Transport: rt}

Expand Down Expand Up @@ -434,8 +442,9 @@ func TestPassthrough(t *testing.T) {
certs := x509.NewCertPool()
certs.AddCert(cloudSack.Certificate())

rt, err := NewFronted(certs, map[string]*Provider{"cloudsack": p}, "cloudsack", "", tls.HelloChrome_100)
rt, err := NewFronted("", tls.HelloChrome_100, "cloudsack")
require.NoError(t, err)
rt.UpdateConfig(certs, map[string]*Provider{"cloudsack": p})

client := &http.Client{Transport: rt}
for _, test := range tests {
Expand Down Expand Up @@ -503,7 +512,12 @@ func TestCustomValidators(t *testing.T) {
"sadcloud": p,
}

return NewFronted(certs, providers, "sadcloud", "", tls.HelloChrome_100)
f, err := NewFronted("", tls.HelloChrome_100, "sadcloud")
if err != nil {
return nil, err
}
f.UpdateConfig(certs, providers)
return f, nil
}

// This error indicates that the validator has discarded all masquerades.
Expand Down
12 changes: 10 additions & 2 deletions test_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@ func ConfigureForTest(t *testing.T) {
func ConfigureCachingForTest(t *testing.T, cacheFile string) {
certs := trustedCACerts(t)
p := testProviders()
NewFronted(certs, p, testProviderID, cacheFile, tls.HelloChrome_100)
f, err := NewFronted(cacheFile, tls.HelloChrome_100, testProviderID)
if err != nil {
t.Fatalf("Unable to create fronted: %v", err)
}
f.UpdateConfig(certs, p)
}

func ConfigureHostAlaisesForTest(t *testing.T, hosts map[string]string) {
certs := trustedCACerts(t)
p := testProvidersWithHosts(hosts)
NewFronted(certs, p, testProviderID, "", tls.HelloChrome_100)
f, err := NewFronted("", tls.HelloChrome_100, testProviderID)
if err != nil {
t.Fatalf("Unable to create fronted: %v", err)
}
f.UpdateConfig(certs, p)
}

func trustedCACerts(t *testing.T) *x509.CertPool {
Expand Down

0 comments on commit 9b577b9

Please sign in to comment.