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
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net"
  8. "net/url"
  9. "regexp"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "github.com/9seconds/mtg/v2/mtglib"
  14. "github.com/alecthomas/units"
  15. "github.com/pelletier/go-toml"
  16. )
  17. type configTypeHostPort struct {
  18. host configTypeIP
  19. port configTypePort
  20. }
  21. func (c *configTypeHostPort) UnmarshalText(data []byte) error {
  22. if len(data) == 0 {
  23. return nil
  24. }
  25. host, port, err := net.SplitHostPort(string(data))
  26. if err != nil {
  27. return fmt.Errorf("incorrect host:port syntax: %w", err)
  28. }
  29. if err := c.port.UnmarshalJSON([]byte(port)); err != nil {
  30. return fmt.Errorf("incorrect port in host:port: %w", err)
  31. }
  32. if err := c.host.UnmarshalText([]byte(host)); err != nil {
  33. return fmt.Errorf("incorrect host: %w", err)
  34. }
  35. return nil
  36. }
  37. func (c configTypeHostPort) MarshalText() ([]byte, error) {
  38. return []byte(c.String()), nil
  39. }
  40. func (c configTypeHostPort) String() string {
  41. return c.Value(net.IP{}, 0)
  42. }
  43. func (c configTypeHostPort) Value(defaultHostValue net.IP, defaultPortValue uint) string {
  44. return net.JoinHostPort(c.host.Value(defaultHostValue).String(),
  45. strconv.Itoa(int(c.port.Value(defaultPortValue))))
  46. }
  47. type configTypePort struct {
  48. value uint
  49. }
  50. func (c *configTypePort) UnmarshalJSON(data []byte) error {
  51. if len(data) == 0 {
  52. return nil
  53. }
  54. intValue, err := strconv.ParseUint(string(data), 10, 16)
  55. if err != nil {
  56. return fmt.Errorf("port number is not a number: %w", err)
  57. }
  58. if intValue == 0 || intValue > 65536 {
  59. return fmt.Errorf("port number should be 0 < portNo < 65536: %d", intValue)
  60. }
  61. c.value = uint(intValue)
  62. return nil
  63. }
  64. func (c *configTypePort) MarshalJSON() ([]byte, error) {
  65. return json.Marshal(c.value)
  66. }
  67. func (c configTypePort) String() string {
  68. return strconv.Itoa(int(c.value))
  69. }
  70. func (c configTypePort) Value(defaultValue uint) uint {
  71. if c.value == 0 {
  72. return defaultValue
  73. }
  74. return c.value
  75. }
  76. type configTypeBytes struct {
  77. value uint
  78. }
  79. func (c *configTypeBytes) UnmarshalText(data []byte) error {
  80. if len(data) == 0 {
  81. return nil
  82. }
  83. value, err := units.ParseStrictBytes(strings.ToUpper(string(data)))
  84. if err != nil {
  85. return fmt.Errorf("incorrect bytes value: %w", err)
  86. }
  87. if value < 0 {
  88. return fmt.Errorf("%d should be positive number", value)
  89. }
  90. c.value = uint(value)
  91. return nil
  92. }
  93. func (c configTypeBytes) MarshalText() ([]byte, error) {
  94. return []byte(c.String()), nil
  95. }
  96. func (c configTypeBytes) String() string {
  97. return units.ToString(int64(c.value), 1024, "ib", "b")
  98. }
  99. func (c configTypeBytes) Value(defaultValue uint) uint {
  100. if c.value == 0 {
  101. return defaultValue
  102. }
  103. return c.value
  104. }
  105. type configTypePreferIP struct {
  106. value string
  107. }
  108. func (c *configTypePreferIP) UnmarshalText(data []byte) error {
  109. if len(data) == 0 {
  110. return nil
  111. }
  112. text := strings.ToLower(string(data))
  113. switch text {
  114. case "prefer-ipv4", "prefer-ipv6", "only-ipv4", "only-ipv6":
  115. c.value = text
  116. default:
  117. return fmt.Errorf("incorrect prefer-ip value: %s", string(data))
  118. }
  119. return nil
  120. }
  121. func (c configTypePreferIP) MarshalText() ([]byte, error) {
  122. return []byte(c.value), nil
  123. }
  124. func (c *configTypePreferIP) String() string {
  125. return c.value
  126. }
  127. func (c *configTypePreferIP) Value(defaultValue string) string {
  128. if c.value == "" {
  129. return defaultValue
  130. }
  131. return c.value
  132. }
  133. type configTypeDuration struct {
  134. value time.Duration
  135. }
  136. func (c *configTypeDuration) UnmarshalText(data []byte) error {
  137. if len(data) == 0 {
  138. return nil
  139. }
  140. dur, err := time.ParseDuration(strings.ToLower(string(data)))
  141. if err != nil {
  142. return fmt.Errorf("incorrect duration: %w", err)
  143. }
  144. if dur < 0 {
  145. return fmt.Errorf("%s should be positive duration", dur)
  146. }
  147. c.value = dur
  148. return nil
  149. }
  150. func (c configTypeDuration) MarshalText() ([]byte, error) {
  151. return []byte(c.value.String()), nil
  152. }
  153. func (c configTypeDuration) String() string {
  154. return c.value.String()
  155. }
  156. func (c configTypeDuration) Value(defaultValue time.Duration) time.Duration {
  157. if c.value == 0 {
  158. return defaultValue
  159. }
  160. return c.value
  161. }
  162. type configTypeFloat struct {
  163. value float64
  164. }
  165. func (c *configTypeFloat) UnmarshalJSON(data []byte) error {
  166. value, err := strconv.ParseFloat(string(data), 64)
  167. if err != nil {
  168. return fmt.Errorf("incorrect float value: %w", err)
  169. }
  170. if value < 0 {
  171. return fmt.Errorf("%f should be positive", value)
  172. }
  173. c.value = value
  174. return nil
  175. }
  176. func (c *configTypeFloat) MarshalText() ([]byte, error) {
  177. return []byte(c.String()), nil
  178. }
  179. func (c configTypeFloat) String() string {
  180. return strconv.FormatFloat(c.value, 'f', -1, 64)
  181. }
  182. func (c configTypeFloat) Value(defaultValue float64) float64 {
  183. if c.value < 0.00001 {
  184. return defaultValue
  185. }
  186. return c.value
  187. }
  188. type configTypeIP struct {
  189. value net.IP
  190. }
  191. func (c *configTypeIP) UnmarshalText(data []byte) error {
  192. if len(data) == 0 {
  193. return nil
  194. }
  195. ip := net.ParseIP(string(data))
  196. if ip == nil {
  197. return fmt.Errorf("incorrect ip address: %s", string(data))
  198. }
  199. c.value = ip
  200. return nil
  201. }
  202. func (c *configTypeIP) MarshalText() ([]byte, error) {
  203. return []byte(c.String()), nil
  204. }
  205. func (c configTypeIP) String() string {
  206. if c.value == nil {
  207. return ""
  208. }
  209. return c.value.String()
  210. }
  211. func (c configTypeIP) Value(defaultValue net.IP) net.IP {
  212. if c.value == nil {
  213. return defaultValue
  214. }
  215. return c.value
  216. }
  217. type configTypeURL struct {
  218. value *url.URL
  219. }
  220. func (c *configTypeURL) UnmarshalText(data []byte) error {
  221. if len(data) == 0 {
  222. return nil
  223. }
  224. value, err := url.Parse(string(data))
  225. if err != nil {
  226. return fmt.Errorf("incorrect URL: %w", err)
  227. }
  228. c.value = value
  229. return nil
  230. }
  231. func (c *configTypeURL) MarshalText() ([]byte, error) {
  232. return []byte(c.String()), nil
  233. }
  234. func (c configTypeURL) String() string {
  235. if c.value == nil {
  236. return ""
  237. }
  238. return c.value.String()
  239. }
  240. func (c configTypeURL) Value(defaultValue *url.URL) *url.URL {
  241. if c.value == nil {
  242. return defaultValue
  243. }
  244. return c.value
  245. }
  246. type configTypeMetricPrefix struct {
  247. value string
  248. }
  249. func (c *configTypeMetricPrefix) UnmarshalText(data []byte) error {
  250. if len(data) == 0 {
  251. return nil
  252. }
  253. prefix := string(data)
  254. if ok, err := regexp.MatchString("^[a-z0-9]+$", prefix); !ok || err != nil {
  255. return fmt.Errorf("incorrect metric prefix: %s", prefix)
  256. }
  257. c.value = prefix
  258. return nil
  259. }
  260. func (c configTypeMetricPrefix) MarshalText() ([]byte, error) {
  261. return []byte(c.String()), nil
  262. }
  263. func (c configTypeMetricPrefix) String() string {
  264. return c.value
  265. }
  266. func (c configTypeMetricPrefix) Value(defaultValue string) string {
  267. if c.value == "" {
  268. return defaultValue
  269. }
  270. return c.value
  271. }
  272. type configTypeHTTPPath struct {
  273. value string
  274. }
  275. func (c *configTypeHTTPPath) UnmarshalText(data []byte) error { // nolint: unparam
  276. if len(data) > 0 {
  277. c.value = "/" + strings.Trim(string(data), "/")
  278. }
  279. return nil
  280. }
  281. func (c configTypeHTTPPath) MarshalText() ([]byte, error) {
  282. return []byte(c.String()), nil
  283. }
  284. func (c configTypeHTTPPath) String() string {
  285. return c.value
  286. }
  287. func (c configTypeHTTPPath) Value(defaultValue string) string {
  288. if c.value == "" {
  289. return defaultValue
  290. }
  291. return c.value
  292. }
  293. type config struct {
  294. Debug bool `json:"debug"`
  295. Secret mtglib.Secret `json:"secret"`
  296. BindTo configTypeHostPort `json:"bind-to"`
  297. TCPBuffer configTypeBytes `json:"tcp-buffer"`
  298. PreferIP configTypePreferIP `json:"prefer-ip"`
  299. CloakPort configTypePort `json:"cloak-port"`
  300. Probes struct {
  301. Time struct {
  302. Enabled bool `json:"enabled"`
  303. AllowSkewness configTypeDuration `json:"allow-skewness"`
  304. } `json:"time"`
  305. AntiReplay struct {
  306. Enabled bool `json:"enabled"`
  307. MaxSize configTypeBytes `json:"max-size"`
  308. ErrorRate configTypeFloat `json:"error-rate"`
  309. } `json:"anti-replay"`
  310. } `json:"probes"`
  311. Network struct {
  312. PublicIP struct {
  313. IPv4 configTypeIP `json:"ipv4"`
  314. IPv6 configTypeIP `json:"ipv6"`
  315. } `json:"public-ip"`
  316. DOHIP configTypeIP `json:"doh-ip"`
  317. Proxies []configTypeURL `json:"proxies"`
  318. } `json:"network"`
  319. Stats struct {
  320. StatsD struct {
  321. Enabled bool `json:"enabled"`
  322. Address configTypeHostPort `json:"address"`
  323. MetricPrefix configTypeMetricPrefix `json:"metric-prefix"`
  324. } `json:"statsd"`
  325. Prometheus struct {
  326. Enabled bool `json:"enabled"`
  327. BindTo configTypeHostPort `json:"bind-to"`
  328. HTTPPath configTypeHTTPPath `json:"http-path"`
  329. MetricPrefix configTypeMetricPrefix `json:"metric-prefix"`
  330. } `json:"prometheus"`
  331. } `json:"stats"`
  332. }
  333. func (c *config) Validate() error {
  334. if len(c.Secret.Key) == 0 || c.Secret.Host == "" {
  335. return fmt.Errorf("incorrect secret %s", c.Secret.String())
  336. }
  337. return nil
  338. }
  339. func (c *config) String() string {
  340. buf := &bytes.Buffer{}
  341. encoder := json.NewEncoder(buf)
  342. encoder.SetEscapeHTML(false)
  343. if err := encoder.Encode(c); err != nil {
  344. panic(err)
  345. }
  346. return buf.String()
  347. }
  348. type configRaw struct {
  349. Debug bool `toml:"debug" json:"debug"`
  350. Secret string `toml:"secret" json:"secret"`
  351. BindTo string `toml:"bind-to" json:"bind-to"`
  352. TCPBuffer string `toml:"tcp-buffer" json:"tcp-buffer"`
  353. PreferIP string `toml:"prefer-ip" json:"prefer-ip"`
  354. CloakPort uint `toml:"cloak-port" json:"cloak-port"`
  355. Probes struct {
  356. Time struct {
  357. Enabled bool `toml:"enabled" json:"enabled"`
  358. AllowSkewness string `toml:"allow-skewness" json:"allow-skewness"`
  359. } `toml:"time" json:"time"`
  360. AntiReplay struct {
  361. Enabled bool `toml:"enabled" json:"enabled"`
  362. MaxSize string `toml:"max-size" json:"max-size"`
  363. ErrorRate float64 `toml:"error-rate" json:"error-rate"`
  364. } `toml:"anti-replay" json:"anti-replay"`
  365. } `toml:"probes" json:"probes"`
  366. Network struct {
  367. PublicIP struct {
  368. IPv4 string `toml:"ipv4" json:"ipv4"`
  369. IPv6 string `toml:"ipv6" json:"ipv6"`
  370. } `toml:"public-ip" json:"public-ip"`
  371. DOHIP string `toml:"doh-ip" json:"doh-ip"`
  372. Proxies []string `toml:"proxies" json:"proxies"`
  373. } `toml:"network" json:"network"`
  374. Stats struct {
  375. StatsD struct {
  376. Enabled bool `toml:"enabled" json:"enabled"`
  377. Address string `toml:"address" json:"address"`
  378. MetricPrefix string `toml:"metric-prefix" json:"metric-prefix"`
  379. } `toml:"statsd" json:"statsd"`
  380. Prometheus struct {
  381. Enabled bool `toml:"enabled" json:"enabled"`
  382. BindTo string `toml:"bind-to" json:"bind-to"`
  383. HTTPPath string `toml:"http-path" json:"http-path"`
  384. MetricPrefix string `toml:"metric-prefix" json:"metric-prefix"`
  385. } `toml:"prometheus" json:"prometheus"`
  386. } `toml:"stats" json:"stats"`
  387. }
  388. func parseConfig(reader io.Reader) (*config, error) {
  389. rawConf := &configRaw{}
  390. if err := toml.NewDecoder(reader).Decode(rawConf); err != nil {
  391. return nil, fmt.Errorf("cannot parse toml config: %w", err)
  392. }
  393. jsonBuf := &bytes.Buffer{}
  394. jsonEncoder := json.NewEncoder(jsonBuf)
  395. jsonEncoder.SetEscapeHTML(false)
  396. jsonEncoder.SetIndent("", "")
  397. if err := jsonEncoder.Encode(rawConf); err != nil {
  398. return nil, fmt.Errorf("cannot dump into interim format: %w", err)
  399. }
  400. conf := &config{}
  401. if err := json.NewDecoder(jsonBuf).Decode(conf); err != nil {
  402. return nil, fmt.Errorf("cannot parse final config: %w", err)
  403. }
  404. if err := conf.Validate(); err != nil {
  405. return nil, fmt.Errorf("cannot validate config: %w", err)
  406. }
  407. return conf, nil
  408. }