Compare commits

..

No commits in common. "master" and "updateDrone" have entirely different histories.

10 changed files with 42 additions and 120 deletions

View File

@ -5,7 +5,7 @@ name: linux-test
steps:
- name: fetch
image: golang:1.19.1
image: golang:1.17.5
volumes:
- name: deps
path: /go
@ -15,14 +15,14 @@ steps:
- chmod a+x tmp/tor
- go mod download
- name: quality
image: golang:1.19.1
image: golang:1.17.5
volumes:
- name: deps
path: /go
commands:
- staticcheck ./...
- name: units-tests
image: golang:1.19.1
image: golang:1.17.5
volumes:
- name: deps
path: /go
@ -33,7 +33,7 @@ steps:
- sh testing/tests.sh
- pkill -9 tor
- name: integration-tests
image: golang:1.19.1
image: golang:1.17.5
volumes:
- name: deps
path: /go

4
.gitignore vendored
View File

@ -4,6 +4,4 @@ tor/tor/
vendor/
*.cover.out
tmp/
testing/tor/*
tor/data-dir*
testing/data-dir*
testing/tor/*

View File

@ -7,12 +7,6 @@ A library providing an ACN (Anonymous Communication Network
* Tor v3 Onion Services
## Environment Variables
- `TOR_LD_LIBRARY_PATH` - override the library path given to the Tor process as different from the one given to the parent process.
- `CWTCH_RESTRICT_PORTS` - forces connectivity to bind to a subset of ports `15000-15378`
- `CWTCH_BIND_EXTERNAL_WHONIX` - forces connectivity to bind to external interfaces (only supported/recommended on certain Whonix-based setups. Please open an issue if you think this should be expanded.)
## Requirements for ACN Support
* Reference an EndPoint via a string / hostname
@ -56,4 +50,4 @@ service:
acn.Restart()
and
acn.Close()
acn.Close()

View File

@ -1,43 +1,38 @@
package connectivity
import (
"errors"
"fmt"
"net"
)
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 {
acnError error
statusCallbackCache func(int, string)
versionCallbackCache func(string)
}
func NewErrorACN(err error) ErrorACN {
return ErrorACN{
acnError: err,
statusCallbackCache: func(int, string) {},
versionCallbackCache: func(string) {},
}
}
func (e *ErrorACN) GetStatusCallback() func(int, string) {
func (e ErrorACN) GetStatusCallback() func(int, string) {
return e.statusCallbackCache
}
func (e *ErrorACN) GetVersionCallback() func(string) {
func (e ErrorACN) GetVersionCallback() func(string) {
return e.versionCallbackCache
}
func (e *ErrorACN) GetInfo(addr string) (map[string]string, error) {
return nil, e.acnError
return nil, errors.New(acnError)
}
func (e *ErrorACN) GetBootstrapStatus() (int, string) {
return -1, e.acnError.Error()
func (e ErrorACN) GetBootstrapStatus() (int, string) {
return -1, acnError
}
func (e *ErrorACN) WaitTillBootstrapped() error {
return e.acnError
func (e ErrorACN) WaitTillBootstrapped() error {
return errors.New(acnError)
}
func (e *ErrorACN) SetStatusCallback(callback func(int, string)) {
@ -48,25 +43,24 @@ func (e *ErrorACN) SetVersionCallback(callback func(string)) {
e.versionCallbackCache = callback
}
func (e *ErrorACN) Restart() {
func (e ErrorACN) Restart() {
}
func (e *ErrorACN) Open(hostname string) (net.Conn, string, error) {
return nil, "", e.acnError
func (e ErrorACN) Open(hostname string) (net.Conn, string, error) {
return nil, "", fmt.Errorf(acnError)
}
func (e *ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) {
return nil, e.acnError
func (e ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) {
return nil, fmt.Errorf(acnError)
}
func (e *ErrorACN) GetPID() (int, error) {
return -1, e.acnError
func (e ErrorACN) GetPID() (int, error) {
return -1, fmt.Errorf(acnError)
}
func (e *ErrorACN) GetVersion() string {
return e.acnError.Error()
func (e ErrorACN) GetVersion() string {
return acnError
}
func (e *ErrorACN) Close() {
// nothing to do...
func (e ErrorACN) Close() {
}

2
go.mod
View File

@ -4,7 +4,7 @@ go 1.17
require (
filippo.io/edwards25519 v1.0.0
git.openprivacy.ca/openprivacy/bine v0.0.5
git.openprivacy.ca/openprivacy/bine v0.0.4
git.openprivacy.ca/openprivacy/log v1.0.3
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d
)

4
go.sum
View File

@ -1,7 +1,7 @@
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
git.openprivacy.ca/openprivacy/bine v0.0.5 h1:DJs5gqw3SkvLSgRDvroqJxZ7F+YsbxbBRg5t0rU5gYE=
git.openprivacy.ca/openprivacy/bine v0.0.5/go.mod h1:fwdeq6RO08WDkV0k7HfArsjRvurVULoUQmT//iaABZM=
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c=
git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
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=

View File

@ -3,6 +3,7 @@ package testing
import (
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
"io/ioutil"
"math/rand"
"os"
path "path/filepath"
@ -29,7 +30,7 @@ func TestLaunchTor(t *testing.T) {
}
dataDir := ""
if dataDir, err = os.MkdirTemp(path.Join("..", "testing"), "data-dir-"); err != nil {
if dataDir, err = ioutil.TempDir(path.Join("..", "testing"), "data-dir-"); err != nil {
t.Fatalf("could not create data dir")
}

View File

@ -170,9 +170,8 @@ var progRe = regexp.MustCompile("PROGRESS=([0-9]*)")
var sumRe = regexp.MustCompile("SUMMARY=\"(.*)\"$")
// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message
//
// returns -1 on network disconnected
// returns -2 on error
// returns -1 on network disconnected
// returns -2 on error
func (tp *torProvider) GetBootstrapStatus() (int, string) {
tp.lock.Lock()
defer tp.lock.Unlock()
@ -268,28 +267,7 @@ func (tp *torProvider) Listen(identity connectivity.PrivateKey, port int) (conne
localport += 1024
}
var localListener net.Listener
var err error
if cwtchRestrictPorts := os.Getenv("CWTCH_RESTRICT_PORTS"); strings.ToLower(cwtchRestrictPorts) == "true" {
// for whonix like systems we tightly restrict possible listen...
// pick a random port between 15000 and 15378
// cwtch = 63 *77 *74* 63* 68 = 1537844616
log.Infof("using restricted ports, CWTCH_RESTRICT_PORTS=true");
localport = 15000 + (localport % 378)
}
if bindExternal := os.Getenv("CWTCH_BIND_EXTERNAL_WHONIX"); strings.ToLower(bindExternal) == "true" {
if _, ferr := os.Stat("/usr/share/anon-ws-base-files/workstation"); !os.IsNotExist(ferr) {
log.Infof("WARNING: binding to external interfaces. This is potentially unsafe outside of a containerized environment.");
localListener, err = net.Listen("tcp", "0.0.0.0:"+strconv.Itoa(localport))
} else {
log.Errorf("CWTCH_BIND_EXTERNAL_WHONIX flag set, but /usr/share/anon-ws-base-files/workstation does not exist. Defaulting to binding to local ports");
localListener, err = net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(localport))
}
} else {
localListener, err = net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(localport))
}
localListener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(localport))
if err != nil {
return nil, err
@ -311,8 +289,6 @@ func (tp *torProvider) Listen(identity connectivity.PrivateKey, port int) (conne
return nil, err
}
// We need to set os.ID here, otherwise os.Close() may not shut down the onion service properly...
os.ID = onion
os.CloseLocalListenerOnClose = true
ols := &onionListenService{os: os, tp: tp}
@ -470,14 +446,6 @@ func newHideCmd(exePath string) process.Creator {
cmd.Stdout = loggerDebug
cmd.Stderr = loggerError
cmd.SysProcAttr = sysProcAttr
// override tor ld_library_path if requested
torLdLibPath, exists := os.LookupEnv("TOR_LD_LIBRARY_PATH")
if exists {
ldLibPath := fmt.Sprintf("LD_LIBRARY_PATH=%v", torLdLibPath)
cmd.Env = append([]string{ldLibPath}, os.Environ()...)
}
return cmd, nil
})
}
@ -518,9 +486,9 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
if err == nil {
log.Debugf("creating tor handler from system tor")
tp.t = createFromExisting(controlport, dataDir)
tp.dialer, err = tp.t.Dialer(context.TODO(), &tor.DialConf{Authenticator: tp.authenticator})
return tp, err
}
tp.dialer, err = tp.t.Dialer(context.TODO(), &tor.DialConf{Authenticator: tp.authenticator})
return tp, err
}
// check if the torrc file is present where expected
@ -559,7 +527,6 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
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
tp.t.Control.TakeOwnership()
return tp, err
}
return nil, fmt.Errorf("could not connect to running tor: %v", err)

View File

@ -3,6 +3,7 @@ package tor
import (
"fmt"
"git.openprivacy.ca/openprivacy/log"
"io/ioutil"
"os"
path "path/filepath"
"runtime"
@ -40,7 +41,7 @@ func TestTorProvider(t *testing.T) {
dataDir := ""
var err error
if dataDir, err = os.MkdirTemp(path.Join("..", "testing"), "data-dir-"); err != nil {
if dataDir, err = ioutil.TempDir(path.Join("..", "testing"), "data-dir-"); err != nil {
t.Fatalf("could not create data dir")
}

View File

@ -6,18 +6,10 @@ import (
"encoding/hex"
"fmt"
"io"
"os"
"io/ioutil"
"strings"
)
type TorLogLevel string
const TorLogLevelDebug TorLogLevel = "debug"
const TorLogLevelNotice TorLogLevel = "notice"
const TorLogLevelInfo TorLogLevel = "info"
const TorLogLevelWarn TorLogLevel = "warn"
const TorLogLevelErr TorLogLevel = "err"
// TorrcBuilder is a a helper for building torrc files
type TorrcBuilder struct {
lines []string
@ -42,28 +34,9 @@ func (tb *TorrcBuilder) WithControlPort(port int) *TorrcBuilder {
return tb
}
// WithLog sets the Log to file directive to the specified file with the specified log level
func (tb *TorrcBuilder) WithLog(logfile string, level TorLogLevel) *TorrcBuilder {
tb.lines = append(tb.lines, fmt.Sprintf("Log %v file %v", level, logfile))
return tb
}
// WithSocksTimeout adjusts how long before a timeout error is generated trying to connect to the SOCKS port
func (tb *TorrcBuilder) WithSocksTimeout(timeOutSecs int) *TorrcBuilder {
tb.lines = append(tb.lines, fmt.Sprintf("SocksTimeout %v", timeOutSecs))
return tb
}
// WithCustom appends to the torrc builder and allows the client to set any option they want, while benefiting
// WithCustom clobbers the torrc builder and allows the client to set any option they want, while benefiting
// from other configuration options.
func (tb *TorrcBuilder) WithCustom(lines []string) *TorrcBuilder {
tb.lines = append(tb.lines, lines...)
return tb
}
// UseCustom clobbers the torrc builder and allows the client to set any option they want, while benefiting
// from other configuration options.
func (tb *TorrcBuilder) UseCustom(lines []string) *TorrcBuilder {
tb.lines = lines
return tb
}
@ -79,12 +52,6 @@ func (tb *TorrcBuilder) WithOnionTrafficOnly() *TorrcBuilder {
return tb
}
// WithOwningPid adds a __OwningControllerProcess line to the config that will attempt to have tor monitor parent PID health and die when parent dies
func (tb *TorrcBuilder) WithOwningPid(pid int) *TorrcBuilder {
tb.lines = append(tb.lines, fmt.Sprintf("__OwningControllerProcess %v", pid))
return tb
}
// WithHashedPassword sets a password for the control port.
func (tb *TorrcBuilder) WithHashedPassword(password string) *TorrcBuilder {
var salt [8]byte
@ -98,7 +65,7 @@ func (tb *TorrcBuilder) WithHashedPassword(password string) *TorrcBuilder {
// Build finalizes the torrc contents and write a file
func (tb *TorrcBuilder) Build(path string) error {
return os.WriteFile(path, []byte(strings.Join(tb.lines, "\n")), 0600)
return ioutil.WriteFile(path, []byte(strings.Join(tb.lines, "\n")), 0600)
}
// Preview provides a string representation of the torrc file without writing it to a file location.