From 488be14329ae213296f5aea30e27fa53c4a34357 Mon Sep 17 00:00:00 2001 From: yaotthaha Date: Sun, 7 May 2023 19:08:02 +0800 Subject: [PATCH] Fix: tor may fail to start in some situations --- outbound/tor.go | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/outbound/tor.go b/outbound/tor.go index 07f4e588..252b532d 100644 --- a/outbound/tor.go +++ b/outbound/tor.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "strings" + "sync/atomic" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" @@ -35,6 +36,8 @@ type Tor struct { events chan control.Event instance *tor.Tor socksClient *socks.Client + + isReady atomic.Bool } func NewTor(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TorOutboundOptions) (*Tor, error) { @@ -142,21 +145,32 @@ func (t *Tor) start() error { } } } - err = torInstance.EnableNetwork(t.ctx, true) + + go t.bootWait() + + return nil +} + +func (t *Tor) bootWait() { + err := t.instance.EnableNetwork(t.ctx, true) if err != nil { - return err + t.logger.Error("enable tor network fail: ", err.Error()) + return } - info, err := torInstance.Control.GetInfo("net/listeners/socks") + info, err := t.instance.Control.GetInfo("net/listeners/socks") if err != nil { - return err + t.logger.Error("get tor socks proxy address fail: ", err.Error()) + return } if len(info) != 1 || info[0].Key != "net/listeners/socks" { - return E.New("get socks proxy address") + t.logger.Error("get socks proxy address") + return } t.logger.Trace("obtained tor socks5 address ", info[0].Val) // TODO: set password for tor socks5 server if supported t.socksClient = socks.NewClient(N.SystemDialer, M.ParseSocksaddr(info[0].Val), socks.Version5, "", "") - return nil + t.isReady.Store(true) + t.logger.Info("tor is ready") } func (t *Tor) recvLoop() { @@ -196,6 +210,9 @@ func (t *Tor) Close() error { func (t *Tor) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { t.logger.InfoContext(ctx, "outbound connection to ", destination) + if !t.isReady.Load() { + return nil, E.New("tor is not ready") + } return t.socksClient.DialContext(ctx, network, destination) }