tor.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package outbound
  2. import (
  3. "context"
  4. "net"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "github.com/sagernet/sing-box/adapter"
  9. "github.com/sagernet/sing-box/common/dialer"
  10. C "github.com/sagernet/sing-box/constant"
  11. "github.com/sagernet/sing-box/log"
  12. "github.com/sagernet/sing-box/option"
  13. "github.com/sagernet/sing/common"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. F "github.com/sagernet/sing/common/format"
  16. M "github.com/sagernet/sing/common/metadata"
  17. N "github.com/sagernet/sing/common/network"
  18. "github.com/sagernet/sing/common/rw"
  19. "github.com/sagernet/sing/protocol/socks"
  20. "github.com/cretz/bine/control"
  21. "github.com/cretz/bine/tor"
  22. )
  23. var _ adapter.Outbound = (*Tor)(nil)
  24. type Tor struct {
  25. myOutboundAdapter
  26. ctx context.Context
  27. proxy *ProxyListener
  28. startConf *tor.StartConf
  29. options map[string]string
  30. events chan control.Event
  31. instance *tor.Tor
  32. socksClient *socks.Client
  33. }
  34. func NewTor(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TorOutboundOptions) (*Tor, error) {
  35. startConf := newConfig()
  36. startConf.DataDir = os.ExpandEnv(options.DataDirectory)
  37. startConf.TempDataDirBase = os.TempDir()
  38. startConf.ExtraArgs = options.ExtraArgs
  39. if options.DataDirectory != "" {
  40. dataDirAbs, _ := filepath.Abs(startConf.DataDir)
  41. if geoIPPath := filepath.Join(dataDirAbs, "geoip"); rw.FileExists(geoIPPath) && !common.Contains(options.ExtraArgs, "--GeoIPFile") {
  42. options.ExtraArgs = append(options.ExtraArgs, "--GeoIPFile", geoIPPath)
  43. }
  44. if geoIP6Path := filepath.Join(dataDirAbs, "geoip6"); rw.FileExists(geoIP6Path) && !common.Contains(options.ExtraArgs, "--GeoIPv6File") {
  45. options.ExtraArgs = append(options.ExtraArgs, "--GeoIPv6File", geoIP6Path)
  46. }
  47. }
  48. if options.ExecutablePath != "" {
  49. startConf.ExePath = options.ExecutablePath
  50. startConf.ProcessCreator = nil
  51. startConf.UseEmbeddedControlConn = false
  52. }
  53. if startConf.DataDir != "" {
  54. torrcFile := filepath.Join(startConf.DataDir, "torrc")
  55. if !rw.FileExists(torrcFile) {
  56. err := rw.WriteFile(torrcFile, []byte(""))
  57. if err != nil {
  58. return nil, err
  59. }
  60. }
  61. startConf.TorrcFile = torrcFile
  62. }
  63. return &Tor{
  64. myOutboundAdapter: myOutboundAdapter{
  65. protocol: C.TypeTor,
  66. network: []string{N.NetworkTCP},
  67. router: router,
  68. logger: logger,
  69. tag: tag,
  70. dependencies: withDialerDependency(options.DialerOptions),
  71. },
  72. ctx: ctx,
  73. proxy: NewProxyListener(ctx, logger, dialer.New(router, options.DialerOptions)),
  74. startConf: &startConf,
  75. options: options.Options,
  76. }, nil
  77. }
  78. func (t *Tor) Start() error {
  79. err := t.start()
  80. if err != nil {
  81. t.Close()
  82. }
  83. return err
  84. }
  85. var torLogEvents = []control.EventCode{
  86. control.EventCodeLogDebug,
  87. control.EventCodeLogErr,
  88. control.EventCodeLogInfo,
  89. control.EventCodeLogNotice,
  90. control.EventCodeLogWarn,
  91. }
  92. func (t *Tor) start() error {
  93. torInstance, err := tor.Start(t.ctx, t.startConf)
  94. if err != nil {
  95. return E.New(strings.ToLower(err.Error()))
  96. }
  97. t.instance = torInstance
  98. t.events = make(chan control.Event, 8)
  99. err = torInstance.Control.AddEventListener(t.events, torLogEvents...)
  100. if err != nil {
  101. return err
  102. }
  103. go t.recvLoop()
  104. err = t.proxy.Start()
  105. if err != nil {
  106. return err
  107. }
  108. proxyPort := "127.0.0.1:" + F.ToString(t.proxy.Port())
  109. proxyUsername := t.proxy.Username()
  110. proxyPassword := t.proxy.Password()
  111. t.logger.Trace("created upstream proxy at ", proxyPort)
  112. t.logger.Trace("upstream proxy username ", proxyUsername)
  113. t.logger.Trace("upstream proxy password ", proxyPassword)
  114. confOptions := []*control.KeyVal{
  115. control.NewKeyVal("Socks5Proxy", proxyPort),
  116. control.NewKeyVal("Socks5ProxyUsername", proxyUsername),
  117. control.NewKeyVal("Socks5ProxyPassword", proxyPassword),
  118. }
  119. err = torInstance.Control.ResetConf(confOptions...)
  120. if err != nil {
  121. return err
  122. }
  123. if len(t.options) > 0 {
  124. for key, value := range t.options {
  125. switch key {
  126. case "Socks5Proxy",
  127. "Socks5ProxyUsername",
  128. "Socks5ProxyPassword":
  129. continue
  130. }
  131. err = torInstance.Control.SetConf(control.NewKeyVal(key, value))
  132. if err != nil {
  133. return E.Cause(err, "set ", key, "=", value)
  134. }
  135. }
  136. }
  137. err = torInstance.EnableNetwork(t.ctx, true)
  138. if err != nil {
  139. return err
  140. }
  141. info, err := torInstance.Control.GetInfo("net/listeners/socks")
  142. if err != nil {
  143. return err
  144. }
  145. if len(info) != 1 || info[0].Key != "net/listeners/socks" {
  146. return E.New("get socks proxy address")
  147. }
  148. t.logger.Trace("obtained tor socks5 address ", info[0].Val)
  149. // TODO: set password for tor socks5 server if supported
  150. t.socksClient = socks.NewClient(N.SystemDialer, M.ParseSocksaddr(info[0].Val), socks.Version5, "", "")
  151. return nil
  152. }
  153. func (t *Tor) recvLoop() {
  154. for rawEvent := range t.events {
  155. switch event := rawEvent.(type) {
  156. case *control.LogEvent:
  157. event.Raw = strings.ToLower(event.Raw)
  158. switch event.Severity {
  159. case control.EventCodeLogDebug, control.EventCodeLogInfo:
  160. t.logger.Trace(event.Raw)
  161. case control.EventCodeLogNotice:
  162. if strings.Contains(event.Raw, "disablenetwork") || strings.Contains(event.Raw, "socks listener") {
  163. t.logger.Trace(event.Raw)
  164. continue
  165. }
  166. t.logger.Info(event.Raw)
  167. case control.EventCodeLogWarn:
  168. t.logger.Warn(event.Raw)
  169. case control.EventCodeLogErr:
  170. t.logger.Error(event.Raw)
  171. }
  172. }
  173. }
  174. }
  175. func (t *Tor) Close() error {
  176. err := common.Close(
  177. common.PtrOrNil(t.proxy),
  178. common.PtrOrNil(t.instance),
  179. )
  180. if t.events != nil {
  181. close(t.events)
  182. t.events = nil
  183. }
  184. return err
  185. }
  186. func (t *Tor) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  187. t.logger.InfoContext(ctx, "outbound connection to ", destination)
  188. return t.socksClient.DialContext(ctx, network, destination)
  189. }
  190. func (t *Tor) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  191. return nil, os.ErrInvalid
  192. }
  193. func (t *Tor) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
  194. return NewConnection(ctx, t, conn, metadata)
  195. }
  196. func (t *Tor) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
  197. return os.ErrInvalid
  198. }