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 }