summaryrefslogtreecommitdiff
path: root/vendor/github.com/cretz/bine/tor/dialer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/cretz/bine/tor/dialer.go')
-rw-r--r--vendor/github.com/cretz/bine/tor/dialer.go111
1 files changed, 111 insertions, 0 deletions
diff --git a/vendor/github.com/cretz/bine/tor/dialer.go b/vendor/github.com/cretz/bine/tor/dialer.go
new file mode 100644
index 0000000..9ef211e
--- /dev/null
+++ b/vendor/github.com/cretz/bine/tor/dialer.go
@@ -0,0 +1,111 @@
+package tor
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "strings"
+
+ "golang.org/x/net/proxy"
+)
+
+// Dialer is a wrapper around a proxy.Dialer for dialing connections.
+type Dialer struct {
+ proxy.Dialer
+}
+
+// DialConf is the configuration used for Dialer.
+type DialConf struct {
+ // ProxyAddress is the address for the SOCKS5 proxy. If empty, it is looked
+ // up.
+ ProxyAddress string
+
+ // ProxyNetwork is the network for the SOCKS5 proxy. If ProxyAddress is
+ // empty, this value is ignored and overridden by what is looked up. If this
+ // is empty and ProxyAddress is not empty, it defaults to "tcp".
+ ProxyNetwork string
+
+ // ProxyAuth is the auth for the proxy. Since Tor's SOCKS5 proxy is
+ // unauthenticated, this is rarely needed. It can be used when
+ // IsolateSOCKSAuth is set to ensure separate circuits.
+ //
+ // This should not be confused with downstream SOCKS proxy authentication
+ // which is set via Tor values for Socks5ProxyUsername and
+ // Socks5ProxyPassword when Socks5Proxy is set.
+ ProxyAuth *proxy.Auth
+
+ // SkipEnableNetwork, if true, will skip the enable network step in Dialer.
+ SkipEnableNetwork bool
+
+ // Forward is the dialer to forward to. If nil, just uses normal net dialer.
+ Forward proxy.Dialer
+}
+
+// Dialer creates a new Dialer for the given configuration. Context can be nil.
+// If conf is nil, a default is used.
+func (t *Tor) Dialer(ctx context.Context, conf *DialConf) (*Dialer, error) {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ if conf == nil {
+ conf = &DialConf{}
+ }
+ // Enable the network if requested
+ if !conf.SkipEnableNetwork {
+ if err := t.EnableNetwork(ctx, true); err != nil {
+ return nil, err
+ }
+ }
+ // Lookup proxy address as needed
+ proxyNetwork := conf.ProxyNetwork
+ proxyAddress := conf.ProxyAddress
+ if proxyAddress == "" {
+ info, err := t.Control.GetInfo("net/listeners/socks")
+ if err != nil {
+ return nil, err
+ }
+ if len(info) != 1 || info[0].Key != "net/listeners/socks" {
+ return nil, fmt.Errorf("Unable to get socks proxy address")
+ }
+ proxyAddress = info[0].Val
+ if strings.HasPrefix(proxyAddress, "unix:") {
+ proxyAddress = proxyAddress[5:]
+ proxyNetwork = "unix"
+ } else {
+ proxyNetwork = "tcp"
+ }
+ } else if proxyNetwork == "" {
+ proxyNetwork = "tcp"
+ }
+
+ dialer, err := proxy.SOCKS5(proxyNetwork, proxyAddress, conf.ProxyAuth, conf.Forward)
+ if err != nil {
+ return nil, err
+ }
+ return &Dialer{dialer}, nil
+}
+
+// DialContext is the equivalent of net.DialContext.
+//
+// TODO: Remove when https://github.com/golang/go/issues/17759 is released.
+func (d *Dialer) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) {
+ errCh := make(chan error, 1)
+ connCh := make(chan net.Conn, 1)
+ go func() {
+ if conn, err := d.Dial(network, addr); err != nil {
+ errCh <- err
+ } else if ctx.Err() != nil {
+ conn.Close()
+ } else {
+ connCh <- conn
+ }
+ }()
+ select {
+ case err := <-errCh:
+ return nil, err
+ case conn := <-connCh:
+ return conn, nil
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+}