| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- package mtglib
-
- import (
- "fmt"
- "time"
- )
-
- // ProxyOpts is a structure with settings to mtg proxy.
- //
- // This is not required per se, but this is to shorten function signature and
- // give an ability to conveniently provide default values.
- type ProxyOpts struct {
- // Secret defines a secret which should be used by a proxy.
- //
- // Deprecated: Use Secrets instead for multi-secret support.
- // Kept for backward compatibility.
- Secret Secret
-
- // Secrets defines a map of named secrets which should be used by a proxy.
- // If set, Secret is ignored. During FakeTLS handshake, each secret is
- // tried until one validates.
- Secrets map[string]Secret
-
- // Network defines a network instance which should be used for all network
- // communications made by proxies.
- //
- // This is a mandatory setting.
- Network Network
-
- // AntiReplayCache defines an instance of antireplay cache.
- //
- // This is a mandatory setting.
- AntiReplayCache AntiReplayCache
-
- // IPBlocklist defines an instance of IP blocklist.
- //
- // This is a mandatory setting.
- IPBlocklist IPBlocklist
-
- // IPAllowlist defines a whitelist of IPs to allow to use proxy.
- //
- // This is an optional setting, ignored by default (no restrictions).
- IPAllowlist IPBlocklist
-
- // EventStream defines an instance of event stream.
- //
- // This ia a mandatory setting.
- EventStream EventStream
-
- // Logger defines an instance of the logger.
- //
- // This is a mandatory setting.
- Logger Logger
-
- // BufferSize is a size of the copy buffer in bytes.
- //
- // Please remember that we multiply this number in 2, because when we relay
- // between proxies, we have to create 2 intermediate buffers: to and from.
- //
- // This is an optional setting.
- //
- // Deprecated: this setting is no longer makes any effect.
- BufferSize uint
-
- // Concurrency is a size of the worker pool for connection management.
- //
- // If we have more connections than this number, they are going to be
- // rejected.
- //
- // This is an optional setting.
- Concurrency uint
-
- // IdleTimeout is a timeout for relay when we have to break a stream.
- //
- // This is a timeout for any activity. So, if we have any message which will
- // pass to either direction, a timer is reset. If we have no any reads or
- // writes for this timeout, a connection will be aborted.
- //
- // This is an optional setting.
- IdleTimeout time.Duration
-
- // HandshakeTimeout is a timeout during which all handshake ceremonies must
- // be completed, otherwise this process will be aborted
- //
- // This is an optional setting.
- HandshakeTimeout time.Duration
-
- // TolerateTimeSkewness is a time boundary that defines a time range where
- // faketls timestamp is acceptable.
- //
- // This means that if if you got a timestamp X, now is Y, then if |X-Y| <
- // TolerateTimeSkewness, then you accept a packet.
- //
- // This is an optional setting.
- TolerateTimeSkewness time.Duration
-
- // PreferIP defines an IP connectivity preference. Valid values are:
- // 'prefer-ipv4', 'prefer-ipv6', 'only-ipv4', 'only-ipv6'.
- //
- // This is an optional setting.
- PreferIP string
-
- // AutoUpdate defines if it is required to auto update proxy list from
- // Telegram instead of relying on a hardcoded list.
- //
- // This is an optional setting.
- AutoUpdate bool
-
- // DomainFrontingPort is a port we use to connect to a fronting domain.
- //
- // This is required because secret does not specify a port. It specifies a
- // hostname only.
- //
- // This is an optional setting.
- DomainFrontingPort uint
-
- // DomainFrontingIP is an IP address to use when connecting to the fronting
- // domain instead of resolving the hostname from the secret via DNS.
- //
- // This is useful when DNS resolution of the fronting host is blocked.
- // The hostname from the secret is still used for SNI in the TLS handshake.
- //
- // This is an optional setting.
- DomainFrontingIP string
-
- // DomainFrontingProxyProtocol is used if communication between upstream
- // endpoint and mtg supports proxy protocol. This is useful in case
- // if mtg is also placed behind load balancer, and this will make
- // fronting webserver to know about real IP addresses
- //
- // This is an optional setting.
- DomainFrontingProxyProtocol bool
-
- // 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.
- //
- // This is required if you use mtglib as an integration library for your
- // Telegram-related projects.
- //
- // This is an optional setting.
- //
- // OBSOLETE and DEPRECATED. Ignored.
- UseTestDCs bool
-
- // DCOverrides defines a set of IP addresses that should be used
- // with a higher priority to those that are calculated somehow by mtg.
- //
- // 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
-
- // DoppelGangerDRS defines if TLS Dynamic Record Sizing is active.
- DoppelGangerDRS bool
-
- // APIBindTo is the address to bind the stats HTTP API server to.
- // If empty, the stats API server is not started.
- //
- // This is an optional setting.
- APIBindTo string
-
- // ThrottleMaxConnections is the total connection limit. When total
- // connections exceed this value, per-user caps are computed using
- // a fair-share algorithm and new connections from over-cap users
- // are rejected. 0 disables throttling.
- //
- // This is an optional setting.
- ThrottleMaxConnections uint
-
- // ThrottleCheckInterval is how often the throttle recomputes per-user
- // caps. Defaults to 5 seconds.
- //
- // This is an optional setting.
- ThrottleCheckInterval time.Duration
- }
-
- func (p ProxyOpts) valid() error {
- switch {
- case p.Network == nil:
- return ErrNetworkIsNotDefined
- case p.AntiReplayCache == nil:
- return ErrAntiReplayCacheIsNotDefined
- case p.IPBlocklist == nil:
- return ErrIPBlocklistIsNotDefined
- case p.IPAllowlist == nil:
- return ErrIPAllowlistIsNotDefined
- case p.EventStream == nil:
- return ErrEventStreamIsNotDefined
- case p.Logger == nil:
- return ErrLoggerIsNotDefined
- }
-
- secrets := p.getSecrets()
- if len(secrets) == 0 {
- return ErrSecretInvalid
- }
-
- var host string
-
- for _, s := range secrets {
- if !s.Valid() {
- return ErrSecretInvalid
- }
-
- if host == "" {
- host = s.Host
- } else if s.Host != host {
- return fmt.Errorf("all secrets must use the same hostname, got %q and %q", host, s.Host)
- }
- }
-
- return nil
- }
-
- // getSecrets returns the effective secrets map. If Secrets is populated, it is
- // returned directly. Otherwise the single Secret is wrapped in a map.
- func (p ProxyOpts) getSecrets() map[string]Secret {
- if len(p.Secrets) > 0 {
- return p.Secrets
- }
-
- if p.Secret.Valid() {
- return map[string]Secret{"default": p.Secret}
- }
-
- return nil
- }
-
- func (p ProxyOpts) getConcurrency() int {
- if p.Concurrency == 0 {
- return DefaultConcurrency
- }
-
- return int(p.Concurrency)
- }
-
- func (p ProxyOpts) getDomainFrontingPort() int {
- if p.DomainFrontingPort == 0 {
- return DefaultDomainFrontingPort
- }
-
- return int(p.DomainFrontingPort)
- }
-
- func (p ProxyOpts) getTolerateTimeSkewness() time.Duration {
- if p.TolerateTimeSkewness == 0 {
- return DefaultTolerateTimeSkewness
- }
-
- return p.TolerateTimeSkewness
- }
-
- func (p ProxyOpts) getPreferIP() string {
- if p.PreferIP == "" {
- return DefaultPreferIP
- }
-
- return p.PreferIP
- }
-
- func (p ProxyOpts) getHandshakeTimeout() time.Duration {
- if p.HandshakeTimeout == 0 {
- return DefaultHandshakeTimeout
- }
-
- return p.HandshakeTimeout
- }
-
- func (p ProxyOpts) getIdleTimeout() time.Duration {
- if p.IdleTimeout == 0 {
- return DefaultIdleTimeout
- }
-
- return p.IdleTimeout
- }
-
- func (p ProxyOpts) getThrottleCheckInterval() time.Duration {
- if p.ThrottleCheckInterval == 0 {
- return 5 * time.Second //nolint: mnd
- }
-
- return p.ThrottleCheckInterval
- }
-
- func (p ProxyOpts) getLogger(name string) Logger {
- return p.Logger.Named(name)
- }
|