diff --git a/.gitignore b/.gitignore index 2c540ff..4067306 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ examples/basic/basic examples/listener/listener examples/dialer/dialer +.idea/* diff --git a/cmd_onion.go b/cmd_onion.go index b616c02..ab11663 100644 --- a/cmd_onion.go +++ b/cmd_onion.go @@ -111,7 +111,7 @@ func (c *Conn) NewOnion(config *NewOnionConfig) (*OnionInfo, error) { } request := fmt.Sprintf("ADD_ONION %s:%s%s%s", hsKeyType, hsKeyStr, portStr, flagsStr) resp, err := c.Request(request) - if err != nil { + if err != nil && fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision" { return nil, err } @@ -153,11 +153,6 @@ func (c *Conn) NewOnion(config *NewOnionConfig) (*OnionInfo, error) { } } } - if serviceID == "" { - // This should *NEVER* happen, since the command succeded, and the spec - // guarantees that this will always be present. - return nil, newProtocolError("failed to determine service ID") - } oi := new(OnionInfo) oi.RawResponse = resp diff --git a/listener.go b/listener.go index 847b50f..2ced657 100644 --- a/listener.go +++ b/listener.go @@ -8,11 +8,15 @@ package bulb import ( - "crypto" + goodrand "crypto/rand" "fmt" - "net" + "net" "strconv" -) + "golang.org/x/crypto/sha3" + badrand "math/rand" + "encoding/binary" + "crypto" + ) type onionAddr struct { info *OnionInfo @@ -55,7 +59,13 @@ func (l *onionListener) Addr() net.Addr { // All of virtual ports specified in vports will be mapped to the port to which // the underlying TCP listener binded. PortSpecs in config will be ignored since // there is only one mapping for a vports set is possible. + +// [DEPRECATED] generate a random port to listen on (this is for backwards compatibility) func (c *Conn) NewListener(config *NewOnionConfig, vports ...uint16) (net.Listener, error) { + return c.RecoverListener(config, "", vports...) +} + +func (c *Conn) RecoverListener(config *NewOnionConfig, onion string, vports ...uint16) (net.Listener, error) { var cfg NewOnionConfig if config == nil { cfg = NewOnionConfig{ @@ -65,7 +75,20 @@ func (c *Conn) NewListener(config *NewOnionConfig, vports ...uint16) (net.Listen cfg = *config } - const loopbackAddr = "127.0.0.1:0" + var port int + if onion == "" { // generate a random port for ephemeral programs + seedbytes := make([]byte, 2) + goodrand.Read(seedbytes) + port = int(binary.LittleEndian.Uint16(seedbytes)) + if port < 1024 { // because why not ^ea + port = 1024 + int(seedbytes[0]) + int(seedbytes[1]) + } + } else { // generate a deterministic port for resumptive programs + seedbytes := sha3.New224().Sum([]byte(onion)) + seed := badrand.NewSource(int64(binary.LittleEndian.Uint64(seedbytes[:8]))) + port = badrand.New(seed).Intn(64511) + 1024 + } + var loopbackAddr = "127.0.0.1:" + strconv.Itoa(port) // Listen on the loopback interface. tcpListener, err := net.Listen("tcp4", loopbackAddr) @@ -79,7 +102,7 @@ func (c *Conn) NewListener(config *NewOnionConfig, vports ...uint16) (net.Listen } if len(vports) < 1 { - return nil, newProtocolError("no virual ports specified") + return nil, newProtocolError("no virtual ports specified") } targetPortStr := strconv.FormatUint((uint64)(tAddr.Port), 10) var portSpecs []OnionPortSpec