Skip to content

Commit

Permalink
Make the fronted API more self-contained
Browse files Browse the repository at this point in the history
  • Loading branch information
myleshorton committed Dec 12, 2024
1 parent ff6c4b4 commit a8af9fe
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 51 deletions.
2 changes: 1 addition & 1 deletion cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ func TestCaching(t *testing.T) {
cacheDirty: make(chan interface{}, 1),
cacheClosed: make(chan interface{}),
providers: providers,
defaultProviderID: cloudsackID,
stopCh: make(chan interface{}, 10),
defaultProviderID: cloudsackID,
}
go f.maintainCache(cacheFile)
return f
Expand Down
28 changes: 12 additions & 16 deletions fronted.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ const (
)

var (
log = golog.LoggerFor("fronted")
log = golog.LoggerFor("fronted")
defaultFrontedProviderID = "cloudfront"
)

// fronted identifies working IP address/domain pairings for domain fronting and is
Expand Down Expand Up @@ -62,22 +63,18 @@ type fronted struct {
type Fronted interface {
http.RoundTripper

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

// Close closes any resources, such as goroutines that are testing fronts.
Close()
}

// NewFronted creates a new Fronted instance with the given cache file, clientHelloID, and defaultProviderID.
// NewFronted creates a new Fronted instance with the given cache file.
// At this point it does not have the actual IPs, domains, etc of the fronts to try.
// defaultProviderID is used when a front without a provider is encountered (eg in a cache file)
func NewFronted(cacheFile string, clientHello tls.ClientHelloID, defaultProviderID string) (Fronted, error) {
func NewFronted(cacheFile string) Fronted {
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())

f := &fronted{
certPool: atomic.Value{},
Expand All @@ -88,23 +85,22 @@ func NewFronted(cacheFile string, clientHello tls.ClientHelloID, defaultProvider
cacheDirty: make(chan interface{}, 1),
cacheClosed: make(chan interface{}),
providers: make(map[string]*Provider),
clientHelloID: clientHello,
clientHelloID: tls.HelloAndroid_11_OkHttp,
connectingFronts: newConnectingFronts(4000),
stopCh: make(chan interface{}, 10),
defaultProviderID: defaultProviderID,
defaultProviderID: defaultFrontedProviderID,
}

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

return f, nil
return f
}

// UpdateConfig sets the domain fronts to use, the trusted root CAs, the fronting providers
// (such as Akamai, Cloudfront, etc), and the cache file for caching fronts to set up
// domain fronting.
func (f *fronted) UpdateConfig(pool *x509.CertPool, providers map[string]*Provider) {
// OnNewFronts sets the domain fronts to use, the trusted root CAs and the fronting providers
// (such as Akamai, Cloudfront, etc)
func (f *fronted) OnNewFronts(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")
Expand Down
45 changes: 22 additions & 23 deletions fronted_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,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(cacheFile, tls.HelloChrome_100, "akamai")
require.NoError(t, err)
transport.UpdateConfig(certs, p)
defaultFrontedProviderID = "akamai"
transport := NewFronted(cacheFile)
transport.OnNewFronts(certs, p)

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

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

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

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

rt.OnNewFronts(certs, map[string]*Provider{"cloudsack": p})

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

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

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

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

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

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

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

Expand Down
17 changes: 6 additions & 11 deletions test_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"testing"

"github.com/getlantern/keyman"
tls "github.com/refraction-networking/utls"
)

var (
Expand All @@ -24,22 +23,18 @@ func ConfigureForTest(t *testing.T) Fronted {
func ConfigureCachingForTest(t *testing.T, cacheFile string) Fronted {
certs := trustedCACerts(t)
p := testProviders()
f, err := NewFronted(cacheFile, tls.HelloChrome_100, testProviderID)
if err != nil {
t.Fatalf("Unable to create fronted: %v", err)
}
f.UpdateConfig(certs, p)
defaultFrontedProviderID = testProviderID
f := NewFronted(cacheFile)
f.OnNewFronts(certs, p)
return f
}

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

Expand Down

0 comments on commit a8af9fe

Please sign in to comment.