lyrebird.go 11 KB

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