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 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package cli
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net"
  9. "net/http"
  10. "sync"
  11. "time"
  12. "github.com/9seconds/mtg/v2/essentials"
  13. "github.com/9seconds/mtg/v2/mtglib"
  14. )
  15. const (
  16. getIPTimeout = 5 * time.Second
  17. )
  18. var getIPServicesPlain = []string{
  19. "https://ifconfig.co",
  20. "https://ifconfig.me",
  21. "https://api.ipify.org",
  22. "https://ipecho.net/plain",
  23. }
  24. func getIP(ctx context.Context, ntw mtglib.Network, protocol string) (net.IP, error) {
  25. ctx, cancel := context.WithTimeout(ctx, getIPTimeout)
  26. defer cancel()
  27. ctx, cancelCause := context.WithCancelCause(ctx)
  28. defer cancelCause(nil)
  29. var ip net.IP
  30. rvChan := make(chan net.IP)
  31. errChan := make(chan error)
  32. errs := []error{}
  33. wg := &sync.WaitGroup{}
  34. dialer := ntw.NativeDialer()
  35. client := ntw.MakeHTTPClient(func(_ context.Context, network, address string) (essentials.Conn, error) {
  36. conn, err := dialer.DialContext(ctx, protocol, address)
  37. if err != nil {
  38. return nil, err
  39. }
  40. return essentials.WrapNetConn(conn), err
  41. })
  42. for _, url := range getIPServicesPlain {
  43. wg.Go(func() {
  44. lErrChan := errChan
  45. rChan := rvChan
  46. ip, err := getIPAddressPlain(ctx, client, url)
  47. if err == nil {
  48. lErrChan = nil
  49. } else {
  50. rChan = nil
  51. }
  52. select {
  53. case <-ctx.Done():
  54. case lErrChan <- fmt.Errorf("%s: %w", url, err):
  55. case rChan <- ip:
  56. }
  57. })
  58. }
  59. wg.Go(func() {
  60. defer cancelCause(nil)
  61. for {
  62. select {
  63. case <-ctx.Done():
  64. return
  65. case foundIP := <-rvChan:
  66. ip = foundIP
  67. return
  68. case err := <-errChan:
  69. errs = append(errs, err)
  70. if len(errs) == len(getIPServicesPlain) {
  71. cancelCause(fmt.Errorf(
  72. "cannot resolve %s address: %w",
  73. protocol,
  74. errors.Join(errs...),
  75. ))
  76. }
  77. }
  78. }
  79. })
  80. wg.Wait()
  81. if ip != nil {
  82. return ip, nil
  83. }
  84. return nil, context.Cause(ctx)
  85. }
  86. func getIPAddressPlain(ctx context.Context, client *http.Client, address string) (net.IP, error) {
  87. req, err := http.NewRequestWithContext(ctx, http.MethodGet, address, nil)
  88. if err != nil {
  89. panic(err)
  90. }
  91. req.Header.Add("Accept", "text/plain")
  92. resp, err := client.Do(req)
  93. if err != nil {
  94. return nil, err
  95. }
  96. defer func() {
  97. io.Copy(io.Discard, resp.Body) //nolint: errcheck
  98. resp.Body.Close() //nolint: errcheck
  99. }()
  100. if resp.StatusCode != http.StatusOK {
  101. return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode)
  102. }
  103. data, err := io.ReadAll(resp.Body)
  104. if err != nil {
  105. return nil, err
  106. }
  107. data = bytes.TrimSpace(data)
  108. ip := net.ParseIP(string(data))
  109. if ip == nil {
  110. return nil, errors.New("cannot parse as IP address")
  111. }
  112. return ip, nil
  113. }