make local port selection deterministic and detach from the control port to improve performane

This commit is contained in:
erinn 2018-10-08 20:14:47 -07:00
parent 85d80d893c
commit 23e043ad93
3 changed files with 30 additions and 11 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
examples/basic/basic
examples/listener/listener
examples/dialer/dialer
.idea/*

View File

@ -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

View File

@ -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