func applyClientConfig(client *client.Client, cfg *config.Config) { cfgMutex.Lock() defer cfgMutex.Unlock() autoupdate.Configure(cfg) logging.Configure(cfg.Addr, cfg.CloudConfigCA, cfg.InstanceId, version, revisionDate) settings.Configure(cfg, version, revisionDate, buildDate) proxiedsites.Configure(cfg.ProxiedSites) analytics.Configure(cfg, version) log.Debugf("Proxy all traffic or not: %v", cfg.Client.ProxyAll) ServeProxyAllPacFile(cfg.Client.ProxyAll) // Note - we deliberately ignore the error from statreporter.Configure here _ = statreporter.Configure(cfg.Stats) // Update client configuration and get the highest QOS dialer available. hqfd := client.Configure(cfg.Client) if hqfd == nil { log.Errorf("No fronted dialer available, not enabling geolocation, config lookup, or stats") } else { // Give everyone their own *http.Client that uses the highest QOS dialer. Separate // clients for everyone avoids data races configuring those clients. config.Configure(hqfd.NewDirectDomainFronter()) geolookup.Configure(hqfd.NewDirectDomainFronter()) statserver.Configure(hqfd.NewDirectDomainFronter()) // Note we don't call Configure on analytics here, as that would // result in an extra analytics call and double counting. } }
// Run runs a client proxy. It blocks as long as the proxy is running. func Run(httpProxyAddr string, socksProxyAddr string, configDir string, stickyConfig bool, proxyAll func() bool, flagsAsMap map[string]interface{}, beforeStart func(cfg *config.Config) bool, afterStart func(cfg *config.Config), onConfigUpdate func(cfg *config.Config), onError func(err error)) error { displayVersion() log.Debug("Initializing configuration") cfg, err := config.Init(PackageVersion, configDir, stickyConfig, flagsAsMap) if err != nil { return fmt.Errorf("Unable to initialize configuration: %v", err) } client := client.NewClient() if beforeStart(cfg) { log.Debug("Preparing to start client proxy") geolookup.Configure(client.Addr) cfgMutex.Lock() applyClientConfig(client, cfg, proxyAll) cfgMutex.Unlock() go func() { err := config.Run(func(updated *config.Config) { log.Debug("Applying updated configuration") cfgMutex.Lock() applyClientConfig(client, updated, proxyAll) onConfigUpdate(updated) cfgMutex.Unlock() log.Debug("Applied updated configuration") }) if err != nil { onError(err) } }() if socksProxyAddr != "" { go func() { log.Debug("Starting client SOCKS5 proxy") err = client.ListenAndServeSOCKS5(socksProxyAddr) if err != nil { log.Errorf("Unable to start SOCKS5 proxy: %v", err) } }() } log.Debug("Starting client HTTP proxy") err = client.ListenAndServeHTTP(httpProxyAddr, func() { log.Debug("Started client HTTP proxy") // We finally tell the config package to start polling for new configurations. // This is the final step because the config polling itself uses the full // proxying capabilities of Lantern, so it needs everything to be properly // set up with at least an initial bootstrap config (on first run) to // complete successfully. config.StartPolling() afterStart(cfg) }) if err != nil { log.Errorf("Error starting client proxy: %v", err) onError(err) } } return nil }