diff --git a/internal/cli/run_proxy.go b/internal/cli/run_proxy.go index b48fcbc..7774953 100644 --- a/internal/cli/run_proxy.go +++ b/internal/cli/run_proxy.go @@ -239,6 +239,11 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen return fmt.Errorf("cannot build ip allowlist: %w", err) } + doppelGangerURLs := make([]string, len(conf.Defense.Doppelganger.URLs)) + for i, v := range conf.Defense.Doppelganger.URLs { + doppelGangerURLs[i] = v.String() + } + opts := mtglib.ProxyOpts{ Logger: logger, Network: ntw, @@ -256,6 +261,10 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false), TolerateTimeSkewness: conf.TolerateTimeSkewness.Value, + + DoppelGangerURLs: doppelGangerURLs, + DoppelGangerPerRaid: conf.Defense.Doppelganger.Repeats.Get(mtglib.DoppelGangerPerRaid), + DoppelGangerEach: conf.Defense.Doppelganger.UpdateEach.Get(mtglib.DoppelGangerEach), } proxy, err := mtglib.NewProxy(opts) diff --git a/mtglib/init.go b/mtglib/init.go index 81dee7a..5b2d0bf 100644 --- a/mtglib/init.go +++ b/mtglib/init.go @@ -99,6 +99,13 @@ const ( // reads from Telegram after which connection will be terminated. This is // required to abort stale connections. TCPRelayReadTimeout = 20 * time.Second + + // DoppelGangerPerRaid defines a number of requests to each URL + // per raid. + DoppelGangerPerRaid = 10 + + // DoppelGangerEach defines a time period between each crawl attempt. + DoppelGangerEach = 6 * time.Hour ) // Network defines a knowledge how to work with a network. It may sound fun but diff --git a/mtglib/proxy.go b/mtglib/proxy.go index 9445752..9ac8412 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -157,6 +157,7 @@ func (p *Proxy) Shutdown() { p.streamWaitGroup.Wait() p.workerPool.Release() p.configUpdater.Wait() + p.doppelGanger.Shutdown() p.allowlist.Shutdown() p.blocklist.Shutdown() @@ -327,6 +328,14 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { tolerateTimeSkewness: opts.getTolerateTimeSkewness(), allowFallbackOnUnknownDC: opts.AllowFallbackOnUnknownDC, telegram: tg, + doppelGanger: doppel.NewGanger( + ctx, + opts.Network, + logger.Named("doppelganger"), + opts.DoppelGangerEach, + int(opts.DoppelGangerPerRaid), + opts.DoppelGangerURLs, + ), configUpdater: dc.NewPublicConfigUpdater( tg, updatersLogger.Named("public-config"), @@ -338,6 +347,8 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { domainFrontingProxyProtocol: opts.DomainFrontingProxyProtocol, } + proxy.doppelGanger.Run() + if opts.AutoUpdate { proxy.configUpdater.Run(ctx, dc.PublicConfigUpdateURLv4, "tcp4") proxy.configUpdater.Run(ctx, dc.PublicConfigUpdateURLv6, "tcp6") diff --git a/mtglib/proxy_opts.go b/mtglib/proxy_opts.go index 88af9ea..0f8600e 100644 --- a/mtglib/proxy_opts.go +++ b/mtglib/proxy_opts.go @@ -142,6 +142,21 @@ type ProxyOpts struct { // // OBSOLETE and DEPRECATED. Ignored. DCOverrides map[int][]string + + // DoppelGangerURLs is a list of URLs that should be crawled by + // mtg to calculate parameters for statistical distribution of a + // traffic for fronting domains. If nothing is given, then predefined + // statistics is going to be used. + DoppelGangerURLs []string + + // DoppelGangerPerRaid defines how many time each URL from + // DoppelGangerURLs list should be crawled per raid. We recommend to + // have this number ~10. + DoppelGangerPerRaid uint + + // DoppelGangerEach defines a time period between each raid. We recommend + // to use hours here. + DoppelGangerEach time.Duration } func (p ProxyOpts) valid() error {