Compare commits

...

28 Commits

Author SHA1 Message Date
Sarah Jamie Lewis 1524e78a4a Merge pull request 'Clarified and Split Apart Environment Variables that alter port binding behaviour.' (#47) from whonix into master
continuous-integration/drone/push Build is pending Details
Reviewed-on: #47
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2023-08-18 21:03:41 +00:00
Sarah Jamie Lewis cd87779e87 Merge branch 'master' into whonix
continuous-integration/drone/pr Build is pending Details
2023-08-18 21:03:33 +00:00
Sarah Jamie Lewis d8dd82d065 Update Docs
continuous-integration/drone/pr Build is pending Details
2023-08-16 10:59:31 -07:00
Sarah Jamie Lewis 932f99fac8 Expand Useable Ports...these apply to hosted servers too..
continuous-integration/drone/pr Build is pending Details
2023-08-16 10:56:43 -07:00
Sarah Jamie Lewis bbacb5539d Documentation
continuous-integration/drone/pr Build is pending Details
2023-08-16 10:49:25 -07:00
Sarah Jamie Lewis 2c9ec9d894 Clean up and seperate flags 2023-08-16 10:46:02 -07:00
Sarah Jamie Lewis c9ea1e4464 Comment os.ID 2023-08-16 10:33:12 -07:00
Sarah Jamie Lewis 61ced82cb4 Restrict Ports when BINE_WHONIX is enabled. 2023-08-16 10:31:48 -07:00
Sarah Jamie Lewis 91c41e2005 Merge pull request 'Support Whonix' (#46) from whonix into master
continuous-integration/drone/push Build is pending Details
Reviewed-on: #46
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2023-08-15 17:21:08 +00:00
Sarah Jamie Lewis caca121441 Support Whonix
continuous-integration/drone/pr Build is passing Details
2023-08-14 13:59:58 -07:00
Sarah Jamie Lewis 9beff8a10a Require error to construct an ErrorACN
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-05-29 10:22:36 -07:00
Sarah Jamie Lewis dedcbdd3cb Merge pull request 'Fix errorAcn reference issues + add support for Tor specific shared library path' (#43) from tor-updates into master
continuous-integration/drone/push Build is pending Details
Reviewed-on: #43
Reviewed-by: Dan Ballard <dan@openprivacy.ca>
2023-05-24 19:24:20 +00:00
Sarah Jamie Lewis c18cd719a1 update readme
continuous-integration/drone/pr Build is pending Details
2023-05-24 12:19:15 -07:00
Sarah Jamie Lewis 380fd1834a Fix errorAcn reference issues + add support for Tor specific shared library path
continuous-integration/drone/pr Build is passing Details
2023-05-24 11:11:18 -07:00
Sarah Jamie Lewis 1162cf4168 Upgrade Bine
continuous-integration/drone/push Build is pending Details
2023-04-05 02:38:26 +00:00
Sarah Jamie Lewis 4a2eeed072 Merge pull request 'add TakeOwnership call once tor started to help ensure tor ends; add support for __OwningControllerProcess' (#39) from takeownpid into master
continuous-integration/drone/push Build is pending Details
Reviewed-on: #39
2022-10-08 22:45:46 +00:00
Dan Ballard 2f3860eb89 drone use go 1.19.1
continuous-integration/drone/pr Build is passing Details
2022-10-08 15:26:39 -07:00
Dan Ballard bbe4198a41 add TakeOwnership call once tor started to help ensure tor ends; add support for __OwningControllerProcess 2022-10-08 11:58:42 -07:00
Sarah Jamie Lewis 51029af959 Merge pull request 'enable logging support for torrc builder' (#36) from logging into master
continuous-integration/drone/push Build is pending Details
Reviewed-on: #36
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
2022-09-21 21:39:19 +00:00
Dan Ballard 1f52dc7138 enable logging support for torrc builder
continuous-integration/drone/pr Build is passing Details
2022-09-21 13:06:15 -07:00
Sarah Jamie Lewis 72f689de26 Merge pull request 'update .drone.yml to new format' (#35) from updateDrone into master
continuous-integration/drone/push Build is passing Details
Reviewed-on: #35
2022-09-07 15:39:47 +00:00
Dan Ballard 69085fc721 update .drone.yml to new format
continuous-integration/drone/pr Build is passing Details
2022-09-06 19:14:42 -07:00
Sarah Jamie Lewis 98b15bd105 Merge pull request 'store bootsrap version, make available; fix tor version parsing for double digit versions' (#33) from verStatus into master
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/tag Build was killed Details
Reviewed-on: #33
2022-08-29 02:56:41 +00:00
Dan Ballard 789de52589 store bootsrap version, make available; fix tor version parsing for double digit versions
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2022-08-28 19:50:01 -07:00
Dan Ballard 1741e63424 Merge pull request 'Upgrade Dependencies. Prevent socks default behaviour in bine' (#34) from binefix into master
continuous-integration/drone/push Build is passing Details
Reviewed-on: #34
2022-08-29 02:05:30 +00:00
Sarah Jamie Lewis 478df967fc Upgrade Dependencies. Prevent socks default behaviour in bine
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2022-08-28 18:57:45 -07:00
Sarah Jamie Lewis 8e5dc44400 Merge pull request 'Get x Callbacks' (#32) from gets into master
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/tag Build was killed Details
Reviewed-on: #32
2022-08-08 19:33:00 +00:00
Dan Ballard 6122ad437d Get x Callbacks
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build was killed Details
2022-08-08 12:24:16 -07:00
13 changed files with 237 additions and 109 deletions

View File

@ -1,63 +1,76 @@
workspace: ---
base: /go kind: pipeline
path: src/git.openprivacy.ca/openprivacy/connectivity type: docker
name: linux-test
pipeline: steps:
fetch: - name: fetch
when: image: golang:1.19.1
repo: openprivacy/connectivity volumes:
branch: master - name: deps
event: [ push, pull_request ] path: /go
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
quality: - name: quality
when: image: golang:1.19.1
repo: openprivacy/connectivity volumes:
branch: master - name: deps
event: [ push, pull_request ] path: /go
image: golang
commands: commands:
- staticcheck ./... - staticcheck ./...
units-tests: - name: units-tests
when: image: golang:1.19.1
repo: openprivacy/connectivity volumes:
branch: master - name: deps
event: [ push, pull_request ] path: /go
image: golang
commands: commands:
- export PATH=$PATH:/go/src/git.openprivacy.ca/openprivacy/connectivity - export PATH=`pwd`:$PATH
- ./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
integration-tests: - name: integration-tests
when: image: golang:1.19.1
repo: openprivacy/connectivity volumes:
branch: master - name: deps
event: [ push, pull_request ] path: /go
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
notify-email: - name: 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:
repo: openprivacy/connectivity
branch: master
status: [ failure ] status: [ failure ]
notify-gogs: - name: notify-gogs
image: openpriv/drone-gogs image: openpriv/drone-gogs
pull: if-not-exists
when: when:
repo: openprivacy/connectivity
branch: master
event: pull_request event: pull_request
status: [ success, changed, failure ] status: [ success, changed, failure ]
secrets: [gogs_account_token] environment:
gogs_url: https://git.openprivacy.ca 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
branch: master
event:
- push
- pull_request
- tag

4
.gitignore vendored
View File

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

View File

@ -7,6 +7,12 @@ 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
@ -50,4 +56,4 @@ service:
acn.Restart() acn.Restart()
and and
acn.Close() acn.Close()

7
acn.go
View File

@ -38,9 +38,14 @@ type ACN interface {
WaitTillBootstrapped() error WaitTillBootstrapped() error
// Sets the callback function to be called when ACN status changes // Sets the callback function to be called when ACN status changes
SetStatusCallback(callback func(int, string)) SetStatusCallback(callback func(int, string))
GetStatusCallback() func(int, string)
// Sets the callback function to be called when ACN reboots to emit the version // Sets the callback function to be called when ACN reboots to emit the version
SetVersionCallback(callback func(string)) SetVersionCallback(callback func(string))
GetVersionCallback() func(string)
// Restarts the underlying connection // Restarts the underlying connection
Restart() Restart()
@ -57,8 +62,6 @@ 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()

View File

@ -1,34 +1,43 @@
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) versionCallbackCache func(string)
} }
func (e ErrorACN) Callback() func(int, string) { func NewErrorACN(err error) ErrorACN {
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, errors.New(acnError) return nil, e.acnError
} }
func (e ErrorACN) GetBootstrapStatus() (int, string) { func (e *ErrorACN) GetBootstrapStatus() (int, string) {
return -1, acnError return -1, e.acnError.Error()
} }
func (e ErrorACN) WaitTillBootstrapped() error { func (e *ErrorACN) WaitTillBootstrapped() error {
return errors.New(acnError) return e.acnError
} }
func (e *ErrorACN) SetStatusCallback(callback func(int, string)) { func (e *ErrorACN) SetStatusCallback(callback func(int, string)) {
@ -39,24 +48,25 @@ func (e *ErrorACN) SetVersionCallback(callback func(string)) {
e.versionCallbackCache = callback e.versionCallbackCache = callback
} }
func (e ErrorACN) Restart() { func (e *ErrorACN) Restart() {
} }
func (e ErrorACN) Open(hostname string) (net.Conn, string, error) { func (e *ErrorACN) Open(hostname string) (net.Conn, string, error) {
return nil, "", fmt.Errorf(acnError) return nil, "", e.acnError
} }
func (e ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) { func (e *ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) {
return nil, fmt.Errorf(acnError) return nil, e.acnError
} }
func (e ErrorACN) GetPID() (int, error) { func (e *ErrorACN) GetPID() (int, error) {
return -1, fmt.Errorf(acnError) return -1, e.acnError
} }
func (e ErrorACN) GetVersion() string { func (e *ErrorACN) GetVersion() string {
return acnError return e.acnError.Error()
} }
func (e ErrorACN) Close() { func (e *ErrorACN) Close() {
// nothing to do...
} }

14
go.mod
View File

@ -1,11 +1,15 @@
module git.openprivacy.ca/openprivacy/connectivity module git.openprivacy.ca/openprivacy/connectivity
go 1.13 go 1.17
require ( require (
filippo.io/edwards25519 v1.0.0-rc.1 filippo.io/edwards25519 v1.0.0
git.openprivacy.ca/openprivacy/bine v0.0.4 git.openprivacy.ca/openprivacy/bine v0.0.5
git.openprivacy.ca/openprivacy/log v1.0.3 git.openprivacy.ca/openprivacy/log v1.0.3
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d
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
) )

24
go.sum
View File

@ -1,9 +1,7 @@
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c= git.openprivacy.ca/openprivacy/bine v0.0.5 h1:DJs5gqw3SkvLSgRDvroqJxZ7F+YsbxbBRg5t0rU5gYE=
git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU= git.openprivacy.ca/openprivacy/bine v0.0.5/go.mod h1:fwdeq6RO08WDkV0k7HfArsjRvurVULoUQmT//iaABZM=
git.openprivacy.ca/openprivacy/log v1.0.2 h1:HLP4wsw4ljczFAelYnbObIs821z+jgMPCe8uODPnGQM=
git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
git.openprivacy.ca/openprivacy/log v1.0.3 h1:E/PMm4LY+Q9s3aDpfySfEDq/vYQontlvNj/scrPaga0= 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= git.openprivacy.ca/openprivacy/log v1.0.3/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
@ -15,23 +13,25 @@ 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-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
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-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
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=

View File

@ -18,10 +18,14 @@ func NewLocalACN() ACN {
return &localProvider{} return &localProvider{}
} }
func (lp *localProvider) Callback() func(int, string) { func (lp *localProvider) GetStatusCallback() 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()
} }

View File

@ -29,7 +29,8 @@ 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.Callback()) acn.SetStatusCallback(p.acn.GetStatusCallback())
acn.SetVersionCallback(p.acn.GetVersionCallback())
p.acn = acn p.acn = acn
} }
@ -77,6 +78,10 @@ func (p *ProxyACN) Close() {
p.acn.Close() p.acn.Close()
} }
func (p *ProxyACN) Callback() func(int, string) { func (p *ProxyACN) GetStatusCallback() func(int, string) {
return p.acn.Callback() return p.acn.GetStatusCallback()
}
func (p *ProxyACN) GetVersionCallback() func(string) {
return p.acn.GetVersionCallback()
} }

View File

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

View File

@ -76,6 +76,7 @@ type torProvider struct {
isClosed bool isClosed bool
dataDir string dataDir string
version string version string
bootProgress int
} }
func (ols *onionListenService) AddressFull() string { func (ols *onionListenService) AddressFull() string {
@ -169,8 +170,9 @@ var progRe = regexp.MustCompile("PROGRESS=([0-9]*)")
var sumRe = regexp.MustCompile("SUMMARY=\"(.*)\"$") 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 -2 on error // returns -1 on network disconnected
// returns -2 on error
func (tp *torProvider) GetBootstrapStatus() (int, string) { func (tp *torProvider) GetBootstrapStatus() (int, string) {
tp.lock.Lock() tp.lock.Lock()
defer tp.lock.Unlock() defer tp.lock.Unlock()
@ -205,6 +207,7 @@ func (tp *torProvider) GetBootstrapStatus() (int, string) {
status = statusMatches[1] status = statusMatches[1]
} }
} }
tp.bootProgress = progress
return progress, status return progress, status
} }
@ -265,7 +268,28 @@ func (tp *torProvider) Listen(identity connectivity.PrivateKey, port int) (conne
localport += 1024 localport += 1024
} }
localListener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(localport)) 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))
}
if err != nil { if err != nil {
return nil, err return nil, err
@ -287,6 +311,8 @@ 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}
@ -298,12 +324,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()
} }
@ -346,6 +372,10 @@ 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
@ -353,14 +383,24 @@ 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 {
@ -370,11 +410,7 @@ func (tp *torProvider) Close() {
log.Debugf("shutting down acn threads..(is already closed: %v)", tp.isClosed) log.Debugf("shutting down acn threads..(is already closed: %v)", tp.isClosed)
if !tp.isClosed { if closing {
// Break out of any background checks and close
// 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
@ -394,12 +430,18 @@ func (tp *torProvider) SetVersionCallback(callback func(string)) {
tp.versionCallback = callback tp.versionCallback = callback
} }
func (tp *torProvider) Callback() func(int, string) { 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() defer tp.lock.Unlock()
@ -428,6 +470,14 @@ 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
}) })
} }
@ -459,7 +509,7 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
os.MkdirAll(torDir, 0700) os.MkdirAll(torDir, 0700)
tp := &torProvider{authenticator: authenticator, controlPort: controlPort, appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool, 1), statusCallback: nil, versionCallback: nil, lastRestartTime: time.Now().Add(-restartCooldown)} tp := &torProvider{authenticator: authenticator, controlPort: controlPort, appDirectory: appDirectory, bundeledTorPath: bundledTorPath, childListeners: make(map[string]*onionListenService), breakChan: make(chan bool, 1), statusCallback: nil, versionCallback: nil, lastRestartTime: time.Now().Add(-restartCooldown), bootProgress: -1}
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 version, err := tp.checkVersion(); err == nil {
@ -468,9 +518,9 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
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})
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 // check if the torrc file is present where expected
@ -484,7 +534,7 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
log.Debugln("checking if we can run bundled tor or system installed tor") log.Debugln("checking if we can run bundled tor or system installed tor")
if version, pass := checkCmdlineTorVersion(bundledTorPath); pass { if version, pass := checkCmdlineTorVersion(bundledTorPath); pass {
log.Debugln("bundled tor appears viable, attempting to use '" + bundledTorPath + "'") log.Debugln("bundled tor appears viable, attempting to use '" + bundledTorPath + "'")
t, err := tor.Start(context.TODO(), &tor.StartConf{ControlPort: tp.controlPort, DisableCookieAuth: true, UseEmbeddedControlConn: false, DisableEagerAuth: true, EnableNetwork: true, DataDir: dataDir, TorrcFile: path.Join(torDir, "torrc"), ExePath: bundledTorPath, DebugWriter: nil, ProcessCreator: newHideCmd(bundledTorPath)}) t, err := tor.Start(context.TODO(), &tor.StartConf{ControlPort: tp.controlPort, 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 { if err != nil {
log.Debugf("Error running bundled tor %v\n", err) log.Debugf("Error running bundled tor %v\n", err)
return nil, err return nil, err
@ -492,7 +542,7 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
tp.t = t tp.t = t
tp.version = version tp.version = version
} else if version, pass := checkCmdlineTorVersion("tor"); pass { } else if version, pass := checkCmdlineTorVersion("tor"); pass {
t, err := tor.Start(context.TODO(), &tor.StartConf{ControlPort: tp.controlPort, DisableCookieAuth: true, UseEmbeddedControlConn: false, DisableEagerAuth: true, EnableNetwork: true, DataDir: dataDir, TorrcFile: path.Join(torDir, "torrc"), DebugWriter: nil, ProcessCreator: newHideCmd("tor")}) 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
@ -509,6 +559,7 @@ func startTor(appDirectory string, bundledTorPath string, dataDir string, contro
tp.t.DeleteDataDirOnClose = false // caller is responsible for dealing with cached information... tp.t.DeleteDataDirOnClose = false // caller is responsible for dealing with cached information...
tp.dialer, err = tp.t.Dialer(context.TODO(), &tor.DialConf{Authenticator: tp.authenticator}) tp.dialer, err = tp.t.Dialer(context.TODO(), &tor.DialConf{Authenticator: tp.authenticator})
tp.version = version 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)
@ -536,7 +587,6 @@ 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
} }
@ -612,7 +662,7 @@ func checkCmdlineTorVersion(torCmd string) (string, bool) {
return "", false return "", false
} }
re := regexp.MustCompile(`[0-1]\.[0-9]\.[0-9]\.[0-9]`) re := regexp.MustCompile(`[0-1]+\.[0-9]+\.[0-9]+\.[0-9]+`)
sysTorVersion := re.Find(outb.Bytes()) sysTorVersion := re.Find(outb.Bytes())
log.Infof("tor version: %v", string(sysTorVersion)) log.Infof("tor version: %v", string(sysTorVersion))
return string(sysTorVersion), minTorVersionReqs(string(sysTorVersion)) return string(sysTorVersion), minTorVersionReqs(string(sysTorVersion))

View File

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

View File

@ -6,10 +6,18 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io" "io"
"io/ioutil" "os"
"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
@ -34,9 +42,28 @@ func (tb *TorrcBuilder) WithControlPort(port int) *TorrcBuilder {
return tb return tb
} }
// WithCustom clobbers the torrc builder and allows the client to set any option they want, while benefiting // 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
// 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
} }
@ -52,6 +79,12 @@ 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
@ -65,7 +98,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 ioutil.WriteFile(path, []byte(strings.Join(tb.lines, "\n")), 0600) return os.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.