From 680ac88134b8cdf09f57dfbb65a8b5755bece28a Mon Sep 17 00:00:00 2001 From: Adam Fisk Date: Tue, 19 Nov 2024 09:25:08 -0700 Subject: [PATCH 1/2] more logs and limit public access to various context-related methods and structs --- context.go | 29 ++++++++++++++--------------- fronted_test.go | 14 +++++++------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/context.go b/context.go index 9c6842e..210670b 100644 --- a/context.go +++ b/context.go @@ -11,9 +11,7 @@ import ( "github.com/getlantern/eventual" ) -var ( - DefaultContext = NewFrontingContext("default") -) +var defaultContext = newFrontingContext("default") // Configure sets the masquerades to use, the trusted root CAs, and the // cache file for caching masquerades to set up direct domain fronting @@ -22,8 +20,8 @@ var ( // defaultProviderID is used when a masquerade without a provider is // encountered (eg in a cache file) func Configure(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string, cacheFile string) { - if err := DefaultContext.Configure(pool, providers, defaultProviderID, cacheFile); err != nil { - log.Errorf("Error configuring fronting %s context: %s!!", DefaultContext.name, err) + if err := defaultContext.Configure(pool, providers, defaultProviderID, cacheFile); err != nil { + log.Errorf("Error configuring fronting %s context: %s!!", defaultContext.name, err) } } @@ -31,22 +29,22 @@ func Configure(pool *x509.CertPool, providers map[string]*Provider, defaultProvi // using the default context. If the default context isn't configured within // the given timeout, this method returns nil, false. func NewFronted(timeout time.Duration) (http.RoundTripper, bool) { - return DefaultContext.NewFronted(timeout) + return defaultContext.NewFronted(timeout) } // Close closes any existing cache file in the default context func Close() { - DefaultContext.Close() + defaultContext.Close() } -func NewFrontingContext(name string) *FrontingContext { - return &FrontingContext{ +func newFrontingContext(name string) *frontingContext { + return &frontingContext{ name: name, instance: eventual.NewValue(), } } -type FrontingContext struct { +type frontingContext struct { name string instance eventual.Value } @@ -55,11 +53,11 @@ type FrontingContext struct { // cache file for caching masquerades to set up direct domain fronting. // defaultProviderID is used when a masquerade without a provider is // encountered (eg in a cache file) -func (fctx *FrontingContext) Configure(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string, cacheFile string) error { +func (fctx *frontingContext) Configure(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string, cacheFile string) error { return fctx.ConfigureWithHello(pool, providers, defaultProviderID, cacheFile, tls.ClientHelloID{}) } -func (fctx *FrontingContext) ConfigureWithHello(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string, cacheFile string, clientHelloID tls.ClientHelloID) error { +func (fctx *frontingContext) ConfigureWithHello(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string, cacheFile string, clientHelloID tls.ClientHelloID) error { log.Debugf("Configuring fronted %s context", fctx.name) if len(providers) == 0 { @@ -74,6 +72,7 @@ func (fctx *FrontingContext) ConfigureWithHello(pool *x509.CertPool, providers m } _, err := newFronted(pool, providers, defaultProviderID, cacheFile, clientHelloID, func(f *fronted) { + log.Debug("Setting fronted instance") fctx.instance.Set(f) }) if err != nil { @@ -85,20 +84,20 @@ func (fctx *FrontingContext) ConfigureWithHello(pool *x509.CertPool, providers m // NewFronted creates a new http.RoundTripper that does direct domain fronting. // If the context isn't configured within the given timeout, this method // returns nil, false. -func (fctx *FrontingContext) NewFronted(timeout time.Duration) (http.RoundTripper, bool) { +func (fctx *frontingContext) NewFronted(timeout time.Duration) (http.RoundTripper, bool) { start := time.Now() instance, ok := fctx.instance.Get(timeout) if !ok { log.Errorf("No DirectHttpClient available within %v for context %s", timeout, fctx.name) return nil, false } else { - log.Debugf("DirectHttpClient available for context %s after %v", fctx.name, time.Since(start)) + log.Debugf("DirectHttpClient available for context %s after %v with duration %v", fctx.name, time.Since(start), timeout) } return instance.(http.RoundTripper), true } // Close closes any existing cache file in the default contexxt. -func (fctx *FrontingContext) Close() { +func (fctx *frontingContext) Close() { _existing, ok := fctx.instance.Get(0) if ok && _existing != nil { existing := _existing.(*fronted) diff --git a/fronted_test.go b/fronted_test.go index a1a1f3f..9bbd2d8 100644 --- a/fronted_test.go +++ b/fronted_test.go @@ -55,7 +55,7 @@ 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"}, }) - testContext := NewFrontingContext("TestDirectDomainFrontingWithSNIConfig") + testContext := newFrontingContext("TestDirectDomainFrontingWithSNIConfig") testContext.Configure(certs, p, "akamai", cacheFile) transport, ok := testContext.NewFronted(30 * time.Second) @@ -84,7 +84,7 @@ func doTestDomainFronting(t *testing.T, cacheFile string, expectedMasqueradesAtE } certs := trustedCACerts(t) p := testProvidersWithHosts(hosts) - testContext := NewFrontingContext("doTestDomainFronting") + testContext := newFrontingContext("doTestDomainFronting") testContext.Configure(certs, p, testProviderID, cacheFile) transport, ok := testContext.NewFronted(30 * time.Second) @@ -239,7 +239,7 @@ func TestHostAliasesBasic(t *testing.T) { certs := x509.NewCertPool() certs.AddCert(cloudSack.Certificate()) - testContext := NewFrontingContext("TestHostAliasesBasic") + testContext := newFrontingContext("TestHostAliasesBasic") testContext.Configure(certs, map[string]*Provider{"cloudsack": p}, "cloudsack", "") rt, ok := testContext.NewFronted(30 * time.Second) @@ -352,7 +352,7 @@ func TestHostAliasesMulti(t *testing.T) { "sadcloud": p2, } - testContext := NewFrontingContext("TestHostAliasesMulti") + testContext := newFrontingContext("TestHostAliasesMulti") testContext.Configure(certs, providers, "cloudsack", "") rt, ok := testContext.NewFronted(30 * time.Second) if !assert.True(t, ok, "failed to obtain direct roundtripper") { @@ -479,7 +479,7 @@ func TestPassthrough(t *testing.T) { certs := x509.NewCertPool() certs.AddCert(cloudSack.Certificate()) - testContext := NewFrontingContext("TestPassthrough") + testContext := newFrontingContext("TestPassthrough") testContext.Configure(certs, map[string]*Provider{"cloudsack": p}, "cloudsack", "") rt, ok := testContext.NewFronted(30 * time.Second) @@ -538,7 +538,7 @@ func TestCustomValidators(t *testing.T) { sadCloudValidator := NewStatusCodeValidator(sadCloudCodes) testURL := "https://abc.forbidden.com/quux" - setup := func(ctx *FrontingContext, validator ResponseValidator) { + setup := func(ctx *frontingContext, validator ResponseValidator) { masq := []*Masquerade{{Domain: "example.com", IpAddress: sadCloudAddr}} alias := map[string]string{ "abc.forbidden.com": "abc.sadcloud.io", @@ -633,7 +633,7 @@ func TestCustomValidators(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - testContext := NewFrontingContext(test.name) + testContext := newFrontingContext(test.name) setup(testContext, test.validator) direct, ok := testContext.NewFronted(30 * time.Second) require.True(t, ok) From 9dc10f730dc3c3977313b0fb5c42d56ca622c3a4 Mon Sep 17 00:00:00 2001 From: Adam Fisk Date: Tue, 19 Nov 2024 09:38:56 -0700 Subject: [PATCH 2/2] Use new eventual --- context.go | 22 +++++++++++++++------- fronted_test.go | 5 +++-- go.mod | 3 +-- go.sum | 10 ++-------- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/context.go b/context.go index 210670b..b3b5e86 100644 --- a/context.go +++ b/context.go @@ -1,6 +1,7 @@ package fronted import ( + "context" "crypto/x509" "fmt" "net/http" @@ -8,7 +9,7 @@ import ( tls "github.com/refraction-networking/utls" - "github.com/getlantern/eventual" + "github.com/getlantern/eventual/v2" ) var defaultContext = newFrontingContext("default") @@ -64,8 +65,9 @@ func (fctx *frontingContext) ConfigureWithHello(pool *x509.CertPool, providers m return fmt.Errorf("no fronted providers for %s context", fctx.name) } - _existing, ok := fctx.instance.Get(0) - if ok && _existing != nil { + if _existing, err := fctx.instance.Get(eventual.DontWait); err != nil { + log.Errorf("Error getting existing instance for %s context: %s", fctx.name, err) + } else if _existing != nil { existing := _existing.(*fronted) log.Debugf("Closing cache from existing instance for %s context", fctx.name) existing.closeCache() @@ -86,8 +88,10 @@ func (fctx *frontingContext) ConfigureWithHello(pool *x509.CertPool, providers m // returns nil, false. func (fctx *frontingContext) NewFronted(timeout time.Duration) (http.RoundTripper, bool) { start := time.Now() - instance, ok := fctx.instance.Get(timeout) - if !ok { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + instance, err := fctx.instance.Get(ctx) + if err != nil { log.Errorf("No DirectHttpClient available within %v for context %s", timeout, fctx.name) return nil, false } else { @@ -98,8 +102,12 @@ func (fctx *frontingContext) NewFronted(timeout time.Duration) (http.RoundTrippe // Close closes any existing cache file in the default contexxt. func (fctx *frontingContext) Close() { - _existing, ok := fctx.instance.Get(0) - if ok && _existing != nil { + _existing, err := fctx.instance.Get(eventual.DontWait) + if err != nil { + log.Errorf("Error getting existing instance for %s context: %s", fctx.name, err) + return + } + if _existing != nil { existing := _existing.(*fronted) log.Debugf("Closing cache from existing instance in %s context", fctx.name) existing.closeCache() diff --git a/fronted_test.go b/fronted_test.go index 9bbd2d8..a89ce84 100644 --- a/fronted_test.go +++ b/fronted_test.go @@ -19,6 +19,7 @@ import ( "testing" "time" + "github.com/getlantern/eventual/v2" . "github.com/getlantern/waitforserver" tls "github.com/refraction-networking/utls" "github.com/stretchr/testify/assert" @@ -103,8 +104,8 @@ func doTestDomainFronting(t *testing.T, cacheFile string, expectedMasqueradesAtE } require.True(t, doCheck(client, http.MethodGet, http.StatusOK, getURL)) - instance, ok := testContext.instance.Get(0) - require.True(t, ok) + instance, err := testContext.instance.Get(eventual.DontWait) + require.NoError(t, err) d := instance.(*fronted) // Check the number of masquerades at the end, waiting until we get the right number diff --git a/go.mod b/go.mod index fc503af..d0649b9 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,8 @@ module github.com/getlantern/fronted go 1.22.3 require ( - github.com/getlantern/eventual v1.0.0 + github.com/getlantern/eventual/v2 v2.0.2 github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 - github.com/getlantern/idletiming v0.0.0-20201229174729-33d04d220c4e github.com/getlantern/keyman v0.0.0-20180207174507-f55e7280e93a github.com/getlantern/netx v0.0.0-20210806160745-b824e2cad607 github.com/getlantern/ops v0.0.0-20230424193308-26325dfed3cf diff --git a/go.sum b/go.sum index bf7c839..2b6f65f 100644 --- a/go.sum +++ b/go.sum @@ -33,30 +33,24 @@ github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFB github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= github.com/getlantern/errors v1.0.3 h1:Ne4Ycj7NI1BtSyAfVeAT/DNoxz7/S2BUc3L2Ht1YSHE= github.com/getlantern/errors v1.0.3/go.mod h1:m8C7H1qmouvsGpwQqk/6NUpIVMpfzUPn608aBZDYV04= -github.com/getlantern/eventual v1.0.0 h1:q56jlZhiDeWvdrc0QJ12AaWqcu/Z67wDDjdAUKGnYqc= -github.com/getlantern/eventual v1.0.0/go.mod h1:xL9T/pQI7i44INFSsKf4zDNz5bXA7P18j1cNd5qy/yI= +github.com/getlantern/eventual/v2 v2.0.2 h1:7b3N2oQBVqSHwm/8u7C8b6W+OkkjgZSmwUc1AdIkrHc= +github.com/getlantern/eventual/v2 v2.0.2/go.mod h1:o1VZHRk8UArBra+pwPSi23WrahBG4qgg4/ew6Mmlq84= github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4 h1:JdD4XSaT6/j6InM7MT1E4WRvzR8gurxfq53A3ML3B/Q= github.com/getlantern/fdcount v0.0.0-20190912142506-f89afd7367c4/go.mod h1:XZwE+iIlAgr64OFbXKFNCllBwV4wEipPx8Hlo2gZdbM= github.com/getlantern/filepersist v0.0.0-20160317154340-c5f0cd24e799 h1:FhkPUYCQYmoxS02r2GRrIV7dahUIncRl36xzs3/mnjA= github.com/getlantern/filepersist v0.0.0-20160317154340-c5f0cd24e799/go.mod h1:8DGAx0LNUfXNnEH+fXI0s3OCBA/351kZCiz/8YSK3i8= github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk= github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc= -github.com/getlantern/grtrack v0.0.0-20160824195228-cbf67d3fa0fd h1:GPrx88jy222gMuRHXxBSViT/3zdNO210nRAaXn+lL6s= -github.com/getlantern/grtrack v0.0.0-20160824195228-cbf67d3fa0fd/go.mod h1:RkQEgBdrJCH5tYJP2D+a/aJ216V3c9q8w/tCJtEiDoY= github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0= github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc= github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= -github.com/getlantern/idletiming v0.0.0-20201229174729-33d04d220c4e h1:b0VWlP1TB369RANq5GnV76sGDm98eQwVJaaoH8OXOmw= -github.com/getlantern/idletiming v0.0.0-20201229174729-33d04d220c4e/go.mod h1:McaLC6faRlxJ9QjjqSjpEeYIjKnKA8+dzjoR+eYXCio= github.com/getlantern/keyman v0.0.0-20180207174507-f55e7280e93a h1:SBw2c296eaLrrnydtLhcjgvNB1mDaXF1SSfW4DGt0kk= github.com/getlantern/keyman v0.0.0-20180207174507-f55e7280e93a/go.mod h1:FMf0g72BHs14jVcD8i8ubEk4sMB6JdidBn67d44i3ws= github.com/getlantern/mockconn v0.0.0-20190708122800-637bd46d8034/go.mod h1:+F5GJ7qGpQ03DBtcOEyQpM30ix4BLswdaojecFtsdy8= -github.com/getlantern/mockconn v0.0.0-20191023022503-481dbcceeb58/go.mod h1:+F5GJ7qGpQ03DBtcOEyQpM30ix4BLswdaojecFtsdy8= github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848 h1:2MhMMVBTnaHrst6HyWFDhwQCaJ05PZuOv1bE2gN8WFY= github.com/getlantern/mockconn v0.0.0-20200818071412-cb30d065a848/go.mod h1:+F5GJ7qGpQ03DBtcOEyQpM30ix4BLswdaojecFtsdy8= github.com/getlantern/mtime v0.0.0-20170117193331-ba114e4a82b0/go.mod h1:u537FS7ld4Whf7h7/0ql/myAudWWBNgeRhgE9XXH4Pk= -github.com/getlantern/mtime v0.0.0-20200228202836-084e1d8282b0/go.mod h1:GfzwugvtH7YcmNIrHHizeyImsgEdyL88YkdnK28B14c= github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7 h1:03J6Cb42EG06lHgpOFGm5BOax4qFqlSbSeKO2RGrj2g= github.com/getlantern/mtime v0.0.0-20200417132445-23682092d1f7/go.mod h1:GfzwugvtH7YcmNIrHHizeyImsgEdyL88YkdnK28B14c= github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd/go.mod h1:wKdY0ikOgzrWSeB9UyBVKPRhjXQ+vTb+BPeJuypUuNE=