|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
package tor
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
@ -333,6 +334,7 @@ func (tp *torProvider) restart() {
|
|
|
|
|
tp.dialer = newTp.dialer
|
|
|
|
|
tp.statusCallback = statusCallback
|
|
|
|
|
tp.lastRestartTime = time.Now()
|
|
|
|
|
tp.isClosed = false
|
|
|
|
|
go tp.monitorRestart()
|
|
|
|
|
} else {
|
|
|
|
|
log.Errorf("Error restarting Tor process: %v", err)
|
|
|
|
@ -368,6 +370,8 @@ func (tp *torProvider) Close() {
|
|
|
|
|
delete(tp.childListeners, addr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Debugf("shutting down acn threads..(is already closed: %v)", tp.isClosed)
|
|
|
|
|
|
|
|
|
|
if !tp.isClosed {
|
|
|
|
|
// Break out of any background checks and close
|
|
|
|
|
// the underlying tor connection
|
|
|
|
@ -404,6 +408,7 @@ func (tp *torProvider) callStatusCallback(prog int, status string) {
|
|
|
|
|
func NewTorACNWithAuth(appDirectory string, bundledTorPath string, dataDir string, controlPort int, authenticator tor.Authenticator) (connectivity.ACN, error) {
|
|
|
|
|
tp, err := startTor(appDirectory, bundledTorPath, dataDir, controlPort, authenticator)
|
|
|
|
|
if err == nil {
|
|
|
|
|
tp.isClosed = false
|
|
|
|
|
go tp.monitorRestart()
|
|
|
|
|
}
|
|
|
|
|
return tp, err
|
|
|
|
@ -450,7 +455,7 @@ 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), 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, lastRestartTime: time.Now().Add(-restartCooldown)}
|
|
|
|
|
|
|
|
|
|
log.Debugf("checking if there is a running system tor")
|
|
|
|
|
if err := tp.checkVersion(); err == nil {
|
|
|
|
@ -494,7 +499,7 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
|
|
|
|
|
|
|
|
|
|
err := tp.checkVersion()
|
|
|
|
|
if err == nil {
|
|
|
|
|
tp.t.DeleteDataDirOnClose = false // caller is repsonsible 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})
|
|
|
|
|
return tp, err
|
|
|
|
|
}
|
|
|
|
@ -567,24 +572,53 @@ func createFromExisting(controlport *control.Conn, datadir string) *tor.Tor {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func checkCmdlineTorVersion(torCmd string) bool {
|
|
|
|
|
// 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...
|
|
|
|
|
cmd := exec.Command(torCmd, "--version")
|
|
|
|
|
cmd.SysProcAttr = sysProcAttr
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
var outb bytes.Buffer
|
|
|
|
|
cmd.Stdout = &outb
|
|
|
|
|
|
|
|
|
|
waiting := make(chan error, 1)
|
|
|
|
|
|
|
|
|
|
// try running the tor process
|
|
|
|
|
go func() {
|
|
|
|
|
log.Debugf("running tor process: %v", torCmd)
|
|
|
|
|
cmd.Run()
|
|
|
|
|
waiting <- nil
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// timeout function
|
|
|
|
|
go func() {
|
|
|
|
|
<-time.After(time.Second * 5)
|
|
|
|
|
waiting <- errors.New("timeout")
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
err := <-waiting
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Debugf("tor process timed out")
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
re := regexp.MustCompile(`[0-1]\.[0-9]\.[0-9]\.[0-9]`)
|
|
|
|
|
sysTorVersion := re.Find(out)
|
|
|
|
|
log.Infoln("tor version: " + string(sysTorVersion))
|
|
|
|
|
return err == nil && minTorVersionReqs(string(sysTorVersion))
|
|
|
|
|
sysTorVersion := re.Find(outb.Bytes())
|
|
|
|
|
log.Infof("tor version: %v", string(sysTorVersion))
|
|
|
|
|
return minTorVersionReqs(string(sysTorVersion))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// returns true if supplied version meets our min requirments
|
|
|
|
|
// min requirement: 0.3.5.x
|
|
|
|
|
func minTorVersionReqs(torversion string) bool {
|
|
|
|
|
torversions := strings.Split(torversion, ".") //eg: 0.3.4.8 or 0.3.5.1-alpha
|
|
|
|
|
log.Debugf("torversions: %v", torversions)
|
|
|
|
|
tva, _ := strconv.Atoi(torversions[0])
|
|
|
|
|
tvb, _ := strconv.Atoi(torversions[1])
|
|
|
|
|
tvc, _ := strconv.Atoi(torversions[2])
|
|
|
|
|
return tva > 0 || (tva == 0 && (tvb > 3 || (tvb == 3 && tvc >= 5)))
|
|
|
|
|
if len(torversions) >= 3 {
|
|
|
|
|
log.Debugf("torversions: %v", torversions)
|
|
|
|
|
tva, _ := strconv.Atoi(torversions[0])
|
|
|
|
|
tvb, _ := strconv.Atoi(torversions[1])
|
|
|
|
|
tvc, _ := strconv.Atoi(torversions[2])
|
|
|
|
|
return tva > 0 || (tva == 0 && (tvb > 3 || (tvb == 3 && tvc >= 5)))
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dialControlPort(port int) (*control.Conn, error) {
|
|
|
|
|