outbound.go 6.1 KB

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