diff --git a/config.go b/config.go index 2fd59518..c36f462b 100644 --- a/config.go +++ b/config.go @@ -20,6 +20,7 @@ import ( flags "github.com/jessevdk/go-flags" "github.com/lightningnetwork/lnd/brontide" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/torsvc" "github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcutil" ) @@ -161,7 +162,7 @@ type config struct { Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65535"` TorSocks string `long:"torsocks" description:"The port that Tor's exposed SOCKS5 proxy is listening on -- NOTE port must be between 1024 and 65535"` - TorDNS string `long:"tordns" description:"The DNS server that Tor will use for SRV queries"` + TorDNS string `long:"tordns" description:"The DNS server as IP:PORT that Tor will use for SRV queries - NOTE must have TCP resolution enabled"` DebugHTLC bool `long:"debughtlc" description:"Activate the debug htlc mode. With the debug HTLC mode, all payments sent use a pre-determined R-Hash. Additionally, all HTLCs sent to a node with the debug HTLC R-Hash are immediately settled in the next available state transition."` HodlHTLC bool `long:"hodlhtlc" description:"Activate the hodl HTLC mode. With hodl HTLC mode, all incoming HTLCs will be accepted by the receiving node, but no attempt will be made to settle the payment with the sender."` @@ -186,7 +187,7 @@ type config struct { Alias string `long:"alias" description:"The node alias. Used as a moniker by peers and intelligence services"` Color string `long:"color" description:"The color of the node in hex format (i.e. '#3399FF'). Used to customize node appearance in intelligence services"` - net NetInterface + net *torsvc.MultiNet } // loadConfig initializes and parses the config using a config file and command @@ -296,7 +297,7 @@ func loadConfig() (*config, error) { // functions. When Tor's proxy is specified, the dial function is set to // the proxy specific dial function and the DNS resolution functions use // Tor. - cfg.net = &RegularNet{} + cfg.net = &torsvc.MultiNet{Tor: false} if cfg.TorSocks != "" && cfg.TorDNS != "" { // Validate Tor port number torport, err := strconv.Atoi(cfg.TorSocks) @@ -318,14 +319,20 @@ func loadConfig() (*config, error) { return nil, err } + cfg.net.TorDNS = cfg.TorDNS + cfg.net.TorSocks = cfg.TorSocks + // If we are using Tor, since we only want connections routed // through Tor, listening is disabled. cfg.DisableListen = true - cfg.net = &TorProxyNet{ - TorSocks: cfg.TorSocks, - TorDNS: cfg.TorDNS, - } + } else if cfg.TorSocks != "" || cfg.TorDNS != "" { + // Both TorSocks and TorDNS must be set. + str := "%s: Both the torsocks and the tordns flags must be set" + + "to properly route connections and avoid DNS leaks while" + + "using Tor" + err := fmt.Errorf(str, funcName) + return nil, err } switch { diff --git a/fundingmanager.go b/fundingmanager.go index 3b812e63..a07c1cff 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -26,6 +26,7 @@ import ( "github.com/roasbeef/btcd/chaincfg/chainhash" "github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcutil" + "net" ) const ( @@ -846,7 +847,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) { chainHash := chainhash.Hash(msg.ChainHash) reservation, err := f.cfg.Wallet.InitChannelReservation(amt, 0, msg.PushAmount, btcutil.Amount(msg.FeePerKiloWeight), 0, - fmsg.peerAddress.IdentityKey, fmsg.peerAddress.Address, + fmsg.peerAddress.IdentityKey, fmsg.peerAddress.Address.(*net.TCPAddr), &chainHash, msg.ChannelFlags) if err != nil { fndgLog.Errorf("Unable to initialize reservation: %v", err) @@ -2333,7 +2334,7 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { // request will fail, and be aborted. reservation, err := f.cfg.Wallet.InitChannelReservation(capacity, localAmt, msg.pushAmt, commitFeePerKw, msg.fundingFeePerWeight, - peerKey, msg.peerAddress.Address, &msg.chainHash, channelFlags) + peerKey, msg.peerAddress.Address.(*net.TCPAddr), &msg.chainHash, channelFlags) if err != nil { msg.err <- err return diff --git a/lnwire/netaddress.go b/lnwire/netaddress.go index 394cb032..9d88fb8f 100644 --- a/lnwire/netaddress.go +++ b/lnwire/netaddress.go @@ -22,8 +22,9 @@ type NetAddress struct { // the node. IdentityKey *btcec.PublicKey - // Address is is the IP address and port of the node. - Address *net.TCPAddr + // Address is is the IP address and port of the node. This is left + // general so that multiple implementations can be used. + Address net.Addr // ChainNet is the Bitcoin network this node is associated with. // TODO(roasbeef): make a slice in the future for multi-chain diff --git a/networking.go b/networking.go deleted file mode 100644 index 3f5e6e03..00000000 --- a/networking.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "net" - - "github.com/lightningnetwork/lnd/torsvc" -) - -// NetInterface is an interface housing a Dial function and several DNS functions. -type NetInterface interface { - Dial(string, string) (net.Conn, error) - LookupHost(string) ([]string, error) - LookupSRV(string, string, string) (string, []*net.SRV, error) - ResolveTCPAddr(string, string) (*net.TCPAddr, error) -} - -// RegularNet is an implementation of NetInterface that uses the net package -// for everything. -type RegularNet struct{} - -// TorProxyNet is an implementation of NetInterface that uses the torsvc module. -type TorProxyNet struct { - TorSocks string - TorDNS string -} - -// A compile time check to ensure RegularNet implements the NetInterface -// interface. -var _ NetInterface = (*RegularNet)(nil) - -// A compile time check to ensure TorProxyNet implements the NetInterface -// interface. -var _ NetInterface = (*TorProxyNet)(nil) - -// Dial is a wrapper of net.Dial -func (r *RegularNet) Dial(network, address string) (net.Conn, error) { - return net.Dial(network, address) -} - -// LookupHost is a wrapper of net.LookupHost -func (r *RegularNet) LookupHost(host string) ([]string, error) { - return net.LookupHost(host) -} - -// LookupSRV is a wrapper of net.LookupSRV -func (r *RegularNet) LookupSRV(service, proto, name string) (string, []*net.SRV, - error) { - return net.LookupSRV(service, proto, name) -} - -// ResolveTCPAddr is a wrapper of net.ResolveTCPAddr -func (r *RegularNet) ResolveTCPAddr(network, address string) (*net.TCPAddr, error) { - return net.ResolveTCPAddr(network, address) -} - -// Dial is a wrapper of torsvc.TorDial -func (t *TorProxyNet) Dial(network, address string) (net.Conn, error) { - return torsvc.TorDial(address, t.TorSocks) -} - -// LookupHost is a wrapper of torsvc.TorLookupHost -func (t *TorProxyNet) LookupHost(host string) ([]string, error) { - return torsvc.TorLookupHost(host, t.TorSocks) -} - -// LookupSRV is a wrapper of torsvc.TorLookupSRV -func (t *TorProxyNet) LookupSRV(service, proto, name string) (string, []*net.SRV, - error) { - return torsvc.TorLookupSRV(service, proto, name, t.TorSocks, t.TorDNS) -} - -// ResolveTCPAddr is a wrapper of torsvc.TorResolveTCP -func (t *TorProxyNet) ResolveTCPAddr(network, address string) (*net.TCPAddr, - error) { - return torsvc.TorResolveTCP(address, t.TorSocks) -} diff --git a/server.go b/server.go index 2aca4a65..cfacf5ee 100644 --- a/server.go +++ b/server.go @@ -13,7 +13,6 @@ import ( "time" "github.com/boltdb/bolt" - "github.com/btcsuite/go-socks/socks" "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/autopilot" "github.com/lightningnetwork/lnd/brontide" @@ -214,7 +213,7 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl, }) // If external IP addresses have been specified, add those to the list - // of this server's addresses. We need to use the general lndResolveTCP + // of this server's addresses. We need to use the cfg.net.ResolveTCPAddr // function in case we wish to resolve hosts over Tor since domains // CAN be passed into the ExternalIPs configuration option. selfAddrs := make([]net.Addr, 0, len(cfg.ExternalIPs)) @@ -1277,25 +1276,10 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq, inbound bool) { brontideConn := conn.(*brontide.Conn) - var peerAddr *lnwire.NetAddress - if _, ok := cfg.net.(*RegularNet); ok { - peerAddr = &lnwire.NetAddress{ - IdentityKey: brontideConn.RemotePub(), - Address: conn.RemoteAddr().(*net.TCPAddr), - ChainNet: activeNetParams.Net, - } - } else { - // We are connected to a Tor SOCKS5 proxy, extract our - // connection information. - proxiedAddr := conn.RemoteAddr().(*socks.ProxiedAddr) - peerAddr = &lnwire.NetAddress{ - IdentityKey: brontideConn.RemotePub(), - Address: &net.TCPAddr{ - IP: net.ParseIP(proxiedAddr.Host), - Port: proxiedAddr.Port, - }, - ChainNet: activeNetParams.Net, - } + peerAddr := &lnwire.NetAddress{ + IdentityKey: brontideConn.RemotePub(), + Address: conn.RemoteAddr(), + ChainNet: activeNetParams.Net, } // With the brontide connection established, we'll now craft the local diff --git a/torsvc/interface.go b/torsvc/interface.go new file mode 100644 index 00000000..6853c1ff --- /dev/null +++ b/torsvc/interface.go @@ -0,0 +1,13 @@ +package torsvc + +import ( + "net" +) + +// Net is an interface housing a Dial function and several DNS functions. +type Net interface { + Dial(string, string) (net.Conn, error) + LookupHost(string) ([]string, error) + LookupSRV(string, string, string) (string, []*net.SRV, error) + ResolveTCPAddr(string, string) (*net.TCPAddr, error) +} diff --git a/torsvc/net.go b/torsvc/net.go new file mode 100644 index 00000000..de528ce9 --- /dev/null +++ b/torsvc/net.go @@ -0,0 +1,58 @@ +package torsvc + +import ( + "fmt" + "net" +) + +// MultiNet is an implementation of the Net interface that abstracts away the +// "net" and "torsvc" functions from the user. This can be used to "switch" +// Tor functionality on/off based on the MultiNet.Tor boolean. MultiNet allows +// for callers to call net functions when necessary and torsvc functions when +// necessary +type MultiNet struct { + Tor bool + TorDNS string + TorSocks string +} + +// A compile time check to ensure MultiNet implements the Net interface. +var _ Net = (*MultiNet)(nil) + +// Dial uses either the "net" or "torsvc" dial function. +func (m *MultiNet) Dial(network, address string) (net.Conn, error) { + if m.Tor { + if network != "tcp" { + return nil, fmt.Errorf("Cannot dial non-tcp network via Tor") + } + return TorDial(address, m.TorSocks) + } + return net.Dial(network, address) +} + +// LookupHost uses either the "net" or "torsvc LookupHost function. +func (m *MultiNet) LookupHost(host string) ([]string, error) { + if m.Tor { + return TorLookupHost(host, m.TorSocks) + } + return net.LookupHost(host) +} + +// LookupSRV uses either the "net" or "torsvc" LookupSRV function. +func (m *MultiNet) LookupSRV(service, proto, name string) (string, []*net.SRV, error) { + if m.Tor { + return TorLookupSRV(service, proto, name, m.TorSocks, m.TorDNS) + } + return net.LookupSRV(service, proto, name) +} + +// ResolveTCPAddr uses either the "net" or "torsvc" ResolveTCP function. +func (m *MultiNet) ResolveTCPAddr(network, address string) (*net.TCPAddr, error) { + if m.Tor { + if network != "tcp" { + return nil, fmt.Errorf("Cannot dial non-tcp network via Tor") + } + return TorResolveTCP(address, m.TorSocks) + } + return net.ResolveTCPAddr(network, address) +} diff --git a/torsvc/torsvc.go b/torsvc/torsvc.go index 02f2ed39..7325000c 100644 --- a/torsvc/torsvc.go +++ b/torsvc/torsvc.go @@ -132,9 +132,8 @@ func TorLookupSRV(service, proto, name, socksPort, dnsServer string) (string, } // 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. +// system resolver that ResolveTCPAddr and related functions use. 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)