diff --git a/example.config.toml b/example.config.toml index c96e354..9a9c96b 100644 --- a/example.config.toml +++ b/example.config.toml @@ -56,6 +56,19 @@ domain-fronting-port = 443 # time range of this parameter. tolerate-time-skewness = "5s" +# Telegram has a concept of DC. You can think about DC as a number of a cluster +# with a certain purpose. Some clusters serve media, some - messages, some rule +# channels and so on. But sometimes unknown DC number is requested by client. +# It could be a bug or some global reconfiguration of the Telegram. +# +# By default, proxy rejects such requests. But it is also possible to fallback +# this request to any DC. Telegram works in a way that any DC is able to serve +# any request but sacrificing a latency. +# +# If this setting is disabled (default), mtg will reject a connection. +# Otherwise, chose a new DC. +allow-fallback-on-unknown-dc = false + # network defines different network-related settings [network] # please be aware that mtg needs to do some external requests. For diff --git a/internal/cli/run_proxy.go b/internal/cli/run_proxy.go index 4fbf7b9..a4fd81e 100644 --- a/internal/cli/run_proxy.go +++ b/internal/cli/run_proxy.go @@ -184,6 +184,8 @@ func runProxy(conf *config.Config, version string) error { BufferSize: conf.TCPBuffer.Get(mtglib.DefaultBufferSize), DomainFrontingPort: conf.DomainFrontingPort.Get(mtglib.DefaultDomainFrontingPort), PreferIP: conf.PreferIP.Get(mtglib.DefaultPreferIP), + + AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false), } proxy, err := mtglib.NewProxy(opts) diff --git a/internal/cli/simple_run.go b/internal/cli/simple_run.go index 5a4bb0e..a0bb25d 100644 --- a/internal/cli/simple_run.go +++ b/internal/cli/simple_run.go @@ -71,6 +71,7 @@ func (s *SimpleRun) Run(cli *CLI, version string) error { // nolint: cyclop } conf.Debug.Value = s.Debug + conf.AllowFallbackOnUnknownDC.Value = true conf.Defense.AntiReplay.Enabled.Value = true if err := conf.Validate(); err != nil { diff --git a/internal/config/config.go b/internal/config/config.go index 6230758..c072dad 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -9,15 +9,16 @@ import ( ) type Config struct { - Debug TypeBool `json:"debug"` - Secret mtglib.Secret `json:"secret"` - BindTo TypeHostPort `json:"bindTo"` - TCPBuffer TypeBytes `json:"tcpBuffer"` - PreferIP TypePreferIP `json:"preferIp"` - DomainFrontingPort TypePort `json:"domainFrontingPort"` - TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"` - Concurrency TypeConcurrency `json:"concurrency"` - Defense struct { + Debug TypeBool `json:"debug"` + AllowFallbackOnUnknownDC TypeBool `json:"allowFallbackOnUnknownDc"` + Secret mtglib.Secret `json:"secret"` + BindTo TypeHostPort `json:"bindTo"` + TCPBuffer TypeBytes `json:"tcpBuffer"` + PreferIP TypePreferIP `json:"preferIp"` + DomainFrontingPort TypePort `json:"domainFrontingPort"` + TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"` + Concurrency TypeConcurrency `json:"concurrency"` + Defense struct { AntiReplay struct { Enabled TypeBool `json:"enabled"` MaxSize TypeBytes `json:"maxSize"` diff --git a/internal/config/parse.go b/internal/config/parse.go index f4e7a05..a364712 100644 --- a/internal/config/parse.go +++ b/internal/config/parse.go @@ -9,15 +9,16 @@ import ( ) type tomlConfig struct { - Debug bool `toml:"debug" json:"debug,omitempty"` - Secret string `toml:"secret" json:"secret"` - BindTo string `toml:"bind-to" json:"bindTo"` - TCPBuffer string `toml:"tcp-buffer" json:"tcpBuffer,omitempty"` - PreferIP string `toml:"prefer-ip" json:"preferIp,omitempty"` - DomainFrontingPort uint `toml:"domain-fronting-port" json:"domainFrontingPort,omitempty"` - TolerateTimeSkewness string `toml:"tolerate-time-skewness" json:"tolerateTimeSkewness,omitempty"` - Concurrency uint `toml:"concurrency" json:"concurrency,omitempty"` - Defense struct { + Debug bool `toml:"debug" json:"debug,omitempty"` + AllowFallbackOnUnknownDC bool `toml:"allow-fallback-on-unknown-dc" json:"allowFallbackOnUnknownDc,omitempty"` + Secret string `toml:"secret" json:"secret"` + BindTo string `toml:"bind-to" json:"bindTo"` + TCPBuffer string `toml:"tcp-buffer" json:"tcpBuffer,omitempty"` + PreferIP string `toml:"prefer-ip" json:"preferIp,omitempty"` + DomainFrontingPort uint `toml:"domain-fronting-port" json:"domainFrontingPort,omitempty"` + TolerateTimeSkewness string `toml:"tolerate-time-skewness" json:"tolerateTimeSkewness,omitempty"` + Concurrency uint `toml:"concurrency" json:"concurrency,omitempty"` + Defense struct { AntiReplay struct { Enabled bool `toml:"enabled" json:"enabled,omitempty"` MaxSize string `toml:"max-size" json:"maxSize,omitempty"` diff --git a/mtglib/proxy.go b/mtglib/proxy.go index 5b685ec..330d2f3 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -23,11 +23,12 @@ type Proxy struct { ctxCancel context.CancelFunc streamWaitGroup sync.WaitGroup - tolerateTimeSkewness time.Duration - bufferSize int - domainFrontingPort int - workerPool *ants.PoolWithFunc - telegram *telegram.Telegram + allowFallbackOnUnknownDC bool + tolerateTimeSkewness time.Duration + bufferSize int + domainFrontingPort int + workerPool *ants.PoolWithFunc + telegram *telegram.Telegram secret Secret network Network @@ -209,7 +210,7 @@ func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error { func (p *Proxy) doTelegramCall(ctx *streamContext) error { dc := ctx.dc - if !p.telegram.IsKnownDC(dc) { + if p.allowFallbackOnUnknownDC && !p.telegram.IsKnownDC(dc) { dc = p.telegram.GetFallbackDC() ctx.logger = ctx.logger.BindInt("fallback_dc", dc) @@ -285,18 +286,19 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { ctx, cancel := context.WithCancel(context.Background()) proxy := &Proxy{ - ctx: ctx, - ctxCancel: cancel, - secret: opts.Secret, - network: opts.Network, - antiReplayCache: opts.AntiReplayCache, - ipBlocklist: opts.IPBlocklist, - eventStream: opts.EventStream, - logger: opts.getLogger("proxy"), - domainFrontingPort: opts.getDomainFrontingPort(), - tolerateTimeSkewness: opts.getTolerateTimeSkewness(), - bufferSize: opts.getBufferSize(), - telegram: tg, + ctx: ctx, + ctxCancel: cancel, + secret: opts.Secret, + network: opts.Network, + antiReplayCache: opts.AntiReplayCache, + ipBlocklist: opts.IPBlocklist, + eventStream: opts.EventStream, + logger: opts.getLogger("proxy"), + domainFrontingPort: opts.getDomainFrontingPort(), + tolerateTimeSkewness: opts.getTolerateTimeSkewness(), + bufferSize: opts.getBufferSize(), + allowFallbackOnUnknownDC: opts.AllowFallbackOnUnknownDC, + telegram: tg, } pool, err := ants.NewPoolWithFunc(opts.getConcurrency(), diff --git a/mtglib/proxy_opts.go b/mtglib/proxy_opts.go index 8d1f6b5..8993de7 100644 --- a/mtglib/proxy_opts.go +++ b/mtglib/proxy_opts.go @@ -90,6 +90,16 @@ type ProxyOpts struct { // This is an optional setting. DomainFrontingPort uint + // AllowFallbackOnUnknownDC defines how proxy behaves if unknown DC was + // requested. If this setting is set to false, then such connection + // will be rejected. Otherwise, proxy will chose any DC. + // + // Telegram is designed in a way that any DC can serve any request, + // the problem is a latency. + // + // This is an optional setting. + AllowFallbackOnUnknownDC bool + // UseTestDCs defines if we have to connect to production or to staging // DCs of Telegram. //