socks5.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Copyright (c) 2015, Yawning Angel <yawning at schwanenlied dot me>
  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 and the required pluggable
  28. // transport specific extensions. For more information see RFC 1928 and RFC
  29. // 1929.
  30. //
  31. // Notes:
  32. // - GSSAPI authentication, is NOT supported.
  33. // - Only the CONNECT command is supported.
  34. // - The authentication provided by the client is always accepted as it is
  35. // used as a channel to pass information rather than for authentication for
  36. // pluggable transports.
  37. package socks5 // import "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/socks5"
  38. import (
  39. "bufio"
  40. "bytes"
  41. "fmt"
  42. "io"
  43. "net"
  44. "syscall"
  45. "time"
  46. "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
  47. )
  48. const (
  49. version = 0x05
  50. rsv = 0x00
  51. cmdConnect = 0x01
  52. atypIPv4 = 0x01
  53. atypDomainName = 0x03
  54. atypIPv6 = 0x04
  55. authNoneRequired = 0x00
  56. authUsernamePassword = 0x02
  57. authNoAcceptableMethods = 0xff
  58. requestTimeout = 5 * time.Second
  59. )
  60. // ReplyCode is a SOCKS 5 reply code.
  61. type ReplyCode byte
  62. // The various SOCKS 5 reply codes from RFC 1928.
  63. const (
  64. ReplySucceeded ReplyCode = iota
  65. ReplyGeneralFailure
  66. ReplyConnectionNotAllowed
  67. ReplyNetworkUnreachable
  68. ReplyHostUnreachable
  69. ReplyConnectionRefused
  70. ReplyTTLExpired
  71. ReplyCommandNotSupported
  72. ReplyAddressNotSupported
  73. )
  74. // Version returns a string suitable to be included in a call to Cmethod.
  75. func Version() string {
  76. return "socks5"
  77. }
  78. // ErrorToReplyCode converts an error to the "best" reply code.
  79. func ErrorToReplyCode(err error) ReplyCode {
  80. opErr, ok := err.(*net.OpError)
  81. if !ok {
  82. return ReplyGeneralFailure
  83. }
  84. errno, ok := opErr.Err.(syscall.Errno)
  85. if !ok {
  86. return ReplyGeneralFailure
  87. }
  88. switch errno {
  89. case syscall.EADDRNOTAVAIL:
  90. return ReplyAddressNotSupported
  91. case syscall.ETIMEDOUT:
  92. return ReplyTTLExpired
  93. case syscall.ENETUNREACH:
  94. return ReplyNetworkUnreachable
  95. case syscall.EHOSTUNREACH:
  96. return ReplyHostUnreachable
  97. case syscall.ECONNREFUSED, syscall.ECONNRESET:
  98. return ReplyConnectionRefused
  99. default:
  100. return ReplyGeneralFailure
  101. }
  102. }
  103. // Request describes a SOCKS 5 request.
  104. type Request struct {
  105. Target string
  106. Args pt.Args
  107. rw *bufio.ReadWriter
  108. }
  109. // Handshake attempts to handle a incoming client handshake over the provided
  110. // connection and receive the SOCKS5 request. The routine handles sending
  111. // appropriate errors if applicable, but will not close the connection.
  112. func Handshake(conn net.Conn) (*Request, error) {
  113. // Arm the handshake timeout.
  114. var err error
  115. if err = conn.SetDeadline(time.Now().Add(requestTimeout)); err != nil {
  116. return nil, err
  117. }
  118. defer func() {
  119. // Disarm the handshake timeout, only propagate the error if
  120. // the handshake was successful.
  121. nerr := conn.SetDeadline(time.Time{})
  122. if err == nil {
  123. err = nerr
  124. }
  125. }()
  126. req := new(Request)
  127. req.rw = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
  128. // Negotiate the protocol version and authentication method.
  129. var method byte
  130. if method, err = req.negotiateAuth(); err != nil {
  131. return nil, err
  132. }
  133. // Authenticate if neccecary.
  134. if err = req.authenticate(method); err != nil {
  135. return nil, err
  136. }
  137. // Read the client command.
  138. if err = req.readCommand(); err != nil {
  139. return nil, err
  140. }
  141. return req, err
  142. }
  143. // Reply sends a SOCKS5 reply to the corresponding request. The BND.ADDR and
  144. // BND.PORT fields are always set to an address/port corresponding to
  145. // "0.0.0.0:0".
  146. func (req *Request) Reply(code ReplyCode) error {
  147. // The server sends a reply message.
  148. // uint8_t ver (0x05)
  149. // uint8_t rep
  150. // uint8_t rsv (0x00)
  151. // uint8_t atyp
  152. // uint8_t bnd_addr[]
  153. // uint16_t bnd_port
  154. var resp [4 + 4 + 2]byte
  155. resp[0] = version
  156. resp[1] = byte(code)
  157. resp[2] = rsv
  158. resp[3] = atypIPv4
  159. if _, err := req.rw.Write(resp[:]); err != nil {
  160. return err
  161. }
  162. return req.flushBuffers()
  163. }
  164. func (req *Request) negotiateAuth() (byte, error) {
  165. // The client sends a version identifier/selection message.
  166. // uint8_t ver (0x05)
  167. // uint8_t nmethods (>= 1).
  168. // uint8_t methods[nmethods]
  169. var err error
  170. if err = req.readByteVerify("version", version); err != nil {
  171. return 0, err
  172. }
  173. // Read the number of methods, and the methods.
  174. var nmethods byte
  175. method := byte(authNoAcceptableMethods)
  176. if nmethods, err = req.readByte(); err != nil {
  177. return method, err
  178. }
  179. methods := make([]byte, int(nmethods))
  180. if err = req.readFull(methods); err != nil {
  181. return 0, err
  182. }
  183. // Pick the best authentication method, prioritizing authenticating
  184. // over not if both options are present.
  185. if bytes.IndexByte(methods, authUsernamePassword) != -1 {
  186. method = authUsernamePassword
  187. } else if bytes.IndexByte(methods, authNoneRequired) != -1 {
  188. method = authNoneRequired
  189. }
  190. // The server sends a method selection message.
  191. // uint8_t ver (0x05)
  192. // uint8_t method
  193. msg := []byte{version, method}
  194. if _, err = req.rw.Write(msg); err != nil {
  195. return 0, err
  196. }
  197. return method, req.flushBuffers()
  198. }
  199. func (req *Request) authenticate(method byte) error {
  200. switch method {
  201. case authNoneRequired:
  202. // No authentication required.
  203. case authUsernamePassword:
  204. if err := req.authRFC1929(); err != nil {
  205. return err
  206. }
  207. case authNoAcceptableMethods:
  208. return fmt.Errorf("no acceptable authentication methods")
  209. default:
  210. // This should never happen as only supported auth methods should be
  211. // negotiated.
  212. return fmt.Errorf("negotiated unsupported method 0x%02x", method)
  213. }
  214. return req.flushBuffers()
  215. }
  216. func (req *Request) readCommand() error {
  217. // The client sends the request details.
  218. // uint8_t ver (0x05)
  219. // uint8_t cmd
  220. // uint8_t rsv (0x00)
  221. // uint8_t atyp
  222. // uint8_t dst_addr[]
  223. // uint16_t dst_port
  224. var err error
  225. if err = req.readByteVerify("version", version); err != nil {
  226. _ = req.Reply(ReplyGeneralFailure)
  227. return err
  228. }
  229. if err = req.readByteVerify("command", cmdConnect); err != nil {
  230. _ = req.Reply(ReplyCommandNotSupported)
  231. return err
  232. }
  233. if err = req.readByteVerify("reserved", rsv); err != nil {
  234. _ = req.Reply(ReplyGeneralFailure)
  235. return err
  236. }
  237. // Read the destination address/port.
  238. var atyp byte
  239. var host string
  240. if atyp, err = req.readByte(); err != nil {
  241. _ = req.Reply(ReplyGeneralFailure)
  242. return err
  243. }
  244. switch atyp {
  245. case atypIPv4:
  246. var addr [net.IPv4len]byte
  247. if err = req.readFull(addr[:]); err != nil {
  248. _ = req.Reply(ReplyGeneralFailure)
  249. return err
  250. }
  251. host = net.IPv4(addr[0], addr[1], addr[2], addr[3]).String()
  252. case atypDomainName:
  253. var alen byte
  254. if alen, err = req.readByte(); err != nil {
  255. _ = req.Reply(ReplyGeneralFailure)
  256. return err
  257. }
  258. if alen == 0 {
  259. _ = req.Reply(ReplyGeneralFailure)
  260. return fmt.Errorf("domain name with 0 length")
  261. }
  262. addr := make([]byte, int(alen))
  263. if err = req.readFull(addr); err != nil {
  264. _ = req.Reply(ReplyGeneralFailure)
  265. return err
  266. }
  267. host = string(addr)
  268. case atypIPv6:
  269. var addr [net.IPv6len]byte
  270. if err = req.readFull(addr[:]); err != nil {
  271. _ = req.Reply(ReplyGeneralFailure)
  272. return err
  273. }
  274. host = fmt.Sprintf("[%s]", net.IP(addr[:]).String())
  275. default:
  276. _ = req.Reply(ReplyAddressNotSupported)
  277. return fmt.Errorf("unsupported address type 0x%02x", atyp)
  278. }
  279. var rawPort [2]byte
  280. if err = req.readFull(rawPort[:]); err != nil {
  281. _ = req.Reply(ReplyGeneralFailure)
  282. return err
  283. }
  284. port := int(rawPort[0])<<8 | int(rawPort[1])
  285. req.Target = fmt.Sprintf("%s:%d", host, port)
  286. return req.flushBuffers()
  287. }
  288. func (req *Request) flushBuffers() error {
  289. if err := req.rw.Flush(); err != nil {
  290. return err
  291. }
  292. if req.rw.Reader.Buffered() > 0 {
  293. return fmt.Errorf("read buffer has %d bytes of trailing data", req.rw.Reader.Buffered())
  294. }
  295. return nil
  296. }
  297. func (req *Request) readByte() (byte, error) {
  298. return req.rw.ReadByte()
  299. }
  300. func (req *Request) readByteVerify(descr string, expected byte) error {
  301. val, err := req.rw.ReadByte()
  302. if err != nil {
  303. return err
  304. }
  305. if val != expected {
  306. return fmt.Errorf("message field '%s' was 0x%02x (expected 0x%02x)", descr, val, expected)
  307. }
  308. return nil
  309. }
  310. func (req *Request) readFull(buf []byte) error {
  311. _, err := io.ReadFull(req.rw, buf)
  312. return err
  313. }