socks5.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package proxy
  5. import (
  6. "errors"
  7. "io"
  8. "net"
  9. "strconv"
  10. )
  11. // SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
  12. // with an optional username and password. See RFC 1928.
  13. func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
  14. s := &socks5{
  15. network: network,
  16. addr: addr,
  17. forward: forward,
  18. }
  19. if auth != nil {
  20. s.user = auth.User
  21. s.password = auth.Password
  22. }
  23. return s, nil
  24. }
  25. type socks5 struct {
  26. user, password string
  27. network, addr string
  28. forward Dialer
  29. }
  30. const socks5Version = 5
  31. const (
  32. socks5AuthNone = 0
  33. socks5AuthPassword = 2
  34. )
  35. const socks5Connect = 1
  36. const (
  37. socks5IP4 = 1
  38. socks5Domain = 3
  39. socks5IP6 = 4
  40. )
  41. var socks5Errors = []string{
  42. "",
  43. "general failure",
  44. "connection forbidden",
  45. "network unreachable",
  46. "host unreachable",
  47. "connection refused",
  48. "TTL expired",
  49. "command not supported",
  50. "address type not supported",
  51. }
  52. // Dial connects to the address addr on the network net via the SOCKS5 proxy.
  53. func (s *socks5) Dial(network, addr string) (net.Conn, error) {
  54. switch network {
  55. case "tcp", "tcp6", "tcp4":
  56. default:
  57. return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
  58. }
  59. conn, err := s.forward.Dial(s.network, s.addr)
  60. if err != nil {
  61. return nil, err
  62. }
  63. closeConn := &conn
  64. defer func() {
  65. if closeConn != nil {
  66. (*closeConn).Close()
  67. }
  68. }()
  69. host, portStr, err := net.SplitHostPort(addr)
  70. if err != nil {
  71. return nil, err
  72. }
  73. port, err := strconv.Atoi(portStr)
  74. if err != nil {
  75. return nil, errors.New("proxy: failed to parse port number: " + portStr)
  76. }
  77. if port < 1 || port > 0xffff {
  78. return nil, errors.New("proxy: port number out of range: " + portStr)
  79. }
  80. // the size here is just an estimate
  81. buf := make([]byte, 0, 6+len(host))
  82. buf = append(buf, socks5Version)
  83. if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
  84. buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
  85. } else {
  86. buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
  87. }
  88. if _, err := conn.Write(buf); err != nil {
  89. return nil, errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
  90. }
  91. if _, err := io.ReadFull(conn, buf[:2]); err != nil {
  92. return nil, errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  93. }
  94. if buf[0] != 5 {
  95. return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
  96. }
  97. if buf[1] == 0xff {
  98. return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
  99. }
  100. if buf[1] == socks5AuthPassword {
  101. buf = buf[:0]
  102. buf = append(buf, 1 /* password protocol version */)
  103. buf = append(buf, uint8(len(s.user)))
  104. buf = append(buf, s.user...)
  105. buf = append(buf, uint8(len(s.password)))
  106. buf = append(buf, s.password...)
  107. if _, err := conn.Write(buf); err != nil {
  108. return nil, errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
  109. }
  110. if _, err := io.ReadFull(conn, buf[:2]); err != nil {
  111. return nil, errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  112. }
  113. if buf[1] != 0 {
  114. return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
  115. }
  116. }
  117. buf = buf[:0]
  118. buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
  119. if ip := net.ParseIP(host); ip != nil {
  120. if ip4 := ip.To4(); ip4 != nil {
  121. buf = append(buf, socks5IP4)
  122. ip = ip4
  123. } else {
  124. buf = append(buf, socks5IP6)
  125. }
  126. buf = append(buf, ip...)
  127. } else {
  128. if len(host) > 255 {
  129. return nil, errors.New("proxy: destination hostname too long: " + host)
  130. }
  131. buf = append(buf, socks5Domain)
  132. buf = append(buf, byte(len(host)))
  133. buf = append(buf, host...)
  134. }
  135. buf = append(buf, byte(port>>8), byte(port))
  136. if _, err := conn.Write(buf); err != nil {
  137. return nil, errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
  138. }
  139. if _, err := io.ReadFull(conn, buf[:4]); err != nil {
  140. return nil, errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  141. }
  142. failure := "unknown error"
  143. if int(buf[1]) < len(socks5Errors) {
  144. failure = socks5Errors[buf[1]]
  145. }
  146. if len(failure) > 0 {
  147. return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
  148. }
  149. bytesToDiscard := 0
  150. switch buf[3] {
  151. case socks5IP4:
  152. bytesToDiscard = net.IPv4len
  153. case socks5IP6:
  154. bytesToDiscard = net.IPv6len
  155. case socks5Domain:
  156. _, err := io.ReadFull(conn, buf[:1])
  157. if err != nil {
  158. return nil, errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  159. }
  160. bytesToDiscard = int(buf[0])
  161. default:
  162. return nil, errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
  163. }
  164. if cap(buf) < bytesToDiscard {
  165. buf = make([]byte, bytesToDiscard)
  166. } else {
  167. buf = buf[:bytesToDiscard]
  168. }
  169. if _, err := io.ReadFull(conn, buf); err != nil {
  170. return nil, errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  171. }
  172. // Also need to discard the port number
  173. if _, err := io.ReadFull(conn, buf[:2]); err != nil {
  174. return nil, errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  175. }
  176. closeConn = nil
  177. return conn, nil
  178. }