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.

addresses.go 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package api
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. "github.com/9seconds/mtg/conntypes"
  10. )
  11. const (
  12. addressesURLV4 = "https://core.telegram.org/getProxyConfig" // nolint: gas
  13. addressesURLV6 = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
  14. )
  15. var addressesProxyForSplitter = regexp.MustCompile(`\s+`)
  16. func AddressesV4() (map[conntypes.DC][]string, conntypes.DC, error) {
  17. return getAddresses(addressesURLV4)
  18. }
  19. func AddressesV6() (map[conntypes.DC][]string, conntypes.DC, error) {
  20. return getAddresses(addressesURLV6)
  21. }
  22. func getAddresses(url string) (map[conntypes.DC][]string, conntypes.DC, error) {
  23. resp, err := request(url)
  24. if err != nil {
  25. return nil, 0, fmt.Errorf("cannot get http response: %w", err)
  26. }
  27. defer resp.Close()
  28. scanner := bufio.NewScanner(resp)
  29. data := map[conntypes.DC][]string{}
  30. var defaultDC = conntypes.DCDefaultIdx
  31. for scanner.Scan() {
  32. text := strings.TrimSpace(scanner.Text())
  33. switch {
  34. case strings.HasPrefix(text, "#"):
  35. continue
  36. case strings.HasPrefix(text, "proxy_for"):
  37. addr, idx, err := addressesParseProxyFor(text)
  38. if err != nil {
  39. return nil, 0, fmt.Errorf("cannot parse 'proxy_for' section: %w", err)
  40. }
  41. if addresses, ok := data[idx]; ok {
  42. data[idx] = append(addresses, addr)
  43. } else {
  44. data[idx] = []string{addr}
  45. }
  46. case strings.HasPrefix(text, "default"):
  47. idx, err := addressesParseDefault(text)
  48. if err != nil {
  49. return nil, 0, fmt.Errorf("cannot parse 'default' section: %w", err)
  50. }
  51. defaultDC = idx
  52. }
  53. }
  54. err = scanner.Err()
  55. if err != nil {
  56. return nil, 0, fmt.Errorf("cannot parse http response: %w", err)
  57. }
  58. return data, defaultDC, nil
  59. }
  60. func addressesParseProxyFor(text string) (string, conntypes.DC, error) {
  61. chunks := addressesProxyForSplitter.Split(text, 3)
  62. if len(chunks) != 3 || chunks[0] != "proxy_for" {
  63. return "", 0, fmt.Errorf("incorrect config %s", text)
  64. }
  65. dc, err := strconv.ParseInt(chunks[1], 10, 16)
  66. if err != nil {
  67. return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
  68. }
  69. addr := strings.TrimRight(chunks[2], ";")
  70. if _, _, err = net.SplitHostPort(addr); err != nil {
  71. return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
  72. }
  73. return addr, conntypes.DC(dc), nil
  74. }
  75. func addressesParseDefault(text string) (conntypes.DC, error) {
  76. chunks := addressesProxyForSplitter.Split(text, 2)
  77. if len(chunks) != 2 || chunks[0] != "default" {
  78. return 0, fmt.Errorf("incorrect config '%s'", text)
  79. }
  80. dcString := strings.TrimRight(chunks[1], ";")
  81. dc, err := strconv.ParseInt(dcString, 10, 16)
  82. if err != nil {
  83. return 0, fmt.Errorf("incorrect config '%s': %w", text, err)
  84. }
  85. return conntypes.DC(dc), nil
  86. }