package server import ( "crypto/rsa" "log" "math/rand" "strconv" "time" "github.com/Yawning/bulb" "github.com/sycamoreone/orc/tor" ) // TorConfig is a wrapper struct for tor configuration. type TorConfig struct { DataDir string HashedControlPassword string ClearPassword string Timeout time.Duration } // StartTor starts a new instance of tor or doesn't with the reason why. func StartTor(cfg TorConfig) (*Tor, error) { tc := tor.NewConfig() tc.Set("DataDirectory", cfg.DataDir) tc.Set("HashedControlPassword", cfg.HashedControlPassword) tc.Set("SocksPort", "0") cp := rand.Intn(64512) tc.Set("ControlPort", cp) tc.Timeout = cfg.Timeout tcmd, err := tor.NewCmd(tc) if err != nil { return nil, err } err = tcmd.Start() if err != nil { return nil, err } log.Println("tor started, sleeping for a few seconds for it to settle...") time.Sleep(5 * time.Second) bc, err := bulb.Dial("tcp", "127.0.0.1:"+strconv.Itoa(cp)) if err != nil { return nil, err } err = bc.Authenticate(cfg.ClearPassword) if err != nil { return nil, err } t := &Tor{ tc: tc, tcmd: tcmd, bc: bc, } return t, nil } // Tor is a higher level wrapper to a child tor process type Tor struct { tc *tor.Config tcmd *tor.Cmd bc *bulb.Conn } // AddOnion adds an onion service to this machine with the given private key // (can be nil for an auto-generated key), virtual onion port and TCP destunation. func (t *Tor) AddOnion(pKey *rsa.PrivateKey, virtPort uint16, destination string) (*bulb.OnionInfo, error) { return t.bc.AddOnion([]bulb.OnionPortSpec{ { VirtPort: virtPort, Target: destination, }, }, pKey, true) }