Merge pull request 'add versionCallback and use on reboot tor; change start preference for bundled tor; new go 1.17 build directives' (#31) from versionCallback into master
continuous-integration/drone/push Build is failing Details
continuous-integration/drone/tag Build is passing Details

Reviewed-on: #31
This commit is contained in:
Dan Ballard 2022-08-04 05:15:03 +00:00
commit 882849b66a
10 changed files with 79 additions and 34 deletions

2
acn.go
View File

@ -38,6 +38,8 @@ type ACN interface {
WaitTillBootstrapped() error
// Sets the callback function to be called when ACN status changes
SetStatusCallback(callback func(int, string))
// Sets the callback function to be called when ACN reboots to emit the version
SetVersionCallback(callback func(string))
// Restarts the underlying connection
Restart()

View File

@ -11,7 +11,8 @@ const acnError = "error initializing anonymous communication network"
// ErrorACN - a status-callback safe errored ACN. Use this when ACN construction goes wrong
// and you need a safe substitute that can later be replaced with a working ACN without impacting calling clients.
type ErrorACN struct {
statusCallbackCache func(int, string)
statusCallbackCache func(int, string)
versionCallbackCache func(string)
}
func (e ErrorACN) Callback() func(int, string) {
@ -34,6 +35,10 @@ func (e *ErrorACN) SetStatusCallback(callback func(int, string)) {
e.statusCallbackCache = callback
}
func (e *ErrorACN) SetVersionCallback(callback func(string)) {
e.versionCallbackCache = callback
}
func (e ErrorACN) Restart() {
}

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.13
require (
filippo.io/edwards25519 v1.0.0-rc.1
git.openprivacy.ca/openprivacy/bine v0.0.4
git.openprivacy.ca/openprivacy/log v1.0.2
git.openprivacy.ca/openprivacy/log v1.0.3
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
)

2
go.sum
View File

@ -4,6 +4,8 @@ git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGy
git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
git.openprivacy.ca/openprivacy/log v1.0.2 h1:HLP4wsw4ljczFAelYnbObIs821z+jgMPCe8uODPnGQM=
git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
git.openprivacy.ca/openprivacy/log v1.0.3 h1:E/PMm4LY+Q9s3aDpfySfEDq/vYQontlvNj/scrPaga0=
git.openprivacy.ca/openprivacy/log v1.0.3/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@ -51,6 +51,10 @@ func (lp *localProvider) SetStatusCallback(callback func(int, string)) {
// nop
}
func (lp *localProvider) SetVersionCallback(callback func(string)) {
// nop
}
func (lp *localProvider) GetPID() (int, error) {
return 0, nil
}

View File

@ -49,6 +49,10 @@ func (p *ProxyACN) SetStatusCallback(callback func(int, string)) {
p.acn.SetStatusCallback(callback)
}
func (p *ProxyACN) SetVersionCallback(callback func(string)) {
p.acn.SetVersionCallback(callback)
}
func (p *ProxyACN) Restart() {
p.acn.Restart()
}

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package tor

View File

@ -1,3 +1,4 @@
//go:build windows
// +build windows
package tor

View File

@ -70,10 +70,12 @@ type torProvider struct {
breakChan chan bool
childListeners map[string]*onionListenService
statusCallback func(int, string)
versionCallback func(string)
lastRestartTime time.Time
authenticator tor.Authenticator
isClosed bool
dataDir string
version string
}
func (ols *onionListenService) AddressFull() string {
@ -209,17 +211,7 @@ func (tp *torProvider) GetBootstrapStatus() (int, string) {
func (tp *torProvider) GetVersion() string {
tp.lock.Lock()
defer tp.lock.Unlock()
if tp.t == nil {
return "No Tor"
}
pinfo, err := tp.t.Control.ProtocolInfo()
if err == nil {
return pinfo.TorVersion
}
return "No Tor"
return tp.version
}
func (tp *torProvider) closed() bool {
@ -324,6 +316,7 @@ func (tp *torProvider) restart() {
// preserve status callback after shutdown
statusCallback := tp.statusCallback
versionCallback := tp.versionCallback
tp.t = nil
log.Debugf("Restarting Tor Process")
@ -334,6 +327,10 @@ func (tp *torProvider) restart() {
tp.t = newTp.t
tp.dialer = newTp.dialer
tp.statusCallback = statusCallback
tp.versionCallback = versionCallback
if tp.versionCallback != nil {
tp.versionCallback(tp.version)
}
tp.lastRestartTime = time.Now()
tp.isClosed = false
go tp.monitorRestart()
@ -391,6 +388,12 @@ func (tp *torProvider) SetStatusCallback(callback func(int, string)) {
tp.statusCallback = callback
}
func (tp *torProvider) SetVersionCallback(callback func(string)) {
tp.lock.Lock()
defer tp.lock.Unlock()
tp.versionCallback = callback
}
func (tp *torProvider) Callback() func(int, string) {
tp.lock.Lock()
defer tp.lock.Unlock()
@ -399,10 +402,10 @@ func (tp *torProvider) Callback() func(int, string) {
func (tp *torProvider) callStatusCallback(prog int, status string) {
tp.lock.Lock()
defer tp.lock.Unlock()
if tp.statusCallback != nil {
tp.statusCallback(prog, status)
}
tp.lock.Unlock()
}
// NewTorACNWithAuth creates/starts a Tor ACN and returns a usable ACN object
@ -429,7 +432,7 @@ func newHideCmd(exePath string) process.Creator {
})
}
func (tp *torProvider) checkVersion() error {
func (tp *torProvider) checkVersion() (string, error) {
// attempt connect to system tor
log.Debugf("dialing tor control port")
controlport, err := dialControlPort(tp.controlPort)
@ -442,13 +445,13 @@ func (tp *torProvider) checkVersion() error {
if err == nil {
if minTorVersionReqs(pinfo.TorVersion) {
log.Debugln("OK version " + pinfo.TorVersion)
return nil
return pinfo.TorVersion, nil
}
return fmt.Errorf("tor version not supported: %v", pinfo.TorVersion)
return pinfo.TorVersion, fmt.Errorf("tor version not supported: %v", pinfo.TorVersion)
}
}
}
return err
return "", err
}
func startTor(appDirectory string, bundledTorPath string, dataDir string, controlPort int, authenticator tor.Authenticator) (*torProvider, error) {
@ -456,10 +459,11 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
os.MkdirAll(torDir, 0700)
tp := &torProvider{authenticator: authenticator, controlPort: controlPort, appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool, 1), statusCallback: nil, lastRestartTime: time.Now().Add(-restartCooldown)}
tp := &torProvider{authenticator: authenticator, controlPort: controlPort, appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool, 1), statusCallback: nil, versionCallback: nil, lastRestartTime: time.Now().Add(-restartCooldown)}
log.Debugf("checking if there is a running system tor")
if err := tp.checkVersion(); err == nil {
if version, err := tp.checkVersion(); err == nil {
tp.version = version
controlport, err := dialControlPort(tp.controlPort)
if err == nil {
log.Debugf("creating tor handler from system tor")
@ -476,16 +480,9 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
return nil, err
}
// if not, try running system tor
log.Debugln("checking if we can run system installed tor or bundled tor")
if checkCmdlineTorVersion("tor") {
t, err := tor.Start(context.TODO(), &tor.StartConf{ControlPort: tp.controlPort, DisableCookieAuth: true, UseEmbeddedControlConn: false, DisableEagerAuth: true, EnableNetwork: true, DataDir: dataDir, TorrcFile: path.Join(torDir, "torrc"), DebugWriter: nil, ProcessCreator: newHideCmd("tor")})
if err != nil {
log.Debugf("Error connecting to self-run system tor: %v\n", err)
return nil, err
}
tp.t = t
} else if bundledTorPath != "" && checkCmdlineTorVersion(bundledTorPath) {
// if not, try bundled tor, then running system tor
log.Debugln("checking if we can run bundled tor or system installed tor")
if version, pass := checkCmdlineTorVersion(bundledTorPath); pass {
log.Debugln("bundled tor appears viable, attempting to use '" + bundledTorPath + "'")
t, err := tor.Start(context.TODO(), &tor.StartConf{ControlPort: tp.controlPort, DisableCookieAuth: true, UseEmbeddedControlConn: false, DisableEagerAuth: true, EnableNetwork: true, DataDir: dataDir, TorrcFile: path.Join(torDir, "torrc"), ExePath: bundledTorPath, DebugWriter: nil, ProcessCreator: newHideCmd(bundledTorPath)})
if err != nil {
@ -493,15 +490,25 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
return nil, err
}
tp.t = t
tp.version = version
} else if version, pass := checkCmdlineTorVersion("tor"); pass {
t, err := tor.Start(context.TODO(), &tor.StartConf{ControlPort: tp.controlPort, DisableCookieAuth: true, UseEmbeddedControlConn: false, DisableEagerAuth: true, EnableNetwork: true, DataDir: dataDir, TorrcFile: path.Join(torDir, "torrc"), DebugWriter: nil, ProcessCreator: newHideCmd("tor")})
if err != nil {
log.Debugf("Error connecting to self-run system tor: %v\n", err)
return nil, err
}
tp.t = t
tp.version = version
} else {
log.Debugln("Could not find a viable tor running or to run")
return nil, fmt.Errorf("could not connect to or start Tor that met requirements (min Tor version 0.3.5.x)")
}
err := tp.checkVersion()
version, err := tp.checkVersion()
if err == nil {
tp.t.DeleteDataDirOnClose = false // caller is responsible for dealing with cached information...
tp.dialer, err = tp.t.Dialer(context.TODO(), &tor.DialConf{Authenticator: tp.authenticator})
tp.version = version
return tp, err
}
return nil, fmt.Errorf("could not connect to running tor: %v", err)
@ -572,7 +579,10 @@ func createFromExisting(controlport *control.Conn, datadir string) *tor.Tor {
return t
}
func checkCmdlineTorVersion(torCmd string) bool {
func checkCmdlineTorVersion(torCmd string) (string, bool) {
if torCmd == "" {
return "", false
}
// ideally we would use CommandContext with Timeout here
// but it doesn't work with programs that may launch other processes via scripts e.g. exec
// and the workout is more complex than just implementing the logic ourselves...
@ -599,13 +609,13 @@ func checkCmdlineTorVersion(torCmd string) bool {
if err != nil {
log.Debugf("tor process timed out")
return false
return "", false
}
re := regexp.MustCompile(`[0-1]\.[0-9]\.[0-9]\.[0-9]`)
sysTorVersion := re.Find(outb.Bytes())
log.Infof("tor version: %v", string(sysTorVersion))
return minTorVersionReqs(string(sysTorVersion))
return string(sysTorVersion), minTorVersionReqs(string(sysTorVersion))
}
// returns true if supplied version meets our min requirments

View File

@ -19,11 +19,19 @@ func getStatusCallback(progChan chan int) func(int, string) {
}
}
func getVersionCallback(verChan chan string) func(string) {
return func(version string) {
fmt.Printf("version: %v\n", version)
verChan <- version
}
}
func TestTorProvider(t *testing.T) {
goRoutineStart := runtime.NumGoroutine()
progChan := make(chan int, 10)
verChan := make(chan string, 10)
log.SetLevel(log.LevelDebug)
torpath := path.Join("..", "tmp/tor")
@ -43,6 +51,7 @@ func TestTorProvider(t *testing.T) {
return
}
acn.SetStatusCallback(getStatusCallback(progChan))
acn.SetVersionCallback(getVersionCallback(verChan))
progress := 0
for progress < 100 {
@ -57,6 +66,13 @@ func TestTorProvider(t *testing.T) {
progress = <-progChan
t.Logf("progress: %v", progress)
}
log.Debugf("Pulling tor version from version callback chan...\n")
version := <-verChan
if version == "" {
t.Errorf("failed to get tor version, got empty string\n")
} else {
log.Debugf("Tor version: %v\n", version)
}
// Test opening the OP Server
_, _, err = acn.Open("isbr2t6bflul2zyi6hjtnuezb2xvfr42svzjg2q3gyqfgg3wmnrbkkqd")