forked from openprivacy/libricochet-go
Compare commits
20 Commits
Author | SHA1 | Date |
---|---|---|
Sarah Jamie Lewis | f82c2f9da4 | |
Dan Ballard | 7c828d3916 | |
Dan Ballard | 79a1ff9161 | |
Sarah Jamie Lewis | 5a1fc1b94d | |
Dan Ballard | 9ba39b93b7 | |
Sarah Jamie Lewis | 29540dcf71 | |
Dan Ballard | 0fdcfd1553 | |
Dan Ballard | ac4993adb7 | |
Dan Ballard | 881ca5c6c2 | |
Dan Ballard | 61f89d7b2c | |
Sarah Jamie Lewis | 725f64020a | |
Dan Ballard | b7cca3fa83 | |
Sarah Jamie Lewis | 07747c4dd2 | |
Dan Ballard | 59ea2902e8 | |
Sarah Jamie Lewis | 4ccdc79526 | |
Dan Ballard | 6517665498 | |
Sarah Jamie Lewis | cd872e9e0a | |
Dan Ballard | b534ecd04e | |
Sarah Jamie Lewis | aca0f63dd2 | |
Dan Ballard | bf57db657a |
14
.drone.yml
14
.drone.yml
|
@ -5,27 +5,35 @@ workspace:
|
||||||
pipeline:
|
pipeline:
|
||||||
fetch:
|
fetch:
|
||||||
image: golang
|
image: golang
|
||||||
|
environment:
|
||||||
|
- GO111MODULE=on
|
||||||
commands:
|
commands:
|
||||||
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/tor
|
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/tor
|
||||||
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/torrc
|
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/torrc
|
||||||
- chmod a+x tor
|
- chmod a+x tor
|
||||||
- go list ./... | xargs go get
|
- go get -u golang.org/x/lint/golint
|
||||||
- go get -u github.com/golang/lint/golint
|
- go mod download
|
||||||
quality:
|
quality:
|
||||||
image: golang
|
image: golang
|
||||||
|
environment:
|
||||||
|
- GO111MODULE=on
|
||||||
commands:
|
commands:
|
||||||
- go list ./... | xargs go vet
|
- go list ./... | xargs go vet
|
||||||
- go list ./... | grep -v "/wire/" | xargs golint -set_exit_status
|
- go list ./... | grep -v "/wire/" | xargs golint -set_exit_status
|
||||||
units-tests:
|
units-tests:
|
||||||
image: golang
|
image: golang
|
||||||
|
environment:
|
||||||
|
- GO111MODULE=on
|
||||||
commands:
|
commands:
|
||||||
- sh testing/tests.sh
|
- sh testing/tests.sh
|
||||||
integ-test:
|
integ-test:
|
||||||
image: golang
|
image: golang
|
||||||
|
environment:
|
||||||
|
- GO111MODULE=on
|
||||||
commands:
|
commands:
|
||||||
- ./tor -f ./torrc
|
- ./tor -f ./torrc
|
||||||
- sleep 15
|
- sleep 15
|
||||||
- go test -v git.openprivacy.ca/openprivacy/libricochet-go/testing
|
- go test -race -v git.openprivacy.ca/openprivacy/libricochet-go/testing
|
||||||
notify-email:
|
notify-email:
|
||||||
image: drillster/drone-email
|
image: drillster/drone-email
|
||||||
host: build.openprivacy.ca
|
host: build.openprivacy.ca
|
||||||
|
|
|
@ -144,7 +144,9 @@ func (ra *RicochetApplication) Run(ls connectivity.ListenService) {
|
||||||
if !ra.v3identity.Initialized() || ra.contactManager == nil {
|
if !ra.v3identity.Initialized() || ra.contactManager == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ra.lock.Lock()
|
||||||
ra.ls = ls
|
ra.ls = ls
|
||||||
|
ra.lock.Unlock()
|
||||||
var err error
|
var err error
|
||||||
for err == nil {
|
for err == nil {
|
||||||
conn, err := ra.ls.Accept()
|
conn, err := ra.ls.Accept()
|
||||||
|
|
|
@ -32,8 +32,9 @@ type Connection struct {
|
||||||
|
|
||||||
messageBuilder utils.MessageBuilder
|
messageBuilder utils.MessageBuilder
|
||||||
|
|
||||||
closed bool
|
closed bool
|
||||||
closing bool
|
closingLock sync.Mutex
|
||||||
|
closing bool
|
||||||
// This mutex is exclusively for preventing races during blocking
|
// This mutex is exclusively for preventing races during blocking
|
||||||
// interactions with Process; specifically Do and Break. Don't use
|
// interactions with Process; specifically Do and Break. Don't use
|
||||||
// it for anything else. See those functions for an explanation.
|
// it for anything else. See those functions for an explanation.
|
||||||
|
@ -311,6 +312,8 @@ func (rc *Connection) Process(handler Handler) error {
|
||||||
go func() {
|
go func() {
|
||||||
rc.processBlockMutex.Lock()
|
rc.processBlockMutex.Lock()
|
||||||
defer rc.processBlockMutex.Unlock()
|
defer rc.processBlockMutex.Unlock()
|
||||||
|
rc.closingLock.Lock()
|
||||||
|
defer rc.closingLock.Unlock()
|
||||||
rc.closed = true
|
rc.closed = true
|
||||||
close(closedChan)
|
close(closedChan)
|
||||||
}()
|
}()
|
||||||
|
@ -468,5 +471,7 @@ func (rc *Connection) Close() {
|
||||||
// Kill the Ricochet Connection.
|
// Kill the Ricochet Connection.
|
||||||
log.Debugf("Closing Ricochet Connection for %v", rc.RemoteHostname)
|
log.Debugf("Closing Ricochet Connection for %v", rc.RemoteHostname)
|
||||||
rc.conn.Close()
|
rc.conn.Close()
|
||||||
|
rc.closingLock.Lock()
|
||||||
rc.closed = true
|
rc.closed = true
|
||||||
|
rc.closingLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,9 @@ func TestProcessAuthAs3DHServer(t *testing.T) {
|
||||||
t.Errorf("Error while testing ProcessAuthAsServer: %v", err)
|
t.Errorf("Error while testing ProcessAuthAsServer: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for server to finish
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
|
||||||
// Test Close
|
// Test Close
|
||||||
rc.Close()
|
rc.Close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,11 @@ type ACN interface {
|
||||||
GetBootstrapStatus() (int, string)
|
GetBootstrapStatus() (int, string)
|
||||||
// WaitTillBootstrapped Blocks until underlying network is bootstrapped
|
// WaitTillBootstrapped Blocks until underlying network is bootstrapped
|
||||||
WaitTillBootstrapped()
|
WaitTillBootstrapped()
|
||||||
|
// Sets the calback function to be called when ACN status changes
|
||||||
|
SetStatusCallback(callback func(int, string))
|
||||||
|
|
||||||
|
// Restarts the underlying connection
|
||||||
|
Restart()
|
||||||
|
|
||||||
// Open takes a hostname and returns a net.conn to the derived endpoint
|
// Open takes a hostname and returns a net.conn to the derived endpoint
|
||||||
// Open allows a client to resolve various hostnames to connections
|
// Open allows a client to resolve various hostnames to connections
|
||||||
|
|
|
@ -34,6 +34,10 @@ func (lp *localProvider) GetBootstrapStatus() (int, string) {
|
||||||
return 100, "Done"
|
return 100, "Done"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lp *localProvider) SetStatusCallback(callback func(int, string)) {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
|
||||||
// WaitTillBootstrapped Blocks until underlying network is bootstrapped
|
// WaitTillBootstrapped Blocks until underlying network is bootstrapped
|
||||||
func (lp *localProvider) WaitTillBootstrapped() {
|
func (lp *localProvider) WaitTillBootstrapped() {
|
||||||
}
|
}
|
||||||
|
@ -59,6 +63,10 @@ func (lp *localProvider) Open(hostname string) (net.Conn, string, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lp *localProvider) Restart() {
|
||||||
|
//noop
|
||||||
|
}
|
||||||
|
|
||||||
func (lp *localProvider) Close() {
|
func (lp *localProvider) Close() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package connectivity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sysProcAttr = &syscall.SysProcAttr{}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package connectivity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
|
@ -1,10 +1,12 @@
|
||||||
package connectivity
|
package connectivity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
||||||
"github.com/cretz/bine/control"
|
"github.com/cretz/bine/control"
|
||||||
|
"github.com/cretz/bine/process"
|
||||||
"github.com/cretz/bine/tor"
|
"github.com/cretz/bine/tor"
|
||||||
bineed255192 "github.com/cretz/bine/torutil/ed25519"
|
bineed255192 "github.com/cretz/bine/torutil/ed25519"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
|
@ -30,6 +32,11 @@ const (
|
||||||
CannotDialRicochetAddressError = utils.Error("CannotDialRicochetAddressError")
|
CannotDialRicochetAddressError = utils.Error("CannotDialRicochetAddressError")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minStatusIntervalMs = 200
|
||||||
|
maxStatusIntervalMs = 2000
|
||||||
|
)
|
||||||
|
|
||||||
type onionListenService struct {
|
type onionListenService struct {
|
||||||
os *tor.OnionService
|
os *tor.OnionService
|
||||||
tp *torProvider
|
tp *torProvider
|
||||||
|
@ -37,11 +44,13 @@ type onionListenService struct {
|
||||||
|
|
||||||
type torProvider struct {
|
type torProvider struct {
|
||||||
t *tor.Tor
|
t *tor.Tor
|
||||||
|
dialer *tor.Dialer
|
||||||
appDirectory string
|
appDirectory string
|
||||||
bundeledTorPath string
|
bundeledTorPath string
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
breakChan chan bool
|
breakChan chan bool
|
||||||
childListeners map[string]*onionListenService
|
childListeners map[string]*onionListenService
|
||||||
|
statusCallback func(int, string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ols *onionListenService) AddressFull() string {
|
func (ols *onionListenService) AddressFull() string {
|
||||||
|
@ -61,14 +70,14 @@ func (ols *onionListenService) Close() {
|
||||||
ols.os.Close()
|
ols.os.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
|
// GetBootstrapStatus returns an int -1 on error or 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
|
||||||
func (tp *torProvider) GetBootstrapStatus() (int, string) {
|
func (tp *torProvider) GetBootstrapStatus() (int, string) {
|
||||||
if tp.t == nil {
|
if tp.t == nil {
|
||||||
return 0, "error: no tor, trying to restart..."
|
return -1, "error: no tor, trying to restart..."
|
||||||
}
|
}
|
||||||
kvs, err := tp.t.Control.GetInfo("status/bootstrap-phase")
|
kvs, err := tp.t.Control.GetInfo("status/bootstrap-phase")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, "error"
|
return -1, "error"
|
||||||
}
|
}
|
||||||
progress := 0
|
progress := 0
|
||||||
status := ""
|
status := ""
|
||||||
|
@ -103,6 +112,9 @@ func (tp *torProvider) Listen(identity PrivateKey, port int) (ListenService, err
|
||||||
var onion = ""
|
var onion = ""
|
||||||
var privkey ed25519.PrivateKey
|
var privkey ed25519.PrivateKey
|
||||||
|
|
||||||
|
tp.lock.Lock()
|
||||||
|
defer tp.lock.Unlock()
|
||||||
|
|
||||||
if tp.t == nil {
|
if tp.t == nil {
|
||||||
return nil, errors.New("Tor Provider closed")
|
return nil, errors.New("Tor Provider closed")
|
||||||
}
|
}
|
||||||
|
@ -125,14 +137,8 @@ func (tp *torProvider) Listen(identity PrivateKey, port int) (ListenService, err
|
||||||
localport += 1024
|
localport += 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
if tp.t == nil {
|
|
||||||
return nil, errors.New("Tor is offline")
|
|
||||||
}
|
|
||||||
|
|
||||||
localListener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(localport))
|
localListener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(localport))
|
||||||
|
|
||||||
tp.lock.Lock()
|
|
||||||
defer tp.lock.Unlock()
|
|
||||||
conf := &tor.ListenConf{NoWait: true, Version3: true, Key: identity, RemotePorts: []int{port}, Detach: true, DiscardKey: true, LocalListener: localListener}
|
conf := &tor.ListenConf{NoWait: true, Version3: true, Key: identity, RemotePorts: []int{port}, Detach: true, DiscardKey: true, LocalListener: localListener}
|
||||||
os, err := tp.t.Listen(nil, conf)
|
os, err := tp.t.Listen(nil, conf)
|
||||||
if err != nil && strings.Contains(err.Error(), "550 Unspecified Tor error: Onion address collision") {
|
if err != nil && strings.Contains(err.Error(), "550 Unspecified Tor error: Onion address collision") {
|
||||||
|
@ -151,30 +157,29 @@ func (tp *torProvider) Listen(identity PrivateKey, port int) (ListenService, err
|
||||||
return ols, nil
|
return ols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tp *torProvider) Restart() {
|
||||||
|
if tp.statusCallback != nil {
|
||||||
|
tp.statusCallback(0, "rebooting")
|
||||||
|
}
|
||||||
|
tp.restart()
|
||||||
|
}
|
||||||
|
|
||||||
func (tp *torProvider) Open(hostname string) (net.Conn, string, error) {
|
func (tp *torProvider) Open(hostname string) (net.Conn, string, error) {
|
||||||
tp.lock.Lock()
|
tp.lock.Lock()
|
||||||
defer tp.lock.Unlock()
|
|
||||||
|
|
||||||
if tp.t == nil {
|
if tp.t == nil {
|
||||||
|
tp.lock.Unlock()
|
||||||
return nil, hostname, errors.New("Tor is offline")
|
return nil, hostname, errors.New("Tor is offline")
|
||||||
}
|
}
|
||||||
torDailer, err := tp.t.Dialer(nil, &tor.DialConf{})
|
tp.lock.Unlock()
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
resolvedHostname := hostname
|
resolvedHostname := hostname
|
||||||
if strings.HasPrefix(hostname, "ricochet:") {
|
if strings.HasPrefix(hostname, "ricochet:") {
|
||||||
addrParts := strings.Split(hostname, ":")
|
addrParts := strings.Split(hostname, ":")
|
||||||
resolvedHostname = addrParts[1]
|
resolvedHostname = addrParts[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := torDailer.Dial("tcp", resolvedHostname+".onion:9878")
|
conn, err := tp.dialer.Dial("tcp", resolvedHostname+".onion:9878")
|
||||||
// if there was an error, we may have been cycling too fast
|
|
||||||
// clear the tor cache and try one more time
|
|
||||||
if err != nil {
|
|
||||||
tp.t.Control.Signal("NEWNYM")
|
|
||||||
conn, err = torDailer.Dial("tcp", resolvedHostname+".onion:9878")
|
|
||||||
}
|
|
||||||
return conn, resolvedHostname, err
|
return conn, resolvedHostname, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,11 +197,39 @@ func (tp *torProvider) Close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tp *torProvider) SetStatusCallback(callback func(int, string)) {
|
||||||
|
tp.lock.Lock()
|
||||||
|
defer tp.lock.Unlock()
|
||||||
|
tp.statusCallback = callback
|
||||||
|
}
|
||||||
|
|
||||||
// StartTor creates/starts a Tor ACN and returns a usable ACN object
|
// StartTor creates/starts a Tor ACN and returns a usable ACN object
|
||||||
func StartTor(appDirectory string, bundledTorPath string) (ACN, error) {
|
func StartTor(appDirectory string, bundledTorPath string) (ACN, error) {
|
||||||
|
tp, err := startTor(appDirectory, bundledTorPath)
|
||||||
|
if err == nil {
|
||||||
|
tp.dialer, err = tp.t.Dialer(nil, &tor.DialConf{})
|
||||||
|
if err == nil {
|
||||||
|
go tp.monitorRestart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// newHideCmd creates a Creator function for bine which generates a cmd that one windows will hide the dosbox
|
||||||
|
func newHideCmd(exePath string) process.Creator {
|
||||||
|
return process.CmdCreatorFunc(func(ctx context.Context, args ...string) (*exec.Cmd, error) {
|
||||||
|
cmd := exec.CommandContext(ctx, exePath, args...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.SysProcAttr = sysProcAttr
|
||||||
|
return cmd, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTor(appDirectory string, bundledTorPath string) (*torProvider, error) {
|
||||||
dataDir := path.Join(appDirectory, "tor")
|
dataDir := path.Join(appDirectory, "tor")
|
||||||
os.MkdirAll(dataDir, 0700)
|
os.MkdirAll(dataDir, 0700)
|
||||||
tp := &torProvider{appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool)}
|
tp := &torProvider{appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool), statusCallback: nil}
|
||||||
|
|
||||||
// attempt connect to system tor
|
// attempt connect to system tor
|
||||||
log.Debugf("dialing system tor control port\n")
|
log.Debugf("dialing system tor control port\n")
|
||||||
|
@ -211,7 +244,6 @@ func StartTor(appDirectory string, bundledTorPath string) (ACN, error) {
|
||||||
if err == nil && minTorVersionReqs(pinfo.TorVersion) {
|
if err == nil && minTorVersionReqs(pinfo.TorVersion) {
|
||||||
log.Debugln("OK version " + pinfo.TorVersion)
|
log.Debugln("OK version " + pinfo.TorVersion)
|
||||||
tp.t = createFromExisting(controlport, dataDir)
|
tp.t = createFromExisting(controlport, dataDir)
|
||||||
go tp.monitorRestart()
|
|
||||||
return tp, nil
|
return tp, nil
|
||||||
}
|
}
|
||||||
controlport.Close()
|
controlport.Close()
|
||||||
|
@ -220,10 +252,9 @@ func StartTor(appDirectory string, bundledTorPath string) (ACN, error) {
|
||||||
|
|
||||||
// if not, try running system tor
|
// if not, try running system tor
|
||||||
if checkCmdlineTorVersion("tor") {
|
if checkCmdlineTorVersion("tor") {
|
||||||
t, err := tor.Start(nil, &tor.StartConf{EnableNetwork: true, DataDir: dataDir, DebugWriter: nil})
|
t, err := tor.Start(nil, &tor.StartConf{EnableNetwork: true, DataDir: dataDir, DebugWriter: nil, ProcessCreator: newHideCmd("tor")})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tp.t = t
|
tp.t = t
|
||||||
go tp.monitorRestart()
|
|
||||||
return tp, nil
|
return tp, nil
|
||||||
}
|
}
|
||||||
log.Debugf("Error connecting to self-run system tor: %v\n", err)
|
log.Debugf("Error connecting to self-run system tor: %v\n", err)
|
||||||
|
@ -232,14 +263,11 @@ func StartTor(appDirectory string, bundledTorPath string) (ACN, error) {
|
||||||
// try running bundledTor
|
// try running bundledTor
|
||||||
if bundledTorPath != "" && checkCmdlineTorVersion(bundledTorPath) {
|
if bundledTorPath != "" && checkCmdlineTorVersion(bundledTorPath) {
|
||||||
log.Debugln("using bundled tor '" + bundledTorPath + "'")
|
log.Debugln("using bundled tor '" + bundledTorPath + "'")
|
||||||
t, err := tor.Start(nil, &tor.StartConf{EnableNetwork: true, DataDir: dataDir, ExePath: bundledTorPath, DebugWriter: nil})
|
t, err := tor.Start(nil, &tor.StartConf{EnableNetwork: true, DataDir: dataDir, ExePath: bundledTorPath, DebugWriter: nil, ProcessCreator: newHideCmd(bundledTorPath)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("Error running bundled tor: %v\n", err)
|
log.Debugf("Error running bundled tor: %v\n", err)
|
||||||
}
|
}
|
||||||
tp.t = t
|
tp.t = t
|
||||||
if err == nil {
|
|
||||||
go tp.monitorRestart()
|
|
||||||
}
|
|
||||||
return tp, err
|
return tp, err
|
||||||
}
|
}
|
||||||
return nil, errors.New("Could not connect to or start Tor that met requirments (min Tor version 0.3.5.x)")
|
return nil, errors.New("Could not connect to or start Tor that met requirments (min Tor version 0.3.5.x)")
|
||||||
|
@ -252,41 +280,56 @@ func (tp *torProvider) unregisterListener(id string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *torProvider) monitorRestart() {
|
func (tp *torProvider) monitorRestart() {
|
||||||
|
lastBootstrapProgress := 0
|
||||||
|
interval := minStatusIntervalMs
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Duration(30 * time.Second)):
|
case <-time.After(time.Millisecond * time.Duration(interval)):
|
||||||
tp.lock.Lock()
|
prog, status := tp.GetBootstrapStatus()
|
||||||
if tp.t != nil {
|
|
||||||
_, err := tp.t.Control.GetInfo("version")
|
|
||||||
|
|
||||||
if err != nil {
|
if prog == -1 && tp.t != nil {
|
||||||
tp.lock.Unlock()
|
if tp.statusCallback != nil {
|
||||||
for _, child := range tp.childListeners {
|
tp.statusCallback(prog, status)
|
||||||
child.Close()
|
}
|
||||||
}
|
tp.restart()
|
||||||
tp.lock.Lock()
|
interval = minStatusIntervalMs
|
||||||
tp.t.Close()
|
} else if prog != lastBootstrapProgress {
|
||||||
tp.t = nil
|
if tp.statusCallback != nil {
|
||||||
|
tp.statusCallback(prog, status)
|
||||||
|
}
|
||||||
|
interval = minStatusIntervalMs
|
||||||
|
} else {
|
||||||
|
if interval < maxStatusIntervalMs {
|
||||||
|
interval *= 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lastBootstrapProgress = prog
|
||||||
if tp.t == nil {
|
|
||||||
newACN, err := StartTor(tp.appDirectory, tp.bundeledTorPath)
|
|
||||||
if err == nil {
|
|
||||||
switch newTp := newACN.(type) {
|
|
||||||
case *torProvider:
|
|
||||||
tp.t = newTp.t
|
|
||||||
// startTor will have started a new monitorRestart thread
|
|
||||||
tp.lock.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tp.lock.Unlock()
|
|
||||||
case <-tp.breakChan:
|
case <-tp.breakChan:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tp *torProvider) restart() {
|
||||||
|
|
||||||
|
for _, child := range tp.childListeners {
|
||||||
|
child.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
tp.lock.Lock()
|
||||||
|
defer tp.lock.Unlock()
|
||||||
|
|
||||||
|
tp.t.Close()
|
||||||
|
tp.t = nil
|
||||||
|
|
||||||
|
for {
|
||||||
|
newTp, err := startTor(tp.appDirectory, tp.bundeledTorPath)
|
||||||
|
if err == nil {
|
||||||
|
tp.t = newTp.t
|
||||||
|
tp.dialer, _ = tp.t.Dialer(nil, &tor.DialConf{})
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +354,7 @@ func createFromExisting(controlport *control.Conn, datadir string) *tor.Tor {
|
||||||
|
|
||||||
func checkCmdlineTorVersion(torCmd string) bool {
|
func checkCmdlineTorVersion(torCmd string) bool {
|
||||||
cmd := exec.Command(torCmd, "--version")
|
cmd := exec.Command(torCmd, "--version")
|
||||||
|
cmd.SysProcAttr = sysProcAttr
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
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(out)
|
sysTorVersion := re.Find(out)
|
||||||
|
|
|
@ -3,21 +3,27 @@ package connectivity
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getStatusCallback(progChan chan int) func(int, string) {
|
||||||
|
return func(prog int, status string) {
|
||||||
|
fmt.Printf("%v %v\n", prog, status)
|
||||||
|
progChan <- prog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTorProvider(t *testing.T) {
|
func TestTorProvider(t *testing.T) {
|
||||||
|
progChan := make(chan int)
|
||||||
acn, err := StartTor(".", "")
|
acn, err := StartTor(".", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
acn.SetStatusCallback(getStatusCallback(progChan))
|
||||||
|
|
||||||
progress := 0
|
progress := 0
|
||||||
status := ""
|
|
||||||
for progress < 100 {
|
for progress < 100 {
|
||||||
progress, status = acn.GetBootstrapStatus()
|
progress = <-progChan
|
||||||
fmt.Printf("%v %v\n", progress, status)
|
|
||||||
time.Sleep(100)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
acn.Close()
|
acn.Close()
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -2,10 +2,12 @@ module git.openprivacy.ca/openprivacy/libricochet-go
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412
|
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412
|
||||||
github.com/cretz/bine v0.1.0
|
github.com/cretz/bine v0.1.1-0.20200124154328-f9f678b84cca
|
||||||
github.com/golang/protobuf v1.2.0
|
github.com/golang/protobuf v1.2.0
|
||||||
github.com/stretchr/testify v1.3.0 // indirect
|
github.com/stretchr/testify v1.3.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b
|
golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b
|
||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -2,6 +2,8 @@ github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7I
|
||||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
||||||
github.com/cretz/bine v0.1.0 h1:1/fvhLE+fk0bPzjdO5Ci+0ComYxEMuB1JhM4X5skT3g=
|
github.com/cretz/bine v0.1.0 h1:1/fvhLE+fk0bPzjdO5Ci+0ComYxEMuB1JhM4X5skT3g=
|
||||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||||
|
github.com/cretz/bine v0.1.1-0.20200124154328-f9f678b84cca h1:Q2r7AxHdJwWfLtBZwvW621M3sPqxPc6ITv2j1FGsYpw=
|
||||||
|
github.com/cretz/bine v0.1.1-0.20200124154328-f9f678b84cca/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||||
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/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
|
|
36
log/log.go
36
log/log.go
|
@ -31,6 +31,7 @@ type Logger struct {
|
||||||
level Level
|
level Level
|
||||||
nothingExceptPatterns []string
|
nothingExceptPatterns []string
|
||||||
everythingFromPatterns []string
|
everythingFromPatterns []string
|
||||||
|
excludeFromPatterns []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Logger with a filter set to the supplied level
|
// New returns a new Logger with a filter set to the supplied level
|
||||||
|
@ -38,8 +39,23 @@ func New(level Level) *Logger {
|
||||||
return &Logger{logger: golog.New(os.Stderr, "", golog.Ldate|golog.Ltime), level: level, everythingFromPatterns: make([]string, 0), nothingExceptPatterns: make([]string, 0)}
|
return &Logger{logger: golog.New(os.Stderr, "", golog.Ldate|golog.Ltime), level: level, everythingFromPatterns: make([]string, 0), nothingExceptPatterns: make([]string, 0)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFile returns a new Logger that logs to the supplied file with a filter set to the supplied level
|
||||||
|
func NewFile(level Level, filename string) (*Logger, error) {
|
||||||
|
logfile, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Logger{logger: golog.New(logfile, "", golog.Ldate|golog.Ltime), level: level, everythingFromPatterns: make([]string, 0), nothingExceptPatterns: make([]string, 0)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
var std = New(LevelWarn)
|
var std = New(LevelWarn)
|
||||||
|
|
||||||
|
// SetStd sets the default logger all other functions use
|
||||||
|
func SetStd(logger *Logger) {
|
||||||
|
std = logger
|
||||||
|
}
|
||||||
|
|
||||||
// filter
|
// filter
|
||||||
func (l *Logger) filter(level Level) bool {
|
func (l *Logger) filter(level Level) bool {
|
||||||
|
|
||||||
|
@ -48,6 +64,12 @@ func (l *Logger) filter(level Level) bool {
|
||||||
file = "???"
|
file = "???"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, pattern := range l.excludeFromPatterns {
|
||||||
|
if strings.Contains(file, pattern) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, pattern := range l.everythingFromPatterns {
|
for _, pattern := range l.everythingFromPatterns {
|
||||||
if strings.Contains(file, pattern) {
|
if strings.Contains(file, pattern) {
|
||||||
return true
|
return true
|
||||||
|
@ -81,11 +103,16 @@ func (l *Logger) AddNothingExceptFilter(pattern string) {
|
||||||
l.nothingExceptPatterns = append(l.nothingExceptPatterns, pattern)
|
l.nothingExceptPatterns = append(l.nothingExceptPatterns, pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEverythingFromPattern adds a pattern to skip log level filtering, guaranteeing all logs matching hte pattern are seen
|
// AddEverythingFromPattern adds a pattern to skip log level filtering, guaranteeing all logs matching the pattern are seen
|
||||||
func (l *Logger) AddEverythingFromPattern(pattern string) {
|
func (l *Logger) AddEverythingFromPattern(pattern string) {
|
||||||
l.everythingFromPatterns = append(l.everythingFromPatterns, pattern)
|
l.everythingFromPatterns = append(l.everythingFromPatterns, pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExcludeFromPattern adds a pattern to exclude logs from
|
||||||
|
func (l *Logger) ExcludeFromPattern(pattern string) {
|
||||||
|
l.excludeFromPatterns = append(l.excludeFromPatterns, pattern)
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Logger) header(level Level) string {
|
func (l *Logger) header(level Level) string {
|
||||||
_, file, _, ok := runtime.Caller(3)
|
_, file, _, ok := runtime.Caller(3)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -131,11 +158,16 @@ func AddNothingExceptFilter(pattern string) {
|
||||||
std.AddNothingExceptFilter(pattern)
|
std.AddNothingExceptFilter(pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEverythingFromPattern adds a pattern to skip log level filtering, guaranteeing all logs matching hte pattern are seen
|
// AddEverythingFromPattern adds a pattern to skip log level filtering, guaranteeing all logs matching the pattern are seen
|
||||||
func AddEverythingFromPattern(pattern string) {
|
func AddEverythingFromPattern(pattern string) {
|
||||||
std.AddEverythingFromPattern(pattern)
|
std.AddEverythingFromPattern(pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExcludeFromPattern adds a pattern to exclude logs from
|
||||||
|
func ExcludeFromPattern(pattern string) {
|
||||||
|
std.ExcludeFromPattern(pattern)
|
||||||
|
}
|
||||||
|
|
||||||
// Printf outputs the format with variables assuming it passes the filter level
|
// Printf outputs the format with variables assuming it passes the filter level
|
||||||
func Printf(level Level, format string, v ...interface{}) {
|
func Printf(level Level, format string, v ...interface{}) {
|
||||||
std.Printf(level, format, v...)
|
std.Printf(level, format, v...)
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
pwd
|
pwd
|
||||||
go test ${1} -coverprofile=model.cover.out -v ./utils
|
GORACE="haltonerror=1"
|
||||||
go test ${1} -coverprofile=channels.cover.out -v ./channels
|
go test -race ${1} -coverprofile=utils.cover.out -v ./utils
|
||||||
go test ${1} -coverprofile=channels.v3.inbound.cover.out -v ./channels/v3/inbound
|
go test -race ${1} -coverprofile=channels.cover.out -v ./channels
|
||||||
go test ${1} -coverprofile=connection.cover.out -v ./connection
|
go test -race ${1} -coverprofile=channels.v3.inbound.cover.out -v ./channels/v3/inbound
|
||||||
go test ${1} -coverprofile=policies.cover.out -v ./policies
|
go test -race ${1} -coverprofile=connection.cover.out -v ./connection
|
||||||
go test ${1} -coverprofile=identity.cover.out -v ./identity
|
go test -race ${1} -coverprofile=policies.cover.out -v ./policies
|
||||||
go test ${1} -coverprofile=root.cover.out -v ./
|
go test -race ${1} -coverprofile=identity.cover.out -v ./identity
|
||||||
|
go test -race ${1} -coverprofile=root.cover.out -v ./
|
||||||
echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \
|
echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \
|
||||||
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out
|
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out
|
||||||
rm -rf *.cover.out
|
rm -rf *.cover.out
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
"golang.org/x/crypto/nacl/secretbox"
|
"golang.org/x/crypto/nacl/secretbox"
|
||||||
"io"
|
"io"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -43,10 +44,13 @@ type RicochetNetwork struct {
|
||||||
// Derived ephemeral session key for connection
|
// Derived ephemeral session key for connection
|
||||||
key [32]byte
|
key [32]byte
|
||||||
encrypt bool
|
encrypt bool
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEncryptionKey sets the ephemeral encryption key for this session.
|
// SetEncryptionKey sets the ephemeral encryption key for this session.
|
||||||
func (rn *RicochetNetwork) SetEncryptionKey(key [32]byte) {
|
func (rn *RicochetNetwork) SetEncryptionKey(key [32]byte) {
|
||||||
|
rn.lock.Lock()
|
||||||
|
defer rn.lock.Unlock()
|
||||||
log.Debugf("turning on ephemeral session encryption for connection")
|
log.Debugf("turning on ephemeral session encryption for connection")
|
||||||
copy(rn.key[:], key[:])
|
copy(rn.key[:], key[:])
|
||||||
|
|
||||||
|
@ -67,6 +71,7 @@ func (rn *RicochetNetwork) SendRicochetPacket(dst io.Writer, channel int32, data
|
||||||
binary.BigEndian.PutUint16(packet[2:4], uint16(channel))
|
binary.BigEndian.PutUint16(packet[2:4], uint16(channel))
|
||||||
copy(packet[4:], data[:])
|
copy(packet[4:], data[:])
|
||||||
|
|
||||||
|
rn.lock.Lock()
|
||||||
if rn.encrypt {
|
if rn.encrypt {
|
||||||
var nonce [24]byte
|
var nonce [24]byte
|
||||||
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
||||||
|
@ -77,6 +82,7 @@ func (rn *RicochetNetwork) SendRicochetPacket(dst io.Writer, channel int32, data
|
||||||
binary.BigEndian.PutUint16(packet[0:2], uint16(len(encrypted)+2))
|
binary.BigEndian.PutUint16(packet[0:2], uint16(len(encrypted)+2))
|
||||||
packet = append(packet[0:2], encrypted...)
|
packet = append(packet[0:2], encrypted...)
|
||||||
}
|
}
|
||||||
|
rn.lock.Unlock()
|
||||||
|
|
||||||
for pos := 0; pos < len(packet); {
|
for pos := 0; pos < len(packet); {
|
||||||
n, err := dst.Write(packet[pos:])
|
n, err := dst.Write(packet[pos:])
|
||||||
|
@ -112,6 +118,7 @@ func (rn *RicochetNetwork) RecvRicochetPacket(reader io.Reader) (RicochetData, e
|
||||||
return packet, err
|
return packet, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rn.lock.Lock()
|
||||||
if rn.encrypt {
|
if rn.encrypt {
|
||||||
var decryptNonce [24]byte
|
var decryptNonce [24]byte
|
||||||
if len(packetBytes) > 24 {
|
if len(packetBytes) > 24 {
|
||||||
|
@ -127,6 +134,7 @@ func (rn *RicochetNetwork) RecvRicochetPacket(reader io.Reader) (RicochetData, e
|
||||||
return packet, errors.New("ciphertext length was too short")
|
return packet, errors.New("ciphertext length was too short")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rn.lock.Unlock()
|
||||||
|
|
||||||
packet.Channel = int32(binary.BigEndian.Uint16(packetBytes[0:2]))
|
packet.Channel = int32(binary.BigEndian.Uint16(packetBytes[0:2]))
|
||||||
packet.Data = make([]byte, len(packetBytes)-2)
|
packet.Data = make([]byte, len(packetBytes)-2)
|
||||||
|
|
Loading…
Reference in New Issue