Statically compiled Tor and examples
This commit is contained in:
parent
3ed91b141c
commit
dba7e8856b
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Chad Retz
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,72 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cretz/bine/process/embedded"
|
||||||
|
"github.com/cretz/bine/tor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() error {
|
||||||
|
// Parse flags. By default, non-verbose served in the current working dir.
|
||||||
|
var verbose bool
|
||||||
|
flag.BoolVar(&verbose, "verbose", false, "Whether to have verbose logging")
|
||||||
|
var directory string
|
||||||
|
flag.StringVar(&directory, "dir", ".", "The directory to serve (current dir is default)")
|
||||||
|
flag.Parse()
|
||||||
|
var err error
|
||||||
|
if directory, err = filepath.Abs(directory); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Start tor
|
||||||
|
startConf := &tor.StartConf{ProcessCreator: embedded.NewCreator()}
|
||||||
|
if verbose {
|
||||||
|
startConf.DebugWriter = os.Stdout
|
||||||
|
} else {
|
||||||
|
startConf.ExtraArgs = []string{"--quiet"}
|
||||||
|
}
|
||||||
|
fmt.Printf("Starting and registering onion service to serve files from %v\n", directory)
|
||||||
|
fmt.Println("Please wait a couple of minutes...")
|
||||||
|
t, err := tor.Start(nil, startConf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer t.Close()
|
||||||
|
// Wait at most a few minutes to publish the service
|
||||||
|
listenCtx, listenCancel := context.WithTimeout(context.Background(), 3*time.Minute)
|
||||||
|
defer listenCancel()
|
||||||
|
// Create an onion service to listen on a random local port but show as 80
|
||||||
|
onion, err := t.Listen(listenCtx, &tor.ListenConf{RemotePorts: []int{80}})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer onion.Close()
|
||||||
|
// Start server asynchronously
|
||||||
|
fmt.Printf("Open Tor browser and navigate to http://%v.onion\n", onion.ID)
|
||||||
|
fmt.Println("Press enter to exit")
|
||||||
|
server := &http.Server{Handler: http.FileServer(http.Dir(directory))}
|
||||||
|
defer server.Shutdown(context.Background())
|
||||||
|
errCh := make(chan error, 1)
|
||||||
|
go func() { errCh <- server.Serve(onion) }()
|
||||||
|
// Wait for key asynchronously
|
||||||
|
go func() {
|
||||||
|
fmt.Scanln()
|
||||||
|
errCh <- nil
|
||||||
|
}()
|
||||||
|
// Stop when one happens
|
||||||
|
defer fmt.Println("Closing")
|
||||||
|
return <-errCh
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/cretz/bine/process/embedded"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() error {
|
||||||
|
p, err := embedded.NewCreator().New(context.Background(), "--version")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("Starting...\n")
|
||||||
|
if err = p.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("Waiting...\n")
|
||||||
|
return p.Wait()
|
||||||
|
}
|
|
@ -1,13 +1,124 @@
|
||||||
// Package embedded implements process interfaces for statically linked,
|
// Package embedded implements process interfaces for statically linked,
|
||||||
// embedded Tor.
|
// embedded Tor. Note, processes created here are not killed when a context is
|
||||||
|
// done like w/ os.Exec.
|
||||||
//
|
//
|
||||||
// TODO: not finished yet
|
// Usage
|
||||||
|
//
|
||||||
|
// This package can be used with CGO to statically compile Tor. This package
|
||||||
|
// expects https://github.com/cretz/tor-static to be cloned at
|
||||||
|
// $GOPATH/src/github.com/cretz/tor-static as if it was fetched with go get. To
|
||||||
|
// build the needed static libs, follow the README in that project. Once the
|
||||||
|
// static libs are built, this uses CGO to statically link them here. For
|
||||||
|
// Windows this means something like http://tdm-gcc.tdragon.net/ needs to be
|
||||||
|
// present with gcc.exe on the PATH.
|
||||||
|
//
|
||||||
|
// NOTE: Other OSs besides Windows have not been tested but likely require an
|
||||||
|
// LDFLAGS setting here. Pull requests are welcomed.
|
||||||
package embedded
|
package embedded
|
||||||
|
|
||||||
import "github.com/cretz/bine/process"
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/cretz/bine/process"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -I${SRCDIR}/../../../tor-static/tor/src/or
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/or -ltor
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/common -lor -lor-crypto -lcurve25519_donna -lor-ctime -lor-event
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/trunnel -lor-trunnel
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/ext/keccak-tiny -lkeccak-tiny
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/ext/ed25519/ref10 -led25519_ref10
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/tor/src/ext/ed25519/donna -led25519_donna
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/libevent/dist/lib -levent
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/xz/dist/lib -llzma
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/zlib/dist/lib -lz
|
||||||
|
#cgo LDFLAGS: -L${SRCDIR}/../../../tor-static/openssl/dist/lib -lssl -lcrypto
|
||||||
|
#cgo windows LDFLAGS: -lws2_32 -lcrypt32 -lgdi32
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <tor_api.h>
|
||||||
|
|
||||||
|
// Ref: https://stackoverflow.com/questions/45997786/passing-array-of-string-as-parameter-from-go-to-c-function
|
||||||
|
|
||||||
|
static char** makeCharArray(int size) {
|
||||||
|
return calloc(sizeof(char*), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setArrayString(char **a, char *s, int n) {
|
||||||
|
a[n] = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freeCharArray(char **a, int size) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
free(a[i]);
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type embeddedCreator struct{}
|
||||||
|
|
||||||
// NewCreator creates a process.Creator for statically-linked Tor embedded in
|
// NewCreator creates a process.Creator for statically-linked Tor embedded in
|
||||||
// the binary.
|
// the binary.
|
||||||
func NewCreator() process.Creator {
|
func NewCreator() process.Creator {
|
||||||
panic("TODO: embedding not implemented yet")
|
return embeddedCreator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type embeddedProcess struct {
|
||||||
|
ctx context.Context
|
||||||
|
args []string
|
||||||
|
doneCh chan int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (embeddedCreator) New(ctx context.Context, args ...string) (process.Process, error) {
|
||||||
|
return &embeddedProcess{ctx: ctx, args: args}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *embeddedProcess) Start() error {
|
||||||
|
if e.doneCh != nil {
|
||||||
|
return fmt.Errorf("Already started")
|
||||||
|
}
|
||||||
|
// Create the char array for the args
|
||||||
|
args := append([]string{"tor"}, e.args...)
|
||||||
|
charArray := C.makeCharArray(C.int(len(args)))
|
||||||
|
for i, a := range args {
|
||||||
|
C.setArrayString(charArray, C.CString(a), C.int(i))
|
||||||
|
}
|
||||||
|
// Build the conf
|
||||||
|
conf := C.tor_main_configuration_new()
|
||||||
|
if code := C.tor_main_configuration_set_command_line(conf, C.int(len(args)), charArray); code != 0 {
|
||||||
|
C.tor_main_configuration_free(conf)
|
||||||
|
C.freeCharArray(charArray, C.int(len(args)))
|
||||||
|
return fmt.Errorf("Failed to set command line args, code: %v", int(code))
|
||||||
|
}
|
||||||
|
// Run it async
|
||||||
|
e.doneCh = make(chan int, 1)
|
||||||
|
go func() {
|
||||||
|
defer C.freeCharArray(charArray, C.int(len(args)))
|
||||||
|
defer C.tor_main_configuration_free(conf)
|
||||||
|
e.doneCh <- int(C.tor_run_main(conf))
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *embeddedProcess) Wait() error {
|
||||||
|
if e.doneCh == nil {
|
||||||
|
return fmt.Errorf("Not started")
|
||||||
|
}
|
||||||
|
ctx := e.ctx
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case code := <-e.doneCh:
|
||||||
|
if code == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Command completed with error exit code: %v", code)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ type Process interface {
|
||||||
// analagous to os/exec.Cmd.Start.
|
// analagous to os/exec.Cmd.Start.
|
||||||
Start() error
|
Start() error
|
||||||
// Wait waits for the Tor process to exit and returns error if it was not a
|
// Wait waits for the Tor process to exit and returns error if it was not a
|
||||||
// successful exit. It is analagous to os/exec.Cmd.Wait.
|
// successful exit. It is analagous to os/exec.Cmd.Wait.
|
||||||
Wait() error
|
Wait() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
tor/tor.go
16
tor/tor.go
|
@ -12,7 +12,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cretz/bine/control"
|
"github.com/cretz/bine/control"
|
||||||
"github.com/cretz/bine/process/embedded"
|
|
||||||
|
|
||||||
"github.com/cretz/bine/process"
|
"github.com/cretz/bine/process"
|
||||||
)
|
)
|
||||||
|
@ -53,12 +52,13 @@ type Tor struct {
|
||||||
// default instance with no fields set is the default used for Start.
|
// default instance with no fields set is the default used for Start.
|
||||||
type StartConf struct {
|
type StartConf struct {
|
||||||
// ExePath is the path to the Tor executable. If it is not present, "tor" is
|
// ExePath is the path to the Tor executable. If it is not present, "tor" is
|
||||||
// used either locally or on the PATH.
|
// used either locally or on the PATH. This is ignored if ProcessCreator is
|
||||||
|
// set.
|
||||||
ExePath string
|
ExePath string
|
||||||
|
|
||||||
// Embedded is true if Tor is statically compiled. If true, ExePath is
|
// ProcessCreator is the override to use a specific process creator. If set,
|
||||||
// ignored.
|
// ExePath is ignored.
|
||||||
Embedded bool
|
ProcessCreator process.Creator
|
||||||
|
|
||||||
// ControlPort is the port to use for the Tor controller. If it is 0, Tor
|
// ControlPort is the port to use for the Tor controller. If it is 0, Tor
|
||||||
// picks a port for use.
|
// picks a port for use.
|
||||||
|
@ -159,10 +159,8 @@ func Start(ctx context.Context, conf *StartConf) (*Tor, error) {
|
||||||
|
|
||||||
func (t *Tor) startProcess(ctx context.Context, conf *StartConf) error {
|
func (t *Tor) startProcess(ctx context.Context, conf *StartConf) error {
|
||||||
// Get the creator
|
// Get the creator
|
||||||
var creator process.Creator
|
creator := conf.ProcessCreator
|
||||||
if conf.Embedded {
|
if creator == nil {
|
||||||
creator = embedded.NewCreator()
|
|
||||||
} else {
|
|
||||||
torPath := conf.ExePath
|
torPath := conf.ExePath
|
||||||
if torPath == "" {
|
if torPath == "" {
|
||||||
torPath = "tor"
|
torPath = "tor"
|
||||||
|
|
Loading…
Reference in New Issue