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 WaitTillBootstrapped() error
// Sets the callback function to be called when ACN status changes // Sets the callback function to be called when ACN status changes
SetStatusCallback(callback func(int, string)) 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 // Restarts the underlying connection
Restart() 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 // 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. // and you need a safe substitute that can later be replaced with a working ACN without impacting calling clients.
type ErrorACN struct { type ErrorACN struct {
statusCallbackCache func(int, string) statusCallbackCache func(int, string)
versionCallbackCache func(string)
} }
func (e ErrorACN) Callback() func(int, string) { func (e ErrorACN) Callback() func(int, string) {
@ -34,6 +35,10 @@ func (e *ErrorACN) SetStatusCallback(callback func(int, string)) {
e.statusCallbackCache = callback e.statusCallbackCache = callback
} }
func (e *ErrorACN) SetVersionCallback(callback func(string)) {
e.versionCallbackCache = callback
}
func (e ErrorACN) Restart() { func (e ErrorACN) Restart() {
} }

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.13
require ( require (
filippo.io/edwards25519 v1.0.0-rc.1 filippo.io/edwards25519 v1.0.0-rc.1
git.openprivacy.ca/openprivacy/bine v0.0.4 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/crypto v0.0.0-20201012173705-84dcc777aaee
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect 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/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 h1:HLP4wsw4ljczFAelYnbObIs821z+jgMPCe8uODPnGQM=
git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw= 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 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= 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 // nop
} }
func (lp *localProvider) SetVersionCallback(callback func(string)) {
// nop
}
func (lp *localProvider) GetPID() (int, error) { func (lp *localProvider) GetPID() (int, error) {
return 0, nil return 0, nil
} }

View File

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

View File

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

View File

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

View File

@ -70,10 +70,12 @@ type torProvider struct {
breakChan chan bool breakChan chan bool
childListeners map[string]*onionListenService childListeners map[string]*onionListenService
statusCallback func(int, string) statusCallback func(int, string)
versionCallback func(string)
lastRestartTime time.Time lastRestartTime time.Time
authenticator tor.Authenticator authenticator tor.Authenticator
isClosed bool isClosed bool
dataDir string dataDir string
version string
} }
func (ols *onionListenService) AddressFull() string { func (ols *onionListenService) AddressFull() string {
@ -209,17 +211,7 @@ func (tp *torProvider) GetBootstrapStatus() (int, string) {
func (tp *torProvider) GetVersion() string { func (tp *torProvider) GetVersion() string {
tp.lock.Lock() tp.lock.Lock()
defer tp.lock.Unlock() defer tp.lock.Unlock()
return tp.version
if tp.t == nil {
return "No Tor"
}
pinfo, err := tp.t.Control.ProtocolInfo()
if err == nil {
return pinfo.TorVersion
}
return "No Tor"
} }
func (tp *torProvider) closed() bool { func (tp *torProvider) closed() bool {
@ -324,6 +316,7 @@ func (tp *torProvider) restart() {
// preserve status callback after shutdown // preserve status callback after shutdown
statusCallback := tp.statusCallback statusCallback := tp.statusCallback
versionCallback := tp.versionCallback
tp.t = nil tp.t = nil
log.Debugf("Restarting Tor Process") log.Debugf("Restarting Tor Process")
@ -334,6 +327,10 @@ func (tp *torProvider) restart() {
tp.t = newTp.t tp.t = newTp.t
tp.dialer = newTp.dialer tp.dialer = newTp.dialer
tp.statusCallback = statusCallback tp.statusCallback = statusCallback
tp.versionCallback = versionCallback
if tp.versionCallback != nil {
tp.versionCallback(tp.version)
}
tp.lastRestartTime = time.Now() tp.lastRestartTime = time.Now()
tp.isClosed = false tp.isClosed = false
go tp.monitorRestart() go tp.monitorRestart()
@ -391,6 +388,12 @@ func (tp *torProvider) SetStatusCallback(callback func(int, string)) {
tp.statusCallback = callback 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) { func (tp *torProvider) Callback() func(int, string) {
tp.lock.Lock() tp.lock.Lock()
defer tp.lock.Unlock() defer tp.lock.Unlock()
@ -399,10 +402,10 @@ func (tp *torProvider) Callback() func(int, string) {
func (tp *torProvider) callStatusCallback(prog int, status string) { func (tp *torProvider) callStatusCallback(prog int, status string) {
tp.lock.Lock() tp.lock.Lock()
defer tp.lock.Unlock()
if tp.statusCallback != nil { if tp.statusCallback != nil {
tp.statusCallback(prog, status) tp.statusCallback(prog, status)
} }
tp.lock.Unlock()
} }
// NewTorACNWithAuth creates/starts a Tor ACN and returns a usable ACN object // 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 // attempt connect to system tor
log.Debugf("dialing tor control port") log.Debugf("dialing tor control port")
controlport, err := dialControlPort(tp.controlPort) controlport, err := dialControlPort(tp.controlPort)
@ -442,13 +445,13 @@ func (tp *torProvider) checkVersion() error {
if err == nil { if err == nil {
if minTorVersionReqs(pinfo.TorVersion) { if minTorVersionReqs(pinfo.TorVersion) {
log.Debugln("OK version " + 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) { 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) 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") 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) controlport, err := dialControlPort(tp.controlPort)
if err == nil { if err == nil {
log.Debugf("creating tor handler from system tor") log.Debugf("creating tor handler from system tor")
@ -476,16 +480,9 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
return nil, err return nil, err
} }
// if not, try running system tor // if not, try bundled tor, then running system tor
log.Debugln("checking if we can run system installed tor or bundled tor") log.Debugln("checking if we can run bundled tor or system installed tor")
if checkCmdlineTorVersion("tor") { if version, pass := checkCmdlineTorVersion(bundledTorPath); 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
} else if bundledTorPath != "" && checkCmdlineTorVersion(bundledTorPath) {
log.Debugln("bundled tor appears viable, attempting to use '" + bundledTorPath + "'") 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)}) 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 { if err != nil {
@ -493,15 +490,25 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
return nil, err return nil, err
} }
tp.t = t 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 { } else {
log.Debugln("Could not find a viable tor running or to run") 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)") 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 { if err == nil {
tp.t.DeleteDataDirOnClose = false // caller is responsible for dealing with cached information... 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.dialer, err = tp.t.Dialer(context.TODO(), &tor.DialConf{Authenticator: tp.authenticator})
tp.version = version
return tp, err return tp, err
} }
return nil, fmt.Errorf("could not connect to running tor: %v", 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 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 // 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 // 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... // and the workout is more complex than just implementing the logic ourselves...
@ -599,13 +609,13 @@ func checkCmdlineTorVersion(torCmd string) bool {
if err != nil { if err != nil {
log.Debugf("tor process timed out") log.Debugf("tor process timed out")
return false return "", false
} }
re := regexp.MustCompile(`[0-1]\.[0-9]\.[0-9]\.[0-9]`) re := regexp.MustCompile(`[0-1]\.[0-9]\.[0-9]\.[0-9]`)
sysTorVersion := re.Find(outb.Bytes()) sysTorVersion := re.Find(outb.Bytes())
log.Infof("tor version: %v", string(sysTorVersion)) 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 // 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) { func TestTorProvider(t *testing.T) {
goRoutineStart := runtime.NumGoroutine() goRoutineStart := runtime.NumGoroutine()
progChan := make(chan int, 10) progChan := make(chan int, 10)
verChan := make(chan string, 10)
log.SetLevel(log.LevelDebug) log.SetLevel(log.LevelDebug)
torpath := path.Join("..", "tmp/tor") torpath := path.Join("..", "tmp/tor")
@ -43,6 +51,7 @@ func TestTorProvider(t *testing.T) {
return return
} }
acn.SetStatusCallback(getStatusCallback(progChan)) acn.SetStatusCallback(getStatusCallback(progChan))
acn.SetVersionCallback(getVersionCallback(verChan))
progress := 0 progress := 0
for progress < 100 { for progress < 100 {
@ -57,6 +66,13 @@ func TestTorProvider(t *testing.T) {
progress = <-progChan progress = <-progChan
t.Logf("progress: %v", progress) 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 // Test opening the OP Server
_, _, err = acn.Open("isbr2t6bflul2zyi6hjtnuezb2xvfr42svzjg2q3gyqfgg3wmnrbkkqd") _, _, err = acn.Open("isbr2t6bflul2zyi6hjtnuezb2xvfr42svzjg2q3gyqfgg3wmnrbkkqd")