obfs4proxy.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. * Copyright (c) 2014-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. // Go language Tor Pluggable Transport suite. Works only as a managed
  28. // client/server.
  29. package main
  30. import (
  31. "flag"
  32. "fmt"
  33. "io"
  34. golog "log"
  35. "net"
  36. "net/url"
  37. "os"
  38. "path"
  39. "sync"
  40. "syscall"
  41. "git.torproject.org/pluggable-transports/goptlib.git"
  42. "gitlab.com/yawning/obfs4.git/common/log"
  43. "gitlab.com/yawning/obfs4.git/common/socks5"
  44. "gitlab.com/yawning/obfs4.git/transports"
  45. "gitlab.com/yawning/obfs4.git/transports/base"
  46. "golang.org/x/net/proxy"
  47. )
  48. const (
  49. obfs4proxyVersion = "0.0.9"
  50. obfs4proxyLogFile = "obfs4proxy.log"
  51. socksAddr = "127.0.0.1:0"
  52. )
  53. var stateDir string
  54. var termMon *termMonitor
  55. func clientSetup() (launched bool, listeners []net.Listener) {
  56. ptClientInfo, err := pt.ClientSetup(transports.Transports())
  57. if err != nil {
  58. golog.Fatal(err)
  59. }
  60. ptClientProxy, err := ptGetProxy()
  61. if err != nil {
  62. golog.Fatal(err)
  63. } else if ptClientProxy != nil {
  64. ptProxyDone()
  65. }
  66. // Launch each of the client listeners.
  67. for _, name := range ptClientInfo.MethodNames {
  68. t := transports.Get(name)
  69. if t == nil {
  70. _ = pt.CmethodError(name, "no such transport is supported")
  71. continue
  72. }
  73. f, err := t.ClientFactory(stateDir)
  74. if err != nil {
  75. _ = pt.CmethodError(name, "failed to get ClientFactory")
  76. continue
  77. }
  78. ln, err := net.Listen("tcp", socksAddr)
  79. if err != nil {
  80. _ = pt.CmethodError(name, err.Error())
  81. continue
  82. }
  83. go func() {
  84. _ = clientAcceptLoop(f, ln, ptClientProxy)
  85. }()
  86. pt.Cmethod(name, socks5.Version(), ln.Addr())
  87. log.Infof("%s - registered listener: %s", name, ln.Addr())
  88. listeners = append(listeners, ln)
  89. launched = true
  90. }
  91. pt.CmethodsDone()
  92. return
  93. }
  94. func clientAcceptLoop(f base.ClientFactory, ln net.Listener, proxyURI *url.URL) error {
  95. defer ln.Close()
  96. for {
  97. conn, err := ln.Accept()
  98. if err != nil {
  99. if e, ok := err.(net.Error); ok && !e.Temporary() {
  100. return err
  101. }
  102. continue
  103. }
  104. go clientHandler(f, conn, proxyURI)
  105. }
  106. }
  107. func clientHandler(f base.ClientFactory, conn net.Conn, proxyURI *url.URL) {
  108. defer conn.Close()
  109. termMon.onHandlerStart()
  110. defer termMon.onHandlerFinish()
  111. name := f.Transport().Name()
  112. // Read the client's SOCKS handshake.
  113. socksReq, err := socks5.Handshake(conn)
  114. if err != nil {
  115. log.Errorf("%s - client failed socks handshake: %s", name, err)
  116. return
  117. }
  118. addrStr := log.ElideAddr(socksReq.Target)
  119. // Deal with arguments.
  120. args, err := f.ParseArgs(&socksReq.Args)
  121. if err != nil {
  122. log.Errorf("%s(%s) - invalid arguments: %s", name, addrStr, err)
  123. _ = socksReq.Reply(socks5.ReplyGeneralFailure)
  124. return
  125. }
  126. // Obtain the proxy dialer if any, and create the outgoing TCP connection.
  127. dialFn := proxy.Direct.Dial
  128. if proxyURI != nil {
  129. dialer, err := proxy.FromURL(proxyURI, proxy.Direct)
  130. if err != nil {
  131. // This should basically never happen, since config protocol
  132. // verifies this.
  133. log.Errorf("%s(%s) - failed to obtain proxy dialer: %s", name, addrStr, log.ElideError(err))
  134. _ = socksReq.Reply(socks5.ReplyGeneralFailure)
  135. return
  136. }
  137. dialFn = dialer.Dial
  138. }
  139. remote, err := f.Dial("tcp", socksReq.Target, dialFn, args)
  140. if err != nil {
  141. log.Errorf("%s(%s) - outgoing connection failed: %s", name, addrStr, log.ElideError(err))
  142. _ = socksReq.Reply(socks5.ErrorToReplyCode(err))
  143. return
  144. }
  145. defer remote.Close()
  146. err = socksReq.Reply(socks5.ReplySucceeded)
  147. if err != nil {
  148. log.Errorf("%s(%s) - SOCKS reply failed: %s", name, addrStr, log.ElideError(err))
  149. return
  150. }
  151. if err = copyLoop(conn, remote); err != nil {
  152. log.Warnf("%s(%s) - closed connection: %s", name, addrStr, log.ElideError(err))
  153. } else {
  154. log.Infof("%s(%s) - closed connection", name, addrStr)
  155. }
  156. }
  157. func serverSetup() (launched bool, listeners []net.Listener) {
  158. ptServerInfo, err := pt.ServerSetup(transports.Transports())
  159. if err != nil {
  160. golog.Fatal(err)
  161. }
  162. for _, bindaddr := range ptServerInfo.Bindaddrs {
  163. name := bindaddr.MethodName
  164. t := transports.Get(name)
  165. if t == nil {
  166. _ = pt.SmethodError(name, "no such transport is supported")
  167. continue
  168. }
  169. f, err := t.ServerFactory(stateDir, &bindaddr.Options)
  170. if err != nil {
  171. _ = pt.SmethodError(name, err.Error())
  172. continue
  173. }
  174. ln, err := net.ListenTCP("tcp", bindaddr.Addr)
  175. if err != nil {
  176. _ = pt.SmethodError(name, err.Error())
  177. continue
  178. }
  179. go func() {
  180. _ = serverAcceptLoop(f, ln, &ptServerInfo)
  181. }()
  182. if args := f.Args(); args != nil {
  183. pt.SmethodArgs(name, ln.Addr(), *args)
  184. } else {
  185. pt.SmethodArgs(name, ln.Addr(), nil)
  186. }
  187. log.Infof("%s - registered listener: %s", name, log.ElideAddr(ln.Addr().String()))
  188. listeners = append(listeners, ln)
  189. launched = true
  190. }
  191. pt.SmethodsDone()
  192. return
  193. }
  194. func serverAcceptLoop(f base.ServerFactory, ln net.Listener, info *pt.ServerInfo) error {
  195. defer ln.Close()
  196. for {
  197. conn, err := ln.Accept()
  198. if err != nil {
  199. if e, ok := err.(net.Error); ok && !e.Temporary() {
  200. return err
  201. }
  202. continue
  203. }
  204. go serverHandler(f, conn, info)
  205. }
  206. }
  207. func serverHandler(f base.ServerFactory, conn net.Conn, info *pt.ServerInfo) {
  208. defer conn.Close()
  209. termMon.onHandlerStart()
  210. defer termMon.onHandlerFinish()
  211. name := f.Transport().Name()
  212. addrStr := log.ElideAddr(conn.RemoteAddr().String())
  213. log.Infof("%s(%s) - new connection", name, addrStr)
  214. // Instantiate the server transport method and handshake.
  215. remote, err := f.WrapConn(conn)
  216. if err != nil {
  217. log.Warnf("%s(%s) - handshake failed: %s", name, addrStr, log.ElideError(err))
  218. return
  219. }
  220. // Connect to the orport.
  221. orConn, err := pt.DialOr(info, conn.RemoteAddr().String(), name)
  222. if err != nil {
  223. log.Errorf("%s(%s) - failed to connect to ORPort: %s", name, addrStr, log.ElideError(err))
  224. return
  225. }
  226. defer orConn.Close()
  227. if err = copyLoop(orConn, remote); err != nil {
  228. log.Warnf("%s(%s) - closed connection: %s", name, addrStr, log.ElideError(err))
  229. } else {
  230. log.Infof("%s(%s) - closed connection", name, addrStr)
  231. }
  232. }
  233. func copyLoop(a net.Conn, b net.Conn) error {
  234. // Note: b is always the pt connection. a is the SOCKS/ORPort connection.
  235. errChan := make(chan error, 2)
  236. var wg sync.WaitGroup
  237. wg.Add(2)
  238. go func() {
  239. defer wg.Done()
  240. defer b.Close()
  241. defer a.Close()
  242. _, err := io.Copy(b, a)
  243. errChan <- err
  244. }()
  245. go func() {
  246. defer wg.Done()
  247. defer a.Close()
  248. defer b.Close()
  249. _, err := io.Copy(a, b)
  250. errChan <- err
  251. }()
  252. // Wait for both upstream and downstream to close. Since one side
  253. // terminating closes the other, the second error in the channel will be
  254. // something like EINVAL (though io.Copy() will swallow EOF), so only the
  255. // first error is returned.
  256. wg.Wait()
  257. if len(errChan) > 0 {
  258. return <-errChan
  259. }
  260. return nil
  261. }
  262. func getVersion() string {
  263. return fmt.Sprintf("obfs4proxy-%s", obfs4proxyVersion)
  264. }
  265. func main() {
  266. // Initialize the termination state monitor as soon as possible.
  267. termMon = newTermMonitor()
  268. // Handle the command line arguments.
  269. _, execName := path.Split(os.Args[0])
  270. showVer := flag.Bool("version", false, "Print version and exit")
  271. logLevelStr := flag.String("logLevel", "ERROR", "Log level (ERROR/WARN/INFO/DEBUG)")
  272. enableLogging := flag.Bool("enableLogging", false, "Log to TOR_PT_STATE_LOCATION/"+obfs4proxyLogFile)
  273. unsafeLogging := flag.Bool("unsafeLogging", false, "Disable the address scrubber")
  274. flag.Parse()
  275. if *showVer {
  276. fmt.Printf("%s\n", getVersion())
  277. os.Exit(0)
  278. }
  279. if err := log.SetLogLevel(*logLevelStr); err != nil {
  280. golog.Fatalf("[ERROR]: %s - failed to set log level: %s", execName, err)
  281. }
  282. // Determine if this is a client or server, initialize the common state.
  283. var ptListeners []net.Listener
  284. var launched bool
  285. isClient, err := ptIsClient()
  286. if err != nil {
  287. golog.Fatalf("[ERROR]: %s - must be run as a managed transport", execName)
  288. }
  289. if stateDir, err = pt.MakeStateDir(); err != nil {
  290. golog.Fatalf("[ERROR]: %s - No state directory: %s", execName, err)
  291. }
  292. if err = log.Init(*enableLogging, path.Join(stateDir, obfs4proxyLogFile), *unsafeLogging); err != nil {
  293. golog.Fatalf("[ERROR]: %s - failed to initialize logging", execName)
  294. }
  295. if err = transports.Init(); err != nil {
  296. log.Errorf("%s - failed to initialize transports: %s", execName, err)
  297. os.Exit(-1)
  298. }
  299. log.Noticef("%s - launched", getVersion())
  300. // Do the managed pluggable transport protocol configuration.
  301. if isClient {
  302. log.Infof("%s - initializing client transport listeners", execName)
  303. launched, ptListeners = clientSetup()
  304. } else {
  305. log.Infof("%s - initializing server transport listeners", execName)
  306. launched, ptListeners = serverSetup()
  307. }
  308. if !launched {
  309. // Initialization failed, the client or server setup routines should
  310. // have logged, so just exit here.
  311. os.Exit(-1)
  312. }
  313. log.Infof("%s - accepting connections", execName)
  314. defer func() {
  315. log.Noticef("%s - terminated", execName)
  316. }()
  317. // At this point, the pt config protocol is finished, and incoming
  318. // connections will be processed. Wait till the parent dies
  319. // (immediate exit), a SIGTERM is received (immediate exit),
  320. // or a SIGINT is received.
  321. if sig := termMon.wait(false); sig == syscall.SIGTERM {
  322. return
  323. }
  324. // Ok, it was the first SIGINT, close all listeners, and wait till,
  325. // the parent dies, all the current connections are closed, or either
  326. // a SIGINT/SIGTERM is received, and exit.
  327. for _, ln := range ptListeners {
  328. ln.Close()
  329. }
  330. termMon.wait(true)
  331. }