Skip to content

Commit

Permalink
triggerforceclose: support Tor connections
Browse files Browse the repository at this point in the history
  • Loading branch information
guggero committed Apr 29, 2024
1 parent 179773f commit e3285da
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 16 deletions.
67 changes: 51 additions & 16 deletions cmd/chantools/triggerforceclose.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"fmt"
"net"
"strconv"
"strings"
"time"
Expand All @@ -16,12 +15,15 @@ import (
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/peer"
"github.com/lightningnetwork/lnd/tor"
"github.com/spf13/cobra"
)

var (
dialTimeout = time.Minute

defaultTorDNSHostPort = "soa.nodes.lightning.directory:53"
)

type triggerForceCloseCommand struct {
Expand All @@ -30,6 +32,8 @@ type triggerForceCloseCommand struct {

APIURL string

TorProxy string

rootKey *rootKey
cmd *cobra.Command
}
Expand Down Expand Up @@ -63,6 +67,10 @@ does not properly respond to a Data Loss Protection re-establish message).'`,
&cc.APIURL, "apiurl", defaultAPIURL, "API URL to use (must "+
"be esplora compatible)",
)
cc.cmd.Flags().StringVar(
&cc.TorProxy, "torproxy", "", "SOCKS5 proxy to use for Tor "+
"connections (to .onion addresses)",
)
cc.rootKey = newRootKey(cc.cmd, "deriving the identity key")

return cc.cmd
Expand Down Expand Up @@ -94,7 +102,9 @@ func (c *triggerForceCloseCommand) Execute(_ *cobra.Command, _ []string) error {
return fmt.Errorf("error parsing channel point: %w", err)
}

err = requestForceClose(c.Peer, pubKey, outPoint, identityECDH)
err = requestForceClose(
c.Peer, c.TorProxy, pubKey, outPoint, identityECDH,
)
if err != nil {
return fmt.Errorf("error requesting force close: %w", err)
}
Expand Down Expand Up @@ -134,34 +144,44 @@ func noiseDial(idKey keychain.SingleKeyECDH, lnAddr *lnwire.NetAddress,
return brontide.Dial(idKey, lnAddr, timeout, netCfg.Dial)
}

func requestForceClose(peerHost string, peerPubKey *btcec.PublicKey,
channelPoint *wire.OutPoint, identity keychain.SingleKeyECDH) error {
func connectPeer(peerHost, torProxy string, peerPubKey *btcec.PublicKey,
identity keychain.SingleKeyECDH,
dialTimeout time.Duration) (*peer.Brontide, error) {

var dialNet tor.Net = &tor.ClearNet{}
if torProxy != "" {
dialNet = &tor.ProxyNet{
SOCKS: torProxy,
DNS: defaultTorDNSHostPort,
StreamIsolation: false,
SkipProxyForClearNetTargets: true,
}
}

log.Debugf("Attempting to resolve peer address %v", peerHost)
peerAddr, err := lncfg.ParseLNAddressString(
peerHost, "9735", net.ResolveTCPAddr,
peerHost, "9735", dialNet.ResolveTCPAddr,
)
if err != nil {
return fmt.Errorf("error parsing peer address: %w", err)
return nil, fmt.Errorf("error parsing peer address: %w", err)
}

channelID := lnwire.NewChanIDFromOutPoint(channelPoint)

conn, err := noiseDial(
identity, peerAddr, &tor.ClearNet{}, dialTimeout,
)
log.Debugf("Attempting to dial resolved peer address %v",
peerAddr.String())
conn, err := noiseDial(identity, peerAddr, dialNet, dialTimeout)
if err != nil {
return fmt.Errorf("error dialing peer: %w", err)
return nil, fmt.Errorf("error dialing peer: %w", err)
}

log.Infof("Attempting to connect to peer %x, dial timeout is %v",
peerPubKey.SerializeCompressed(), dialTimeout)
log.Infof("Attempting to establish p2p connection to peer %x, dial"+
"timeout is %v", peerPubKey.SerializeCompressed(), dialTimeout)
req := &connmgr.ConnReq{
Addr: peerAddr,
Permanent: false,
}
p, err := lnd.ConnectPeer(conn, req, chainParams, identity)
if err != nil {
return fmt.Errorf("error connecting to peer: %w", err)
return nil, fmt.Errorf("error connecting to peer: %w", err)
}

log.Infof("Connection established to peer %x",
Expand All @@ -171,10 +191,25 @@ func requestForceClose(peerHost string, peerPubKey *btcec.PublicKey,
select {
case <-p.ActiveSignal():
case <-p.QuitSignal():
return fmt.Errorf("peer %x disconnected",
return nil, fmt.Errorf("peer %x disconnected",
peerPubKey.SerializeCompressed())
}

return p, nil
}

func requestForceClose(peerHost, torProxy string, peerPubKey *btcec.PublicKey,
channelPoint *wire.OutPoint, identity keychain.SingleKeyECDH) error {

p, err := connectPeer(
peerHost, torProxy, peerPubKey, identity, dialTimeout,
)
if err != nil {
return fmt.Errorf("error connecting to peer: %w", err)
}

channelID := lnwire.NewChanIDFromOutPoint(channelPoint)

// Channel ID (32 byte) + u16 for the data length (which will be 0).
data := make([]byte, 34)
copy(data[:32], channelID[:])
Expand Down
1 change: 1 addition & 0 deletions doc/chantools_triggerforceclose.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ chantools triggerforceclose \
-h, --help help for triggerforceclose
--peer string remote peer address (<pubkey>@<host>[:<port>])
--rootkey string BIP32 HD root key of the wallet to use for deriving the identity key; leave empty to prompt for lnd 24 word aezeed
--torproxy string SOCKS5 proxy to use for Tor connections (to .onion addresses)
--walletdb string read the seed/master root key to use fro deriving the identity key from an lnd wallet.db file instead of asking for a seed or providing the --rootkey flag
```

Expand Down

0 comments on commit e3285da

Please sign in to comment.