From 8ba66edb0c80993bd098e3f29859eea5b4a70308 Mon Sep 17 00:00:00 2001 From: Chad Retz Date: Fri, 21 Sep 2018 12:03:30 -0500 Subject: [PATCH] More explicit embedded socket support for issue #13 --- process/embedded/tor-0.3.3/process.go | 4 ++ .../embedded/tor-0.3.5/embeddedtest/main.go | 45 +++++++++++++--- process/embedded/tor-0.3.5/process.go | 52 ++++++++----------- process/process.go | 21 +++++++- 4 files changed, 86 insertions(+), 36 deletions(-) diff --git a/process/embedded/tor-0.3.3/process.go b/process/embedded/tor-0.3.3/process.go index 698999d..b0c4f0e 100644 --- a/process/embedded/tor-0.3.3/process.go +++ b/process/embedded/tor-0.3.3/process.go @@ -110,3 +110,7 @@ func (e *embeddedProcess) Wait() error { return fmt.Errorf("Command completed with error exit code: %v", code) } } + +func (e *embeddedProcess) EmbeddedControlConn() (net.Conn, error) { + return nil, process.ErrControlConnUnsupported +} \ No newline at end of file diff --git a/process/embedded/tor-0.3.5/embeddedtest/main.go b/process/embedded/tor-0.3.5/embeddedtest/main.go index 8e24f06..9ffa77b 100644 --- a/process/embedded/tor-0.3.5/embeddedtest/main.go +++ b/process/embedded/tor-0.3.5/embeddedtest/main.go @@ -4,26 +4,59 @@ import ( "context" "fmt" "log" + "net/textproto" "os" + "github.com/cretz/bine/control" tor035 "github.com/cretz/bine/process/embedded/tor-0.3.5" ) -// Simply calls Tor will the same parameters +// Simply calls Tor will the same parameters, unless "embedconn" is the arg func main() { - if err := runTor(os.Args[1:]...); err != nil { + fmt.Printf("Provider version: %v\n", tor035.ProviderVersion()) + var err error + if len(os.Args) == 2 && os.Args[1] == "embedconn" { + fmt.Println("Testing embedded conn") + err = testEmbedConn() + } else { + fmt.Println("Running Tor with given args") + err = runTor(os.Args[1:]...) + } + if err != nil { log.Fatal(err) } } func runTor(args ...string) error { - creator := tor035.NewProcessCreator() - creator.SetupControlSocket = true - process, err := creator.New(context.Background(), args...) + process, err := tor035.NewCreator().New(context.Background(), args...) if err == nil { - fmt.Printf("Socket pointer: %v\n", tor035.ProcessControlSocket(process)) process.Start() err = process.Wait() } return err } + +func testEmbedConn() error { + process, err := tor035.NewCreator().New(context.Background()) + if err != nil { + return fmt.Errorf("Failed creating process: %v", err) + } + // Try to create an embedded conn + embedConn, err := process.EmbeddedControlConn() + if err != nil { + return fmt.Errorf("Failed creating embedded control conn: %v", err) + } + if err = process.Start(); err != nil { + return fmt.Errorf("Failed starting process: %v", err) + } + controlConn := control.NewConn(textproto.NewConn(embedConn)) + info, err := controlConn.GetInfo("version") + if err != nil { + return fmt.Errorf("Failed getting version: %v", err) + } + fmt.Printf("Got info, %v: %v\n", info[0].Key, info[0].Val) + if err = process.Wait(); err != nil { + return fmt.Errorf("Failed waiting for process: %v", err) + } + return nil +} diff --git a/process/embedded/tor-0.3.5/process.go b/process/embedded/tor-0.3.5/process.go index 4f224ef..355f8e7 100644 --- a/process/embedded/tor-0.3.5/process.go +++ b/process/embedded/tor-0.3.5/process.go @@ -6,6 +6,8 @@ package tor035 import ( "context" "fmt" + "net" + "os" "github.com/cretz/bine/process" ) @@ -50,12 +52,7 @@ static void freeCharArray(char **a, int size) { */ import "C" -// ProcessCreator implements process.Creator -type ProcessCreator struct { - // If set to true, ProcessControlSocket will have a raw socket to - // communicate with Tor on. - SetupControlSocket bool -} +type embeddedCreator struct{} // ProviderVersion returns the Tor provider name and version exposed from the // Tor embedded API. @@ -63,32 +60,27 @@ func ProviderVersion() string { return C.GoString(C.tor_api_get_provider_version()) } -// NewProcessCreator creates a process.Creator for statically-linked Tor -// embedded in the binary. -func NewProcessCreator() *ProcessCreator { - return &ProcessCreator{} +// NewCreator creates a process.Creator for statically-linked Tor embedded in +// the binary. +func NewCreator() process.Creator { + return embeddedCreator{} } type embeddedProcess struct { - ctx context.Context - mainConf *C.struct_tor_main_configuration_t - controlSocket uintptr - args []string - doneCh chan int + ctx context.Context + mainConf *C.struct_tor_main_configuration_t + args []string + doneCh chan int } // New implements process.Creator.New -func (p *ProcessCreator) New(ctx context.Context, args ...string) (process.Process, error) { - ret := &embeddedProcess{ - ctx: ctx, +func (embeddedCreator) New(ctx context.Context, args ...string) (process.Process, error) { + return &embeddedProcess{ + ctx: ctx, + // TODO: mem leak if they never call Start; consider adding a Close() mainConf: C.tor_main_configuration_new(), args: args, - } - // If they want a control socket, this is where we add it - if p.SetupControlSocket { - ret.controlSocket = uintptr(C.tor_main_configuration_setup_control_socket(ret.mainConf)) - } - return ret, nil + }, nil } func (e *embeddedProcess) Start() error { @@ -136,9 +128,11 @@ func (e *embeddedProcess) Wait() error { } } -// ProcessControlSocket returns a non-zero value for a process created by a -// ProcessCreator with SetupControlSocket as true. Note, the value of this is -// invalid when Start returns. -func ProcessControlSocket(p process.Process) uintptr { - return p.(*embeddedProcess).controlSocket +func (e *embeddedProcess) EmbeddedControlConn() (net.Conn, error) { + file := os.NewFile(uintptr(C.tor_main_configuration_setup_control_socket(e.mainConf)), "") + conn, err := net.FileConn(file) + if err != nil { + err = fmt.Errorf("Unable to create conn from control socket: %v", err) + } + return conn, err } diff --git a/process/process.go b/process/process.go index 331c34b..a9b4d33 100644 --- a/process/process.go +++ b/process/process.go @@ -10,6 +10,7 @@ package process import ( "context" "fmt" + "net" "os" "os/exec" "strconv" @@ -26,6 +27,12 @@ type Process interface { // 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. Wait() error + // ControlConn is used for statically linked, embedded processes to create + // a controller connection. For non-embedded processes or Tor versions that + // don't support embedded control connections, ErrControlConnUnsupported is + // returned. Note, this should only be called once per process before + // Start, and the connection does not need to be closed. + EmbeddedControlConn() (net.Conn, error) } // Creator is the interface for process creation. @@ -43,11 +50,23 @@ func NewCreator(exePath string) Creator { return &exeProcessCreator{exePath} } +type exeProcess struct { + *exec.Cmd +} + func (e *exeProcessCreator) New(ctx context.Context, args ...string) (Process, error) { cmd := exec.CommandContext(ctx, e.exePath, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - return cmd, nil + return &exeProcess{cmd}, nil +} + +// ErrControlConnUnsupported is returned by Process.EmbeddedControlConn when +// it is unsupported. +var ErrControlConnUnsupported = fmt.Errorf("Control conn not supported") + +func (e *exeProcess) EmbeddedControlConn() (net.Conn, error) { + return nil, ErrControlConnUnsupported } // ControlPortFromFileContents reads a control port file that is written by Tor