Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package mtglib
  2. import (
  3. "context"
  4. "errors"
  5. "net"
  6. "net/http"
  7. "time"
  8. )
  9. var (
  10. // ErrSecretEmpty is returned if you are trying to create a proxy
  11. // but do not provide a secret.
  12. ErrSecretEmpty = errors.New("secret is empty")
  13. // ErrSecretInvalid is returned if you are trying to create a proxy
  14. // but secret value is invalid (no host or payload are zeroes).
  15. ErrSecretInvalid = errors.New("secret is invalid")
  16. // ErrNetworkIsNotDefined is returned if you are trying to create a
  17. // proxy but network value is undefined.
  18. ErrNetworkIsNotDefined = errors.New("network is not defined")
  19. // ErrAntiReplayCacheIsNotDefined is returned if you are trying to
  20. // create a proxy but anti replay cache value is undefined.
  21. ErrAntiReplayCacheIsNotDefined = errors.New("anti-replay cache is not defined")
  22. // ErrTimeAttackDetectorIsNotDefined is returned if you are trying to
  23. // create a proxy but time attack detector is not defined.
  24. ErrTimeAttackDetectorIsNotDefined = errors.New("time attack detector is not defined")
  25. // ErrIPBlocklistIsNotDefined is returned if you are trying to
  26. // create a proxy but ip blocklist instance is not defined.
  27. ErrIPBlocklistIsNotDefined = errors.New("ip blocklist is not defined")
  28. // ErrEventStreamIsNotDefined is returned if you are trying to create a
  29. // proxy but event stream instance is not defined.
  30. ErrEventStreamIsNotDefined = errors.New("event stream is not defined")
  31. // ErrLoggerIsNotDefined is returned if you are trying to
  32. // create a proxy but logger is not defined.
  33. ErrLoggerIsNotDefined = errors.New("logger is not defined")
  34. )
  35. const (
  36. // DefaultConcurrency is a default max count of simultaneously
  37. // connected clients.
  38. DefaultConcurrency = 4096
  39. // DefaultBufferSize is a default size of a copy buffer.
  40. DefaultBufferSize = 16 * 1024 // 16 kib
  41. // DefaultDomainFrontingPort is a default port (HTTPS) to connect to in
  42. // case of probe-resistance activity.
  43. DefaultDomainFrontingPort = 443
  44. // DefaultIdleTimeout is a default timeout for closing a connection
  45. // in case of idling.
  46. DefaultIdleTimeout = time.Minute
  47. // DefaultPreferIP is a default value for Telegram IP connectivity
  48. // preference.
  49. DefaultPreferIP = "prefer-ipv6"
  50. // SecretKeyLength defines a length of the secret bytes used
  51. // by Telegram and a proxy.
  52. SecretKeyLength = 16
  53. // ConnectionIDBytesLength defines a count of random bytes
  54. // used to generate a stream/connection ids.
  55. ConnectionIDBytesLength = 16
  56. )
  57. // Network defines a knowledge how to work with a network. It may sound
  58. // fun but it encapsulates all the knowledge how to properly establish
  59. // connections to remote hosts and configure HTTP clients.
  60. //
  61. // For example, if you want to use SOCKS5 proxy, you probably want to
  62. // have all traffic routed to this proxy: telegram connections, http
  63. // requests and so on. This knowledge is encapsulated into instances of
  64. // such interface.
  65. //
  66. // mtglib uses Network for:
  67. //
  68. // 1. Dialing to Telegram
  69. //
  70. // 2. Dialing to front domain
  71. //
  72. // 3. Doing HTTP requests (for example, for FireHOL ipblocklist).
  73. type Network interface {
  74. // Dial establishes context-free TCP connections.
  75. Dial(network, address string) (net.Conn, error)
  76. // DialContext dials using a context. This is a preferrable
  77. // way of establishing TCP connections.
  78. DialContext(ctx context.Context, network, address string) (net.Conn, error)
  79. // MakeHTTPClient build an HTTP client with given dial function. If
  80. // nothing is provided, then DialContext of this interface is going
  81. // to be used.
  82. MakeHTTPClient(func(ctx context.Context, network, address string) (net.Conn, error)) *http.Client
  83. }
  84. // AntiReplayCache is an interface that is used to detect replay attacks
  85. // based on some traffic fingerprints.
  86. //
  87. // Replay attacks are probe attacks whose main goal is to identify if
  88. // server software can be classified in some way. For example, if you
  89. // send some HTTP request to a web server, then you can expect that this
  90. // server will respond with HTTP response back.
  91. //
  92. // There is a problem though. Let's imagine, that connection is
  93. // encrypted. Let's imagine, that it is encrypted with some static key
  94. // like ShadowSocks (https://shadowsocks.org/assets/whitepaper.pdf).
  95. // In that case, in theory, if you repeat the same bytes, you can get
  96. // the same responses. Let's imagine, that you've cracked the key. then
  97. // if you send the same bytes, you can decrypt a response and see its
  98. // structure. Based on its structure you can identify if this server is
  99. // SOCKS5, MTPROTO proxy etc.
  100. //
  101. // This is just one example, maybe not the best or not the most
  102. // relevant. In real life, different organizations use such replay
  103. // attacks to perform some reverse engineering of the proxy, do some
  104. // statical analysis to identify server software.
  105. //
  106. // There are many ways how to protect your proxy against them. One
  107. // is domain fronting which is a core part of mtg. Another one is to
  108. // collect some 'handshake fingerprints' and forbid duplication.
  109. //
  110. // So, it one is sending the same byte flow right after you (or a couple
  111. // of hours after), mtg should detect that and reject this connection
  112. // (or redirect to fronting domain).
  113. type AntiReplayCache interface {
  114. // Seen before checks if this set of bytes was observed before or
  115. // not. If it is required to store this information somewhere else,
  116. // then it has to do that.
  117. SeenBefore(data []byte) bool
  118. }
  119. // IPBlocklist filters requests based on IP address.
  120. //
  121. // If this filter has an IP address, then mtg closes a request without
  122. // reading anything from a socket. It also does not give such request to
  123. // a worker pool, so in worst cases you can expect that you invoke this
  124. // object more frequent than defined proxy concurrency.
  125. type IPBlocklist interface {
  126. // Contains checks if given IP address belongs to this blocklist If.
  127. // it is, a connection is terminated .
  128. Contains(net.IP) bool
  129. }
  130. // Event is a data structure which is populated during mtg request
  131. // processing lifecycle. Each request popluates many events:
  132. //
  133. // 1. Client connected
  134. //
  135. // 2. Request is finished
  136. //
  137. // 3. Connection to Telegram server is established
  138. //
  139. // and so on. All these events are data structures but all of them
  140. // must conform the same interface.
  141. type Event interface {
  142. // StreamID returns an identifier of the stream, connection,
  143. // request, you name it. All events within the same stream returns
  144. // the same stream id.
  145. StreamID() string
  146. // Timestamp returns a timestamp when this event was generated.
  147. Timestamp() time.Time
  148. }
  149. // EventStream is an abstraction that accepts a set of events produced
  150. // by mtg. Its main goal is to inject your logging or monitoring system.
  151. //
  152. // The idea is simple. When mtg works, it emits a set of events during
  153. // a lifecycle of the requestor: EventStart, EventFinish etc. mtg is a
  154. // producer which puts these events into a stream. Responsibility of
  155. // the stream is to deliver this event to consumers/observers. There
  156. // might be many different observers (for example, you want to have both
  157. // statsd and prometheus), mtg should know nothing about them.
  158. type EventStream interface {
  159. // Send delivers an event to observers. Given context has to be
  160. // respected. If the context is closed, all blocking operations should
  161. // be released ASAP.
  162. //
  163. // It is possible that context is closed but the message is delivered.
  164. // EventStream implementations should solve this issue somehow.
  165. Send(context.Context, Event)
  166. }
  167. // TimeAttackDetector is an abstraction that checks a time, taken from
  168. // the faketls client hello message. This timestamp is encoded into
  169. // client-generated random bytes and can be extracted after some client
  170. // hello verification.
  171. //
  172. // This is mostly to prevent replay attacks.
  173. type TimeAttackDetector interface {
  174. // Valid returns an error if timestamp is invalid or should not be
  175. // accepted.
  176. Valid(time.Time) error
  177. }
  178. // Logger defines an interface of the logger used by mtglib.
  179. //
  180. // Each logger has a name. It is possible to stack names to organize
  181. // poor-man namespaces. Also, each logger must be able to bind
  182. // parameters to avoid pushing them all the time.
  183. //
  184. // Example
  185. //
  186. // logger := SomeLogger{}
  187. // logger = logger.BindStr("ip", net.IP{127, 0, 0, 1})
  188. // logger.Info("Hello")
  189. //
  190. // In that case, ip is bound as a parameter. It is a great idea to
  191. // put this parameter somewhere in a log message.
  192. //
  193. // logger1 = logger.BindStr("param1", "11")
  194. // logger2 = logger.BindInt("param2", 11)
  195. //
  196. // logger1 should see no param2 and vice versa, logger2 should not see param1
  197. // If you attach a parameter to a logger, parents should not know about that.
  198. type Logger interface {
  199. Named(name string) Logger
  200. BindInt(name string, value int) Logger
  201. BindStr(name, value string) Logger
  202. Printf(format string, args ...interface{})
  203. Info(msg string)
  204. InfoError(msg string, err error)
  205. Warning(msg string)
  206. WarningError(msg string, err error)
  207. Debug(msg string)
  208. DebugError(msg string, err error)
  209. }