Compare commits
No commits in common. "master" and "v1.7.0" have entirely different histories.
93
.drone.yml
93
.drone.yml
|
@ -1,76 +1,63 @@
|
||||||
---
|
workspace:
|
||||||
kind: pipeline
|
base: /go
|
||||||
type: docker
|
path: src/git.openprivacy.ca/openprivacy/connectivity
|
||||||
name: linux-test
|
|
||||||
|
|
||||||
steps:
|
pipeline:
|
||||||
- name: fetch
|
fetch:
|
||||||
image: golang:1.19.1
|
when:
|
||||||
volumes:
|
repo: openprivacy/connectivity
|
||||||
- name: deps
|
branch: master
|
||||||
path: /go
|
event: [ push, pull_request ]
|
||||||
|
image: golang
|
||||||
commands:
|
commands:
|
||||||
- go install honnef.co/go/tools/cmd/staticcheck@latest
|
- go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||||
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/tor -P tmp/
|
- wget https://git.openprivacy.ca/openprivacy/buildfiles/raw/master/tor/tor -P tmp/
|
||||||
- chmod a+x tmp/tor
|
- chmod a+x tmp/tor
|
||||||
- go mod download
|
- go mod download
|
||||||
- name: quality
|
quality:
|
||||||
image: golang:1.19.1
|
when:
|
||||||
volumes:
|
repo: openprivacy/connectivity
|
||||||
- name: deps
|
branch: master
|
||||||
path: /go
|
event: [ push, pull_request ]
|
||||||
|
image: golang
|
||||||
commands:
|
commands:
|
||||||
- staticcheck ./...
|
- staticcheck ./...
|
||||||
- name: units-tests
|
units-tests:
|
||||||
image: golang:1.19.1
|
when:
|
||||||
volumes:
|
repo: openprivacy/connectivity
|
||||||
- name: deps
|
branch: master
|
||||||
path: /go
|
event: [ push, pull_request ]
|
||||||
|
image: golang
|
||||||
commands:
|
commands:
|
||||||
- export PATH=`pwd`:$PATH
|
- export PATH=$PATH:/go/src/git.openprivacy.ca/openprivacy/connectivity
|
||||||
- ./tmp/tor -f ./testing/torrc
|
- ./tmp/tor -f ./testing/torrc
|
||||||
- sleep 15
|
- sleep 15
|
||||||
- sh testing/tests.sh
|
- sh testing/tests.sh
|
||||||
- pkill -9 tor
|
- pkill -9 tor
|
||||||
- name: integration-tests
|
integration-tests:
|
||||||
image: golang:1.19.1
|
when:
|
||||||
volumes:
|
repo: openprivacy/connectivity
|
||||||
- name: deps
|
branch: master
|
||||||
path: /go
|
event: [ push, pull_request ]
|
||||||
|
image: golang
|
||||||
commands:
|
commands:
|
||||||
- export PATH=`pwd`:$PATH
|
|
||||||
- go test -race -v ./testing/launch_tor_integration_test.go
|
- go test -race -v ./testing/launch_tor_integration_test.go
|
||||||
- name: notify-email
|
notify-email:
|
||||||
image: drillster/drone-email
|
image: drillster/drone-email
|
||||||
pull: if-not-exists
|
|
||||||
host: build.openprivacy.ca
|
host: build.openprivacy.ca
|
||||||
port: 25
|
port: 25
|
||||||
skip_verify: true
|
skip_verify: true
|
||||||
from: drone@openprivacy.ca
|
from: drone@openprivacy.ca
|
||||||
when:
|
when:
|
||||||
status: [ failure ]
|
|
||||||
- name: notify-gogs
|
|
||||||
image: openpriv/drone-gogs
|
|
||||||
pull: if-not-exists
|
|
||||||
when:
|
|
||||||
event: pull_request
|
|
||||||
status: [ success, changed, failure ]
|
|
||||||
environment:
|
|
||||||
GOGS_ACCOUNT_TOKEN:
|
|
||||||
from_secret: gogs_account_token
|
|
||||||
settings:
|
|
||||||
gogs_url: https://git.openprivacy.ca
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
# gopath where bin and pkg lives to persist across steps
|
|
||||||
- name: deps
|
|
||||||
temp: {}
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
repo: openprivacy/connectivity
|
repo: openprivacy/connectivity
|
||||||
branch: master
|
branch: master
|
||||||
event:
|
status: [ failure ]
|
||||||
- push
|
notify-gogs:
|
||||||
- pull_request
|
image: openpriv/drone-gogs
|
||||||
- tag
|
when:
|
||||||
|
repo: openprivacy/connectivity
|
||||||
|
branch: master
|
||||||
|
event: pull_request
|
||||||
|
status: [ success, changed, failure ]
|
||||||
|
secrets: [gogs_account_token]
|
||||||
|
gogs_url: https://git.openprivacy.ca
|
||||||
|
|
|
@ -5,5 +5,3 @@ vendor/
|
||||||
*.cover.out
|
*.cover.out
|
||||||
tmp/
|
tmp/
|
||||||
testing/tor/*
|
testing/tor/*
|
||||||
tor/data-dir*
|
|
||||||
testing/data-dir*
|
|
|
@ -7,12 +7,6 @@ A library providing an ACN (Anonymous Communication Network
|
||||||
|
|
||||||
* Tor v3 Onion Services
|
* 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
|
## Requirements for ACN Support
|
||||||
|
|
||||||
* Reference an EndPoint via a string / hostname
|
* Reference an EndPoint via a string / hostname
|
||||||
|
|
9
acn.go
9
acn.go
|
@ -39,13 +39,6 @@ type ACN interface {
|
||||||
// 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))
|
||||||
|
|
||||||
GetStatusCallback() func(int, string)
|
|
||||||
|
|
||||||
// Sets the callback function to be called when ACN reboots to emit the version
|
|
||||||
SetVersionCallback(callback func(string))
|
|
||||||
|
|
||||||
GetVersionCallback() func(string)
|
|
||||||
|
|
||||||
// Restarts the underlying connection
|
// Restarts the underlying connection
|
||||||
Restart()
|
Restart()
|
||||||
|
|
||||||
|
@ -62,6 +55,8 @@ type ACN interface {
|
||||||
// GetVersion returns a string of what the ACN returns when asked for a version
|
// GetVersion returns a string of what the ACN returns when asked for a version
|
||||||
GetVersion() string
|
GetVersion() string
|
||||||
|
|
||||||
|
Callback() func(int, string)
|
||||||
|
|
||||||
GetInfo(onion string) (map[string]string, error)
|
GetInfo(onion string) (map[string]string, error)
|
||||||
|
|
||||||
Close()
|
Close()
|
||||||
|
|
55
error_acn.go
55
error_acn.go
|
@ -1,72 +1,57 @@
|
||||||
package connectivity
|
package connectivity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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 {
|
||||||
acnError error
|
|
||||||
statusCallbackCache func(int, string)
|
statusCallbackCache func(int, string)
|
||||||
versionCallbackCache func(string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewErrorACN(err error) ErrorACN {
|
func (e ErrorACN) Callback() func(int, string) {
|
||||||
return ErrorACN{
|
|
||||||
acnError: err,
|
|
||||||
statusCallbackCache: func(int, string) {},
|
|
||||||
versionCallbackCache: func(string) {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ErrorACN) GetStatusCallback() func(int, string) {
|
|
||||||
return e.statusCallbackCache
|
return e.statusCallbackCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) GetVersionCallback() func(string) {
|
|
||||||
return e.versionCallbackCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ErrorACN) GetInfo(addr string) (map[string]string, error) {
|
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) {
|
func (e ErrorACN) GetBootstrapStatus() (int, string) {
|
||||||
return -1, e.acnError.Error()
|
return -1, acnError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) WaitTillBootstrapped() error {
|
func (e ErrorACN) WaitTillBootstrapped() error {
|
||||||
return e.acnError
|
return errors.New(acnError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) SetStatusCallback(callback func(int, string)) {
|
func (e *ErrorACN) SetStatusCallback(callback func(int, string)) {
|
||||||
e.statusCallbackCache = callback
|
e.statusCallbackCache = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) SetVersionCallback(callback func(string)) {
|
func (e ErrorACN) Restart() {
|
||||||
e.versionCallbackCache = callback
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) Restart() {
|
func (e ErrorACN) Open(hostname string) (net.Conn, string, error) {
|
||||||
|
return nil, "", fmt.Errorf(acnError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) Open(hostname string) (net.Conn, string, error) {
|
func (e ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) {
|
||||||
return nil, "", e.acnError
|
return nil, fmt.Errorf(acnError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) {
|
func (e ErrorACN) GetPID() (int, error) {
|
||||||
return nil, e.acnError
|
return -1, fmt.Errorf(acnError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) GetPID() (int, error) {
|
func (e ErrorACN) GetVersion() string {
|
||||||
return -1, e.acnError
|
return acnError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorACN) GetVersion() string {
|
func (e ErrorACN) Close() {
|
||||||
return e.acnError.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ErrorACN) Close() {
|
|
||||||
// nothing to do...
|
|
||||||
}
|
}
|
||||||
|
|
16
go.mod
16
go.mod
|
@ -1,15 +1,11 @@
|
||||||
module git.openprivacy.ca/openprivacy/connectivity
|
module git.openprivacy.ca/openprivacy/connectivity
|
||||||
|
|
||||||
go 1.17
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
filippo.io/edwards25519 v1.0.0
|
filippo.io/edwards25519 v1.0.0-rc.1
|
||||||
git.openprivacy.ca/openprivacy/bine v0.0.5
|
git.openprivacy.ca/openprivacy/bine v0.0.4
|
||||||
git.openprivacy.ca/openprivacy/log v1.0.3
|
git.openprivacy.ca/openprivacy/log v1.0.2
|
||||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee
|
||||||
)
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
||||||
|
|
||||||
require (
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
26
go.sum
26
go.sum
|
@ -1,9 +1,9 @@
|
||||||
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
|
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
||||||
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||||
git.openprivacy.ca/openprivacy/bine v0.0.5 h1:DJs5gqw3SkvLSgRDvroqJxZ7F+YsbxbBRg5t0rU5gYE=
|
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c=
|
||||||
git.openprivacy.ca/openprivacy/bine v0.0.5/go.mod h1:fwdeq6RO08WDkV0k7HfArsjRvurVULoUQmT//iaABZM=
|
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.2 h1:HLP4wsw4ljczFAelYnbObIs821z+jgMPCe8uODPnGQM=
|
||||||
git.openprivacy.ca/openprivacy/log v1.0.3/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
git.openprivacy.ca/openprivacy/log v1.0.2/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=
|
||||||
|
@ -13,25 +13,23 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
|
||||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo=
|
|
||||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -18,14 +18,10 @@ func NewLocalACN() ACN {
|
||||||
return &localProvider{}
|
return &localProvider{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lp *localProvider) GetStatusCallback() func(int, string) {
|
func (lp *localProvider) Callback() func(int, string) {
|
||||||
return func(int, string) {}
|
return func(int, string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lp *localProvider) GetVersionCallback() func(string) {
|
|
||||||
return func(string) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *localListenService) AddressFull() string {
|
func (ls *localListenService) AddressFull() string {
|
||||||
return ls.l.Addr().String()
|
return ls.l.Addr().String()
|
||||||
}
|
}
|
||||||
|
@ -55,10 +51,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|
15
proxy_acn.go
15
proxy_acn.go
|
@ -29,8 +29,7 @@ func (p *ProxyACN) ReplaceACN(acn ACN) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
p.acn.Close()
|
p.acn.Close()
|
||||||
acn.SetStatusCallback(p.acn.GetStatusCallback())
|
acn.SetStatusCallback(p.acn.Callback())
|
||||||
acn.SetVersionCallback(p.acn.GetVersionCallback())
|
|
||||||
p.acn = acn
|
p.acn = acn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +49,6 @@ 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()
|
||||||
}
|
}
|
||||||
|
@ -78,10 +73,6 @@ func (p *ProxyACN) Close() {
|
||||||
p.acn.Close()
|
p.acn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyACN) GetStatusCallback() func(int, string) {
|
func (p *ProxyACN) Callback() func(int, string) {
|
||||||
return p.acn.GetStatusCallback()
|
return p.acn.Callback()
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProxyACN) GetVersionCallback() func(string) {
|
|
||||||
return p.acn.GetVersionCallback()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,12 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/log"
|
"git.openprivacy.ca/openprivacy/log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
path "path/filepath"
|
"path"
|
||||||
"runtime"
|
|
||||||
"runtime/pprof"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLaunchTor(t *testing.T) {
|
func TestLaunchTor(t *testing.T) {
|
||||||
goRoutineStart := runtime.NumGoroutine()
|
|
||||||
log.SetLevel(log.LevelDebug)
|
log.SetLevel(log.LevelDebug)
|
||||||
|
|
||||||
rand.Seed(int64(time.Now().Nanosecond()))
|
rand.Seed(int64(time.Now().Nanosecond()))
|
||||||
|
@ -28,15 +25,10 @@ func TestLaunchTor(t *testing.T) {
|
||||||
t.Fatalf("failed to create torrc file: %v", err)
|
t.Fatalf("failed to create torrc file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dataDir := ""
|
|
||||||
if dataDir, err = os.MkdirTemp(path.Join("..", "testing"), "data-dir-"); err != nil {
|
|
||||||
t.Fatalf("could not create data dir")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current working director, clean the paths to remove relative references
|
// Get the current working director, clean the paths to remove relative references
|
||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
t.Logf("Launching bundled tor at %v", path.Clean(wd+"/../tmp/tor"))
|
t.Logf("Launching bundled tor at %v", path.Clean(wd+"/../tmp/tor"))
|
||||||
acn, err := tor.NewTorACNWithAuth(path.Clean(wd+"/../tmp/data"), path.Clean(wd+"/../tmp/tor"), dataDir, controlPort, tor.HashedPasswordAuthenticator{Password: password})
|
acn, err := tor.NewTorACNWithAuth(path.Clean(wd+"/../tmp/data"), path.Clean(wd+"/../tmp/tor"), controlPort, tor.HashedPasswordAuthenticator{Password: password})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("tor failed to start: %v", err)
|
t.Fatalf("tor failed to start: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -53,15 +45,4 @@ func TestLaunchTor(t *testing.T) {
|
||||||
t.Log("we have bootstrapped!")
|
t.Log("we have bootstrapped!")
|
||||||
acn.Close()
|
acn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(time.Second * 5)
|
|
||||||
|
|
||||||
goRoutineEnd := runtime.NumGoroutine()
|
|
||||||
|
|
||||||
if goRoutineEnd != goRoutineStart {
|
|
||||||
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
|
|
||||||
|
|
||||||
t.Fatalf("goroutine leak in ACN: %v %v", goRoutineStart, goRoutineEnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//go:build !windows
|
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
package tor
|
package tor
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//go:build windows
|
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package tor
|
package tor
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package tor
|
package tor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -13,11 +12,12 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/log"
|
"git.openprivacy.ca/openprivacy/log"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
path "path/filepath"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -70,13 +70,9 @@ 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
|
|
||||||
version string
|
|
||||||
bootProgress int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ols *onionListenService) AddressFull() string {
|
func (ols *onionListenService) AddressFull() string {
|
||||||
|
@ -166,11 +162,7 @@ func (tp *torProvider) GetInfo(onion string) (map[string]string, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// 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 -1 on network disconnected
|
||||||
// returns -2 on error
|
// returns -2 on error
|
||||||
func (tp *torProvider) GetBootstrapStatus() (int, string) {
|
func (tp *torProvider) GetBootstrapStatus() (int, string) {
|
||||||
|
@ -198,6 +190,8 @@ func (tp *torProvider) GetBootstrapStatus() (int, string) {
|
||||||
status := ""
|
status := ""
|
||||||
|
|
||||||
if len(kvs) > 0 {
|
if len(kvs) > 0 {
|
||||||
|
progRe := regexp.MustCompile("PROGRESS=([0-9]*)")
|
||||||
|
sumRe := regexp.MustCompile("SUMMARY=\"(.*)\"$")
|
||||||
|
|
||||||
if progMatches := progRe.FindStringSubmatch(kvs[0].Val); len(progMatches) > 1 {
|
if progMatches := progRe.FindStringSubmatch(kvs[0].Val); len(progMatches) > 1 {
|
||||||
progress, _ = strconv.Atoi(progMatches[1])
|
progress, _ = strconv.Atoi(progMatches[1])
|
||||||
|
@ -207,14 +201,23 @@ func (tp *torProvider) GetBootstrapStatus() (int, string) {
|
||||||
status = statusMatches[1]
|
status = statusMatches[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tp.bootProgress = progress
|
|
||||||
return progress, status
|
return progress, status
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -268,28 +271,7 @@ func (tp *torProvider) Listen(identity connectivity.PrivateKey, port int) (conne
|
||||||
localport += 1024
|
localport += 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
var localListener net.Listener
|
localListener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(localport))
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -311,8 +293,6 @@ func (tp *torProvider) Listen(identity connectivity.PrivateKey, port int) (conne
|
||||||
return nil, err
|
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
|
os.CloseLocalListenerOnClose = true
|
||||||
|
|
||||||
ols := &onionListenService{os: os, tp: tp}
|
ols := &onionListenService{os: os, tp: tp}
|
||||||
|
@ -324,12 +304,12 @@ func (tp *torProvider) Restart() {
|
||||||
log.Debugf("launching restart...")
|
log.Debugf("launching restart...")
|
||||||
|
|
||||||
tp.lock.Lock()
|
tp.lock.Lock()
|
||||||
|
defer tp.lock.Unlock()
|
||||||
log.Debugf("checking last restart time")
|
log.Debugf("checking last restart time")
|
||||||
if time.Since(tp.lastRestartTime) < restartCooldown {
|
if time.Since(tp.lastRestartTime) < restartCooldown {
|
||||||
tp.lock.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tp.lock.Unlock()
|
|
||||||
go tp.restart()
|
go tp.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,23 +322,17 @@ 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")
|
||||||
newTp, err := startTor(tp.appDirectory, tp.bundeledTorPath, tp.dataDir, tp.controlPort, tp.authenticator)
|
newTp, err := startTor(tp.appDirectory, tp.bundeledTorPath, tp.controlPort, tp.authenticator)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// we need to reassign tor, dialer and callback which will have changed by swapping out
|
// we need to reassign tor, dialer and callback which will have changed by swapping out
|
||||||
// the underlying connection.
|
// the underlying connection.
|
||||||
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
|
|
||||||
go tp.monitorRestart()
|
go tp.monitorRestart()
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("Error restarting Tor process: %v", err)
|
log.Errorf("Error restarting Tor process: %v", err)
|
||||||
|
@ -372,10 +346,6 @@ func (tp *torProvider) Open(hostname string) (net.Conn, string, error) {
|
||||||
tp.lock.Unlock()
|
tp.lock.Unlock()
|
||||||
return nil, hostname, errors.New("tor is offline")
|
return nil, hostname, errors.New("tor is offline")
|
||||||
}
|
}
|
||||||
if tp.bootProgress != 100 {
|
|
||||||
tp.lock.Unlock()
|
|
||||||
return nil, hostname, fmt.Errorf("tor not online, bootstrap progress only %v", tp.bootProgress)
|
|
||||||
}
|
|
||||||
tp.lock.Unlock()
|
tp.lock.Unlock()
|
||||||
|
|
||||||
resolvedHostname := hostname
|
resolvedHostname := hostname
|
||||||
|
@ -383,24 +353,14 @@ func (tp *torProvider) Open(hostname string) (net.Conn, string, error) {
|
||||||
addrParts := strings.Split(hostname, ":")
|
addrParts := strings.Split(hostname, ":")
|
||||||
resolvedHostname = addrParts[1]
|
resolvedHostname = addrParts[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := tp.dialer.Dial("tcp", resolvedHostname+".onion:9878")
|
conn, err := tp.dialer.Dial("tcp", resolvedHostname+".onion:9878")
|
||||||
return conn, resolvedHostname, err
|
return conn, resolvedHostname, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *torProvider) Close() {
|
func (tp *torProvider) Close() {
|
||||||
closing := false
|
|
||||||
tp.lock.Lock()
|
tp.lock.Lock()
|
||||||
defer tp.lock.Unlock()
|
defer tp.lock.Unlock()
|
||||||
if !tp.isClosed {
|
|
||||||
// Break out of any background checks and close
|
|
||||||
// the underlying tor connection
|
|
||||||
tp.isClosed = true
|
|
||||||
tp.breakChan <- true
|
|
||||||
// wiggle lock to make sure if monitorRestart is waiting for the lock, it gets it, and finished that branch and gets the channel request to exit
|
|
||||||
tp.lock.Unlock()
|
|
||||||
tp.lock.Lock()
|
|
||||||
closing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unregister Child Listeners
|
// Unregister Child Listeners
|
||||||
for addr, child := range tp.childListeners {
|
for addr, child := range tp.childListeners {
|
||||||
|
@ -408,9 +368,11 @@ func (tp *torProvider) Close() {
|
||||||
delete(tp.childListeners, addr)
|
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
|
||||||
if closing {
|
// the underlying tor connection
|
||||||
|
tp.isClosed = true
|
||||||
|
tp.breakChan <- true
|
||||||
if tp.t != nil {
|
if tp.t != nil {
|
||||||
tp.t.Close()
|
tp.t.Close()
|
||||||
tp.t = nil
|
tp.t = nil
|
||||||
|
@ -424,42 +386,34 @@ func (tp *torProvider) SetStatusCallback(callback func(int, string)) {
|
||||||
tp.statusCallback = callback
|
tp.statusCallback = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *torProvider) SetVersionCallback(callback func(string)) {
|
func (tp *torProvider) Callback() func(int, string) {
|
||||||
tp.lock.Lock()
|
|
||||||
defer tp.lock.Unlock()
|
|
||||||
tp.versionCallback = callback
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *torProvider) GetStatusCallback() func(int, string) {
|
|
||||||
tp.lock.Lock()
|
tp.lock.Lock()
|
||||||
defer tp.lock.Unlock()
|
defer tp.lock.Unlock()
|
||||||
return tp.statusCallback
|
return tp.statusCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *torProvider) GetVersionCallback() func(string) {
|
|
||||||
tp.lock.Lock()
|
|
||||||
defer tp.lock.Unlock()
|
|
||||||
return tp.versionCallback
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
func NewTorACNWithAuth(appDirectory string, bundledTorPath string, dataDir string, controlPort int, authenticator tor.Authenticator) (connectivity.ACN, error) {
|
func NewTorACNWithAuth(appDirectory string, bundledTorPath string, controlPort int, authenticator tor.Authenticator) (connectivity.ACN, error) {
|
||||||
tp, err := startTor(appDirectory, bundledTorPath, dataDir, controlPort, authenticator)
|
tp, err := startTor(appDirectory, bundledTorPath, controlPort, authenticator)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tp.isClosed = false
|
|
||||||
go tp.monitorRestart()
|
go tp.monitorRestart()
|
||||||
}
|
}
|
||||||
return tp, err
|
return tp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTorACN creates/starts a Tor ACN and returns a usable ACN object with a NullAuthenticator - this will fail.
|
||||||
|
func NewTorACN(appDirectory string, bundledTorPath string) (connectivity.ACN, error) {
|
||||||
|
return NewTorACNWithAuth(appDirectory, bundledTorPath, 9051, NullAuthenticator{})
|
||||||
|
}
|
||||||
|
|
||||||
// newHideCmd creates a Creator function for bine which generates a cmd that one windows will hide the dosbox
|
// newHideCmd creates a Creator function for bine which generates a cmd that one windows will hide the dosbox
|
||||||
func newHideCmd(exePath string) process.Creator {
|
func newHideCmd(exePath string) process.Creator {
|
||||||
return process.CmdCreatorFunc(func(ctx context.Context, args ...string) (*exec.Cmd, error) {
|
return process.CmdCreatorFunc(func(ctx context.Context, args ...string) (*exec.Cmd, error) {
|
||||||
|
@ -470,19 +424,11 @@ func newHideCmd(exePath string) process.Creator {
|
||||||
cmd.Stdout = loggerDebug
|
cmd.Stdout = loggerDebug
|
||||||
cmd.Stderr = loggerError
|
cmd.Stderr = loggerError
|
||||||
cmd.SysProcAttr = sysProcAttr
|
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
|
return cmd, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *torProvider) checkVersion() (string, error) {
|
func (tp *torProvider) checkVersion() 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)
|
||||||
|
@ -495,33 +441,37 @@ func (tp *torProvider) checkVersion() (string, 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 pinfo.TorVersion, nil
|
return nil
|
||||||
}
|
}
|
||||||
return pinfo.TorVersion, fmt.Errorf("tor version not supported: %v", pinfo.TorVersion)
|
return 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, controlPort int, authenticator tor.Authenticator) (*torProvider, error) {
|
||||||
torDir := path.Join(appDirectory, "tor")
|
torDir := path.Join(appDirectory, "tor")
|
||||||
|
|
||||||
os.MkdirAll(torDir, 0700)
|
os.MkdirAll(torDir, 0700)
|
||||||
|
dataDir := ""
|
||||||
|
var err error
|
||||||
|
if dataDir, err = ioutil.TempDir(torDir, "data-dir-"); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create temp data dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
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), bootProgress: -1}
|
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)}
|
||||||
|
|
||||||
log.Debugf("checking if there is a running system tor")
|
log.Debugf("checking if there is a running system tor")
|
||||||
if version, err := tp.checkVersion(); err == nil {
|
if 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")
|
||||||
tp.t = createFromExisting(controlport, dataDir)
|
tp.t = createFromExisting(controlport, dataDir)
|
||||||
|
}
|
||||||
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})
|
||||||
return tp, err
|
return tp, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// check if the torrc file is present where expected
|
// check if the torrc file is present where expected
|
||||||
if _, err := os.Stat(path.Join(torDir, "torrc")); os.IsNotExist(err) {
|
if _, err := os.Stat(path.Join(torDir, "torrc")); os.IsNotExist(err) {
|
||||||
|
@ -530,36 +480,32 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not, try bundled tor, then running system tor
|
// if not, try running system tor
|
||||||
log.Debugln("checking if we can run bundled tor or system installed tor")
|
log.Debugln("checking if we can run system installed tor or bundled tor")
|
||||||
if version, pass := checkCmdlineTorVersion(bundledTorPath); pass {
|
if checkCmdlineTorVersion("tor") {
|
||||||
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"), DebugWriter: nil, ProcessCreator: newHideCmd("tor")})
|
||||||
t, err := tor.Start(context.TODO(), &tor.StartConf{ControlPort: tp.controlPort, NoAutoSocksPort: true, 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 {
|
|
||||||
log.Debugf("Error running bundled tor %v\n", err)
|
|
||||||
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, NoAutoSocksPort: true, DisableCookieAuth: true, UseEmbeddedControlConn: false, DisableEagerAuth: true, EnableNetwork: true, DataDir: dataDir, TorrcFile: path.Join(torDir, "torrc"), DebugWriter: nil, ProcessCreator: newHideCmd("tor")})
|
|
||||||
if err != nil {
|
if err != 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)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tp.t = t
|
tp.t = t
|
||||||
tp.version = version
|
} else if bundledTorPath != "" && checkCmdlineTorVersion(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)})
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Error running bundled tor %v\n", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp.t = t
|
||||||
} 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)")
|
||||||
}
|
}
|
||||||
|
|
||||||
version, err := tp.checkVersion()
|
err = tp.checkVersion()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tp.t.DeleteDataDirOnClose = false // caller is responsible for dealing with cached information...
|
tp.t.DeleteDataDirOnClose = true
|
||||||
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
|
|
||||||
tp.t.Control.TakeOwnership()
|
|
||||||
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)
|
||||||
|
@ -587,6 +533,7 @@ func (tp *torProvider) monitorRestart() {
|
||||||
prog, status := tp.GetBootstrapStatus()
|
prog, status := tp.GetBootstrapStatus()
|
||||||
|
|
||||||
if prog == torDown && tp.t != nil {
|
if prog == torDown && tp.t != nil {
|
||||||
|
log.Warnf("monitorRestart calling tp.restart() with prog:%v\n", prog)
|
||||||
tp.restart()
|
tp.restart()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -618,7 +565,7 @@ func createFromExisting(controlport *control.Conn, datadir string) *tor.Tor {
|
||||||
Control: controlport,
|
Control: controlport,
|
||||||
ProcessCancelFunc: nil,
|
ProcessCancelFunc: nil,
|
||||||
DataDir: datadir,
|
DataDir: datadir,
|
||||||
DeleteDataDirOnClose: false,
|
DeleteDataDirOnClose: true,
|
||||||
DebugWriter: nil,
|
DebugWriter: nil,
|
||||||
StopProcessOnClose: false,
|
StopProcessOnClose: false,
|
||||||
GeoIPCreatedFile: "",
|
GeoIPCreatedFile: "",
|
||||||
|
@ -629,57 +576,25 @@ func createFromExisting(controlport *control.Conn, datadir string) *tor.Tor {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkCmdlineTorVersion(torCmd string) (string, bool) {
|
func checkCmdlineTorVersion(torCmd 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...
|
|
||||||
cmd := exec.Command(torCmd, "--version")
|
cmd := exec.Command(torCmd, "--version")
|
||||||
var outb bytes.Buffer
|
cmd.SysProcAttr = sysProcAttr
|
||||||
cmd.Stdout = &outb
|
out, err := cmd.CombinedOutput()
|
||||||
|
re := regexp.MustCompile(`[0-1]\.[0-9]\.[0-9]\.[0-9]`)
|
||||||
waiting := make(chan error, 1)
|
sysTorVersion := re.Find(out)
|
||||||
|
log.Infoln("tor version: " + string(sysTorVersion))
|
||||||
// try running the tor process
|
return err == nil && minTorVersionReqs(string(sysTorVersion))
|
||||||
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(outb.Bytes())
|
|
||||||
log.Infof("tor version: %v", 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
|
||||||
// min requirement: 0.3.5.x
|
// min requirement: 0.3.5.x
|
||||||
func minTorVersionReqs(torversion string) bool {
|
func minTorVersionReqs(torversion string) bool {
|
||||||
torversions := strings.Split(torversion, ".") //eg: 0.3.4.8 or 0.3.5.1-alpha
|
torversions := strings.Split(torversion, ".") //eg: 0.3.4.8 or 0.3.5.1-alpha
|
||||||
if len(torversions) >= 3 {
|
|
||||||
log.Debugf("torversions: %v", torversions)
|
log.Debugf("torversions: %v", torversions)
|
||||||
tva, _ := strconv.Atoi(torversions[0])
|
tva, _ := strconv.Atoi(torversions[0])
|
||||||
tvb, _ := strconv.Atoi(torversions[1])
|
tvb, _ := strconv.Atoi(torversions[1])
|
||||||
tvc, _ := strconv.Atoi(torversions[2])
|
tvc, _ := strconv.Atoi(torversions[2])
|
||||||
return tva > 0 || (tva == 0 && (tvb > 3 || (tvb == 3 && tvc >= 5)))
|
return tva > 0 || (tva == 0 && (tvb > 3 || (tvb == 3 && tvc >= 5)))
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dialControlPort(port int) (*control.Conn, error) {
|
func dialControlPort(port int) (*control.Conn, error) {
|
||||||
|
|
|
@ -3,12 +3,8 @@ package tor
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.openprivacy.ca/openprivacy/log"
|
"git.openprivacy.ca/openprivacy/log"
|
||||||
"os"
|
|
||||||
path "path/filepath"
|
path "path/filepath"
|
||||||
"runtime"
|
|
||||||
"runtime/pprof"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getStatusCallback(progChan chan int) func(int, string) {
|
func getStatusCallback(progChan chan int) func(int, string) {
|
||||||
|
@ -18,39 +14,20 @@ 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) {
|
||||||
|
progChan := make(chan int)
|
||||||
goRoutineStart := runtime.NumGoroutine()
|
|
||||||
|
|
||||||
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")
|
||||||
|
|
||||||
NewTorrc().WithControlPort(9051).WithHashedPassword("examplehashedpassword").Build(path.Join("..", "testing", "tor", "torrc"))
|
NewTorrc().WithControlPort(9051).WithHashedPassword("examplehashedpassword").Build(path.Join("..", "testing", "tor", "torrc"))
|
||||||
|
|
||||||
log.Debugf("setting tor path %v", torpath)
|
log.Debugf("setting tor path %v", torpath)
|
||||||
|
acn, err := NewTorACNWithAuth(path.Join("../testing/"), torpath, 9051, HashedPasswordAuthenticator{"examplehashedpassword"})
|
||||||
dataDir := ""
|
|
||||||
var err error
|
|
||||||
if dataDir, err = os.MkdirTemp(path.Join("..", "testing"), "data-dir-"); err != nil {
|
|
||||||
t.Fatalf("could not create data dir")
|
|
||||||
}
|
|
||||||
|
|
||||||
acn, err := NewTorACNWithAuth(path.Join("../testing/"), torpath, dataDir, 9051, HashedPasswordAuthenticator{"examplehashedpassword"})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
acn.SetStatusCallback(getStatusCallback(progChan))
|
acn.SetStatusCallback(getStatusCallback(progChan))
|
||||||
acn.SetVersionCallback(getVersionCallback(verChan))
|
|
||||||
|
|
||||||
progress := 0
|
progress := 0
|
||||||
for progress < 100 {
|
for progress < 100 {
|
||||||
|
@ -65,13 +42,6 @@ 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")
|
||||||
|
@ -88,7 +58,7 @@ func TestTorProvider(t *testing.T) {
|
||||||
|
|
||||||
_, err = acn.GetInfo("not_a_real_onion")
|
_, err = acn.GetInfo("not_a_real_onion")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("GetInfo for non existent onion should have errored")
|
t.Fatalf("GetInfo for non existant onion should have errored")
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -101,15 +71,4 @@ func TestTorProvider(t *testing.T) {
|
||||||
acn.Restart()
|
acn.Restart()
|
||||||
|
|
||||||
acn.Close()
|
acn.Close()
|
||||||
|
|
||||||
time.Sleep(time.Second * 10)
|
|
||||||
|
|
||||||
goRoutineEnd := runtime.NumGoroutine()
|
|
||||||
|
|
||||||
if goRoutineEnd != goRoutineStart {
|
|
||||||
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
|
|
||||||
|
|
||||||
t.Fatalf("goroutine leak in ACN: %v %v", goRoutineStart, goRoutineEnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,18 +6,10 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"io/ioutil"
|
||||||
"strings"
|
"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
|
// TorrcBuilder is a a helper for building torrc files
|
||||||
type TorrcBuilder struct {
|
type TorrcBuilder struct {
|
||||||
lines []string
|
lines []string
|
||||||
|
@ -42,28 +34,9 @@ func (tb *TorrcBuilder) WithControlPort(port int) *TorrcBuilder {
|
||||||
return tb
|
return tb
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithLog sets the Log to file directive to the specified file with the specified log level
|
// WithCustom clobbers the torrc builder and allows the client to set any option they want, while benefiting
|
||||||
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
|
|
||||||
// from other configuration options.
|
// from other configuration options.
|
||||||
func (tb *TorrcBuilder) WithCustom(lines []string) *TorrcBuilder {
|
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
|
tb.lines = lines
|
||||||
return tb
|
return tb
|
||||||
}
|
}
|
||||||
|
@ -79,12 +52,6 @@ func (tb *TorrcBuilder) WithOnionTrafficOnly() *TorrcBuilder {
|
||||||
return tb
|
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.
|
// WithHashedPassword sets a password for the control port.
|
||||||
func (tb *TorrcBuilder) WithHashedPassword(password string) *TorrcBuilder {
|
func (tb *TorrcBuilder) WithHashedPassword(password string) *TorrcBuilder {
|
||||||
var salt [8]byte
|
var salt [8]byte
|
||||||
|
@ -98,7 +65,7 @@ func (tb *TorrcBuilder) WithHashedPassword(password string) *TorrcBuilder {
|
||||||
|
|
||||||
// Build finalizes the torrc contents and write a file
|
// Build finalizes the torrc contents and write a file
|
||||||
func (tb *TorrcBuilder) Build(path string) error {
|
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.
|
// Preview provides a string representation of the torrc file without writing it to a file location.
|
||||||
|
|
Loading…
Reference in New Issue