socks5.go 5.4 KB

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