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
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

socks5.go 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package network
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "net"
  7. "net/url"
  8. "github.com/9seconds/mtg/v2/essentials"
  9. "github.com/txthinking/socks5"
  10. )
  11. type socks5Dialer struct {
  12. Dialer
  13. username []byte
  14. password []byte
  15. proxyAddress string
  16. }
  17. func (s socks5Dialer) Dial(network, address string) (essentials.Conn, error) {
  18. return s.DialContext(context.Background(), network, address)
  19. }
  20. func (s socks5Dialer) DialContext(ctx context.Context, network, address string) (essentials.Conn, error) {
  21. switch network {
  22. case "tcp", "tcp4", "tcp6":
  23. default:
  24. return nil, fmt.Errorf("%s network type is not supported", network)
  25. }
  26. conn, err := s.Dialer.DialContext(ctx, network, s.proxyAddress)
  27. if err != nil {
  28. return nil, fmt.Errorf("cannot dial to the proxy: %w", err)
  29. }
  30. if err := s.handshake(conn); err != nil {
  31. conn.Close()
  32. return nil, fmt.Errorf("cannot perform a handshake: %w", err)
  33. }
  34. if err := s.connect(conn, address); err != nil {
  35. conn.Close()
  36. return nil, fmt.Errorf("cannot connect to a destination host %s: %w", address, err)
  37. }
  38. return conn, nil
  39. }
  40. func (s socks5Dialer) handshake(conn io.ReadWriter) error {
  41. authMethod := socks5.MethodUsernamePassword
  42. if len(s.username)+len(s.password) == 0 {
  43. authMethod = socks5.MethodNone
  44. }
  45. if err := s.handshakeNegotiation(conn, authMethod); err != nil {
  46. return fmt.Errorf("cannot perform negotiation: %w", err)
  47. }
  48. if authMethod == socks5.MethodNone {
  49. return nil
  50. }
  51. if err := s.handshakeAuth(conn); err != nil {
  52. return fmt.Errorf("cannot authenticate: %w", err)
  53. }
  54. return nil
  55. }
  56. func (s socks5Dialer) handshakeNegotiation(conn io.ReadWriter, authMethod byte) error {
  57. request := socks5.NewNegotiationRequest([]byte{authMethod})
  58. if _, err := request.WriteTo(conn); err != nil {
  59. return fmt.Errorf("cannot send request: %w", err)
  60. }
  61. response, err := socks5.NewNegotiationReplyFrom(conn)
  62. if err != nil {
  63. return fmt.Errorf("cannot read response: %w", err)
  64. }
  65. if response.Method != authMethod {
  66. return fmt.Errorf("%v is unsupported auth method", authMethod)
  67. }
  68. return nil
  69. }
  70. func (s socks5Dialer) handshakeAuth(conn io.ReadWriter) error {
  71. request := socks5.NewUserPassNegotiationRequest(s.username, s.password)
  72. if _, err := request.WriteTo(conn); err != nil {
  73. return fmt.Errorf("cannot send a request: %w", err)
  74. }
  75. response, err := socks5.NewUserPassNegotiationReplyFrom(conn)
  76. if err != nil {
  77. return fmt.Errorf("cannot read a response: %w", err)
  78. }
  79. if response.Status != socks5.UserPassStatusSuccess {
  80. return fmt.Errorf("authenticate has failed: %v", response.Status)
  81. }
  82. return nil
  83. }
  84. func (s socks5Dialer) connect(conn io.ReadWriter, address string) error {
  85. addrType, host, port, err := socks5.ParseAddress(address)
  86. if err != nil {
  87. return fmt.Errorf("cannot parse address: %w", err)
  88. }
  89. if addrType == socks5.ATYPDomain {
  90. host = host[1:]
  91. }
  92. request := socks5.NewRequest(socks5.CmdConnect, addrType, host, port)
  93. if _, err := request.WriteTo(conn); err != nil {
  94. return fmt.Errorf("cannot send a request: %w", err)
  95. }
  96. response, err := socks5.NewReplyFrom(conn)
  97. if err != nil {
  98. return fmt.Errorf("cannot read a response: %w", err)
  99. }
  100. if response.Rep != socks5.RepSuccess {
  101. return fmt.Errorf("unsuccessful request: %v", response.Rep)
  102. }
  103. return nil
  104. }
  105. // NewSocks5Dialer build a new dialer from a given one (so, in theory
  106. // you can chain here). Proxy parameters are passed with URI in a form of:
  107. //
  108. // socks5://[user:[password]]@host:port
  109. func NewSocks5Dialer(baseDialer Dialer, proxyURL *url.URL) (Dialer, error) {
  110. if _, _, err := net.SplitHostPort(proxyURL.Host); err != nil {
  111. return nil, fmt.Errorf("incorrect url %s", proxyURL.Redacted())
  112. }
  113. dialer := socks5Dialer{
  114. Dialer: baseDialer,
  115. proxyAddress: proxyURL.Host,
  116. }
  117. if proxyURL.User != nil {
  118. password, isSet := proxyURL.User.Password()
  119. if isSet {
  120. dialer.username = []byte(proxyURL.User.Username())
  121. dialer.password = []byte(password)
  122. }
  123. }
  124. return dialer, nil
  125. }