Skip to content

Commit

Permalink
Change to separately track working fronts
Browse files Browse the repository at this point in the history
  • Loading branch information
myleshorton committed Nov 22, 2024
1 parent eedcd71 commit d16339d
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 254 deletions.
68 changes: 68 additions & 0 deletions connecting_fronts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package fronted

import (
"errors"
"sort"
"sync"
"time"
)

type connectTimeFront struct {
MasqueradeInterface
connectTime time.Duration
}

type connectingFronts struct {
fronts []connectTimeFront
//frontsChan chan MasqueradeInterface
sync.RWMutex
}

// Make sure that connectingFronts is a connectListener
var _ workingFronts = &connectingFronts{}

// newConnectingFronts creates a new ConnectingFronts struct with an empty slice of Masquerade IPs and domains.
func newConnectingFronts() *connectingFronts {
return &connectingFronts{
fronts: make([]connectTimeFront, 0),
//frontsChan: make(chan MasqueradeInterface),
}
}

// AddFront adds a new front to the list of fronts.
func (cf *connectingFronts) onConnected(m MasqueradeInterface, connectTime time.Duration) {
cf.Lock()
defer cf.Unlock()

cf.fronts = append(cf.fronts, connectTimeFront{
MasqueradeInterface: m,
connectTime: connectTime,
})
// Sort fronts by connect time.
sort.Slice(cf.fronts, func(i, j int) bool {
return cf.fronts[i].connectTime < cf.fronts[j].connectTime
})
//cf.frontsChan <- m
}

func (cf *connectingFronts) onError(m MasqueradeInterface) {
cf.Lock()
defer cf.Unlock()

// Remove the front from connecting fronts.
for i, front := range cf.fronts {
if front.MasqueradeInterface == m {
cf.fronts = append(cf.fronts[:i], cf.fronts[i+1:]...)
return
}
}
}

func (cf *connectingFronts) workingFront() (MasqueradeInterface, error) {
cf.RLock()
defer cf.RUnlock()
if len(cf.fronts) == 0 {
return nil, errors.New("no fronts available")
}
return cf.fronts[0].MasqueradeInterface, nil
}
60 changes: 34 additions & 26 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,60 @@ import (
"github.com/getlantern/eventual/v2"
)

// Create an interface for the fronting context
type Fronting interface {
UpdateConfig(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string)
NewRoundTripper(timeout time.Duration) (http.RoundTripper, bool)
Close()
}

var defaultContext = newFrontingContext("default")

// Make sure that the default context is a Fronting
var _ Fronting = defaultContext

// Configure sets the masquerades to use, the trusted root CAs, and the
// cache file for caching masquerades to set up direct domain fronting
// in the default context.
//
// 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)
func NewFronter(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string, cacheFile string) (Fronting, error) {
if err := defaultContext.configure(pool, providers, defaultProviderID, cacheFile); err != nil {
return nil, log.Errorf("Error configuring fronting %s context: %s!!", defaultContext.name, err)
}
}

// NewFronted creates a new http.RoundTripper that does direct domain fronting
// 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)
}

// Close closes any existing cache file in the default context
func Close() {
defaultContext.Close()
return defaultContext, nil
}

func newFrontingContext(name string) *frontingContext {
return &frontingContext{
name: name,
instance: eventual.NewValue(),
name: name,
instance: eventual.NewValue(),
connectingFronts: newConnectingFronts(),
}
}

type frontingContext struct {
name string
instance eventual.Value
name string
instance eventual.Value
fronted *fronted
connectingFronts *connectingFronts
}

// Configure sets the masquerades to use, the trusted root CAs, and the
// UpdateConfig updates the configuration of the fronting context
func (fctx *frontingContext) UpdateConfig(pool *x509.CertPool, providers map[string]*Provider, defaultProviderID string) {
fctx.fronted.updateConfig(pool, providers, defaultProviderID)
}

// configure sets the masquerades to use, the trusted root CAs, and the
// 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 {
return fctx.ConfigureWithHello(pool, providers, defaultProviderID, cacheFile, tls.ClientHelloID{})
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 {
Expand All @@ -73,10 +80,11 @@ func (fctx *frontingContext) ConfigureWithHello(pool *x509.CertPool, providers m
existing.closeCache()
}

_, err := newFronted(pool, providers, defaultProviderID, cacheFile, clientHelloID, func(f *fronted) {
var err error
fctx.fronted, err = newFronted(pool, providers, defaultProviderID, cacheFile, clientHelloID, func(f *fronted) {
log.Debug("Setting fronted instance")
fctx.instance.Set(f)
})
}, fctx.connectingFronts)
if err != nil {
return err
}
Expand All @@ -86,7 +94,7 @@ 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) NewRoundTripper(timeout time.Duration) (http.RoundTripper, bool) {
start := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
Expand Down
Loading

0 comments on commit d16339d

Please sign in to comment.