A SOCKS (SOCKS4, SOCKS4A and SOCKS5) Proxy Package for Go
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

219 Zeilen
5.4 KiB

  1. // Copyright 2012, Hailiang Wang. 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. /*
  5. Package socks implements a SOCKS (SOCKS4, SOCKS4A and SOCKS5) proxy client.
  6. A complete example using this package:
  7. package main
  8. import (
  9. "code.as/core/socks"
  10. "fmt"
  11. "net/http"
  12. "io/ioutil"
  13. )
  14. func main() {
  15. dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
  16. tr := &http.Transport{Dial: dialSocksProxy}
  17. httpClient := &http.Client{Transport: tr}
  18. bodyText, err := TestHttpsGet(httpClient, "https://h12.io/about")
  19. if err != nil {
  20. fmt.Println(err.Error())
  21. }
  22. fmt.Print(bodyText)
  23. }
  24. func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) {
  25. resp, err := c.Get(url)
  26. if err != nil { return }
  27. defer resp.Body.Close()
  28. body, err := ioutil.ReadAll(resp.Body)
  29. if err != nil { return }
  30. bodyText = string(body)
  31. return
  32. }
  33. */
  34. package socks
  35. import (
  36. "errors"
  37. "fmt"
  38. "net"
  39. "strconv"
  40. )
  41. // Constants to choose which version of SOCKS protocol to use.
  42. const (
  43. SOCKS4 = iota
  44. SOCKS4A
  45. SOCKS5
  46. )
  47. // DialSocksProxy returns the dial function to be used in http.Transport object.
  48. // Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5.
  49. // Argument proxy should be in this format "127.0.0.1:1080".
  50. func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) {
  51. if socksType == SOCKS5 {
  52. return func(_, targetAddr string) (conn net.Conn, err error) {
  53. return dialSocks5(proxy, targetAddr)
  54. }
  55. }
  56. // SOCKS4, SOCKS4A
  57. return func(_, targetAddr string) (conn net.Conn, err error) {
  58. return dialSocks4(socksType, proxy, targetAddr)
  59. }
  60. }
  61. func dialSocks5(proxy, targetAddr string) (conn net.Conn, err error) {
  62. // dial TCP
  63. conn, err = net.Dial("tcp", proxy)
  64. if err != nil {
  65. return
  66. }
  67. // version identifier/method selection request
  68. req := []byte{
  69. 5, // version number
  70. 1, // number of methods
  71. 0, // method 0: no authentication (only anonymous access supported for now)
  72. }
  73. resp, err := sendReceive(conn, req)
  74. if err != nil {
  75. return
  76. } else if len(resp) != 2 {
  77. err = errors.New("Server does not respond properly.")
  78. return
  79. } else if resp[0] != 5 {
  80. err = errors.New("Server does not support Socks 5.")
  81. return
  82. } else if resp[1] != 0 { // no auth
  83. err = errors.New("socks method negotiation failed.")
  84. return
  85. }
  86. // detail request
  87. host, port, err := splitHostPort(targetAddr)
  88. req = []byte{
  89. 5, // version number
  90. 1, // connect command
  91. 0, // reserved, must be zero
  92. 3, // address type, 3 means domain name
  93. byte(len(host)), // address length
  94. }
  95. req = append(req, []byte(host)...)
  96. req = append(req, []byte{
  97. byte(port >> 8), // higher byte of destination port
  98. byte(port), // lower byte of destination port (big endian)
  99. }...)
  100. resp, err = sendReceive(conn, req)
  101. if err != nil {
  102. return
  103. } else if len(resp) != 10 {
  104. err = errors.New("Server does not respond properly.")
  105. } else if resp[1] != 0 {
  106. err = errors.New("Can't complete SOCKS5 connection.")
  107. }
  108. return
  109. }
  110. func dialSocks4(socksType int, proxy, targetAddr string) (conn net.Conn, err error) {
  111. // dial TCP
  112. conn, err = net.Dial("tcp", proxy)
  113. if err != nil {
  114. return
  115. }
  116. // connection request
  117. host, port, err := splitHostPort(targetAddr)
  118. if err != nil {
  119. return
  120. }
  121. ip := net.IPv4(0, 0, 0, 1).To4()
  122. if socksType == SOCKS4 {
  123. ip, err = lookupIP(host)
  124. if err != nil {
  125. return
  126. }
  127. }
  128. req := []byte{
  129. 4, // version number
  130. 1, // command CONNECT
  131. byte(port >> 8), // higher byte of destination port
  132. byte(port), // lower byte of destination port (big endian)
  133. ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided
  134. 0, // user id is empty, anonymous proxy only
  135. }
  136. if socksType == SOCKS4A {
  137. req = append(req, []byte(host+"\x00")...)
  138. }
  139. resp, err := sendReceive(conn, req)
  140. if err != nil {
  141. return
  142. } else if len(resp) != 8 {
  143. err = errors.New("Server does not respond properly.")
  144. return
  145. }
  146. switch resp[1] {
  147. case 90:
  148. // request granted
  149. case 91:
  150. err = errors.New("Socks connection request rejected or failed.")
  151. case 92:
  152. err = errors.New("Socks connection request rejected becasue SOCKS server cannot connect to identd on the client.")
  153. case 93:
  154. err = errors.New("Socks connection request rejected because the client program and identd report different user-ids.")
  155. default:
  156. err = errors.New("Socks connection request failed, unknown error.")
  157. }
  158. return
  159. }
  160. func sendReceive(conn net.Conn, req []byte) (resp []byte, err error) {
  161. _, err = conn.Write(req)
  162. if err != nil {
  163. return
  164. }
  165. resp, err = readAll(conn)
  166. return
  167. }
  168. func readAll(conn net.Conn) (resp []byte, err error) {
  169. resp = make([]byte, 1024)
  170. n, err := conn.Read(resp)
  171. resp = resp[:n]
  172. return
  173. }
  174. func lookupIP(host string) (ip net.IP, err error) {
  175. ips, err := net.LookupIP(host)
  176. if err != nil {
  177. return
  178. }
  179. if len(ips) == 0 {
  180. err = errors.New(fmt.Sprintf("Cannot resolve host: %s.", host))
  181. return
  182. }
  183. ip = ips[0].To4()
  184. if len(ip) != net.IPv4len {
  185. fmt.Println(len(ip), ip)
  186. err = errors.New("IPv6 is not supported by SOCKS4.")
  187. return
  188. }
  189. return
  190. }
  191. func splitHostPort(addr string) (host string, port uint16, err error) {
  192. host, portStr, err := net.SplitHostPort(addr)
  193. portInt, err := strconv.ParseUint(portStr, 10, 16)
  194. port = uint16(portInt)
  195. return
  196. }