mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 18:10:34 +01:00
8c482f2be7
This commit adds a new interface named NetInterface and two implementations of it: RegularNet & TorProxyNet. These two structs are used in config.go in an attempt to clean up the code and abstract away the dialer and DNS functions.
163 lines
4.3 KiB
Go
163 lines
4.3 KiB
Go
package torsvc
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
|
|
"github.com/btcsuite/go-socks/socks"
|
|
"github.com/miekg/dns"
|
|
"github.com/roasbeef/btcd/connmgr"
|
|
"golang.org/x/net/proxy"
|
|
)
|
|
|
|
const (
|
|
localhost = "127.0.0.1"
|
|
)
|
|
|
|
var (
|
|
// DNS Message Response Codes, see
|
|
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
|
|
dnsCodes = map[int]string{
|
|
0: "No Error",
|
|
1: "Format Error",
|
|
2: "Server Failure",
|
|
3: "Non-Existent Domain",
|
|
4: "Not Implemented",
|
|
5: "Query Refused",
|
|
6: "Name Exists when it should not",
|
|
7: "RR Set Exists when it should not",
|
|
8: "RR Set that should exist does not",
|
|
9: "Server Not Authoritative for zone",
|
|
10: "Name not contained in zone",
|
|
// Left out 16: "Bad OPT Version" because of duplicate keys and
|
|
// because miekg/dns does not use this message response code.
|
|
16: "TSIG Signature Failure",
|
|
17: "Key not recognized",
|
|
18: "Signature out of time window",
|
|
19: "Bad TKEY Mode",
|
|
20: "Duplicate key name",
|
|
21: "Algorithm not supported",
|
|
22: "Bad Truncation",
|
|
23: "Bad/missing Server Cookie",
|
|
}
|
|
)
|
|
|
|
// TorDial returns a connection to a remote peer via Tor's socks proxy. Only
|
|
// TCP is supported over Tor.
|
|
func TorDial(address, socksPort string) (net.Conn, error) {
|
|
p := &socks.Proxy{Addr: localhost + ":" + socksPort}
|
|
return p.Dial("tcp", address)
|
|
}
|
|
|
|
// TorLookupHost performs DNS resolution on a given hostname via Tor's
|
|
// native resolver. Only IPv4 addresses are returned.
|
|
func TorLookupHost(host, socksPort string) ([]string, error) {
|
|
ip, err := connmgr.TorLookupIP(host, localhost+":"+socksPort)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var addrs []string
|
|
// Only one IPv4 address is returned by the TorLookupIP function.
|
|
addrs = append(addrs, ip[0].String())
|
|
return addrs, nil
|
|
}
|
|
|
|
// TorLookupSRV uses Tor's socks proxy to route DNS SRV queries. Tor does not
|
|
// natively support SRV queries so we must route all SRV queries THROUGH the
|
|
// Tor proxy and connect directly to a DNS server and query it.
|
|
// NOTE: TorLookupSRV uses golang's proxy package since go-socks will cause
|
|
// the SRV request to hang.
|
|
func TorLookupSRV(service, proto, name, socksPort, dnsServer string) (string,
|
|
[]*net.SRV, error) {
|
|
// _service._proto.name as described in RFC#2782.
|
|
host := "_" + service + "._" + proto + "." + name + "."
|
|
|
|
// Set up golang's proxy dialer - Tor's socks proxy doesn't support
|
|
// authentication.
|
|
dialer, err := proxy.SOCKS5(
|
|
"tcp",
|
|
localhost+":"+socksPort,
|
|
nil,
|
|
proxy.Direct,
|
|
)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
// Dial dnsServer via Tor. dnsServer must have TCP resolution enabled
|
|
// for the port we are dialing.
|
|
conn, err := dialer.Dial("tcp", dnsServer)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
// Construct the actual SRV request.
|
|
msg := new(dns.Msg)
|
|
msg.SetQuestion(host, dns.TypeSRV)
|
|
msg.RecursionDesired = true
|
|
|
|
dnsConn := &dns.Conn{Conn: conn}
|
|
defer dnsConn.Close()
|
|
|
|
// Write the SRV request.
|
|
dnsConn.WriteMsg(msg)
|
|
|
|
// Read the response.
|
|
resp, err := dnsConn.ReadMsg()
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
|
|
// If the message response code was not the success code, fail.
|
|
if resp.Rcode != dns.RcodeSuccess {
|
|
return "", nil, fmt.Errorf("Unsuccessful SRV request, "+
|
|
"received: %s", dnsCodes[resp.Rcode])
|
|
}
|
|
|
|
// Retrieve the RR(s) of the Answer section.
|
|
var rrs []*net.SRV
|
|
for _, rr := range resp.Answer {
|
|
srv := rr.(*dns.SRV)
|
|
rrs = append(rrs, &net.SRV{
|
|
Target: srv.Target,
|
|
Port: srv.Port,
|
|
Priority: srv.Priority,
|
|
Weight: srv.Weight,
|
|
})
|
|
}
|
|
|
|
return "", rrs, nil
|
|
}
|
|
|
|
// TorResolveTCP uses Tor's proxy to resolve TCP addresses instead of the
|
|
// system resolver that ResolveTCPAddr and related functions use. This resolver
|
|
// only queries DNS servers in the case that a hostname is passed in the
|
|
// address parameter. Only TCP resolution is supported.
|
|
func TorResolveTCP(address, socksPort string) (*net.TCPAddr, error) {
|
|
// Split host:port since the lookup function does not take a port.
|
|
host, port, err := net.SplitHostPort(address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Look up the host's IP address via Tor.
|
|
ip, err := TorLookupHost(host, socksPort)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Convert port to an int.
|
|
p, err := strconv.Atoi(port)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Return a *net.TCPAddr exactly like net.ResolveTCPAddr.
|
|
return &net.TCPAddr{
|
|
IP: net.ParseIP(ip[0]),
|
|
Port: p,
|
|
}, nil
|
|
}
|