snowflake.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Client transport plugin for the Snowflake pluggable transport.
  2. package main
  3. import (
  4. "flag"
  5. "io"
  6. "io/ioutil"
  7. "log"
  8. "net"
  9. "os"
  10. "os/signal"
  11. "path/filepath"
  12. "strings"
  13. "syscall"
  14. "time"
  15. "git.torproject.org/pluggable-transports/goptlib.git"
  16. sf "git.torproject.org/pluggable-transports/snowflake.git/client/lib"
  17. "git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
  18. "github.com/keroserene/go-webrtc"
  19. )
  20. const (
  21. DefaultSnowflakeCapacity = 1
  22. )
  23. // Maintain |SnowflakeCapacity| number of available WebRTC connections, to
  24. // transfer to the Tor SOCKS handler when needed.
  25. func ConnectLoop(snowflakes sf.SnowflakeCollector) {
  26. for {
  27. // Check if ending is necessary.
  28. _, err := snowflakes.Collect()
  29. if nil != err {
  30. log.Println("WebRTC:", err,
  31. " Retrying in", sf.ReconnectTimeout, "seconds...")
  32. }
  33. select {
  34. case <-time.After(time.Second * sf.ReconnectTimeout):
  35. continue
  36. case <-snowflakes.Melted():
  37. log.Println("ConnectLoop: stopped.")
  38. return
  39. }
  40. }
  41. }
  42. // Accept local SOCKS connections and pass them to the handler.
  43. func socksAcceptLoop(ln *pt.SocksListener, snowflakes sf.SnowflakeCollector) error {
  44. defer ln.Close()
  45. log.Println("Started SOCKS listener.")
  46. for {
  47. log.Println("SOCKS listening...")
  48. conn, err := ln.AcceptSocks()
  49. if err != nil {
  50. if e, ok := err.(net.Error); ok && e.Temporary() {
  51. continue
  52. }
  53. return err
  54. }
  55. log.Println("SOCKS accepted: ", conn.Req)
  56. err = sf.Handler(conn, snowflakes)
  57. if err != nil {
  58. log.Printf("handler error: %s", err)
  59. }
  60. }
  61. }
  62. func main() {
  63. iceServersCommas := flag.String("ice", "", "comma-separated list of ICE servers")
  64. brokerURL := flag.String("url", "", "URL of signaling broker")
  65. frontDomain := flag.String("front", "", "front domain")
  66. logFilename := flag.String("log", "", "name of log file")
  67. logToStateDir := flag.Bool("logToStateDir", false, "resolve the log file relative to tor's pt state dir")
  68. max := flag.Int("max", DefaultSnowflakeCapacity,
  69. "capacity for number of multiplexed WebRTC peers")
  70. flag.Parse()
  71. webrtc.SetLoggingVerbosity(1)
  72. log.SetFlags(log.LstdFlags | log.LUTC)
  73. // Don't write to stderr; versions of tor earlier than about
  74. // 0.3.5.6 do not read from the pipe, and eventually we will
  75. // deadlock because the buffer is full.
  76. // https://bugs.torproject.org/26360
  77. // https://bugs.torproject.org/25600#comment:14
  78. var logOutput io.Writer = ioutil.Discard
  79. if *logFilename != "" {
  80. if *logToStateDir {
  81. stateDir, err := pt.MakeStateDir()
  82. if err != nil {
  83. log.Fatal(err)
  84. }
  85. *logFilename = filepath.Join(stateDir, *logFilename)
  86. }
  87. logFile, err := os.OpenFile(*logFilename,
  88. os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
  89. if err != nil {
  90. log.Fatal(err)
  91. }
  92. defer logFile.Close()
  93. logOutput = logFile
  94. }
  95. //We want to send the log output through our scrubber first
  96. log.SetOutput(&safelog.LogScrubber{Output: logOutput})
  97. log.Println("\n\n\n --- Starting Snowflake Client ---")
  98. var iceServers sf.IceServerList
  99. if len(strings.TrimSpace(*iceServersCommas)) > 0 {
  100. option := webrtc.OptionIceServer(*iceServersCommas)
  101. iceServers = append(iceServers, option)
  102. }
  103. // Prepare to collect remote WebRTC peers.
  104. snowflakes := sf.NewPeers(*max)
  105. // Use potentially domain-fronting broker to rendezvous.
  106. broker := sf.NewBrokerChannel(*brokerURL, *frontDomain, sf.CreateBrokerTransport())
  107. snowflakes.Tongue = sf.NewWebRTCDialer(broker, iceServers)
  108. if nil == snowflakes.Tongue {
  109. log.Fatal("Unable to prepare rendezvous method.")
  110. return
  111. }
  112. // Use a real logger to periodically output how much traffic is happening.
  113. snowflakes.BytesLogger = &sf.BytesSyncLogger{
  114. InboundChan: make(chan int, 5),
  115. OutboundChan: make(chan int, 5),
  116. Inbound: 0,
  117. Outbound: 0,
  118. InEvents: 0,
  119. OutEvents: 0,
  120. }
  121. go snowflakes.BytesLogger.Log()
  122. go ConnectLoop(snowflakes)
  123. // Begin goptlib client process.
  124. ptInfo, err := pt.ClientSetup(nil)
  125. if err != nil {
  126. log.Fatal(err)
  127. }
  128. if ptInfo.ProxyURL != nil {
  129. pt.ProxyError("proxy is not supported")
  130. os.Exit(1)
  131. }
  132. listeners := make([]net.Listener, 0)
  133. for _, methodName := range ptInfo.MethodNames {
  134. switch methodName {
  135. case "snowflake":
  136. // TODO: Be able to recover when SOCKS dies.
  137. ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
  138. if err != nil {
  139. pt.CmethodError(methodName, err.Error())
  140. break
  141. }
  142. go socksAcceptLoop(ln, snowflakes)
  143. pt.Cmethod(methodName, ln.Version(), ln.Addr())
  144. listeners = append(listeners, ln)
  145. default:
  146. pt.CmethodError(methodName, "no such method")
  147. }
  148. }
  149. pt.CmethodsDone()
  150. var numHandlers int = 0
  151. var sig os.Signal
  152. sigChan := make(chan os.Signal, 1)
  153. signal.Notify(sigChan, syscall.SIGTERM)
  154. if os.Getenv("TOR_PT_EXIT_ON_STDIN_CLOSE") == "1" {
  155. // This environment variable means we should treat EOF on stdin
  156. // just like SIGTERM: https://bugs.torproject.org/15435.
  157. go func() {
  158. io.Copy(ioutil.Discard, os.Stdin)
  159. log.Printf("synthesizing SIGTERM because of stdin close")
  160. sigChan <- syscall.SIGTERM
  161. }()
  162. }
  163. // keep track of handlers and wait for a signal
  164. sig = nil
  165. for sig == nil {
  166. select {
  167. case n := <-sf.HandlerChan:
  168. numHandlers += n
  169. case sig = <-sigChan:
  170. }
  171. }
  172. // signal received, shut down
  173. for _, ln := range listeners {
  174. ln.Close()
  175. }
  176. snowflakes.End()
  177. for numHandlers > 0 {
  178. numHandlers += <-sf.HandlerChan
  179. }
  180. log.Println("snowflake is done.")
  181. }