socks5.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * Copyright (c) 2015, Yawning Angel <yawning at torproject dot org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. *
  11. * * Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  19. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. * POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. // Package socks5 implements a SOCKS 5 server
  28. //
  29. // Notes:
  30. // * GSSAPI authentication, is NOT supported.
  31. // * Only the CONNECT command is supported.
  32. // * The authentication provided by the client is always accepted as is.
  33. package socks5
  34. import (
  35. "bufio"
  36. "bytes"
  37. "fmt"
  38. "io"
  39. "net"
  40. "syscall"
  41. "time"
  42. )
  43. const (
  44. version = 0x05
  45. rsv = 0x00
  46. cmdConnect = 0x01
  47. atypIPv4 = 0x01
  48. atypDomainName = 0x03
  49. atypIPv6 = 0x04
  50. authNoneRequired = 0x00
  51. authUsernamePassword = 0x02
  52. authNoAcceptableMethods = 0xff
  53. requestTimeout = 5 * time.Second
  54. )
  55. // ReplyCode is a SOCKS 5 reply code.
  56. type ReplyCode byte
  57. // The various SOCKS 5 reply codes from RFC 1928.
  58. const (
  59. ReplySucceeded ReplyCode = iota
  60. ReplyGeneralFailure
  61. ReplyConnectionNotAllowed
  62. ReplyNetworkUnreachable
  63. ReplyHostUnreachable
  64. ReplyConnectionRefused
  65. ReplyTTLExpired
  66. ReplyCommandNotSupported
  67. ReplyAddressNotSupported
  68. )
  69. // ErrorToReplyCode converts an error to the "best" reply code.
  70. func ErrorToReplyCode(err error) ReplyCode {
  71. opErr, ok := err.(*net.OpError)
  72. if !ok {
  73. return ReplyGeneralFailure
  74. }
  75. errno, ok := opErr.Err.(syscall.Errno)
  76. if !ok {
  77. return ReplyGeneralFailure
  78. }
  79. switch errno {
  80. case syscall.EADDRNOTAVAIL:
  81. return ReplyAddressNotSupported
  82. case syscall.ETIMEDOUT:
  83. return ReplyTTLExpired
  84. case syscall.ENETUNREACH:
  85. return ReplyNetworkUnreachable
  86. case syscall.EHOSTUNREACH:
  87. return ReplyHostUnreachable
  88. case syscall.ECONNREFUSED, syscall.ECONNRESET:
  89. return ReplyConnectionRefused
  90. default:
  91. return ReplyGeneralFailure
  92. }
  93. }
  94. // Request describes a SOCKS 5 request.
  95. type Request struct {
  96. Target string
  97. Uname []byte
  98. Passwd []byte
  99. rw *bufio.ReadWriter
  100. }
  101. // Handshake attempts to handle a incoming client handshake over the provided
  102. // connection and receive the SOCKS5 request. The routine handles sending
  103. // appropriate errors if applicable, but will not close the connection.
  104. func Handshake(conn net.Conn) (*Request, error) {
  105. // Arm the handshake timeout.
  106. var err error
  107. if err = conn.SetDeadline(time.Now().Add(requestTimeout)); err != nil {
  108. return nil, err
  109. }
  110. defer func() {
  111. // Disarm the handshake timeout, only propagate the error if
  112. // the handshake was successful.
  113. nerr := conn.SetDeadline(time.Time{})
  114. if err == nil {
  115. err = nerr
  116. }
  117. }()
  118. req := new(Request)
  119. req.rw = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
  120. // Negotiate the protocol version and authentication method.
  121. var method byte
  122. if method, err = req.negotiateAuth(); err != nil {
  123. return nil, err
  124. }
  125. // Authenticate if neccecary.
  126. if err = req.authenticate(method); err != nil {
  127. return nil, err
  128. }
  129. // Read the client command.
  130. if err = req.readCommand(); err != nil {
  131. return nil, err
  132. }
  133. return req, err
  134. }
  135. // Reply sends a SOCKS5 reply to the corresponding request. The BND.ADDR and
  136. // BND.PORT fields are always set to an address/port corresponding to
  137. // "0.0.0.0:0".
  138. func (req *Request) Reply(code ReplyCode) error {
  139. // The server sends a reply message.
  140. // uint8_t ver (0x05)
  141. // uint8_t rep
  142. // uint8_t rsv (0x00)
  143. // uint8_t atyp
  144. // uint8_t bnd_addr[]
  145. // uint16_t bnd_port
  146. var resp [4 + 4 + 2]byte
  147. resp[0] = version
  148. resp[1] = byte(code)
  149. resp[2] = rsv
  150. resp[3] = atypIPv4
  151. if _, err := req.rw.Write(resp[:]); err != nil {
  152. return err
  153. }
  154. return req.flushBuffers()
  155. }
  156. func (req *Request) negotiateAuth() (byte, error) {
  157. // The client sends a version identifier/selection message.
  158. // uint8_t ver (0x05)
  159. // uint8_t nmethods (>= 1).
  160. // uint8_t methods[nmethods]
  161. var err error
  162. if err = req.readByteVerify("version", version); err != nil {
  163. return 0, err
  164. }
  165. // Read the number of methods, and the methods.
  166. var nmethods byte
  167. method := byte(authNoAcceptableMethods)
  168. if nmethods, err = req.readByte(); err != nil {
  169. return method, err
  170. }
  171. var methods []byte
  172. if methods, err = req.readBytes(int(nmethods)); err != nil {
  173. return 0, err
  174. }
  175. // Pick the best authentication method, prioritizing authenticating
  176. // over not if both options are present.
  177. if bytes.IndexByte(methods, authUsernamePassword) != -1 {
  178. method = authUsernamePassword
  179. } else if bytes.IndexByte(methods, authNoneRequired) != -1 {
  180. method = authNoneRequired
  181. }
  182. // The server sends a method selection message.
  183. // uint8_t ver (0x05)
  184. // uint8_t method
  185. msg := []byte{version, method}
  186. if _, err = req.rw.Write(msg); err != nil {
  187. return 0, err
  188. }
  189. return method, req.flushBuffers()
  190. }
  191. func (req *Request) authenticate(method byte) error {
  192. switch method {
  193. case authNoneRequired:
  194. // No authentication required.
  195. case authUsernamePassword:
  196. if err := req.authRFC1929(); err != nil {
  197. return err
  198. }
  199. case authNoAcceptableMethods:
  200. return fmt.Errorf("no acceptable authentication methods")
  201. default:
  202. // This should never happen as only supported auth methods should be
  203. // negotiated.
  204. return fmt.Errorf("negotiated unsupported method 0x%02x", method)
  205. }
  206. return req.flushBuffers()
  207. }
  208. func (req *Request) readCommand() error {
  209. // The client sends the request details.
  210. // uint8_t ver (0x05)
  211. // uint8_t cmd
  212. // uint8_t rsv (0x00)
  213. // uint8_t atyp
  214. // uint8_t dst_addr[]
  215. // uint16_t dst_port
  216. var err error
  217. if err = req.readByteVerify("version", version); err != nil {
  218. req.Reply(ReplyGeneralFailure)
  219. return err
  220. }
  221. if err = req.readByteVerify("command", cmdConnect); err != nil {
  222. req.Reply(ReplyCommandNotSupported)
  223. return err
  224. }
  225. if err = req.readByteVerify("reserved", rsv); err != nil {
  226. req.Reply(ReplyGeneralFailure)
  227. return err
  228. }
  229. // Read the destination address/port.
  230. var atyp byte
  231. var host string
  232. if atyp, err = req.readByte(); err != nil {
  233. req.Reply(ReplyGeneralFailure)
  234. return err
  235. }
  236. switch atyp {
  237. case atypIPv4:
  238. var addr []byte
  239. if addr, err = req.readBytes(net.IPv4len); err != nil {
  240. req.Reply(ReplyGeneralFailure)
  241. return err
  242. }
  243. host = net.IPv4(addr[0], addr[1], addr[2], addr[3]).String()
  244. case atypDomainName:
  245. var alen byte
  246. if alen, err = req.readByte(); err != nil {
  247. req.Reply(ReplyGeneralFailure)
  248. return err
  249. }
  250. if alen == 0 {
  251. req.Reply(ReplyGeneralFailure)
  252. return fmt.Errorf("domain name with 0 length")
  253. }
  254. var addr []byte
  255. if addr, err = req.readBytes(int(alen)); err != nil {
  256. req.Reply(ReplyGeneralFailure)
  257. return err
  258. }
  259. host = string(addr)
  260. case atypIPv6:
  261. var rawAddr []byte
  262. if rawAddr, err = req.readBytes(net.IPv6len); err != nil {
  263. req.Reply(ReplyGeneralFailure)
  264. return err
  265. }
  266. addr := make(net.IP, net.IPv6len)
  267. copy(addr[:], rawAddr[:])
  268. host = fmt.Sprintf("[%s]", addr.String())
  269. default:
  270. req.Reply(ReplyAddressNotSupported)
  271. return fmt.Errorf("unsupported address type 0x%02x", atyp)
  272. }
  273. var rawPort []byte
  274. if rawPort, err = req.readBytes(2); err != nil {
  275. req.Reply(ReplyGeneralFailure)
  276. return err
  277. }
  278. port := int(rawPort[0])<<8 | int(rawPort[1])
  279. req.Target = fmt.Sprintf("%s:%d", host, port)
  280. return req.flushBuffers()
  281. }
  282. func (req *Request) flushBuffers() error {
  283. if err := req.rw.Flush(); err != nil {
  284. return err
  285. }
  286. if req.rw.Reader.Buffered() > 0 {
  287. return fmt.Errorf("read buffer has %d bytes of trailing data", req.rw.Reader.Buffered())
  288. }
  289. return nil
  290. }
  291. func (req *Request) readByte() (byte, error) {
  292. return req.rw.ReadByte()
  293. }
  294. func (req *Request) readByteVerify(descr string, expected byte) error {
  295. val, err := req.rw.ReadByte()
  296. if err != nil {
  297. return err
  298. }
  299. if val != expected {
  300. return fmt.Errorf("message field '%s' was 0x%02x (expected 0x%02x)", descr, val, expected)
  301. }
  302. return nil
  303. }
  304. func (req *Request) readBytes(n int) ([]byte, error) {
  305. b := make([]byte, n)
  306. if _, err := io.ReadFull(req.rw, b); err != nil {
  307. return nil, err
  308. }
  309. return b, nil
  310. }