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",