github.com/decred/dcrlnd@v0.7.6/tor/tor.go (about)

     1  package tor
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"encoding/hex"
     7  	"fmt"
     8  	"net"
     9  	"strconv"
    10  	"time"
    11  
    12  	"github.com/decred/dcrd/connmgr"
    13  	"github.com/miekg/dns"
    14  	"golang.org/x/net/proxy"
    15  )
    16  
    17  var (
    18  	// dnsCodes maps the DNS response codes to a friendly description. This
    19  	// does not include the BADVERS code because of duplicate keys and the
    20  	// underlying DNS (miekg/dns) package not using it. For more info, see
    21  	// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml.
    22  	dnsCodes = map[int]string{
    23  		0:  "no error",
    24  		1:  "format error",
    25  		2:  "server failure",
    26  		3:  "non-existent domain",
    27  		4:  "not implemented",
    28  		5:  "query refused",
    29  		6:  "name exists when it should not",
    30  		7:  "RR set exists when it should not",
    31  		8:  "RR set that should exist does not",
    32  		9:  "server not authoritative for zone",
    33  		10: "name not contained in zone",
    34  		16: "TSIG signature failure",
    35  		17: "key not recognized",
    36  		18: "signature out of time window",
    37  		19: "bad TKEY mode",
    38  		20: "duplicate key name",
    39  		21: "algorithm not supported",
    40  		22: "bad truncation",
    41  		23: "bad/missing server cookie",
    42  	}
    43  
    44  	// onionPrefixBytes is a special purpose IPv6 prefix to encode Onion v2
    45  	// addresses with. Because Neutrino uses the address manager of btcd
    46  	// which only understands net.IP addresses instead of net.Addr, we need
    47  	// to convert any .onion addresses into fake IPv6 addresses if we want
    48  	// to use a Tor hidden service as a Neutrino backend. This is the same
    49  	// range used by OnionCat, which is part part of the RFC4193 unique
    50  	// local IPv6 unicast address range.
    51  	onionPrefixBytes = []byte{0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43}
    52  )
    53  
    54  // proxyConn is a wrapper around net.Conn that allows us to expose the actual
    55  // remote address we're dialing, rather than the proxy's address.
    56  type proxyConn struct {
    57  	net.Conn
    58  	remoteAddr net.Addr
    59  }
    60  
    61  func (c *proxyConn) RemoteAddr() net.Addr {
    62  	return c.remoteAddr
    63  }
    64  
    65  // Dial is a wrapper over the non-exported dial function that returns a wrapper
    66  // around net.Conn in order to expose the actual remote address we're dialing,
    67  // rather than the proxy's address.
    68  func Dial(address, socksAddr string, streamIsolation bool,
    69  	skipProxyForClearNetTargets bool,
    70  	timeout time.Duration) (net.Conn, error) {
    71  
    72  	conn, err := dialProxy(
    73  		address, socksAddr, streamIsolation,
    74  		skipProxyForClearNetTargets, timeout,
    75  	)
    76  	if err != nil {
    77  		return nil, fmt.Errorf("dial proxy failed: %w", err)
    78  	}
    79  
    80  	// Now that the connection is established, we'll create our internal
    81  	// proxyConn that will serve in populating the correct remote address
    82  	// of the connection, rather than using the proxy's address.
    83  	remoteAddr, err := ParseAddr(address, socksAddr)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	return &proxyConn{
    89  		Conn:       conn,
    90  		remoteAddr: remoteAddr,
    91  	}, nil
    92  }
    93  
    94  // dialProxy establishes a connection to the address via the provided TOR SOCKS
    95  // proxy. Only TCP traffic may be routed via Tor.
    96  //
    97  // streamIsolation determines if we should force stream isolation for this new
    98  // connection. If enabled, new connections will use a fresh circuit, rather than
    99  // possibly re-using an existing circuit.
   100  //
   101  // skipProxyForClearNetTargets argument allows the dialer to directly connect
   102  // to the provided address if it does not represent an union service, skipping
   103  // the SOCKS proxy.
   104  func dialProxy(address, socksAddr string, streamIsolation bool,
   105  	skipProxyForClearNetTargets bool,
   106  	timeout time.Duration) (net.Conn, error) {
   107  
   108  	// If we were requested to force stream isolation for this connection,
   109  	// we'll populate the authentication credentials with random data as
   110  	// Tor will create a new circuit for each set of credentials.
   111  	var auth *proxy.Auth
   112  	if streamIsolation {
   113  		var b [16]byte
   114  		if _, err := rand.Read(b[:]); err != nil {
   115  			return nil, err
   116  		}
   117  
   118  		auth = &proxy.Auth{
   119  			User:     hex.EncodeToString(b[:8]),
   120  			Password: hex.EncodeToString(b[8:]),
   121  		}
   122  	}
   123  
   124  	clearDialer := &net.Dialer{Timeout: timeout}
   125  	if skipProxyForClearNetTargets {
   126  		host, _, err := net.SplitHostPort(address)
   127  		if err != nil {
   128  			return nil, err
   129  		}
   130  
   131  		// The SOCKS proxy is skipped if the target
   132  		// is not an union address.
   133  		if !IsOnionHost(host) {
   134  			return clearDialer.Dial("tcp", address)
   135  		}
   136  	}
   137  
   138  	// Establish the connection through Tor's SOCKS proxy.
   139  	dialer, err := proxy.SOCKS5("tcp", socksAddr, auth, clearDialer)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("establish sock proxy: %w", err)
   142  	}
   143  
   144  	return dialer.Dial("tcp", address)
   145  }
   146  
   147  // LookupHost performs DNS resolution on a given host via Tor's native resolver.
   148  // Only IPv4 addresses are returned.
   149  func LookupHost(host, socksAddr string) ([]string, error) {
   150  	ip, err := connmgr.TorLookupIP(host, socksAddr)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	// Only one IPv4 address is returned by the TorLookupIP function.
   156  	return []string{ip[0].String()}, nil
   157  }
   158  
   159  // LookupSRV uses Tor's SOCKS proxy to route DNS SRV queries. Tor does not
   160  // natively support SRV queries so we must route all SRV queries through the
   161  // proxy by connecting directly to a DNS server and querying it. The DNS server
   162  // must have TCP resolution enabled for the given port.
   163  func LookupSRV(service, proto, name, socksAddr,
   164  	dnsServer string, streamIsolation bool, skipProxyForClearNetTargets bool,
   165  	timeout time.Duration) (string, []*net.SRV, error) {
   166  
   167  	// Connect to the DNS server we'll be using to query SRV records.
   168  	conn, err := dialProxy(
   169  		dnsServer, socksAddr, streamIsolation,
   170  		skipProxyForClearNetTargets, timeout,
   171  	)
   172  	if err != nil {
   173  		return "", nil, err
   174  	}
   175  
   176  	dnsConn := &dns.Conn{Conn: conn}
   177  	defer dnsConn.Close()
   178  
   179  	// Once connected, we'll construct the SRV request for the host
   180  	// following the format _service._proto.name. as described in RFC #2782.
   181  	host := fmt.Sprintf("_%s._%s.%s.", service, proto, name)
   182  	msg := new(dns.Msg).SetQuestion(host, dns.TypeSRV)
   183  
   184  	// Send the request to the DNS server and read its response.
   185  	if err := dnsConn.WriteMsg(msg); err != nil {
   186  		return "", nil, err
   187  	}
   188  	resp, err := dnsConn.ReadMsg()
   189  	if err != nil {
   190  		return "", nil, err
   191  	}
   192  
   193  	// We'll fail if we were unable to query the DNS server for our record.
   194  	if resp.Rcode != dns.RcodeSuccess {
   195  		return "", nil, fmt.Errorf("unable to query for SRV records: "+
   196  			"%s", dnsCodes[resp.Rcode])
   197  	}
   198  
   199  	// Retrieve the RR(s) of the Answer section.
   200  	var rrs []*net.SRV
   201  	for _, rr := range resp.Answer {
   202  		srv := rr.(*dns.SRV)
   203  		rrs = append(rrs, &net.SRV{
   204  			Target:   srv.Target,
   205  			Port:     srv.Port,
   206  			Priority: srv.Priority,
   207  			Weight:   srv.Weight,
   208  		})
   209  	}
   210  
   211  	return "", rrs, nil
   212  }
   213  
   214  // ResolveTCPAddr uses Tor's proxy to resolve TCP addresses instead of the
   215  // standard system resolver provided in the `net` package.
   216  func ResolveTCPAddr(address, socksAddr string) (*net.TCPAddr, error) {
   217  	// Split host:port since the lookup function does not take a port.
   218  	host, port, err := net.SplitHostPort(address)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  
   223  	ip, err := LookupHost(host, socksAddr)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	p, err := strconv.Atoi(port)
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  
   233  	return &net.TCPAddr{
   234  		IP:   net.ParseIP(ip[0]),
   235  		Port: p,
   236  	}, nil
   237  }
   238  
   239  // ParseAddr parses an address from its string format to a net.Addr.
   240  func ParseAddr(address, socksAddr string) (net.Addr, error) {
   241  	host, portStr, err := net.SplitHostPort(address)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  
   246  	port, err := strconv.Atoi(portStr)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  
   251  	if IsOnionHost(host) {
   252  		return &OnionAddr{OnionService: host, Port: port}, nil
   253  	}
   254  
   255  	return ResolveTCPAddr(address, socksAddr)
   256  }
   257  
   258  // IsOnionHost determines whether a host is part of an onion address.
   259  func IsOnionHost(host string) bool {
   260  	// Note the starting index of the onion suffix in the host depending
   261  	// on its length.
   262  	var suffixIndex int
   263  	switch len(host) {
   264  	case V2Len:
   265  		suffixIndex = V2Len - OnionSuffixLen
   266  	case V3Len:
   267  		suffixIndex = V3Len - OnionSuffixLen
   268  	default:
   269  		return false
   270  	}
   271  
   272  	// Make sure the host ends with the ".onion" suffix.
   273  	if host[suffixIndex:] != OnionSuffix {
   274  		return false
   275  	}
   276  
   277  	// We'll now attempt to decode the host without its suffix, as the
   278  	// suffix includes invalid characters. This will tell us if the host is
   279  	// actually valid if successful.
   280  	host = host[:suffixIndex]
   281  	if _, err := Base32Encoding.DecodeString(host); err != nil {
   282  		return false
   283  	}
   284  
   285  	return true
   286  }
   287  
   288  // IsOnionFakeIP checks whether a given net.Addr is a fake IPv6 address that
   289  // encodes an Onion v2 address.
   290  func IsOnionFakeIP(addr net.Addr) bool {
   291  	_, err := FakeIPToOnionHost(addr)
   292  	return err == nil
   293  }
   294  
   295  // OnionHostToFakeIP encodes an Onion v2 address into a fake IPv6 address that
   296  // encodes the same information but can be used for libraries that operate on an
   297  // IP address base only, like btcd's address manager. For example, this will
   298  // turn the onion host ld47qlr6h2b7hrrf.onion into the ip6 address
   299  // fd87:d87e:eb43:58f9:f82e:3e3e:83f3:c625.
   300  func OnionHostToFakeIP(host string) (net.IP, error) {
   301  	if len(host) != V2Len {
   302  		return nil, fmt.Errorf("invalid onion v2 host: %v", host)
   303  	}
   304  
   305  	data, err := Base32Encoding.DecodeString(host[:V2Len-OnionSuffixLen])
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  
   310  	ip := make([]byte, len(onionPrefixBytes)+len(data))
   311  	copy(ip, onionPrefixBytes)
   312  	copy(ip[len(onionPrefixBytes):], data)
   313  	return ip, nil
   314  }
   315  
   316  // FakeIPToOnionHost turns a fake IPv6 address that encodes an Onion v2 address
   317  // back into its onion host address representation. For example, this will turn
   318  // the fake tcp6 address [fd87:d87e:eb43:58f9:f82e:3e3e:83f3:c625]:8333 back
   319  // into ld47qlr6h2b7hrrf.onion:8333.
   320  func FakeIPToOnionHost(fakeIP net.Addr) (net.Addr, error) {
   321  	tcpAddr, ok := fakeIP.(*net.TCPAddr)
   322  	if !ok {
   323  		return nil, fmt.Errorf("invalid fake onion IP address: %v",
   324  			fakeIP)
   325  	}
   326  
   327  	ip := tcpAddr.IP
   328  	if len(ip) != len(onionPrefixBytes)+V2DecodedLen {
   329  		return nil, fmt.Errorf("invalid fake onion IP address length: "+
   330  			"%v", fakeIP)
   331  	}
   332  
   333  	if !bytes.Equal(ip[:len(onionPrefixBytes)], onionPrefixBytes) {
   334  		return nil, fmt.Errorf("invalid fake onion IP address prefix: "+
   335  			"%v", fakeIP)
   336  	}
   337  
   338  	host := Base32Encoding.EncodeToString(ip[len(onionPrefixBytes):])
   339  	return &OnionAddr{
   340  		OnionService: host + ".onion",
   341  		Port:         tcpAddr.Port,
   342  	}, nil
   343  }