torsvc: added new type that multiplexes torsvc and net packages

This commit adds the `lnnet` package which contains an
implementation of the newly created LightningNet interface which
multiplexes the Dial and DNS-related functions to use net
by default and torsvc if a flag is specified. This modularization
makes for cleaner code.
This commit is contained in:
nsa 2017-10-25 15:06:26 -04:00 committed by Olaoluwa Osuntokun
parent 8c482f2be7
commit 698df2ac16
8 changed files with 98 additions and 111 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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

13
torsvc/interface.go Normal file
View File

@ -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)
}

58
torsvc/net.go Normal file
View File

@ -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)
}

View File

@ -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)