25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

214 lines
5.7 KiB

  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. if err := s.connect(conn, addr); err != nil {
  64. conn.Close()
  65. return nil, err
  66. }
  67. return conn, nil
  68. }
  69. // connect takes an existing connection to a socks5 proxy server,
  70. // and commands the server to extend that connection to target,
  71. // which must be a canonical address with a host and port.
  72. func (s *socks5) connect(conn net.Conn, target string) error {
  73. host, portStr, err := net.SplitHostPort(target)
  74. if err != nil {
  75. return err
  76. }
  77. port, err := strconv.Atoi(portStr)
  78. if err != nil {
  79. return errors.New("proxy: failed to parse port number: " + portStr)
  80. }
  81. if port < 1 || port > 0xffff {
  82. return errors.New("proxy: port number out of range: " + portStr)
  83. }
  84. // the size here is just an estimate
  85. buf := make([]byte, 0, 6+len(host))
  86. buf = append(buf, socks5Version)
  87. if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
  88. buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
  89. } else {
  90. buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
  91. }
  92. if _, err := conn.Write(buf); err != nil {
  93. return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
  94. }
  95. if _, err := io.ReadFull(conn, buf[:2]); err != nil {
  96. return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  97. }
  98. if buf[0] != 5 {
  99. return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
  100. }
  101. if buf[1] == 0xff {
  102. return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
  103. }
  104. if buf[1] == socks5AuthPassword {
  105. buf = buf[:0]
  106. buf = append(buf, 1 /* password protocol version */)
  107. buf = append(buf, uint8(len(s.user)))
  108. buf = append(buf, s.user...)
  109. buf = append(buf, uint8(len(s.password)))
  110. buf = append(buf, s.password...)
  111. if _, err := conn.Write(buf); err != nil {
  112. return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
  113. }
  114. if _, err := io.ReadFull(conn, buf[:2]); err != nil {
  115. return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  116. }
  117. if buf[1] != 0 {
  118. return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
  119. }
  120. }
  121. buf = buf[:0]
  122. buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
  123. if ip := net.ParseIP(host); ip != nil {
  124. if ip4 := ip.To4(); ip4 != nil {
  125. buf = append(buf, socks5IP4)
  126. ip = ip4
  127. } else {
  128. buf = append(buf, socks5IP6)
  129. }
  130. buf = append(buf, ip...)
  131. } else {
  132. if len(host) > 255 {
  133. return errors.New("proxy: destination hostname too long: " + host)
  134. }
  135. buf = append(buf, socks5Domain)
  136. buf = append(buf, byte(len(host)))
  137. buf = append(buf, host...)
  138. }
  139. buf = append(buf, byte(port>>8), byte(port))
  140. if _, err := conn.Write(buf); err != nil {
  141. return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
  142. }
  143. if _, err := io.ReadFull(conn, buf[:4]); err != nil {
  144. return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  145. }
  146. failure := "unknown error"
  147. if int(buf[1]) < len(socks5Errors) {
  148. failure = socks5Errors[buf[1]]
  149. }
  150. if len(failure) > 0 {
  151. return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
  152. }
  153. bytesToDiscard := 0
  154. switch buf[3] {
  155. case socks5IP4:
  156. bytesToDiscard = net.IPv4len
  157. case socks5IP6:
  158. bytesToDiscard = net.IPv6len
  159. case socks5Domain:
  160. _, err := io.ReadFull(conn, buf[:1])
  161. if err != nil {
  162. return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  163. }
  164. bytesToDiscard = int(buf[0])
  165. default:
  166. return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
  167. }
  168. if cap(buf) < bytesToDiscard {
  169. buf = make([]byte, bytesToDiscard)
  170. } else {
  171. buf = buf[:bytesToDiscard]
  172. }
  173. if _, err := io.ReadFull(conn, buf); err != nil {
  174. return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  175. }
  176. // Also need to discard the port number
  177. if _, err := io.ReadFull(conn, buf[:2]); err != nil {
  178. return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
  179. }
  180. return nil
  181. }