You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.1 KiB
132 lines
4.1 KiB
package tor |
|
|
|
import ( |
|
"context" |
|
"errors" |
|
"net" |
|
"time" |
|
) |
|
|
|
// TODO: this interface and its implementations should ideally be moved |
|
// elsewhere as they are not Tor-specific. |
|
|
|
const ( |
|
// DefaultConnTimeout is the maximum amount of time a dial will wait for |
|
// a connect to complete. |
|
DefaultConnTimeout time.Duration = time.Second * 120 |
|
) |
|
|
|
// DialFunc is a type defines the signature of a dialer used by our Net |
|
// interface. |
|
type DialFunc func(net, addr string, timeout time.Duration) (net.Conn, error) |
|
|
|
// Net is an interface housing a Dial function and several DNS functions that |
|
// allows us to abstract the implementations of these functions over different |
|
// networks, e.g. clearnet, Tor net, etc. |
|
type Net interface { |
|
// Dial connects to the address on the named network. |
|
Dial(network, address string, timeout time.Duration) (net.Conn, error) |
|
|
|
// LookupHost performs DNS resolution on a given host and returns its |
|
// addresses. |
|
LookupHost(host string) ([]string, error) |
|
|
|
// LookupSRV tries to resolve an SRV query of the given service, |
|
// protocol, and domain name. |
|
LookupSRV(service, proto, name string, |
|
timeout time.Duration) (string, []*net.SRV, error) |
|
|
|
// ResolveTCPAddr resolves TCP addresses. |
|
ResolveTCPAddr(network, address string) (*net.TCPAddr, error) |
|
} |
|
|
|
// ClearNet is an implementation of the Net interface that defines behaviour |
|
// for regular network connections. |
|
type ClearNet struct{} |
|
|
|
// Dial on the regular network uses net.Dial |
|
func (r *ClearNet) Dial( |
|
network, address string, timeout time.Duration) (net.Conn, error) { |
|
|
|
return net.DialTimeout(network, address, timeout) |
|
} |
|
|
|
// LookupHost for regular network uses the net.LookupHost function |
|
func (r *ClearNet) LookupHost(host string) ([]string, error) { |
|
return net.LookupHost(host) |
|
} |
|
|
|
// LookupSRV for regular network uses net.LookupSRV function |
|
func (r *ClearNet) LookupSRV(service, proto, name string, |
|
timeout time.Duration) (string, []*net.SRV, error) { |
|
|
|
// Create a context with a timeout value. |
|
ctxt, cancel := context.WithTimeout(context.Background(), timeout) |
|
defer cancel() |
|
|
|
return net.DefaultResolver.LookupSRV(ctxt, service, proto, name) |
|
} |
|
|
|
// ResolveTCPAddr for regular network uses net.ResolveTCPAddr function |
|
func (r *ClearNet) ResolveTCPAddr(network, address string) (*net.TCPAddr, error) { |
|
return net.ResolveTCPAddr(network, address) |
|
} |
|
|
|
// ProxyNet is an implementation of the Net interface that defines behaviour |
|
// for Tor network connections. |
|
type ProxyNet struct { |
|
// SOCKS is the host:port which Tor's exposed SOCKS5 proxy is listening |
|
// on. |
|
SOCKS string |
|
|
|
// DNS is the host:port of the DNS server for Tor to use for SRV |
|
// queries. |
|
DNS string |
|
|
|
// StreamIsolation is a bool that determines if we should force the |
|
// creation of a new circuit for this connection. If true, then this |
|
// means that our traffic may be harder to correlate as each connection |
|
// will now use a distinct circuit. |
|
StreamIsolation bool |
|
} |
|
|
|
// Dial uses the Tor Dial function in order to establish connections through |
|
// Tor. Since Tor only supports TCP connections, only TCP networks are allowed. |
|
func (p *ProxyNet) Dial(network, address string, |
|
timeout time.Duration) (net.Conn, error) { |
|
|
|
switch network { |
|
case "tcp", "tcp4", "tcp6": |
|
default: |
|
return nil, errors.New("cannot dial non-tcp network via Tor") |
|
} |
|
return Dial(address, p.SOCKS, p.StreamIsolation, timeout) |
|
} |
|
|
|
// LookupHost uses the Tor LookupHost function in order to resolve hosts over |
|
// Tor. |
|
func (p *ProxyNet) LookupHost(host string) ([]string, error) { |
|
return LookupHost(host, p.SOCKS) |
|
} |
|
|
|
// LookupSRV uses the Tor LookupSRV function in order to resolve SRV DNS queries |
|
// over Tor. |
|
func (p *ProxyNet) LookupSRV(service, proto, |
|
name string, timeout time.Duration) (string, []*net.SRV, error) { |
|
|
|
return LookupSRV( |
|
service, proto, name, p.SOCKS, p.DNS, |
|
p.StreamIsolation, timeout, |
|
) |
|
} |
|
|
|
// ResolveTCPAddr uses the Tor ResolveTCPAddr function in order to resolve TCP |
|
// addresses over Tor. |
|
func (p *ProxyNet) ResolveTCPAddr(network, address string) (*net.TCPAddr, error) { |
|
switch network { |
|
case "tcp", "tcp4", "tcp6": |
|
default: |
|
return nil, errors.New("cannot dial non-tcp network via Tor") |
|
} |
|
return ResolveTCPAddr(address, p.SOCKS) |
|
}
|
|
|