From 5b732d901271447019bda87f8af8ee2a52cc7a32 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Fri, 6 Mar 2020 16:37:14 -0800 Subject: [PATCH] loopd: add SOCKS proxy config option to dial swap server over Tor This allows Loop users to further improve their privacy by not revealing their source IP address. Note that the identity of the lnd node behind Loop can still be revealed when performing a Loop In due to the swap server extending an off-chain HTLC to the user. Onion addresses don't yet exist for the swap servers, but they will be added at a later time. --- client.go | 6 +++--- loopd/config.go | 3 ++- loopd/daemon.go | 2 ++ loopd/utils.go | 2 +- swap_server_client.go | 27 +++++++++++++++++++++------ 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/client.go b/client.go index bf95ba2..78c142e 100644 --- a/client.go +++ b/client.go @@ -78,7 +78,7 @@ type Client struct { } // NewClient returns a new instance to initiate swaps with. -func NewClient(dbDir string, serverAddress string, insecure bool, +func NewClient(dbDir string, serverAddress, proxyAddress string, insecure bool, tlsPathServer string, lnd *lndclient.LndServices, maxLSATCost, maxLSATFee btcutil.Amount) (*Client, func(), error) { @@ -92,8 +92,8 @@ func NewClient(dbDir string, serverAddress string, insecure bool, } swapServerClient, err := newSwapServerClient( - serverAddress, insecure, tlsPathServer, lsatStore, lnd, - maxLSATCost, maxLSATFee, + serverAddress, proxyAddress, insecure, tlsPathServer, lsatStore, + lnd, maxLSATCost, maxLSATFee, ) if err != nil { return nil, nil, err diff --git a/loopd/config.go b/loopd/config.go index 9aa313b..c421c4b 100644 --- a/loopd/config.go +++ b/loopd/config.go @@ -45,7 +45,8 @@ type config struct { MaxLSATCost uint32 `long:"maxlsatcost" description:"Maximum cost in satoshis that loopd is going to pay for an LSAT token automatically. Does not include routing fees."` MaxLSATFee uint32 `long:"maxlsatfee" description:"Maximum routing fee in satoshis that we are willing to pay while paying for an LSAT token."` - Lnd *lndConfig `group:"lnd" namespace:"lnd"` + Lnd *lndConfig `group:"lnd" namespace:"lnd"` + Proxy string `long:"proxy" description:"The host:port of a SOCKS proxy through which all connections to the swap server will be established over."` View viewParameters `command:"view" alias:"v" description:"View all swaps in the database. This command can only be executed when loopd is not running."` } diff --git a/loopd/daemon.go b/loopd/daemon.go index 9ba8e76..919e27c 100644 --- a/loopd/daemon.go +++ b/loopd/daemon.go @@ -50,6 +50,8 @@ func daemon(config *config, lisCfg *listenerCfg) error { // If no swap server is specified, use the default addresses for mainnet // and testnet. if config.SwapServer == "" { + // TODO(wilmer): Use onion service addresses when proxy is + // active. switch config.Network { case "mainnet": config.SwapServer = mainnetServer diff --git a/loopd/utils.go b/loopd/utils.go index a03c477..146841e 100644 --- a/loopd/utils.go +++ b/loopd/utils.go @@ -19,7 +19,7 @@ func getClient(config *config, lnd *lndclient.LndServices) (*loop.Client, } swapClient, cleanUp, err := loop.NewClient( - storeDir, config.SwapServer, config.Insecure, + storeDir, config.SwapServer, config.Proxy, config.Insecure, config.TLSPathSwapSrv, lnd, btcutil.Amount(config.MaxLSATCost), btcutil.Amount(config.MaxLSATFee), ) diff --git a/swap_server_client.go b/swap_server_client.go index 38204a2..804e882 100644 --- a/swap_server_client.go +++ b/swap_server_client.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "net" "time" "github.com/btcsuite/btcd/btcec" @@ -15,6 +16,7 @@ import ( "github.com/lightninglabs/loop/lsat" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/routing/route" + "github.com/lightningnetwork/lnd/tor" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) @@ -52,8 +54,8 @@ type grpcSwapServerClient struct { var _ swapServerClient = (*grpcSwapServerClient)(nil) -func newSwapServerClient(address string, insecure bool, tlsPath string, - lsatStore lsat.Store, lnd *lndclient.LndServices, +func newSwapServerClient(address, proxyAddress string, insecure bool, + tlsPath string, lsatStore lsat.Store, lnd *lndclient.LndServices, maxLSATCost, maxLSATFee btcutil.Amount) (*grpcSwapServerClient, error) { // Create the server connection with the interceptor that will handle @@ -62,7 +64,7 @@ func newSwapServerClient(address string, insecure bool, tlsPath string, lnd, lsatStore, serverRPCTimeout, maxLSATCost, maxLSATFee, ) serverConn, err := getSwapServerConn( - address, insecure, tlsPath, clientInterceptor, + address, proxyAddress, insecure, tlsPath, clientInterceptor, ) if err != nil { return nil, err @@ -243,9 +245,11 @@ func (s *grpcSwapServerClient) Close() { s.conn.Close() } -// getSwapServerConn returns a connection to the swap server. -func getSwapServerConn(address string, insecure bool, tlsPath string, - interceptor *lsat.Interceptor) (*grpc.ClientConn, error) { +// getSwapServerConn returns a connection to the swap server. A non-empty +// proxyAddr indicates that a SOCKS proxy found at the address should be used to +// establish the connection. +func getSwapServerConn(address, proxyAddress string, insecure bool, + tlsPath string, interceptor *lsat.Interceptor) (*grpc.ClientConn, error) { // Create a dial options array. opts := []grpc.DialOption{grpc.WithUnaryInterceptor( @@ -273,6 +277,17 @@ func getSwapServerConn(address string, insecure bool, tlsPath string, opts = append(opts, grpc.WithTransportCredentials(creds)) } + // If a SOCKS proxy address was specified, then we should dial through + // it. + if proxyAddress != "" { + log.Infof("Proxying connection to %v over Tor SOCKS proxy %v", + address, proxyAddress) + torDialer := func(_ context.Context, addr string) (net.Conn, error) { + return tor.Dial(addr, proxyAddress, false) + } + opts = append(opts, grpc.WithContextDialer(torDialer)) + } + conn, err := grpc.Dial(address, opts...) if err != nil { return nil, fmt.Errorf("unable to connect to RPC server: %v",