Skip to content

Commit e3285da

Browse files
committed
triggerforceclose: support Tor connections
1 parent 179773f commit e3285da

File tree

2 files changed

+52
-16
lines changed

2 files changed

+52
-16
lines changed

cmd/chantools/triggerforceclose.go

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"fmt"
5-
"net"
65
"strconv"
76
"strings"
87
"time"
@@ -16,12 +15,15 @@ import (
1615
"github.com/lightningnetwork/lnd/keychain"
1716
"github.com/lightningnetwork/lnd/lncfg"
1817
"github.com/lightningnetwork/lnd/lnwire"
18+
"github.com/lightningnetwork/lnd/peer"
1919
"github.com/lightningnetwork/lnd/tor"
2020
"github.com/spf13/cobra"
2121
)
2222

2323
var (
2424
dialTimeout = time.Minute
25+
26+
defaultTorDNSHostPort = "soa.nodes.lightning.directory:53"
2527
)
2628

2729
type triggerForceCloseCommand struct {
@@ -30,6 +32,8 @@ type triggerForceCloseCommand struct {
3032

3133
APIURL string
3234

35+
TorProxy string
36+
3337
rootKey *rootKey
3438
cmd *cobra.Command
3539
}
@@ -63,6 +67,10 @@ does not properly respond to a Data Loss Protection re-establish message).'`,
6367
&cc.APIURL, "apiurl", defaultAPIURL, "API URL to use (must "+
6468
"be esplora compatible)",
6569
)
70+
cc.cmd.Flags().StringVar(
71+
&cc.TorProxy, "torproxy", "", "SOCKS5 proxy to use for Tor "+
72+
"connections (to .onion addresses)",
73+
)
6674
cc.rootKey = newRootKey(cc.cmd, "deriving the identity key")
6775

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

97-
err = requestForceClose(c.Peer, pubKey, outPoint, identityECDH)
105+
err = requestForceClose(
106+
c.Peer, c.TorProxy, pubKey, outPoint, identityECDH,
107+
)
98108
if err != nil {
99109
return fmt.Errorf("error requesting force close: %w", err)
100110
}
@@ -134,34 +144,44 @@ func noiseDial(idKey keychain.SingleKeyECDH, lnAddr *lnwire.NetAddress,
134144
return brontide.Dial(idKey, lnAddr, timeout, netCfg.Dial)
135145
}
136146

137-
func requestForceClose(peerHost string, peerPubKey *btcec.PublicKey,
138-
channelPoint *wire.OutPoint, identity keychain.SingleKeyECDH) error {
147+
func connectPeer(peerHost, torProxy string, peerPubKey *btcec.PublicKey,
148+
identity keychain.SingleKeyECDH,
149+
dialTimeout time.Duration) (*peer.Brontide, error) {
150+
151+
var dialNet tor.Net = &tor.ClearNet{}
152+
if torProxy != "" {
153+
dialNet = &tor.ProxyNet{
154+
SOCKS: torProxy,
155+
DNS: defaultTorDNSHostPort,
156+
StreamIsolation: false,
157+
SkipProxyForClearNetTargets: true,
158+
}
159+
}
139160

161+
log.Debugf("Attempting to resolve peer address %v", peerHost)
140162
peerAddr, err := lncfg.ParseLNAddressString(
141-
peerHost, "9735", net.ResolveTCPAddr,
163+
peerHost, "9735", dialNet.ResolveTCPAddr,
142164
)
143165
if err != nil {
144-
return fmt.Errorf("error parsing peer address: %w", err)
166+
return nil, fmt.Errorf("error parsing peer address: %w", err)
145167
}
146168

147-
channelID := lnwire.NewChanIDFromOutPoint(channelPoint)
148-
149-
conn, err := noiseDial(
150-
identity, peerAddr, &tor.ClearNet{}, dialTimeout,
151-
)
169+
log.Debugf("Attempting to dial resolved peer address %v",
170+
peerAddr.String())
171+
conn, err := noiseDial(identity, peerAddr, dialNet, dialTimeout)
152172
if err != nil {
153-
return fmt.Errorf("error dialing peer: %w", err)
173+
return nil, fmt.Errorf("error dialing peer: %w", err)
154174
}
155175

156-
log.Infof("Attempting to connect to peer %x, dial timeout is %v",
157-
peerPubKey.SerializeCompressed(), dialTimeout)
176+
log.Infof("Attempting to establish p2p connection to peer %x, dial"+
177+
"timeout is %v", peerPubKey.SerializeCompressed(), dialTimeout)
158178
req := &connmgr.ConnReq{
159179
Addr: peerAddr,
160180
Permanent: false,
161181
}
162182
p, err := lnd.ConnectPeer(conn, req, chainParams, identity)
163183
if err != nil {
164-
return fmt.Errorf("error connecting to peer: %w", err)
184+
return nil, fmt.Errorf("error connecting to peer: %w", err)
165185
}
166186

167187
log.Infof("Connection established to peer %x",
@@ -171,10 +191,25 @@ func requestForceClose(peerHost string, peerPubKey *btcec.PublicKey,
171191
select {
172192
case <-p.ActiveSignal():
173193
case <-p.QuitSignal():
174-
return fmt.Errorf("peer %x disconnected",
194+
return nil, fmt.Errorf("peer %x disconnected",
175195
peerPubKey.SerializeCompressed())
176196
}
177197

198+
return p, nil
199+
}
200+
201+
func requestForceClose(peerHost, torProxy string, peerPubKey *btcec.PublicKey,
202+
channelPoint *wire.OutPoint, identity keychain.SingleKeyECDH) error {
203+
204+
p, err := connectPeer(
205+
peerHost, torProxy, peerPubKey, identity, dialTimeout,
206+
)
207+
if err != nil {
208+
return fmt.Errorf("error connecting to peer: %w", err)
209+
}
210+
211+
channelID := lnwire.NewChanIDFromOutPoint(channelPoint)
212+
178213
// Channel ID (32 byte) + u16 for the data length (which will be 0).
179214
data := make([]byte, 34)
180215
copy(data[:32], channelID[:])

doc/chantools_triggerforceclose.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ chantools triggerforceclose \
3030
-h, --help help for triggerforceclose
3131
--peer string remote peer address (<pubkey>@<host>[:<port>])
3232
--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
33+
--torproxy string SOCKS5 proxy to use for Tor connections (to .onion addresses)
3334
--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
3435
```
3536

0 commit comments

Comments
 (0)